Hi,
I have the function below which I believe should sign some data, and then use the public key and the signature to decrypt to get back to the original data. But I get the following error in smartcard shell using an RSA 2048 key (supporting all algorithms) on a Nitrokey:
My function is run via context menu function and simply signs some test data and then tries to decrypt it. My code is based on the sample code at Crypto - Reference Documentation
function test(source) {
var crypto = this.km.sc.getCrypto();
var cert = source.childs[source.childs.length - 1].cert;
if (cert.byteAt(0) == 0x30) {
cert = new X509(cert);
} else {
cert = new CVC(cert);
}
// RSA with SHA-1
var rsaprkey = source.key;//new Key("profiles/kp_rsa_private_crt.xml");
var rsapukey = cert.getPublicKey();//new Key("profiles/kp_rsa_public.xml");
var message = new ByteString("Hello World !", ASCII);
var signature = crypto.sign(rsaprkey, Crypto.RSA, message);
var decrypted = crypto.decrypt(rsapukey, Crypto.RSA, signature);
print("Plain PKCS#1 V1.5 = " + decrypted);
assert(crypto.verify(rsapukey, Crypto.RSA, message, signature));
return decrypted;
In the second example you are signing an SHA1 hash of the message hex bytes 7be07aaf460d593a323d0db33da05b64bfdcb3a5. This is what will be signed.
Signatures are not designed to be “decrypted”, just verified. For RSA, however, it is possible to “decrypt” the signature. Decrypted signature will look like lots of bytes with the PKCS v1.5 padding and the signature hex bytes at the end.
Since the message has been hashed, there is no way to go back to the original text.
Thanks for your response. I now realise I was not clear in my question so I’ll start again - it’s not the original data i am trying to get, it’s the hash - ultimately i am trying to verify a signed hash…
I have a hex string that I would like to sign (the hex string is currently converted using ByteString(“…”, HEX) in my smart card shell plugin).
i would like to know if the code below would do the job of extracting “data” from the pkcs1 v1.5 data returned from decrypt(…):
var data = new ByteString(“0102030405060708090a0b0c0d0e0f1011121314”, HEX);
var signature = crypto.sign(rsaprkey, Crypto.RSA_SHA1, data);
var pkcs = crypto.decrypt(rsapukey, Crypto.RSA_PKCS1, signature);
pkcs should now contain something like 0001ffffff… | sha1_magic_code | hash
is one of the following true?:
hash == data
hash == SHA1(data)
something else?
when i run the code above, the “hash” that i extract from decrypt(…) does not match the input “data”. I am wondering, does RSA sign(…) do a hash of it’s own and therefore lose “data”? (i.e. hash == SHA1(data)?)
because i am already doing the SHA1 bit myself, is it possible to manually create the PKCS#1 v1.5 buffer (padding + sha1 magic number + my sha1) and sign that instead?
I have resolved my issue. My call to sign(…) needs to use RSA_PKCS1 because I have already done the SHA1 hash myself. So the following now works:
// hash must be a hex string representing 20 bytes (for SHA1)
var data = new ByteString(hash, HEX);
var sig = crypto.sign(privateKey, Crypto.RSA_PKCS1, data);
var pkcs = crypto.decrypt(publicKey, Crypto.RSA, sig);
// pkcs is now in the form 00 01 | ff … | 00 | <sha1_magic_number> | h
// h should now match “data” above
Any reason why you do not want to use verify() ? It does what you did “by hand” and can do a lot more, including using non-RSA signatures and paddings different than widely criticized PKCS#1 v1.5…
my plugin code never has access to the original data, only the hash. i think verify() verifies a signature against the original data? anyway, the code above is working for me (the solution to the original problem was to switch to RSA_PKCS1).