2011-02-03 122 views
1

我知道这是一个有很多现有问题的主题,但我无法找到涵盖我的确切情况的任何现有答案。验证由C#中的Java生成的DSA签名

我需要在某些Java代码中签署一个字符串(URL),并将该字符串与签名一起传递给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”文件。

任何人都可以提供一个代码块,结合这些元素以及合适的库来确定字符串是否被篡改?

+0

谷歌搜索“C#dsa验证示例”获得大量命中,可以解释这些示例如何不能满足您的需求? – 2011-02-04 00:16:13

+0

[在C#验证DSA签名]的可能重复(http://stackoverflow.com/questions/1628305/verify-dsa-signature-in-c) – 2011-02-04 00:17:22

回答

1

我现在已经解决了这个从这篇文章中的一些关键输入来: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。我从AsnKeyParser中删除了RSA函数,以除去对BigInteger文件的依赖。

该类处理解析由我的Java代码创建的“key.public”文件。

2)将Java生成的46-48字节DER编码签名转换为C#将接受的DSA签名的函数。

该功能基于链接文章评论中的代码。

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; 
}