Теперь я решил эту проблему с помощью ключевого ввода из этой статьи: 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;
}