Error on nitrokey trying to decrypt original data from public key and signature

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:

Card (CARD_INVALID_SW/26368) - “Unexpected SW1/SW2=6700 (Checking error: Wrong length) received”

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;

}

Thanks,
Doug

The following changes now cause it to at least give me some output (i changed algorithm ids and now call decrypt via crypto.crypto):

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("ABCDE", ASCII);

var signature = crypto.sign(rsaprkey, Crypto.RSA_SHA1, message);

print("Original = " + message);
print("Plain PKCS#1 V1.5 = ");
var decrypted = crypto.crypto.decrypt(rsapukey, Crypto.RSA_PKCS1, signature);

assert(crypto.verify(rsapukey, Crypto.RSA_SHA1, message, signature));

return decrypted;

}

But the decrypted data doesn’t match the original ByteString (“ABCDE”).

I would like to decrypt the signature to get back to the original data - any ideas what I am doing wrong?

Thanks
Doug

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?:

  1. hash == data
  2. hash == SHA1(data)
  3. 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?

Thanks
Doug

Hi,

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

Thanks
Doug

No worries, we always have to start somewhere…

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).