5

I have already posted a similar question concerning how to load RSA keys in java. See the best response of this question to fully understand the first part of my code (the method getPulicKey, I mean).

private static PublicKey getPublicKey(String publicKey)
        throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
    try (PEMParser pp = new PEMParser(new StringReader(publicKey))) {
        SubjectPublicKeyInfo subjPubKeyInfo = (SubjectPublicKeyInfo) pp.readObject();
        RSAKeyParameters rsa = (RSAKeyParameters) PublicKeyFactory.createKey(subjPubKeyInfo);

        RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getExponent());
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PublicKey myKey = kf.generatePublic(rsaSpec);
        System.out.println(myKey);
        return myKey;
    }
}

The method verify (below) raises the following exception

Signature length not correct: got 768 but was expecting 512, in Java verify

In the following code, I decode the signature because I suppose it is Base64, but I'm not sure, sorry. I don't know wether I could show you the signature and the object. The signature is a sequence of 1024 digits and numbers. It does not end with "=". The object I have to verify is a json object in String format. The following is the method I have written to verify a String object, given a sign and a publicKey. It calls the above method getPublicKey(...).

public static boolean verify(String object, String sign, String publicKey) throws NoSuchAlgorithmException,
        InvalidKeySpecException, IOException, InvalidKeyException, SignatureException {
    //object to be verified
    //sign is the signature stored in the postgres DB
    //publicKey is the public key stored in the postgres DB
    Signature signature = Signature.getInstance("SHA256withRSA");
    signature.initVerify(getPublicKey(publicKey));
    byte[] objectBytes = Base64.getEncoder().encode(object.getBytes("utf-8"));
    signature.update(objectBytes);
    byte[] signBytes = Base64.getDecoder().decode(sign.getBytes("utf-8"));
    System.out.println(signBytes.length); //this line prints 768, with decode. 1024, otherwhise
    return signature.verify(signBytes);
}

EDIT:

My workmates are using the following two nodejs methods (verifySign and createSign).

