I would like to generate a digital signature in my java/android project with a private key(RSA) stored in DB.
My 2 keys was generated with the below code (project is in production and I cannot change it):
// Get keys pair (RSA)
KeyPair rsaKyePair = createKeyPair();
// Get private/ public keys and store them in DB
String pri = getPrivateKeyBase64Str(rsaKyePair);
String pub = getPublicKeyBase64Str(rsaKyePair));
public static KeyPair createKeyPair() {
    KeyPair keyPair = null;
    try {
        KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
        keygen.initialize(KEY_LENGTH);
        keyPair = keygen.generateKeyPair();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
    return keyPair;
}
public static String getPrivateKeyBase64Str(KeyPair keyPair){
    if (keyPair == null) return null;
    return getBase64StrFromByte(keyPair.getPrivate().getEncoded());
}
public static String getPublicKeyBase64Str(KeyPair keyPair){
    if (keyPair == null) return null;
    return getBase64StrFromByte(keyPair.getPublic().getEncoded());
}
public static String getBase64StrFromByte(byte[] key){
    if (key == null || key.length == 0) return null;
    return new String(Base64.encode(key));
}
Based on different sites (here and here), I'll try to write code for generate a signature:
String mySignature = getDigitalSignature("my_string_", "my_private_string" );
/*
 * Generated a signed String
 * @param text : string to sign
 * @param strPrivateKey : private key (String format)
 */
public String getDigitalSignature(String text, String strPrivateKey)  {
    try {
        // Get private key from String
        PrivateKey pk = loadPrivateKey(strPrivateKey);
        // text to bytes
        byte[] data = text.getBytes("UTF8");
        // signature
        Signature sig = Signature.getInstance("MD5WithRSA");
        sig.initSign(pk);
        sig.update(data);
        byte[] signatureBytes = sig.sign();
        return javax.xml.bind.DatatypeConverter.printBase64Binary(signatureBytes);
    }catch(Exception e){
        return null;
    }
}
private PrivateKey loadPrivateKey(String key64) throws GeneralSecurityException {
    byte[] clear = Base64.decode(key64, Base64.DEFAULT);
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey priv = fact.generatePrivate(keySpec);
    Arrays.fill(clear, (byte) 0);
    return priv;
}
For verify the signature, I use this code in my java API :
/*
 * Verify signature of a string
 * @param signature : signature
 * @param origina: original string to verify
 * @param publicKey: user public key 
 */
public static boolean verfiySignature(String signature, String original, String publicKey){
    try{
        // Get private key from String
        PublicKey pk = loadPublicKey(publicKey);
        // text to bytes
        byte[] originalBytes = original.getBytes("UTF8");
        //signature to bytes
        //byte[] signatureBytes = signature.getBytes("UTF8");
        byte[] signatureBytes =javax.xml.bind.DatatypeConverter.parseBase64Binary(signature);
        Signature sig = Signature.getInstance("MD5WithRSA");
        sig.initVerify(pk);
        sig.update(originalBytes);
        return sig.verify(signatureBytes);
    }catch(Exception e){
        e.printStackTrace();
        Logger log = Logger.getLogger(RsaCipher.class);
        log.error("error for signature:" + e.getMessage());
        return false;
    }
}
/*
 * Generate a PublicKey object from a string
 * @ key64 : public key in string format (BASE 64)
 */
private static PublicKey loadPublicKey(String key64) throws GeneralSecurityException {
    byte[] data = javax.xml.bind.DatatypeConverter.parseBase64Binary(key64);
    X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    return fact.generatePublic(spec);
}
I've run this code with real data, but the "verifySignature" always returns "False".
I am a newbie in Encryption world, forgive me for my dirty code.
--- EDIT
I got an exception when the verify method is called:
java.security.SignatureException: Signature encoding error
When signing you returned your signature base64-encoded:
return Base64.encodeToString(signatureBytes, Base64.DEFAULT);
Thus, when verifying you have to base64-decode the signature string. But what you do is:
byte[] signatureBytes = signature.getBytes("UTF8");
So the signatureBytes you try to verify are completely different from the signatureBytes you had as a result of signing.
You sign using
Signature sig = Signature.getInstance("RSA");
But You verify using
Signature sig = Signature.getInstance("MD5WithRSA");
Obviously you should use the same algorithm in both cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With