Strange data received from java smart card APDU? - java

I can send most data from the smart card without a problem. I noticed i always need to remove the first 6 bytes in the APDU to get the real data for some reason.
However, when sending one particular data, it's very hard to know where the data is in the APDU.
This is the code of the Java smartcard simulator:
data = new byte[] {(byte)0x6302};
apdu.setOutgoing();
apdu.setOutgoingLength((short) data.length);
apdu.sendBytesLong(data, (short) 0, (short) data.length);
The data expected to be sent/received is:
{0x2}
However, the data received in the middleware response APDU is:
responseApdu.getData():
{0x80, 0x32, 0x0, 0x0, 0x8, 0x0, 0x0, 0x1, 0x5c, 0x6, 0xf9, 0x63, 0x33, 0x1, 0x2, 0x90, 0x0}
I also tried logging the APDU that is sent by the java card simulator; it is the following data:
SendAPDU() data (apdu.getBuffer()):
{0x2, 0x32, 0x0, 0x0, 0x8, 0x0, 0x0, 0x1, 0x5c, 0x6, 0xf9, 0x63, 0x33, 0x0, ..... (all 0x0 after this point)}
Offset CDATA: 5
Can somebody help me understand why the data sent (or read before even sending) is so different from the actual data sent? Is it some kind of padding? How can I get the original data sent?

Change code to:
data = new byte[] {(byte) 0x63, (byte) 0x02};
apdu.setOutgoing();
apdu.setOutgoingLength((short) data.length);
apdu.sendBytesLong(data, (short) 0, (short) data.length);
The data bytes { 0x63, 0x02 } will be sent out.
And the data you mentioned in your question:
The Response APDU data is:
responseApdu.getData():
{0x80, 0x32, 0x0, 0x0, 0x8, 0x0, 0x0, 0x1, 0x5c, 0x6, 0xf9, 0x63, 0x33, 0x1, 0x2, 0x90, 0x0}
Means command data is: { 0x80, 0x32, 0x0, 0x0, 0x8, 0x0, 0x0, 0x1, 0x5c, 0x6, 0xf9, 0x63, 0x33, 0x1};, and response data is: { 0x2, 0x90, 0x0 };
The apdu buffer is:
SendAPDU() data (apdu.getBuffer()):
{0x2, 0x32, 0x0, 0x0, 0x8, 0x0, 0x0, 0x1, 0x5c, 0x6, 0xf9, 0x63, 0x33, 0x0, ..... (all 0x0 after this point)}
Offset CDATA: 5
Means the data byte 0x02 will be sent (the sent length is 1 byte), the SW 0x9000 ({ 0x90, 0x00 }) will be sent after this byte. The Offset CDATA is not used when outgoing. And other data bytes in the APDU buffer is your APDU commands, the first byte is overwrite by the outgoing bytes (Here only 1 byte, 0x02).
Note:
process of APDU.sendBytesLong(data, offset, length):
1). Copy data with offset and length to APDU buffer;
2). Send data using APDU buffer;
3). Send SW;

Related

LengthFieldBasedFrameDecoder not parsing correctly when buffer size is less than frame size

