2009-08-11 99 views
0

我期待將一些C#代碼轉換爲Java中的等效代碼。使用證書公鑰驗證java中的簽名

C#代碼需要一些字符串內容和一個簽名(使用私鑰在單獨的計算機上生成),並與公鑰驗證簽名匹配,以提供一定程度的保證請求未被篡改。

public bool VerifySignature(string content, byte[] signatureBytes, AsymmetricAlgorithm publicKey) 
    { 
     var hash = new MD5CryptoServiceProvider(); 

     byte[] dataBuffer = Encoding.ASCII.GetBytes(content); 

     var cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write); 
     cs.Write(dataBuffer, 0, dataBuffer.Length); 
     cs.Close(); 

     var deformatter = new RSAPKCS1SignatureDeformatter(publicKey); 
     deformatter.SetHashAlgorithm("MD5"); 

     return deformatter.VerifySignature(hash, signatureBytes); 
    } 

公鑰本身是一個X509證書 - 從一個.cer文件構成,存儲爲集資源即

byte[] data; // data is read from a resource stream. 
var publicKey = new X509Certificate2(data, "", X509KeyStorageFlags.MachineKeySet).PublicKey.Key 

什麼我希望做的是模擬在Java中這樣的功能,所以我可以驗證由C#中的一些代碼生成的簽名...我已經開始研究Java的加密功能,但我是一個java noob。下面是我想出迄今:

byte[] certContents=null; 
byte[] signature=null; 
String contents = "abc"; 

// load cert 
CertificateFactory factory = CertificateFactory.getInstance("X.509"); 
X509Certificate cert = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certContents)); 

// grab public key 
RSAPublicKey publicKey = (RSAPublicKey)cert.getPublicKey(); 

// get sha1 hash for contents   
Mac mac = Mac.getInstance("HmacSHA1"); 
mac.update(contents.getBytes());     
byte[] hash = mac.doFinal(); 

// get cipher 
Cipher cipher = Cipher.getInstance("RSA"); 
cipher.init(Cipher.DECRYPT_MODE, publicKey); 

// verify signature of contents matches signature passed to method somehow (and this is where I'm stuck) 

誰能提供任何洞察我如何驗證簽名 - 或者提供鏈接到一些資源,這或許可以解釋的java.crypto和java.security.cert中用法更好,然後運行java文檔。

回答

2

C#代碼看起來讓我感到困惑。它使用SHA1CryptoServiceProvider,但使用MD5哈希值,所以我不知道它正在使用哪種哈希算法。我認爲它是MD5。

簽名驗證過程涉及填充,因此您的代碼將無法工作。以下是我的代碼片段,您可以使用它來驗證簽名。數據是要簽名的字節,sigBytes保存簽名。

String algorithm = "MD5withRSA"; 

// Initialize JCE provider  
Signature verifier = Signature.getInstance(algorithm); 

// Do the verification 
boolean result=false; 

try { 
    verifier.initVerify(cert); // This one checks key usage in the cert 
    verifier.update(data); 
    result = verifier.verify(sigBytes); 
} 
catch (Exception e) { 
    throw new VerificationException("Verification error: "+e, e); 
} 
+1

我同意。在Java中驗證簽名很簡單,但是C#代碼沒有任何意義:簽名中應該包含單個散列算法。 – erickson 2009-08-11 06:23:09

+0

完全同意 - 這不是我寫的代碼(我最近才採用代碼庫),但你是對的 - 我會認爲它應該使用MD5或SHA1,但不是兩者兼而有之! 在SHA1的情況下算法是「SHA1withRSA」? 我會做一些實驗,看看C#代碼實際使用哪兩種算法。 – Bittercoder 2009-08-11 10:33:25

+0

實施您的代碼(並整理應用程序中的C#代碼,以僅使用MD5簽名),它的工作效果很好。非常感激! – Bittercoder 2009-08-14 02:43:06