I am writing Java Applet. I need to upload pre-generated RSAPrivateCrtKey to applet with APDU Command.
In my computer I am generating key. Next I serialize this key in privateKeyBuffer:
keyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_512);
keyPair.genKeyPair();
rsaPrivateKey = (RSAPrivateCrtKey) keyPair.getPrivate();
byte[] privateKeyBuffer = new byte[165];
short lengthDP1 = rsaPrivateKey.getDP1(privateKeyBuffer, 0);
offset += lengthDP1;
short lengthDQ1 = rsaPrivateKey.getDQ1(privateKeyBuffer, offset);
offset += lengthDQ1;
short lengthP = rsaPrivateKey.getP(privateKeyBuffer, offset);
offset += lengthP;
short lengthQ = rsaPrivateKey.getQ(privateKeyBuffer, offset);
offset += lengthQ;
short lengthPQ = rsaPrivateKey.getPQ(privateKeyBuffer, offset);
After generating a buffer I should convert each array element to hex and then send with APDU and last in applet restore my private key, but in privateKeyBuffer we have negative numbers :
37,65,-96,-110,38,6,-2,73,-37,28,120,-90... (etc)
How I should convert them to hex and keep APDU correct (because as I know only positive numbers allowed) or may be there another way to push key to JavaCard?
Any ideas?
You can simply copy your byte array to the APDU buffer and send it. It will work.
final byte[] apduBuffer = apdu.getBuffer();
Util.arrayCopyNonAtomic(privateKeyBuffer, (short) 0, apduBuffer, (short) 0, (short) privateKeyBuffer.length);
apdu.setOutgoingAndSend((short) 0, (short) privateKeyBuffer.length);
You do not have to think about hex values and positive/negative numbers at all! When you send a byte = 8 bits, you do not deal with its number representation or meaning at all.
An extra note:
byte[] privateKeyBuffer = new byte[165]; is generally a bad idea. You do not need this buffer at all. You can copy key values directly into the APDU buffer, save some persistent memory and make your applet faster.
Another note based on dear #Abraham's comment:
The only problem with positive/negative numbers you could face in Java Card is the fact that Java Card byte is signed, unfortunately. That means its values are always in range [-128,127], although people often forget about it:
final byte b = getSomeByteValue(); //from APDU buffer, for example
if (b == 0x80) { //always false!
//this never happens!
}
If you want to understand your byte as unsigned (range [0, 255]), you have to cast it to short this way:
final byte b = getSomeByteValue(); //from APDU buffer, for example
final short unsignedValue = (short) (b & 0xFF);
if (unsignedValue == 0x80) { //correct!
//can happen
}
Related
I received a CRC function written in C from a hardware partner. Messages send by his devices are signed using this code. Can anyone help me to translate it to Java?
int8 crc8(int8*buf, int8 data_byte)
{
int8 crc=0x00;
int8 data_bit=0x80;
while(data_byte>0)
{
if(((crc&0x01)!=0)!=((buf[data_byte]&data_bit)!=0))
{
crc>>=1;
crc^=0xCD;
}
else
crc>>=1;
data_bit>>=1;
if(!data_bit)
{
data_bit=0x80;
data_byte--;
}
}
return(crc);
}
I tried to convert this to Java, but the result is not I expect.
public static byte crc8(byte [] buf, byte data_byte)
{
byte crc = 0x00;
byte data_bit = (byte)0x80;
while(data_byte>0)
{
if(((crc&0x01)!=0)!=((buf[data_byte]&data_bit)!=0))
{
crc>>=1;
crc^=0xCD;
}
else
{
crc>>=1;
}
data_bit>>=1;
if(data_bit == 0)
{
data_bit= (byte)0x80;
data_byte--;
}
}
return crc;
}
I suppose that this is the error: if(data_bit != 0)
EDIT:
I changed the code to byte in my conversion method. I receive my data from a socket and convert this then to a String where I get a byteArray out from.
An input example is 16, 0, 1, -15, 43, 6, 1, 6, 8, 0, 111, 0, 0 ,49
where the last field (49) should be the checksum
I also tried Durandals version, but my result is still not valid.
This is how I read the data
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
char[] buffer = new char[14];
int count= bufferedReader.read(buffer, 0, 14);
String msg = new String(buffer, 0, count);
byte[] content = msg.getBytes();
if(!data_bit)
translates to
if(data_bit == 0)
You really need to use bytes and not shorts. To get around the problem you had using bytes, use this
byte data_bit = (byte)0x80;
Also, as Mark says, you need to use >>> instead of >>.
Translate the code 1:1, paying extra attention to all operations done on bytes to account for java's implicit cast to int (e.g. (byte >>> 1) is absolutely worthless because the byte is first extendet to int, shifted and then cast back, making it effectively a signed shift no matter what).
Therefore local variables are best declared as int and when loaded from a bytearray masked to yield unsigned extension: int x = byte[i] & 0xFF; Since in the only place that is done data is already masked down to a single bit (in the if) there is nothing special to be done.
Applying to the C code yields:
int crc8(byte[] buf, int dataCount) {
int crc = 0;
int data_bit = 0x80;
while(dataCount > 0) {
if ( ((crc & 0x01)!=0) != ((buf[dataCount] & data_bit)!=0)) {
crc >>= 1;
crc ^= 0xCD;
} else {
crc >>= 1;
}
data_bit >>= 1;
if (data_bit == 0) {
data_bit = 0x80;
dataCount--;
}
}
return crc;
}
That said, the code isn't very efficient (it processes input bit by bit, there are faster implementations processing entire bytes, using a table for each possible byte added, but you probably don't care for this use case).
Also, beware when you compare the crc from this method to a byte, you must mask the byte properly with 0xFF, otherwise comparison will fail for values >=0x80:
(int) crc == (byte) crc & 0xFF
EDIT:
What worries my even about the original code, that data_byte is clearly intended to specify a length, first it calculates in reverse order and also, it will access an additional byte after the specfied number (data_byte is not decremented before the loop). I suspect the original is (already) broken code, or the calls to it are very messy.
I'm working on porting an Android app that has already been developed in Python. In the Python program, there is a line that I'm trying to fully understand:
self.comfd = Serial(...) # from the pySerial API
....
self.buffer = list(struct.unpack('192H', self.comfd.read(384)))
From what I understand, self.comfd.read(384) is reading 384 bytes, and the unpack('192H' is unpacking 192 unsigned shorts from that data. Is this correct?
Now in Java, I've been able to read the buffer using
SerialPort device = SerialPort(file, baud, flags);
InputStream in = device.getInputStream();
My question is, now that I have the input stream, how do I create the unsigned shorts like the Python program is doing?
What I've tried (not producing correct values):
byte[] buffer = new byte[384];
in.read(buffer);
ByteBuffer bb = ByteBuffer.allocate(2);
for (int i = 0; i < buffer.length / 2; i++) {
bb.put(buffer[i]);
bb.put(buffer[i + 1]);
short val = bb.getShort(0);
System.out.println(val);
bb.clear();
}
What am I doing wrong? Thanks for any help!
edit: I incorporated Jason C's answer and also I was looping incorrectly. By changing it to
for (int i = 0; i < buffer.length; i=i+2) that fixed my problem.
You could use a char (it's a 16-bit unsigned value in Java), e.g.:
byte[] buffer = ...;
ByteBuffer bb = ByteBuffer.wrap(buffer); // don't need to put()
int val = (int)bb.getChar(0);
Use bb.order() to set big- vs. little-endian.
You can also just pack the 2 bytes into an int (assuming little-endian) without using a ByteBuffer. Byte is signed in Java, so you will have to convert the byte to an unsigned value before shifting, which you can do by temporarily storing it in a short (or an int or anything large enough to hold 0-255):
short b0 = (buffer[0] & 255); // trick converts to unsigned
short b1 = (buffer[1] & 255);
int val = b0 | (b1 << 8);
// or just put it all inline:
int val = (buffer[0]&255) | ((buffer[1]&255) << 8);
For big-endian data just swap b0 and b1.
Hope that helps.
Java has no unsigned numbers (char is 16bit unsigned but it's not a number and math with char will always result in implicit casts to int)
If you read 2 bytes of unsigned data into a short and want to see values in range from 0-65535 (instead of -32768 - 32767) you'll have to use a type that can have values in that range.
In case of 16bit short next bigger one is 32bit int. The conversion that does the trick is
short signed = ...;
int unsigned = signed & 0xFFFF;
Assuming signed has a value of 0xFFFF this is what happens:
short signed = -1; // FFFF on byte level
The expression signed & 0xFFFF contains a short and an int. 0xFFFF is a literal integer type number which when found in Java source is considered int. You could make it long by changing it to 0xFFFFL (you would need that if you want to convert unsigned int to long).
Since the & operator needs both sides in a common type Java will silently convert the smaller one.
int stillSigned = (int) signed; // hidden step
It will still have the exact same value of -1 since that's what it was before when looking at it unsigned but it is changed on bytelevel to 0xFFFFFFFF.
Now the bit-manipulation is applied to remove all the added FFs
int unsigned = stillSigned & 0xFFFF;
and you end up with 0x0000FFFF on byte level and can finally see the value of 65535.
Since you happen to have 16bit values you can use char and simply cast it to int.
char value = ...;
int unsigned = value;
But above approach works for any unsigned conversion: byteValue & 0xFF, shortValue & 0xFFFF, intValue & 0xFFFFFFFFL
The next thing you should do is not to use a simple InputStream to do
SerialPort device = SerialPort(file, baud, flags);
InputStream in = device.getInputStream();
byte[] buffer = new byte[384];
in.read(buffer);
Reason is that InputStream#read(byte[]) is not guaranteed to read all the bytes you want in your buffer. It returns you the number of bytes it has read or -1 if the stream is done. Manually writing code that ensures you have a filled buffer is nasty but there is a simple solution: DataInputStream
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
byte[] buffer = new byte[384];
in.readFully(buffer);
DataInputStream has very nice functionality that you could use:
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
int unsignedShort = in.readUnsignedShort();
Another way to get different numbers out of byte[] data is to use ByteBuffer since that provides methods like .getShort()
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
byte[] buffer = new byte[384];
in.readFully(buffer);
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
while (byteBuffer.hasRemaining()) {
int unsigned = byteBuffer.getChar();
System.out.println(unsigned);
}
I have an array of bytes (because unsigned byte isn't an option) and need to take 4 of them into a 32 bit int. I'm using this:
byte rdbuf[] = new byte[fileLen+1];
int i = (rdbuf[i++]) | ((rdbuf[i++]<<8)&0xff00) | ((rdbuf[i++]<<16)&0xff0000) | ((rdbuf[i++]<<24)&0xff000000);
If i don't do all the logical ands, it sign extends the bytes which is clearly not what I want.
In c this would be a no brainer. Is there a better way in Java?
You do not have to do this, you can use a ByteBuffer:
int i = ByteBuffer.wrap(rdbuf).order(ByteOrder.LITTLE_ENDIAN).getInt();
If you have many ints to read, the code becomes:
ByteBuffer buf = ByteBuffer.wrap(rdbuf).order(ByteOrder.LITTLE_ENDIAN);
while (buf.remaining() >= 4) // at least four bytes
i = bb.getInt();
Javadoc here. Recommended for use in any situation where binary data has to be dealt with (whether you read or write such data). Can do little endian, big endian and even native ordering. (NOTE: big endian by default).
(edit: #PeterLawrey rightly mentions that this looks like little endian data, fixed code extract -- also, see his answer for how to wrap the contents of a file directly into a ByteBuffer)
NOTES:
ByteOrder has a static method called .nativeOrder(), which returns the byte order used by the underlying architecture;
a ByteBuffer has a builtin offset; the current offset can be queried using .position(), and modified using .position(int); .remaining() will return the number of bytes left to read from the current offset until the end;
there are relative methods which will read from/write at the buffer's current offset, and absolute methods, which will read from/write at an offset you specify.
Instead of reading into a byte[] which you have to wrap with a ByteBuffer which does the shift/mask for you, you can use a direct ByteBuffer which avoid all this overhead.
FileChannel fc = new FileInputStream(filename).getChannel();
ByteBuffer bb = ByteBuffer.allocateDirect(fc.size()).order(ByteBuffer.nativeOrder());
fc.read(bb);
bb.flip();
while(bb.remaining() > 0) {
int n = bb.getInt(); // grab 32-bit from direct memory without shift/mask etc.
short s = bb.getShort(); // grab 16-bit from direct memory without shift/mask etc.
// get a String with an unsigned 16 bit length followed by ISO-8859-1 encoding.
int len = bb.getShort() & 0xFFFF;
StringBuilder sb = new StringBuilder(len);
for(int i=0;i<len;i++) sb.append((char) (bb.get() & 0xFF));
String text = sb.toString();
}
fc.close();
I'm making a system where I want to verify the server's identity via RSA, but I can't seem to get the server to properly decrypt the client's message.
The public and private keys are in slot 0 of the array, and mod is in slot 1, so they are setup correctly.
Client side code
int keyLength = 3072 / 8;//RSA key size
byte[] data = new byte[keyLength];
//Generate some random data. Note that
//Only the fist half of this will be used.
new SecureRandom().nextBytes(data);
int serverKeySize = in.readInt();
if (serverKeySize != keyLength) {//Definitely not the right heard
return false;
}
//Take the server's half of the random data and pass ours
in.readFully(data, keyLength / 2 , keyLength / 2);
//Encrypt the data
BigInteger[] keys = getKeys();
BigInteger original = new BigInteger(data);
BigInteger encrypted = original.modPow(keys[0], keys[1]);
data = encrypted.toByteArray();
out.write(data);
//If the server's hash doesn't match, the server has the wrong key!
in.readFully(data, 0, data.length);
BigInteger decrypted = new BigInteger(data);
return original.equals(decrypted);
Server side code
int keyLength = 3072 / 8;//Key length
byte[] data = new byte[keyLength];
//Send the second half of the key
out.write(data, keyLength / 2, keyLength / 2);
in.readFully(data);
BigInteger[] keys = getKeys();
BigInteger encrypted = new BigInteger(data);
BigInteger original = encrypted.modPow(keys[0], keys[1]);
data = original.toByteArray();
out.write(data);
AFAIK that implementation is correct however it doesn't seem to produce the correct output. Also no, I do not wish to use a Cipher for various reasons.
There are some critical details that are not being accounted for. The data you want to apply RSA to must be encoded as BigInteger x, with 0 <= x < n, where n is your modulus. You aren't doing that. In fact, because you are filling your entire data array with random data you cannot guarantee that. The PKCS#1 padding algorithm is designed to do this correctly, but since you are rolling your own you'll have to fix this in your code. Also, examine carefully how the BigInteger(byte[]) constructor and BigInteger.toByteArray() decode/encode integers. Naively many expect simply the base 256 encoding, and forget that BigInteger must accommodate negative integer also. It does so by using the ASN.1 DER integer rules. If the positive integer's high-order byte would be >= 128 then a leading zero byte is added.
I'm working with java.
I have a byte array (8 bits in each position of the array) and what I need to do is to put together 2 of the values of the array and get a value.
I'll try to explain myself better; I'm extracting audio data from a audio file. This data is stored in a byte array. Each audio sample has a size of 16 bits. If the array is:
byte[] audioData;
What I need is to get 1 value from samples audioData[0] and audioData[1] in order to get 1 audio sample.
Can anyone explain me how to do this?
Thanks in advance.
I'm not a Java developer so this could be completely off-base, but have you considered using a ByteBuffer?
Assume the LSB is at data[0]
int val;
val = (((int)data[0]) & 0x00FF) | ((int)data[1]<<8);
As suggested before, Java has classes to help you with this. You can wrap your array with a ByteBuffer and then get an IntBuffer view of it.
ByteBuffer bb = ByteBuffer.wrap(audioData);
// optional: bb.order(ByteOrder.BIG_ENDIAN) or bb.order(ByteOrder.LITTLE_ENDIAN)
IntBuffer ib = bb.asIntBuffer();
int firstInt = ib.get(0);
ByteInputStream b = new ByteInputStream(audioData);
DataInputStream data = new DataInputStream(b);
short value = data.readShort();
The advantage of the above code is that you can keep reading the rest of 'data' in the same way.
A simpler solution for just two values might be:
short value = (short) ((audioData[0]<<8) | (audioData[1] & 0xff));
This simple solution extracts two bytes, and pieces them together with the first byte being the higher order bits and the second byte the lower order bits (this is known as Big-Endian; if your byte array contained Little-Endian data, you would shift the second byte over instead for 16-bit numbers; for Little-Endian 32-bit numbers, you would have to reverse the order of all 4 bytes, because Java's integers follow Big-Endian ordering).
easier way in Java to parse an array of bytes to bits is JBBP usage
class Parsed { #Bin(type = BinType.BIT_ARRAY) byte [] bits;}
final Parsed parsed = JBBPParser.prepare("bit:1 [_] bits;").parse(theByteArray).mapTo(Parsed.class);
the code will place parsed bits of each byte as 8 bytes in the bits array of the Parsed class instance
You can convert to a short (2 bytes) by logical or-ing the two bytes together:
short value = ((short) audioData[0]) | ((short) audioData[1] << 8);
I suggest you take a look at Preon. In Preon, you would be able to say something like this:
class Sample {
#BoundNumber(size="16") // Size of the sample in bits
int value;
}
class AudioFile {
#BoundList(size="...") // Number of samples
Sample[] samples;
}
byte[] buffer = ...;
Codec<AudioFile> codec = Codecs.create(AudioFile.class);
AudioFile audioFile = codec.decode(buffer);
You can do it like this, no libraries or external classes.
byte myByte = (byte) -128;
for(int i = 0 ; i < 8 ; i++) {
boolean val = (myByte & 256) > 0;
myByte = (byte) (myByte << 1);
System.out.print(val ? 1 : 0);
}
System.out.println();
byte myByte = 0x5B;
boolean bits = new boolean[8];
for(int i = 0 ; i < 8 ; i++)
bit[i] = (myByte%2 == 1);
The results is an array of zeros and ones where 1=TRUE and 0=FALSE :)