I am unit testing a netty pipeline using the frame based decoder. It looks like the framing is incorrect if I use buffer size that is smaller that the largest frame. I am testing with a file that contains two messages. The length field is the second work and includes the length of the entire message including the length field and the work before it.
new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0)
I am reading a file with various block sizes. The size of the first message is 348 bytes, the second is 456 bytes. If block size of 512, 3456, or larger, is used both messages are read and correctly framed to the next handler which for diagnostic purposes will print out as a hexadecimal string the contents of the buffer it received. If a smaller block size is used framing errors occur. The code used to read and write the file is shown below.
public class NCCTBinAToCSV {
private static String inputFileName = "/tmp/combined.bin";
private static final int BLOCKSIZE = 456;
public static void main(String[] args) throws Exception {
byte[] bytes = new byte[BLOCKSIZE];
EmbeddedChannel channel = new EmbeddedChannel(
new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0),
new NCCTMessageDecoder(),
new StringOutputHandler());
FileInputStream fis = new FileInputStream(new File(inputFileName));
int bytesRead = 0;
while ((bytesRead = fis.read(bytes)) != -1) {
ByteBuf buf = Unpooled.wrappedBuffer(bytes, 0, bytesRead);
channel.writeInbound(buf);
}
channel.flush();
}
}
Output from a successful run with block size of 356 bytes is show below (with the body of the messages truncated for brevity
LOG:DEBUG 2017-04-24 04:19:24,675[main](netty.NCCTMessageDecoder) - com.ticomgeo.mtr.ncct.netty.NCCTMessageDecoder.decode(NCCTMessageDecoder.java:21) ]received 348 bytes
Frame Start========================================
(byte) 0xbb, (byte) 0x55, (byte) 0x05, (byte) 0x16,
(byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x5c,
(byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x02,
(byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x50, (byte) 0x3a, (byte) 0xc9, (byte) 0x17,
....
Frame End========================================
Frame Start========================================
(byte) 0xbb, (byte) 0x55, (byte) 0x05, (byte) 0x1c,
(byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0xc8,
(byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x02,
(byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x04, (byte) 0x02, (byte) 0x00, (byte) 0x01,
If I change the block size to 256, the wrong bytes seem to be read as the length field.
Exception in thread "main" io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 65536: 4294967040 - discarded
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:499)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403)
TL;DR; Your problem is caused because netty reuses the passed in bytebuf, and then you are overwriting the contents.
LengthFieldBasedFrameDecoder is designed through inheritance to reuse the passed in ByteBuf, because it is useless to let the object decay through garbage collection when you can reuse it because its reference count is 1. The problem however comes from the fact that you are changing the internals of the passed in bytebuf, and therefore changing the frame on the fly. Instead of making a wrappedBuffer, that uses your passed in variable as storage, you should use copiedBuffer, because that one properly makes a copy of it, so the internals of LengthFieldBasedFrameDecoder can do freely things with it.

javax.smarcardio unknown exception 0x1f

I'm working on a card reader now. I want to take data from the card. I took uid. I want to take encrypted data. So I want to enter the secure mode and start session. I did something. I send a command apdu to start session but every time return unknown exception 0x1f here is the code.
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
terminal = terminals.get(0);
card = terminal.connect("T=1");
CardChannel channel = card.getBasicChannel();
byte[] c1 = { (byte) 0x80, (byte) 0x72, (byte) 0x80, (byte) 0x00, (byte) 0x18, (byte) 0x5c, (byte) 0xc5,
(byte) 0x0a, (byte) 0xa2, (byte) 0x5b, (byte) 0x38, (byte) 0x7f, (byte) 0x81, (byte) 0x3a, (byte) 0x3d,
(byte) 0x1a, (byte) 0x88, (byte) 0x7d, (byte) 0x26, (byte) 0xfc, (byte) 0x2b, (byte) 0xa8, (byte) 0xa7,
(byte) 0xdd, (byte) 0xdc, (byte) 0x71, (byte) 0xe0, (byte) 0xf3, (byte) 0xc6 };
ResponseAPDU response = channel.transmit(new CommandAPDU(0xFF, 0x00,0x00,0x00,c1,5,24));
This code returns me 6a81( it means function not supported),
if I send directly start session command(84 72 00 00) this time returns unknown exception.
Please help me. You don't have to find the error in code. Tell me How Can I Start Session in a Smart Card. I use HID OMNÄ°KEY 5021 CL.
Exception in thread "main" javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: Unknown error 0x1f
at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:219)
at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
at CardReader.GetUID.getUID(GetUID.java:48)
at CardReader.GetUID.main(GetUID.java:86)
APDU you're sending is wrong, because you use CommandAPDU in an incorrect way.
new CommandAPDU(0xFF, 0x00,0x00,0x00,c1,5,24)
creates an APDU starting FF000000185CC50AA2... which is not what you (probably) want.
Try new CommandAPDU(0x84, 0x72,0x00,0x00,c1,5,24) instead.
See CommandAPDU javadoc and APDU format description.
I found the problem. The problem is byte types .net and java. C# byte type between 0 and 255 but java byte type -127 and +128. So if I send a higher than 127 value to java, card interpret like minus value.

Android - Writing to ISO15693 Tags

I'm currently trying to write a couple of bytes to a specific block. My read commands work fine and I am able to read any block of my tag using the code below:
command = new byte[]{
(byte) 0x02, // Flags
(byte) 0x23, // Command: Read multiple blocks
(byte) 0x09, // First block (offset)
(byte) 0x03 // Number of blocks // MAX READ SIZE: 32 blocks:1F
};
byte[] data = nfcvTag.transceive(command);
When I try to write with the code below, my app crashes.
Write = new byte[]{
(byte) 0x02, // Flags
(byte) 0x21, // Command: Write 1 blocks
(byte) 0x5A, // First block (offset)
(byte) 0x41 // Data
};
nfcvTag.transceive(Write);
I'm doing this in an AsyncTask and getting the java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() exception.
Any tips? The tag is a STMicroelectronics M24LR04E-R
Figured it out. I was only writing 8 bits of data while the tag has 32 bits per block. Added 3 0x00's and the write was successful.
Write = new byte[]{
(byte) 0x02, // Flags
(byte) 0x21, // Command: Write 1 blocks
(byte) 0x5A, // First block (offset)
(byte) 0x41,
(byte) 0x00,
(byte) 0x00,
(byte) 0x00
};
nfcvTag.transceive(Write);

How to initialize a EC key pair with an existing key pair in JavaCard?

I already have a EC key pair(secp256r1) in a binary format which is stored in a byte array, like this:
// private key, 32 bytes
byte[] privKey = {0x4c, (byte)0xc7, (byte)0xcf, 0x68, (byte)0x91, 0x18, (byte)0x96, (byte)0xc8, (byte)0xe2, (byte)0xf9, (byte)0xc8, (byte)0xcc, 0x2f, 0x7f, 0x0a, (byte)0xa2, 0x1c, 0x6a, (byte)0xcb, (byte)0xba, 0x38, 0x1c, 0x10, (byte)0x9a, (byte)0xfe, (byte)0x91, 0x18, (byte)0xf6, (byte)0xca, (byte)0xd9, 0x0f, 0x0b};
//public key, 65 bytes, which is contained in a X.509 certificate
byte[] pubKey = {0x04, 0x72, (byte)0x9a, 0x71, (byte)0xd0, (byte)0x81, 0x62, 0x42, (byte)0x84, (byte)0x92, (byte)0xf2, (byte)0xd9, 0x61, (byte)0x92, 0x4d, 0x37, 0x44, 0x3a, 0x4f, 0x1b, (byte)0xda, 0x58, 0x0f, (byte)0x8a, (byte)0xea, 0x29, 0x20, (byte)0xd2, (byte)0x99, 0x7c, (byte)0xbe, (byte)0xa4, 0x39, 0x60, (byte)0xce, 0x72, (byte)0x9e, 0x35, (byte)0xc1, (byte)0xf7, 0x40, (byte)0x92, (byte)0xf2, 0x25, 0x0e, 0x60, 0x74, (byte)0x82, 0x3f, (byte)0xc5, 0x7f, 0x33, 0x60, (byte)0xb7, (byte)0xcd, 0x39, 0x69, (byte)0xc3, (byte)0xc3, 0x12, 0x5e, (byte)0xce, 0x26, 0x5c, 0x29};
This EC key pair is generated by openssl. I want to store this EC key pair in my javacard applet, so that I can signature message with this EC private key every time.
But I don't find any appropriate API in javacard 3 to set the EC key pair.
I use this project https://github.com/Yubico/ykneo-curves/blob/master/applet/src/com/yubico/ykneo/curves/SecP256r1.java to set the parameters in secp256r1.
UPDATE
I do have set the parameters setW in ECPublicKey and setS in ECPrivateKey, and other parameters according to https://github.com/Yubico/ykneo-curves/blob/master/applet/src/com/yubico/ykneo/curves/SecP256r1.java. Like this:
privKey.setFieldFP(p, (short) 0, (short) p.length);
privKey.setA(a, (short) 0, (short) a.length);
privKey.setB(b, (short) 0, (short) b.length);
privKey.setG(G, (short) 0, (short) G.length);
privKey.setR(r, (short) 0, (short) r.length);
byte[] privData = {(byte)0x25, (byte)0xc9, (byte)0xec, (byte)0xdc, (byte)0x4c, (byte)0x59, (byte)0xa3, (byte)0xe0, (byte)0x4f, (byte)0x01, (byte)0x56, (byte)0x97, (byte)0xf3, (byte)0xcb, (byte)0x60, (byte)0x5b, (byte)0x84, (byte)0x49, (byte)0x45, (byte)0x3a, (byte)0xe2, (byte)0x0e, (byte)0xd1, (byte)0xbd, (byte)0xc0, (byte)0xa7, (byte)0xe1, (byte)0xfa, (byte)0x82, (byte)0xee, (byte)0x3c, (byte)0x73};
privKey.setS(privData, (short) 0, (short) privData.length);
pubKey.setFieldFP(p, (short) 0, (short) p.length);
pubKey.setA(a, (short) 0, (short) a.length);
pubKey.setB(b, (short) 0, (short) b.length);
pubKey.setG(G, (short) 0, (short) G.length);
pubKey.setR(r, (short) 0, (short) r.length);
byte[] pubData = {0x04, 0x00, (byte)0xb9, (byte)0x8f, (byte)0xcf, (byte)0xc3, (byte)0xc0, (byte)0xae, (byte)0x95, 0x6a, 0x5b, 0x12, 0x6d, (byte)0xbe, 0x43, (byte)0xe4, 0x7f, 0x09, 0x0d, (byte)0xde, 0x02, (byte)0xd2, 0x6b, 0x28, (byte)0x86, (byte)0xed, 0x2b, (byte)0xd7, (byte)0xe2, (byte)0xc2, 0x69, (byte)0xc1, (byte)0x89, (byte)0xb2, 0x53, (byte)0x96, (byte)0xc1, 0x2d, (byte)0xbf, 0x4c, 0x30, (byte)0xae, (byte)0xd5, (byte)0xd5, 0x3c, (byte)0xb5, (byte)0xf9, 0x3b, 0x20, 0x37, (byte)0x83, (byte)0x88, (byte)0x9f, 0x34, 0x74, (byte)0xf5, 0x6c, (byte)0x97, 0x1e, 0x0a, (byte)0xa9, (byte)0xe7, (byte)0xfa, (byte)0xa6, 0x69};
pubKey.setW(pubData, (short) 0, (short)pubData.length);
Now I signature the message:
// the class Secp256r1 can be found in above link
pair = SecP256r1.newKeyPair();
ECPublicKey pubKey = (ECPublicKey) pair.getPublic();
ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate();
byte[] data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
signature = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);
signature.init(pair.getPrivate(), Signature.MODE_SIGN);
byte[] signData = new byte[127];
short sendLen = signature.sign(data, (short) 0, (short) data.length, buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, sendLen);
I send several APDUs to call this code fragment. But every time I receive a differnt sign message. Why should this happened?
There are methods setW(...) on ECPublicKey and setS(...) on ECPrivateKey.
The tricky part is that your keyPair.getPublic() and keyPair.getPrivate() return general interfaces. You have to cast them:
KeyPair keyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
pub.setW(pubBytes, (short) 0, (short) pubBytes.length);
priv.setS(privBytes, (short) 0, (short) privBytes.length);
//do not forget to set parameters of your curve to both private and public key HERE!!!
https://docs.oracle.com/javacard/3.0.5/api/javacard/security/ECPublicKey.html
void setW(byte[] buffer,
short offset,
short length)
throws CryptoException
Sets the point of the curve comprising the public key. The point
should be specified as an octet string as per ANSI X9.62. A specific
implementation need not support the compressed form, but must support
the uncompressed form of the point. The plain text data format is
big-endian and right-aligned (the least significant bit is the least
significant bit of last byte). Input parameter data is copied into the
internal representation.
https://docs.oracle.com/javacard/3.0.5/api/javacard/security/ECPrivateKey.html
void setS(byte[] buffer,
short offset,
short length)
throws CryptoException
Sets the value of the secret key. The plain text data format is
big-endian and right-aligned (the least significant bit is the least
significant bit of last byte). Input parameter data is copied into the
internal representation.
ANSWER to UPDATE:
Signatures based on an elliptic curve contain a random number, that is why you get a different result each time you compute a signature. It is a feature, not a bug.

how to build a rsa key with a modulus of 64 bytes in java

I have a java card applet which will generate a RSA private public key pair (512 bits each). And it will send the public key modulus and exponent (modulus is 64 bytes)
In the host application (java) i need to re build the rsa public key using the same exponent and modulus, but when i try to reconstruct using the following code i am getting an error.
Java card code:
// this one to create the key pair
rsa_KeyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_512);
rsa_KeyPair.genKeyPair();
rsa_PublicKey = (RSAPublicKey) rsa_KeyPair.getPublic();
rsa_PrivateCrtKey 0= (RSAPrivateCrtKey) rsa_KeyPair.getPrivate();
cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
//this is to send the modulus
byte[] buffer = apdu.getBuffer();
rsa_PublicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoing();
apdu.setOutgoingLength((short) 64);
apdu.sendBytesLong(buffer, ISO7816.OFFSET_CDATA, (short) 64);
This part of the code is working fine. i am able to send the modulus perfectly to the host side.
Java code for host application below:
//command for retrieving modulus
resp = channel.transmit(new CommandAPDU(cmdMod));
BigInteger modulus = new BigInteger(resp.getData());
I am getting the 64 byte modulus as expected but when i make a big integer out of it its showing a large negative value.
//command for retrieving exponent
resp = channel.transmit(new CommandAPDU(cmdExp));
BigInteger modulus = new BigInteger(resp.getData());
byte[] input = { (byte) 0x92, (byte) 0x84, (byte) 0x3B,
(byte) 0xD3, (byte) 0x5D, (byte) 0x8A, (byte) 0x6B,
(byte) 0x56, (byte) 0xDA, (byte) 0xEA, (byte) 0xE0,
(byte) 0x2F, (byte) 0x6D, (byte) 0xAA, (byte) 0x62,
(byte) 0x4B, (byte) 0x38, (byte) 0xCE, (byte) 0xD4,
(byte) 0x70, (byte) 0xA2, (byte) 0x16, (byte) 0x35,
(byte) 0xCC, (byte) 0xEE, (byte) 0xB8, (byte) 0x31,
(byte) 0x13, (byte) 0x37, (byte) 0x40, (byte) 0xBE,
(byte) 0xA1, (byte) 0xCD, (byte) 0x84, (byte) 0xD9,
(byte) 0xF3, (byte) 0xE6, (byte) 0xCE, (byte) 0x26,
(byte) 0x0A, (byte) 0xC1, (byte) 0x40, (byte) 0xED,
(byte) 0x20, (byte) 0x8F, (byte) 0x3D, (byte) 0x9F,
(byte) 0x0D, (byte) 0xE7, (byte) 0x19, (byte) 0xC8,
(byte) 0x87, (byte) 0x96, (byte) 0x29, (byte) 0xF2,
(byte) 0x63, (byte) 0x34, (byte) 0x6D, (byte) 0x10,
(byte) 0xB9, (byte) 0xFB, (byte) 0xB4, (byte) 0x75,
(byte) 0xE9 };
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new RSAPublicKeySpec(modulus, exponent));
Cipher cipher = null;
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherText = cipher.doFinal(input);
Error:
javax.crypto.BadPaddingException: Message is larger than modulus
at sun.security.rsa.RSACore.parseMsg(Unknown Source)
at sun.security.rsa.RSACore.crypt(Unknown Source)
at sun.security.rsa.RSACore.rsa(Unknown Source)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:355)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2121)
at testAuth.main(testAuth.java:150)
I checked the reponse from the card. i am getting all the 64 bytes of the modulus correctly. but when i make the Big Integer i am getting a large negative value. what should i do?
The issue is that BigInteger by default encodes to a signed big endian representation. If you decode the bytes using the constructor it does the opposite, i.e. it expects a signed value. Now most cryptography is performed on (large) unsigned integers. This is because the calculations are performed within a mathematical group (modulus calculations). These calculations are always performed on positive numbers, and RSA is no exception to this rule.
Now the size of the modulus is equal to the key size (not the key strength) of the RSA key. This means that an RSA key of 512 bit has a modulus of exactly 512 bits when encoded as a unsiged, big endian number. For numbers this means that the most significant bit is always set to '1'. However, that bit is used to indicate the sign bit for unsigned numbers encoded as a two-complement value. In other words, any modulus that has a key size dividable by 8 will be negative when interpreted as signed value.
The solution is of course to use the constructor where you can indicate the sign bit yourself:
BigInteger(int signum, byte[] magnitude)
where magnitude is the unsigned representation, in your case:
new BigInteger(1, resp.getData());
Java Card uses unsigned representations in the API, as it is more cryptographically oriented. No need for complicated methods in there.
Note that the reverse - creating a statically sized byte array out of an encoded signed BigInteger is even trickier, see this answer for information about how to perform that particular conversion.

Categories

Resources