Überprüfen einer Signatur in Java mithilfe eines öffentlichen Schlüssels eines Zertifikats
-
12-09-2019 - |
Frage
Ich möchte C#-Code in das Äquivalent in Java konvertieren.
Der C#-Code nimmt einige Zeichenfolgeninhalte und eine Signatur (generiert mit dem privaten Schlüssel auf einem separaten Computer) und überprüft in Kombination mit dem öffentlichen Schlüssel die Signaturübereinstimmungen, wodurch ein gewisses Maß an Sicherheit geboten wird, dass die Anfrage nicht manipuliert wurde.
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);
}
Der öffentliche Schlüssel selbst ist ein X509-Zertifikat – erstellt aus einer .cer-Datei, gespeichert als Assembly-Ressource, d. h.
byte[] data; // data is read from a resource stream.
var publicKey = new X509Certificate2(data, "", X509KeyStorageFlags.MachineKeySet).PublicKey.Key
Ich möchte diese Funktionalität in Java emulieren, damit ich die von einem Code in C# generierte Signatur überprüfen kann ...Ich habe begonnen, die Krypto-Funktionalität von Java zu untersuchen, bin aber eher ein Java-Neuling.Folgendes habe ich bisher herausgefunden:
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)
Kann mir jemand einen Einblick geben, wie ich die Signatur überprüfen kann – oder Links zu einigen Ressourcen bereitstellen, die die Verwendung von java.crypto und java.security.cert besser erklären könnten als die gewöhnlichen Java-Dokumente?
Lösung
Dieser C#-Code sieht für mich wirklich verwirrend aus.Es verwendet SHA1CryptoServiceProvider, aber MD5-Hash, sodass ich nicht sagen kann, welchen Hashing-Algorithmus es verwendet.Ich gehe davon aus, dass es MD5 ist.
Bei der Signaturüberprüfung ist eine Auffüllung erforderlich, damit Ihr Code nicht funktioniert.Im Folgenden finden Sie einen Ausschnitt meines Codes, mit dem Sie die Signatur überprüfen können.Daten sind die zu signierenden Bytes und sigBytes enthält die Signatur.
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);
}