2009-12-16 118 views
1

这里是设置:DSA问题 - 使用.NET创建DSA公钥/私钥,使用Java公钥(android)

我使用.NET创建公钥/私钥对,我想签署一个串。 我拿一个随机字符串,从它得到一个字节[],签名,然后在java应用程序中签名。我想验证它在Java((!)我在谈论Android的Java)。

的过程中采取的公共密钥给Java环境:当我创建公共密钥,我采取的公共密钥的字节阵列(P,Q,G,Y)和 在Java中创建公钥与这些值。 P,Q,G,Y在.NET中有byte [],我将它们转换到sbyte [],并使用这些为sbyte []在Java中,创建大整数:

的byte [] byteP =新的字节[ ] {-34,...... -117};

...

BigInteger的p值=新的BigInteger(1,byteP);

...

新DSAPublicKeySpec(Y,P,Q,G);

为了测试过程,我从C#中取得签名字节[],将其转换为sbyte [],然后在Java中使用它。

问题是,我以后无法验证签名字符串。我

java.security.SignatureException:签名字节有无效的编码

任何想法表示赞赏! (比如,一个更好的,完全不同的方式来做整件事情))

回答

2

一个DSA签名实际上是两个数字并没有如何将其格式化为字节阵列的真正标准。

爪哇选择它编码为DER编码含有两个ASN.1-整数一个ASN.1序列的。

.NET选择前面加上零到两个号码,将他们正好是20字节长,将它们连接起来。

从.NET到Java格式转换做这样的事情(未经测试,但应该主要是正确的):

public byte[] ConvertToDsaSignatureToJavaEncoding(byte[] dsa){ 
    if(dsa.Length!=40) 
    throw new ArgumentException("dsa", "DSA signature should always be 40 bytes long"); 
    // Split into r and s. 
    byte[] r = new byte[20]; 
    Array.Copy(dsa, 0, r, 0, 20); 
    byte[] s = new byte[20]; 
    Array.Copy(dsa, 20, s, 0, 20); 

    // Convert to complement-2 
    byte[] complementTwoR = ToComplementTwo(r); 
    byte[] complementTwoS = ToComplementTwo(s); 

    // Build the result 
    byte[] res = new byte[complementTwoR.Length + complementTwoS.Length + 6]; 
    // Sequence{ 
    res[0] = 0x30; 
    res[1] = (byte) (complementTwoR.Length + complementTwoS.Length + 4); 
    // Integer (R) 
    res[2] = 0x02; 
    res[3] = (byte) complementTwoR.Length; 
    Array.Copy(complementTwoR, 0, res, 4, complementTwoR.Length); 
    // Integer (S) 
    res[complementTwoR.Length + 4] = 0x02; 
    res[complementTwoR.Length + 5] = (byte) complementTwoS.Length; 
    Array.Copy(complementTwoS, 0, res, complementTwoR.Length + 6, complementTwoS.Length); 

    return res; 
} 

public byte[] ToComplementTwo(byte[] d){ 
// Ensure the top-bit is zero, otherwise remove unneeded zeroes 
// - Find non-zero byte 
int i = 0; 
while (i < d.Length && d[i] == 0) i++; 
// - Do we need an extra byte 
int extraByte = (d[i] & 0x80) == 1 ? 1 : 0; 
// - Build the result 
byte[] res = new byte[d.Length-i+extraByte]; 
Array.Copy(d, i, res, extraByte, d.Length-i); 
return res; 

}

+0

太棒了!谢谢!仍然无法成功验证字节数组,但我不再有异常了!一个微小的错误遗留下来:Array.Copy(complementTwoS,0,res,6,complementTwoS.Length) - 6应该是26.10x! – Danail 2009-12-16 20:20:22

0

不知道我是否在这里把你扔到鹅追逐,但(太阳的!)BigInteger使用你在构造函数中传递的1该数值的符号 - 因此它可能对得到的签名计算的影响......我已经使用问题,在使用RSA过去......

+0

是的,我知道。如果不将Signum传递给BigInteger(),应用程序会抛出异常“坏p”。我认为它必须是正面的,但我不确定这是我应该如何转换byte [] c#在Java中给我的方式。 – Danail 2009-12-16 20:22:16