Проверьте подпись DSA, созданную Java в C # - PullRequest
1 голос
/ 03 февраля 2011

Я знаю, что это тема с большим количеством существующих вопросов, но я не могу найти какие-либо существующие ответы, которые охватывают мой точный случай.

Мне нужно подписать строку (URL) в некотором коде Java идоставить строку вместе с подписью в программу на C #.

Я запускаю следующий Java-код один раз, чтобы сгенерировать пару ключей DSA:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);

KeyPair pair = keyGen.generateKeyPair();
PrivateKey priv = pair.getPrivate();
PublicKey pub = pair.getPublic();

/* save the private key in a file */
byte[] privkey = priv.getEncoded();
FileOutputStream privkeyfos = new FileOutputStream("key.priv");
privkeyfos.write(privkey);
privkeyfos.close();

/* save the public key in a file */
byte[] pubkey = pub.getEncoded();
FileOutputStream pubkeyfos = new FileOutputStream("key.public");
pubkeyfos.write(pubkey);
pubkeyfos.close();

Затем я использую следующий код для генерацииподпись.

public static String Sign(String keyPath, byte[] data)
{
  FileInputStream keyfis = new FileInputStream(new File(keyPath, "key.priv"));
  byte[] encKey = new byte[keyfis.available()];
  keyfis.read(encKey);
  keyfis.close();

  PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
  KeyFactory keyFactory = KeyFactory.getInstance("DSA");
  PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);

  Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");

  dsa.initSign(privKey);

  ByteArrayInputStream in = new ByteArrayInputStream(data);
  BufferedInputStream bufin = new BufferedInputStream(in);
  byte[] buffer = new byte[1024];
  int len;
  while ((len = bufin.read(buffer)) >= 0)
  {
    dsa.update(buffer, 0, len);
  }
  bufin.close();

  byte[] realSig = dsa.sign();

  return new String(Base64.encodeBase64(realSig), "UTF-8");
}

В моем коде C # у меня есть доступ к строке, закодированной Base64 подписи и файлу "key.public" с первого шага.

Может кто-нибудь предоставить блоккода, который объединяет эти элементы вместе с подходящей библиотекой, чтобы определить, была ли строка подделана?

1 Ответ

1 голос
/ 04 февраля 2011

Теперь я решил эту проблему с помощью ключевого ввода из этой статьи: http://www.codeproject.com/KB/security/CryptoInteropSign.aspx

Основная проверка выполняется с использованием следующей функции C #.

private static Boolean isValid(String xiString, String xiSig)
{
  AsnKeyParser keyParser = new AsnKeyParser("path/to/key.public");
  DSAParameters publicKey = keyParser.ParseDSAPublicKey();

  DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
  DSA.ImportParameters(publicKey);
  DSASignatureDeformatter DSADeformatter = new DSASignatureDeformatter(DSA);
  UTF8Encoding UTF8 = new UTF8Encoding();
  byte[] plainBytes = UTF8.GetBytes(xiString);      
  var sha1 = new SHA1Managed();
  var hash = sha1.ComputeHash(plainBytes);
  byte[] asn1SigBytes = Convert.FromBase64String(xiSig);
  byte[] sigBytes = ConvertToP1363Signature(asn1SigBytes);
  Boolean retVal = DSADeformatter.VerifySignature(hash, sigBytes);
  return retVal;
}

Это зависит от двух вспомогательных методов.

1) AsnKeyParser - это класс, прикрепленный к связанной статье. В статье предлагается загрузка C #, из которой я использовал два файла: AsnKeyParser.cs и BerDecodeError.cs. Я удалил функции RSA из AsnKeyParser, чтобы удалить зависимость от файла BigInteger.

Этот класс обрабатывает файл "key.public", созданный моим Java-кодом.

2) Функция для преобразования 46-48-байтовой подписи в кодировке DER, сгенерированной Java, в подпись DSA, которую примет C #.

Эта функция основана на коде в комментариях к связанной статье.

private static byte[] ConvertToP1363Signature(byte[] ASN1Sig)
{
  AsnParser asn = new AsnParser(ASN1Sig);
  asn.NextSequence();
  byte[] r = asn.NextInteger();
  byte[] s = asn.NextInteger();

  // Returned to caller
  byte[] p1363Signature = new byte[40];

  if (r.Length > 21 || (r.Length == 21 && r[0] != 0))
  {
    // WTF???
    // Reject - signature verification failed
  }
  else if (r.Length == 21)
  {
    // r[0] = 0
    // r[1]'s high bit *should* be set
    Array.Copy(r, 1, p1363Signature, 0, 20);
  }
  else if (r.Length == 20)
  {
    // r[0]'s high bit *should not* be set
    Array.Copy(r, 0, p1363Signature, 0, 20);
  }
  else
  {
    // fewer than 20 bytes
    int len = r.Length;
    int off = 20 - len;
    Array.Copy(r, 0, p1363Signature, off, len);
  }

  if (s.Length > 21 || (s.Length == 21 && s[0] != 0))
  {
    // WTF???
    // Reject - signature verification failed
  }
  else if (s.Length == 21)
  {
    // s[0] = 0
    // s[1]'s high bit *should* be set
    Array.Copy(s, 1, p1363Signature, 20, 20);
  }
  else if (s.Length == 20)
  {
    // s[0]'s high bit *should not* be set
    Array.Copy(s, 0, p1363Signature, 20, 20);
  }
  else
  {
    // fewer than 20 bytes
    int len = s.Length;
    int off = 40 - len;
    Array.Copy(s, 0, p1363Signature, off, len);
  }

  return p1363Signature;
}
...