Can anyone explain me why when I constructing BigInteger with 2 byte value toByteArray() then returns 3.
BigInteger data = new BigInteger("FFFF", 16))
data.toByteArray() <-- here am getting 3 bytes.
I think this is because BIgInteger signed by default.
Is there any work-around for this?
Also, why BigInteger stores 1 byte value without two's complement additional byte? I am just trying to figure out one elegant way to process all my values.
Related
I need to sum all data bytes in ByteArrayOutputStream, adding +1 to the result and taking the 2 least significant bytes.
int checksum = 1;
for(byte b : byteOutputStream.toByteArray()) {
checksum += b;
}
Any input on taking the 2 least significant bytes would be helpful. Java 8 is used in the environment.
If you really mean least significant bytes then:
checksum & 0xFFFF
If you meant that you want to take least significant bits from checksum, then:
checksum & 0x3
Add
checksum &= 0x0000ffff;
That will zero out everything to the left of the 2 least significant bytes.
Your question is a bit underspecified. You didn’t say neither, what you want to do with these two bytes nor how you want to store them (which depends on what you want to do).
To get to individual bytes, you can use
byte lowest = (byte)checksum, semiLowest=(byte)(checksum>>8);
In case you want to store them in a single integer variable, you have to decide, how these bytes are to be interpreted numerically, i.e signed or unsigned.
If you want a signed interpretation, the operation is as simple as
short lowest2bytes = (short)checksum;
If you want an unsigned interpretation, there’s the obstacle that Java has no dedicated type for that. There is a 2 byte sized unsigned type (char), but using it for numerical values can cause confusion when other code tries to interpret it as character value (i.e. when printing). So in that case, the best solution is to use an int variable again and only initialize it with the unsigned char value:
int lowest2bytes = (char)checksum;
Note that this is semantically equivalent to
int lowest2bytes = checksum&0xffff;
seen in other solutions.
I was trying to store byte value in a variable and trying to perform some logic based upon this calculation.
byte mByteValue = -129; // Holding byte value
Problem is I am always getting value 127, due to which my logic fails everytime.
Any specific reason behind this, why its behaving strange in my case?
A byte in java is a signed 8-bit value. 8 bits gives you 256 possible values, but since a byte is signed and can represent positive and negative values, those 256 values must be roughly split in half across the possible positive and negative values. So you can't store negative values past -128; in particular don't expect to be able to store -256.
What you're actually observing when your byte has the value 127 is known as overflow (see this wiki article)
If you need to manipulate values outside this range, as in your example code, or e.g. an unsigned byte, at some point you'll need to make use of a wider integer type, like short.
The standard libraries provide these limits as Byte.MIN_VALUE and Byte.MAX_VALUE (docs here and here).
The range of byte is from -128 to 127. You can not store any value beyond these range.
This is because byte is 8 bits. So the maximum positive number stored at byte is -
2^7 -1 = 127. // since the first bit is sing bit; 0 for positive
And minimum negative number stored at byte is-
2^7 = -128 //since the first bit is sign bit; 1 for negative.
And if you use unsigned byte the it would be 255.
To correctly convert a byte to an int use mByteValue & 0xFF. You can read more about the Two's complement here: https://en.wikipedia.org/wiki/Two%27s_complement.
So, I'm using a proprietary library that has its own implementation for the creation of RSA key pairs. The public key struct looks like this:
typedef struct
{
unsigned int bits; //Length of modulus in bits
unsigned char modulus[MAX_RSA_MOD_LEN]; //Modulus
unsigned char exponent[MAX_RSA_MOD_LEN]; //Exponent
} RSA_PUB_KEY
I need to figure out a way to extract both the exponent and the module so I can send them to a server as part of a validation scheme. I guess that this is a pretty standard procedure (or so I hope). I've already read these two similar questions:
How to convert an Unsigned Character array into a hexadecimal string in C
Printing the hexadecimal representation of a char array[]
But so far I've had no luck. I'm also not sure of how to use if at all necessary the "bits" field to extract the modulus. In short what I have to do is be able to recreate this public key in Java:
BigInteger m = new BigInteger(MODULUS);
BigInteger e = new BigInteger(EXPONENT);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
Edit:
This is what I'm doing right now: (RSAPublic is a RSA_PUB_KEY struct as described above).
//RSAPublic.bits = length of modulus in bits
log("Modulus length: "+std::to_string(RSAPublic.bits));
log("Key length: "+std::to_string(keyLengthInBits));
//Calculating buffer size for converted hexadec. representations
int modulusLengthInBytes = (RSAPublic.bits+7)/8 ;
int exponentLengthInBytes = (keyLengthInBits+7)/8;
char convertedMod[modulusLengthInBytes*2+1];
char convertedExp[exponentLengthInBytes*2+1];
//Conversion
int i;
for(i=0; i<modulusLengthInBytes ; i++){
sprintf(&convertedMod[i*2], "%02X", RSAPublic.modulus[i]);
}
for(i=0; i<exponentLengthInBytes ; i++){
sprintf(&convertedExp[i*2], "%02X", RSAPublic.exponent[i]);
}
//Print results
printf("Modulus: %s\n", convertedMod);
printf("Exponent: %s\n", convertedExp);
And this is the output:
Modulus length: 16
Key length: 512
Modulus: 0000
Exponent: 0A000200FFFFFFFFFFFF0000600007004DDA0100B01D0000AEC642017A4513000000000000000000000000000000000000000000000000000000000000000000
I'm assuming that you can't just send binary data since you mention the hexadecimal conversion. The most compact way you can send the data as text would be with base 64 but this is more complex than hexadecimal.
Client side
Convert the unsigned char array to a hexadecimal string using a method from the links you have. The bits field will determine how many bytes from the array to use given by (bits+7)/8.
Depending on implementation you might have to explicitly select the overflow bits or the rest might be zeroed, this also depends on the endianness so since you are unsure on implementation details you might have to fiddle around with it a bit.
Once you have the encoded strings, send them to the server.
Server side
Read the encoded strings from the connection and then pass them to the BigInteger(String val, int radix) constructor using the radix of hexadecimal (16).
You will then have A BigInteger with the value you require.
If the first bytes of the public exponent are all zero's then you are dealing with a big endian array. This is most common. In principle the public exponent can be as large as the modulus, but this is commonly not the case. Most common values are 65537, 17 and 3, maybe even 2 but the 3 and 2 are not such good values. Other 2-4 byte primes are also common.
Now if you know the endianness, you can have a look at the modulus. If the highest byte value is 00 then you are dealing with a signed representation of the modulus. Otherwise it is likely unsigned. The highest order byte of the modulus that contains bits should always be 80 or higher. The reason is that otherwise the key size would be smaller than the given key size. This is assuming that the key size is a multiple of 8 of course.
Java only works with big endian for BigInteger (and any other number representation). So if you have little endian encoding in C then you need to reverse the values in Java. It is probably the best to reverse the hexadecimal values in the string to accomplish that. Make sure you handle 2 hexadecimal characters at a time.
Then, as DrYap suggested, use the hexadecimal constructor of BigInteger. Note that if you end up using a byte array then you may want to use new BigInteger(1, MODULUS) as this makes sure you get a positive number regardless of the highest order bit value in the encoding.
This code
byte b = Byte.parseByte("10000000", 2);
throws an exception in Java. This should be -128 or 255.
Byte has 8 bit. Why can't I parse a 8 bit string?
The reason is down to the range of a byte in Java. Bytes are signed, so you can have anything from -128 ("-10000000") through to 127 ("1111111"), but no values outside that range.
The MAX_VALUE of a byte in java (or in C#) is 127 where as 10000000 return 128 which cannot be stored in a byte variable
What you can do treat the value as signed this way.
byte b = (byte) Integer.parseInt("10000000", 2);
Strictly, you passed not eight bits to parse method, but string representation of usual number with radix 2. And it may contain a sign character. Particularly, byte b = Byte.parseByte("-10000000", 2) works nice and gives -128.
That's not an 8-bit string, it's an 8-character string, and it's not being read the way you think it is...
From the MSDN documentation (here), you'll see that byte.Parse accepts strings in the integer format. So, you're trying to parse 10 million, not -1. The exception you're getting gives this away: you should see an OverflowException.
byte.parse("255") gives the effect you expect (byte is unsigned; using -128 also gives an overflow).
I believe conversion exactly to BigInteger[] would be optimal in my case. Anyone had done or found this written in Java and willing to share?
So imagine I have arbitrary size byte[] = {0xff,0x3e,0x12,0x45,0x1d,0x11,0x2a,0x80,0x81,0x45,0x1d,0x11,0x2a,0x80,0x81}
How do I convert it to array of BigInteger's and then be able to recover it back the original byte array safely?
ty in advance.
Use BigInteger.toByteArray() and BigInteger(byte[]).
According to the javadoc, the latter ...
Translates a byte array containing the two's-complement binary representation of a BigInteger into a BigInteger. The input array is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element.
If your byte-wise representation is different, you may need to apply some extra transformations.
EDIT - if you need to preserve leading (i.e. non-significant) zeros, do the following:
When you convert from the byte array to a BigInteger, also make a note of the size of the byte array. This information is not encoded in the BigInteger value.
When you convert from the BigInteger to a byte array, sign-extend the byte array out to the same length as the original byte array.
EDIT 2 - if you want to turn a byte array into an array of BigIntegers with at most N bytes in each one, you need to create a temporary array of size N, repeatedly 1) fill it with bytes from the input byte array (with left padding at the end) and 2) use it to create BigInteger values using the constructor above. Maybe 20 lines of code?
But I'm frankly baffled that you would (apparently) pick a value for N based on memory usage rather than based on the mathematical algorithm you are trying to implement.