以下是设置:
我用.NET创建公钥/私钥对,我想签一个字符串。 我取一个随机字符串,从中获取一个byte [],签名,并在java应用程序中获取签名。我想在java中验证它((!)我在谈论Android的java)。
将公钥带到Java环境的过程:当我创建公钥时,我将字节数组用于公钥(P,Q,G,Y)和 使用这些值在Java中创建PublicKey。 .NET中的P,Q,G,Y是byte [],我将它们转换为sbyte []并在Java中使用这些sbyte [],创建大整数:
byte [] byteP = new byte [] {-34,...... -117};
...
BigInteger p = new BigInteger(1,byteP);
...
新的DSAPublicKeySpec(y,p,q,g);
为了测试这个过程,我从C#中获取签名byte [],将其转换为sbyte [],然后在Java中使用它。
问题是,我以后无法验证签名字符串。我得到了
java.security.SignatureException:签名字节具有无效编码
任何想法都赞赏! (比如,完成整个事情的更好,完全不同的方式;))
答案 0 :(得分:2)
DSA签名实际上是两个数字,并且没有关于如何将其格式化为bytearray的真实标准。
Java选择将其编码为包含两个ASN.1整数的ASN.1序列的DER编码。
.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;
}
答案 1 :(得分:0)
我不确定我是否会在这里追逐你,但是(太阳的!)BigInteger使用您在构造函数中传递的1作为数字的符号 - 因此它可能会对生成的签名计算产生影响。 ..过去我使用RSA已经遇到过这个问题...