2009-12-16 156 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