Search code examples
javasecuritydigital-signatureencryption-asymmetricmessage-digest

signature verification process in java security


I want to send a original_message between two person. let say Alice and Bob, and I want to know if these steps are correct for verification of the signature or not

  1. Alice hash the original_message with her PrivateKey -> h(m)
  2. Alice cipher the hashed message -> c(h(m))
  3. Alice sign the message with her PrivateKey -> s(c(h(m)))

Alice send the final signed message with her (PublicKey) and (the original_message) to Bob. in Bob side:

  1. Bob hash the original_message -> h(m)
  2. Bob decipher the signed message with Alice public key -> d(s(c(h(m))))
  3. Bob check deciphered message with hashed message if they are equal or not ? if ( h(m) == d(s(c(h(m)))) )

I know that I am doing some mistake. does any one knows what is the good order in both side ?

Here I used java.security for doing this but when I check the hashes at final step it gives me false !

in Alice part :

public byte[] Sign(byte[] aMessage) {

        try {
            // get an instance of a cipher with RSA with ENCRYPT_MODE
            // Init the signature with the private key
            // Compute signature
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, thePrivateKey);

            Signature instance = Signature.getInstance("MD5withRSA");
            instance.initSign(thePrivateKey);

            // get an instance of the java.security.MessageDigest with MD5
            // process the digest
            MessageDigest md5_digest = MessageDigest.getInstance("MD5");
            md5_digest.update(aMessage);
            byte[] digest = md5_digest.digest();

            // return the encrypted digest
            byte[] cipherText = cipher.doFinal(digest);

            instance.update(cipherText);            
            byte[] signedMSG = instance.sign();

            return signedMSG;

        } catch (Exception e) {
            System.out.println("Signature error");
            e.printStackTrace();
            return null;
        }

    }

in Bob part :

public boolean CheckSignature(byte[] aMessage, byte[] aSignature,
            PublicKey aPK) {
        try {
            // get an instance of a cipher with RSA with ENCRYPT_MODE
            // Init the signature with the private key
            // decrypt the signature
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, aPK);
            byte[] decrypted_digest =  cipher.doFinal(aSignature);

            // get an instance of the java.security.MessageDigest with MD5
            MessageDigest md5_digest = MessageDigest.getInstance("MD5");

            // process the digest
            md5_digest.update(aMessage);
            byte[] digest = md5_digest.digest();

            // check if digest1 == digest2
            if (decrypted_digest == digest) {
                return true;
            }else {
                return false;
            }

        } catch (Exception e) {
            System.out.println("Verify signature error");
            e.printStackTrace();
            return false;
        }
    }

Solution

  • Finally I found the answer. The mistake was, doing a sign() in Alice part. Because when you are doing the hashing and encryption it already became a signature, and when you sign() it another time in the Bob's part became impossible to recover the hashed signature .

    my code is also a good example of "One-way hashing in java security public key encryption"

    this is the modification in Alice part and everything work after.

    public byte[] Sign(byte[] aMessage) {
    
            try {
                // get an instance of a cipher with RSA with ENCRYPT_MODE
                // Init the signature with the private key
                // Compute signature
                Cipher cipher = Cipher.getInstance("RSA");
                cipher.init(Cipher.ENCRYPT_MODE, thePrivateKey);
    
                // get an instance of the java.security.MessageDigest with MD5
                // process the digest
                MessageDigest md5_digest = MessageDigest.getInstance("MD5");
                byte[] digest = md5_digest.digest(aMessage);
    
                // return the encrypted digest
                byte[] cipherText = cipher.doFinal(digest);
    
                return cipherText;
    
            } catch (Exception e) {
                System.out.println("Signature error");
                e.printStackTrace();
                return null;
            }
    
        }