How to validate a signature with a private key?

Asked

Viewed 1,526 times

2

I receive an HTTP request that comes in the HEADER a signature (SHA1). I own, stored in a String, a private key. I need to generate the signature between the BODY of the HTTP request and my key and compare it to the signature that comes in the HEADER. I tried it this way:

public static boolean checkSignature(String body, String key, String assinatura) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException, SignatureException{
       Signature sig = Signature.getInstance("SHA1withRSA");


       PublicKey pkey;

       byte encKey[] = key.getBytes();

       X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);

       KeyFactory keyFactory = KeyFactory.getInstance("RSA");

       PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);


       sig.initVerify(pubKey);  
       sig.update(body.getBytes());

       return sig.verify(assinatura.getBytes());


    }

However, error occurs in keyFactory.generatePublic (pubKeySpec). The java.security.spec.Invalidkeyspecexception: java.security.Invalidkeyexception: invalid key format is triggered. I have tried with Sha1withdsa as well. My key is in String. Do I need to turn it to some other format? How do I fix it? Thanks in advance.

Anderson

  • Please give more details as it is difficult to understand what is really happening. SHA-1 is a hash, not a digital signature (although a hash is usually the first step in a signature algorithm). Also, private keys are not used to verify signatures, they are used to sign (signature verification is done by public key). Finally, there is no point in "trying" RSA or DSA, you need to use the exact key format you have, and the exact signature algorithm employed. Please give more details of the protocol being used. Who signed what, and how?

  • I’ll try to improve it. I get an HTTP request signed by a server. The signature comes in HEADER. I get it as a JAVA string. The signature is generated from my private key along with the BODY of the request. My private key is in a JAVA String as well. What I need is to play this signature in my application (because I also know the private key and BODY) to compare it to the signature sent by the server that sent me the HTTP request. If the signatures match, I’m sure my document was signed by the server.

  • I’m not sure which algorithm is used! I don’t really understand the subject. However, the documentation from the server sending me the request says that the signature is SHA-1. The message comes something like sha1=3f547499cabz7876cfeed... representing the signature.

  • That’s not how the public key digital signature works... You can sign the same data twice and exit two completely different signatures - and both valid! That’s because the signature algorithm is randomized. The only way I know how to verify a signature is by using the public key. However, from what you are saying, it is not a signature that is being sent, but a hash. This does not guarantee authenticity, it only helps integrity. I will try to write an answer explaining this.

  • Ok mgibsonbr! I really appreciate the help!

  • For reference only, the server documentation shows an example of how it was done in Ruby: def generated_signature 'sha1=' + Openssl::HMAC.hexdigest(Openssl::Digest.new('sha1'), secret_key, request_body)&#Xa end;

  • Now I understand what this is about. An HMAC is a type of signature, yes, but one that can only be verified by the person who signed it (since the verifier shares the same secret of the person who signs it). In this context, we do not use the term "private key", only "secret key" or even "key" to differentiate from asymmetric cryptography (where there is a pair of keys, a public and a private). See my answer, and pay close attention to the details, because any little mistake will make the signatures not match each other.

Show 2 more comments

1 answer

0


There is a difference between signature via asymmetric cryptography (the one using public and private keys, usually called "digital signature") and signature via symmetric cryptography. In this one, a single secret value is used both to sign and to verify the signature. This "signature" in this context is often called Message Authentication Code (Message Authentication Code - MAC), and is commonly implemented with the aid of a hashing - resulting in a Hash-based Message Authentication Code - HMAC. According to your last comment, this is what is being used by your server.

According to that question on Soen, a way to generate an HMAC (and therefore check it, in which case it is sufficient to compare the signatures) would be the following:

public static boolean checkSignature(String body, String key, String assinatura) throws NoSuchAlgorithmException, InvalidKeyException {
    byte encKey[] = key.getBytes();
    SecretKeySpec keySpec = new SecretKeySpec(encKey, "HmacSHA1");

    Mac mac = Mac.getInstance("HmacSHA1");
    mac.init(keySpec);

    byte[] result = mac.doFinal(body.getBytes(CODIFICACAO_COMUM));

    // Compara o resultado com a assinatura, e retorna se são ou não iguais
}

Note: if your signature is coming encoded in hexadecimal, it is necessary convert the result (variable result) of an array of bytes for a hexadecimal string before making the comparison. Or the opposite, convert the string signature to array of bytes and then compare the arrays.

Heed: str.getBytes() is not the same thing which convert from/to hexadecimal, so be careful! Also, getBytes uses standard platform encoding, which may not be the same on the client and server (e.g.: if your server is Linux and your client is Windows the text will be signed in UTF-8 and checked in Cp1252, and the results will not be equal).

  • Dear mgibsonbr, it worked right! Converted result to hexadecimal and hit with the signature! Thank you very much! Helped a lot!!!

  • @user2826942 Good! Don’t forget to test with sharp files too, just to make sure that the encoding is okay.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.