In the following nodejs code (where there are workmates' methods), I encript with "createSign" the message "fake message". The sign is the following:

5f188225c68dee2ce8de588dfaccb667710da94abb5388deabfe3ad83f7a94a72ee4a3c8c51be26c5b58cdec8c82cf8135c478ad609b7985496e201b23de6c5d03e93dcd9df7b5e2315efbfd2ff6496b0aea3b425bb99c912a16aeb5efb6cefc1e175c32aaf16af3a2baca5b54f974af0f14c853228bc06410e7ad1b2b0ecec19f5aed151389bd9ccebd5e998159d5205d81a7c7e37b502df3eb5229a5fd3492680576ebfa1e76b7c47fb757a9bfb18aa9ea0b71512ab9e1afc8e551ebf6d74a042bd447233953efbf374a3a6a210ead2019b8cc8548bb304979b4bfdc90dce644cb109bbddb75dda9df1322fd8e08ef1144e870324f34d4c826d9a4b64be0442aedc6f3d5f571d7336af212825c4e0216aa5eabab6218d685a3e73d81693149b45af5f1857c4a0e50b396d1a2ea5a3effafcc4e124fd23d0427abfe5509357936ef5e7c7ca4476d6a5ae7a26e9563923a03d0780f0d897039d4d3aa2ce49dc84b31907a50045456acb57edd11a896632969245d0f97fd88dace7eb256099bbc4eedf52b5d53b481b2aeb829101d0089903ea9c3621bcbd763962b84ad57407623b576cc6a9c3328d85e0f7dd78565cd39a6648a68dd6f4334dd3a68e48491ae655601a5c9be7673ae0d3f955431fb21f33c0178ecb9067072a6b1e360ee77a45f8e855e6c545276aefc7ae70b5c7e0f1ec0b66460575e3386f8a4bbf7fd3704

Then, I verify it with public key pk (see below).

const PASSPHRASE_KEY = "...";
const crypto = require('crypto');

const prk = "...";

const pk = "-----BEGIN RSA PUBLIC KEY-----\r\n" + 
            "MIICCgKCAgEA1ht0OqZpP7d/05373OE7pB7yCVGNGzkUEuCneyfOzps6iA03NbvI\r\n" + 
            "1ZL0Jpp/N3AW73lGdhaoa3X3JE4GsI/bsToVLQwTKmIOC4yjTvBctmFEoyhhTfxW\r\n" + 
            "s1UHZKl4XZ/7THbRlKHhRaTKyfDAbikkMAxNT/qutLAPjnN1qOwjb1oRq52NP6FJ\r\n" + 
            "KWTTikz4UeOHroX+Xthn2fJSJDlQ4YMdBbgrZVx5JcHKNuPTKRf5gI8QQKMSA9Q9\r\n" + 
            "QJRE5OGp7b6dG14ZmOUnUxb00Mp20LgcaGPcuWU+oFsbQaF6W4G4bdkSZRJJXhSg\r\n" + 
            "d4Q7mahpar94/gnztJmth0GzqTWUYyZIWNqIFoMwuOgeaiDV43zb3uLsRVpRKYYy\r\n" + 
            "esmzcOy/jTScVLRCD8QRyu9B2wgCkNAVztQOXPCOOa4O1LlVQWaecIs4WPhOqDhi\r\n" + 
            "KTBhyVkpC1TrrBkp+QMqMqWll1OyVb6k/7uV0qE/i6rHJtjo5v9bcIgYzswyx9CD\r\n" + 
            "9PKl2Q0L0Jg7TMG+yLDIrLfGeuSeEc4XYJzN7bJcCeiizzu5iU9dQUkrncOrq9jn\r\n" + 
            "Ub2pM/+A+JqIsoPK3IY/pJKqH4JYpGKhO1iPQF6iXIZT1r3ZgJUSQtzSeyYqhkla\r\n" + 
            "2uR2BsbPbDqebCuXm3lAsY5w+dujijcn96PKwYha1LsK5sACHuJ79AMCAwEAAQ==\r\n" + 
            "-----END RSA PUBLIC KEY-----\r\n" + 
            "";

function createSign(pvt_key, data_unsigned) {
    //Create a SHA256 sign generator
    const signer = crypto.createSign('SHA256');

    //Update context with data to sign
    signer.update(data_unsigned);

    //Sign the document based to user's private key
    return signer.sign({
        key: pvt_key,
        passphrase: PASSPHRASE_KEY
        },
        'hex'
    );
}

function verifySign(pub_key, signed_data, signature) {
  const verifier = crypto.createVerify('sha256');

  //Update context with data to verify
  verifier.update(signed_data);

  //Verify sign with user's public key
  const verified = verifier.verify(
    pub_key,
    signature,
    'hex'
  );

  //Send result
  return verified;
}

const phrase = "fake message";
var signMade = createSign(prk, phrase);
console.log("my signature: " + signMade);
//The signature is 5f188225c68dee2ce8de588dfaccb667710da94abb5388deabfe3ad83f7a94a72ee4a3c8c51be26c5b58cdec8c82cf8135c478ad609b7985496e201b23de6c5d03e93dcd9df7b5e2315efbfd2ff6496b0aea3b425bb99c912a16aeb5efb6cefc1e175c32aaf16af3a2baca5b54f974af0f14c853228bc06410e7ad1b2b0ecec19f5aed151389bd9ccebd5e998159d5205d81a7c7e37b502df3eb5229a5fd3492680576ebfa1e76b7c47fb757a9bfb18aa9ea0b71512ab9e1afc8e551ebf6d74a042bd447233953efbf374a3a6a210ead2019b8cc8548bb304979b4bfdc90dce644cb109bbddb75dda9df1322fd8e08ef1144e870324f34d4c826d9a4b64be0442aedc6f3d5f571d7336af212825c4e0216aa5eabab6218d685a3e73d81693149b45af5f1857c4a0e50b396d1a2ea5a3effafcc4e124fd23d0427abfe5509357936ef5e7c7ca4476d6a5ae7a26e9563923a03d0780f0d897039d4d3aa2ce49dc84b31907a50045456acb57edd11a896632969245d0f97fd88dace7eb256099bbc4eedf52b5d53b481b2aeb829101d0089903ea9c3621bcbd763962b84ad57407623b576cc6a9c3328d85e0f7dd78565cd39a6648a68dd6f4334dd3a68e48491ae655601a5c9be7673ae0d3f955431fb21f33c0178ecb9067072a6b1e360ee77a45f8e855e6c545276aefc7ae70b5c7e0f1ec0b66460575e3386f8a4bbf7fd3704
console.log("was it me to sign that?");
var res = verifySign(pk, phrase, signMade);
console.log(res);

It returns true. However, If I pass to the java method verify the following (same) parameters:

  1. object = "fake message"
  2. sign = 5f188225c68dee2ce8de588dfaccb667710da94abb5388deabfe3ad83f7a94a72ee4a3c8c51be26c5b58cdec8c82cf8135c478ad609b7985496e201b23de6c5d03e93dcd9df7b5e2315efbfd2ff6496b0aea3b425bb99c912a16aeb5efb6cefc1e175c32aaf16af3a2baca5b54f974af0f14c853228bc06410e7ad1b2b0ecec19f5aed151389bd9ccebd5e998159d5205d81a7c7e37b502df3eb5229a5fd3492680576ebfa1e76b7c47fb757a9bfb18aa9ea0b71512ab9e1afc8e551ebf6d74a042bd447233953efbf374a3a6a210ead2019b8cc8548bb304979b4bfdc90dce644cb109bbddb75dda9df1322fd8e08ef1144e870324f34d4c826d9a4b64be0442aedc6f3d5f571d7336af212825c4e0216aa5eabab6218d685a3e73d81693149b45af5f1857c4a0e50b396d1a2ea5a3effafcc4e124fd23d0427abfe5509357936ef5e7c7ca4476d6a5ae7a26e9563923a03d0780f0d897039d4d3aa2ce49dc84b31907a50045456acb57edd11a896632969245d0f97fd88dace7eb256099bbc4eedf52b5d53b481b2aeb829101d0089903ea9c3621bcbd763962b84ad57407623b576cc6a9c3328d85e0f7dd78565cd39a6648a68dd6f4334dd3a68e48491ae655601a5c9be7673ae0d3f955431fb21f33c0178ecb9067072a6b1e360ee77a45f8e855e6c545276aefc7ae70b5c7e0f1ec0b66460575e3386f8a4bbf7fd3704
  3. publicKey copied from pk (see node code above)

java raises the exception:

Signature length not correct: got 768 but was expecting 512 Signature lenght not correct.

Peter
  • 399
  • 2
  • 6
  • 23
  • 1
    `=` is just padding, Base64 encoded data doesn't have to end with it – Karol Dowbecki Mar 07 '19 at 13:12
  • 1
    Well, was the object signed with the private key that corresponds to the public key you are using? It doesn't appear that way based on the error message. – President James K. Polk Mar 07 '19 at 15:11
  • @Polk My workmates told me the object has been signed with private key – Peter Mar 07 '19 at 16:25
  • @JamesKPolk, I'm sorry. I misunderstood your comment. I'll reply now correctly. The exception that is raised is indipendent by the structure of the object. Indeed, if you delete the row "signature.update(...)", the same exception is raised. Another clue is the fact that the signature, as I said, is 1024 characters long and, when I decode it, it becomes 768 bytes long. 768 cannot be a coincidence. – Peter Mar 07 '19 at 20:24
  • @JamesKPolk, what is the relation between the length of the signature and the public key? – Peter Mar 07 '19 at 21:03
  • 1
    In RSA the signature always have the same length (or a little less) as the RSA key (in detail the RSA modulus) – Robert Mar 08 '19 at 08:21
  • Thank you @Robert for the explanation. Do you mean the same length of the modulus of the public key, or the same length of the modulus of the private key? Maybe the length of the modulus of private and public key are equal? – Peter Mar 08 '19 at 14:21
  • Each RSA key-pair has only one modulus. – Robert Mar 08 '19 at 15:03
  • I think you are all way off base. See my edits, please. – Peter Mar 08 '19 at 15:36
  • Ok, then you garbled the data. As you can see, the signature in your edit is 512 bytes long, not 768. There are no facts in your question that would explain why you are receiving anything other than 512 bytes to verify. – President James K. Polk Mar 08 '19 at 18:00
  • @JamesKPolk I used the same signature in node and java. Only java does not work. Wasn't it clear? – Peter Mar 08 '19 at 18:03

1 Answers1

5

You're treating the signature as if it's base64-encoded, but it's not - it's just hex.

1024 characters represents 768 base64-encoded bytes, or 512 hex-encoded bytes.

Just decode using hex instead of base64 and it should be fine.

Hint that this is along the right lines, as well as observing that every character of your signature is a valid hex digit (which would be extremely unlikely if it's actually base64):

return signer.sign({
    key: pvt_key,
    passphrase: PASSPHRASE_KEY
    },
    'hex' // Note this use of 'hex'...
);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194