Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java OpenSSL Verify and getPublicKey

We're porting PHP (Yii framework) to Java (Play! Framework 2.2.x) and came across this piece of code:

    $sign = base64_decode($sign64);

    // $cert is a string read from a file.
    $pubkey = openssl_get_publickey($cert);

    // $data is composed of incoming username data, time, etc.
    if(openssl_verify("$data", $sign, $pubkey) != 1) {
        $this->verifies = false;
    } else {
        $this->verifies = true;
    }
    openssl_free_key($pubkey);

I've shortened this code so that it contains the essentials.
$data is a field sent with the GET request.
$sign64 is another field sent with this GET request. It is provided by another server and is a signature that verifies the data sent to be valid.
The $cert file contains the string "-----BEGIN CERTIFICATE-----".
So I must ask; what is a standard way of implementing this verification code in Java?

Specifically; we're using the Play! Framework. So far I have done the following:

String sign = new String(javax.xml.bind.DatatypeConverter.parseBase64Binary(sign64));
java.io.FileInputStream filestream = new java.io.FileInputStream(new java.io.File("certificate.crt"));
java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
java.security.cert.Certificate cert = cf.generateCertificate(filestream);
java.security.PublicKey pubkey = cert.getPublicKey();

try
{
    cert.verify(pubkey, sign64); // This seems to be the closest to what I desire...
}
catch (...)
{
    // Here I output the error message...
}

What I end up with is a "NoSuchProviderException". It shows some cryptic text which is the same as the string "sign". My question is: Am I doing something fundamentally wrong? Is parseBase64Binary correct? Is the method of signing correct? It shouldn't be; since I do not sign the data variable at all here. How do I do this correctly in Java/Play! Framework?


1 Answers

The issue was resolved with the following code: (This is for those who have the same question)

import java.security.*;
// ...
public static boolean verifySignature(String data, PublicKey key, byte[] signature) throws Exception {
    Signature signer = Signature.getInstance("SHA1withRSA");
    signer.initVerify(key);
    signer.update(data.getBytes());
    return (signer.verify(signature));
}

The public key is read in using the code given in the question. The signature uses: byte[] sign = java.util.Base64.getDecoder().decode(sign64);

The biggest challenge was finding out which algorithm to use. The example I got the above code from had "SHA1withDSA", much was tried. Eventually the string "SHA1withRSA" worked. It correctly verifies the signed data from our data provider.