What steps will reproduce the problem? Attempt to use ALG_RSA_NOPAD with AssymetricCipherImpl. What is the expected output? What do you see instead? I expect plain text and cipher text to have the same length as the RSA key modulus. Instead, plain text must be one byte shorter on encryption, and the result of decryption is one byte shorter too. What version of the product are you using? On what operating system? jCardSim-2.2.1, OS-independent. Please provide any additional information below. The Bouncy Castle implementation of raw RSA is a little quirky in that it requires plain text to be one byte shorter than the modulus on encryption, and returns one byte less on decryption. This is a defensible choice for truly "unpadded" message, and clearly documented in the BouncyCastle library, but it isn't consistent with my smart cards (Gemalto and G&D), which always require cipher text and plain text the same size of the RSA modulus.
I created a wrapper around the BC RSAEngine to fix this. You might want to swap some operations with calls to JCSystem and Util.
final class RawRSAWrapper
implements AsymmetricBlockCipher
{
private final AsymmetricBlockCipher rsa = new RSAEngine();
private boolean encrypt;
@Override
public int getInputBlockSize()
{
int iblk = rsa.getInputBlockSize();
return encrypt ? iblk + 1 : iblk;
}
@Override
public int getOutputBlockSize()
{
int oblk = rsa.getOutputBlockSize();
return encrypt ? oblk : oblk + 1;
}
@Override
public byte[] processBlock(byte[] buf, int off, int len)
throws InvalidCipherTextException
{
if (encrypt) {
if (buf[off] != 0)
/* Maybe only most significant BIT needs to be clear. Need to check. */
throw new InvalidCipherTextException("Leading byte must be zero.");
return rsa.processBlock(buf, off + 1, len - 1);
}
else {
byte[] unpadded = rsa.processBlock(buf, off, len);
byte[] padded = new byte[unpadded.length + 1];
System.arraycopy(unpadded, 0, padded, 1, unpadded.length);
return padded;
}
}
}
Here's how I use it in AssymetricCipherImpl(byte) constructor:
...
case ALG_RSA_NOPAD:
engine = new RawRSAWrapper();
...
BTW, since padding is always null currently, it's dead code, and I removed all references to it for simplification.
From erick...@bitflash.net on September 20, 2013 21:38:03
What steps will reproduce the problem? Attempt to use ALG_RSA_NOPAD with AssymetricCipherImpl. What is the expected output? What do you see instead? I expect plain text and cipher text to have the same length as the RSA key modulus. Instead, plain text must be one byte shorter on encryption, and the result of decryption is one byte shorter too. What version of the product are you using? On what operating system? jCardSim-2.2.1, OS-independent. Please provide any additional information below. The Bouncy Castle implementation of raw RSA is a little quirky in that it requires plain text to be one byte shorter than the modulus on encryption, and returns one byte less on decryption. This is a defensible choice for truly "unpadded" message, and clearly documented in the BouncyCastle library, but it isn't consistent with my smart cards (Gemalto and G&D), which always require cipher text and plain text the same size of the RSA modulus.
I created a wrapper around the BC RSAEngine to fix this. You might want to swap some operations with calls to JCSystem and Util.
final class RawRSAWrapper implements AsymmetricBlockCipher {
private final AsymmetricBlockCipher rsa = new RSAEngine();
private boolean encrypt;
@Override public int getInputBlockSize() { int iblk = rsa.getInputBlockSize(); return encrypt ? iblk + 1 : iblk; }
@Override public int getOutputBlockSize() { int oblk = rsa.getOutputBlockSize(); return encrypt ? oblk : oblk + 1; }
@Override public void init(boolean encrypt, CipherParameters params) { this.encrypt = encrypt; rsa.init(encrypt, params); }
@Override public byte[] processBlock(byte[] buf, int off, int len) throws InvalidCipherTextException { if (encrypt) { if (buf[off] != 0) /* Maybe only most significant BIT needs to be clear. Need to check. */ throw new InvalidCipherTextException("Leading byte must be zero."); return rsa.processBlock(buf, off + 1, len - 1); } else { byte[] unpadded = rsa.processBlock(buf, off, len); byte[] padded = new byte[unpadded.length + 1]; System.arraycopy(unpadded, 0, padded, 1, unpadded.length); return padded; } }
}
Here's how I use it in AssymetricCipherImpl(byte) constructor:
... case ALG_RSA_NOPAD: engine = new RawRSAWrapper(); ...
BTW, since padding is always null currently, it's dead code, and I removed all references to it for simplification.
Original issue: http://code.google.com/p/jcardsim/issues/detail?id=18