from Hbase rowkey design
I dont unstand the sample in "Byte Pattern":
// hash
//
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(Bytes.toBytes(s));
System.out.println("md5 digest bytes length: " + digest.length); // returns 16
String sDigest = new String(digest);
byte[] sbDigest = Bytes.toBytes(sDigest);
System.out.println("md5 digest as string length: " + sbDigest.length); // returns 26
why sbDigent.length != digest.length ?
Thank you
in my eclipse,
"digest" is 0xE807F1FCF82D132F9BB018CA6738A19F, 16 bytes, so its length is 16.
"sbDigest" is 0xEFBFBD07EFBFBDEFBFBDEFBFBD2D132FEFBFBDEFBFBD18EFBFBD6738EFBFBDEFBFBD,34 bytes, so its length is 34 (not 26).
The root reason is java.lang.String's constructor:
public String(byte[] bytes)
Constructs a new String by decoding the specified array of bytes using
the platform's default charset. The length of the new String is a
function of the charset, and hence may not be equal to the length
of the byte array.
Related
For this question I am asked to:
convert text to hash,
then put it into a byte array,
construct a new byte array 0b, with a zero byte at index 0 then b.
I am able to get the hash of the message c84291b88e8367ef3448899117f8b497f58ac7d43689239783f708ea0092c39b with my code:
MessageDigest md = MessageDigest.getInstance("SHA-256");
//Convert Message to hash
md.update(message1.getBytes());
byte[] digest = md.digest();
String Hash = hexaToString(digest);
System.out.println( "Message 1 in hash is = " + Hash);
And I am able to convert it into a byte array but I am not sure how to add the zerobyte to the start of the byte array?
When computing the digest, you can provide an output array via an overloaded form of digest(). You can allocate an extra byte, and store whatever you like in the extra space at the beginning.
int len = md.getDigestLength();
byte[] digest = new byte[len + 1];
md.digest(digest, 1, len);
I would like to compare two byte arrays. One is calculated from plaintext with MessageDigest SHA1, the other is the hex itself in byte array, without calculation.
MessageDigest returns 20 byte long result, String.getBytes() returns 40 byte long array. bytesToHex() function is the same that was provided in this answer, used only for printing.
The question:
How can I convert a string to byte array (and then compare with one calculated with MessageDigest) without the additional overhead? String comparison with bytesToHex() and .toUppercase() is working, but not an option, since speed is cruital in the application.
The code:
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-1");
byte[] toEncode = "test".getBytes();
byte[] encoded = md.digest(toEncode);
System.out.println("String to encode:\t\t" + new String(toEncode));
System.out.println("Encoded in hex:\t\t\t" + bytesToHex(encoded));
System.out.println("Encoded length:\t\t\t" + encoded.length);
byte[] hash = new String("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3").getBytes(); // "test" representation in SHA1
System.out.println("\nHash to compare with:\t\t" + new String(hash));
System.out.println("Hash length:\t\t\t" + hash.length);
System.out.println("Two byte array equals:\t\t" + Arrays.equals(hash, encoded));
System.out.println("Two equals in string:\t\t" + new String(hash).equals(bytesToHex(encoded).toLowerCase()));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
The result:
String to encode: test
Encoded in hex: A94A8FE5CCB19BA61C4C0873D391E987982FBBD3
Encoded length: 20
Hash to compare with: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
Hash length: 40
Two byte array equals: false
Two equals in string: true
You're not decoding your hex representation to bytes. If you would, for example using the solution from this answer, the two arrays would match:
try {
byte[] encoded = MessageDigest.getInstance("SHA-1").digest("test".getBytes());
byte[] hash = DatatypeConverter.parseHexBinary("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");
System.out.println("Two byte array equals:\t\t" + Arrays.equals(hash, encoded));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
I'm using this:
import com.sun.org.apache.xml.internal.security.utils.Base64; to encode/decode Base64 strings and byte arrays to store into a db.
I'm testing out encoding and decoding to see if I can get back the original string:
SecureRandom srand = new SecureRandom();
byte[] randomSalt = new byte[64];
srand.nextBytes(randomSalt);
System.out.println("rand salt bytes: " + randomSalt); // first line
String salt = Base64.encode(randomSalt);
try {
System.out.println(Base64.decode(salt)); // second line
}catch(Base64DecodingException e){
System.out.println(e);
}
However, this prints out:
rand salt bytes: [B#68286c59
[B#44d01f20
Why are these not the same, so that I can get back the original byte array?
What you are doing is actually dealing with the java pointer instead of the actual bytes.
This is the correct way to implement
byte[] bytesEncoded = Base64.encodeBase64(str .getBytes());
System.out.println("ecncoded value is " + new String(bytesEncoded ));
// Decode data on other side, by processing encoded data
byte[] valueDecoded= Base64.decodeBase64(bytesEncoded );
System.out.println("Decoded value is " + new String(valueDecoded));
I'm trying to convert from using Chilkat's proprietary decryption library to Apache's commons crypto. I have 2 example encrypted inputs I'm working with. The first is 16 bytes and the second is 96 bytes. The first one works great, but on the second one the CryptoCipher doesn't appear to be consuming the last 16 bytes.
Here's some example code of the setup and decryption and the output:
Properties properties = new Properties();
CryptoCipher crypt = CryptoCipherFactory.getCryptoCipher("AES/CBC/PKCS5Padding", properties);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashedKeyBytes = digest.digest("SHARED_SECRET".getBytes(
StandardCharsets.UTF_8));
MessageDigest ivDigest = MessageDigest.getInstance("MD5");
byte[] ivBytes = ivDigest.digest("SHARED_SECRET".getBytes(StandardCharsets.UTF_8));
final SecretKeySpec key = new SecretKeySpec(hashedKeyBytes, "AES");
IvParameterSpec iv = new IvParameterSpec(ivBytes);
crypt.init(Cipher.DECRYPT_MODE, key, iv);
ByteBuffer encBuffer = ByteBuffer.allocateDirect(enc.length);
System.out.println("--" + enc.length);
encBuffer.put(enc);
encBuffer.flip();
System.out.println("encln " + encBuffer.limit());
ByteBuffer decoded = ByteBuffer.allocateDirect(bufferSize);
CryptoCipher crypt = init();
System.out.println("consume " + crypt.update(encBuffer, decoded));
System.out.println("finish " + crypt.doFinal(encBuffer, decoded));
decoded.flip();
return asString(decoded);
This produces these 2 outputs for the 2 inputs:
Short input:
--16
encln 16
consume 0
finish 13
Long input:
--96
encln 96
consume 80
finish 3
As you can see it's only consuming 80 bytes out of the input... Since the shorter input produces the correct output as compared to what Chilkat produced, I'm not sure where to approach this to get it to work with the longer input.
The number returned by crypt.update() and crypt.doFinal(..) is the number of bytes decrypted, not the number of bytes consumed by the operation. As your data is padded (or at least you specify it as PKCS5Padded), your encrypted data will always be a bit bigger than the decrypted version. With PSCS5 and AES the padding will add 1 to 16 bytes of padding to the nearest multiplum of 16 bytes which is the block size of AES.
In the the first example your 13 bytes of clear data have 3 bytes of padding giving 16 bytes of encrypted data (or one full AES block). In the second example you have 83 bytes of clear data and 13 bytes of padding (giving 6 AES blocks of 16 bytes).
I am experiencing some problems with my code.
When I try to write to file byte[] (eg. of length 173517) using the function Files.write write into file random bytes (eg. 3355) each time, I get a different value.
This is my code:
byte[] dataBytes = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
byte[] cipByte = cipher.doFinal(dataBytes);
byte[] encr = Base64.getEncoder().encode(cipByte);
Files.write(Paths.get(encryptedFile.getAbsolutePath()), encr); //encr len = 173517
From my tests, it seems the problem is not the Files.write. I managed to write an array of byte of size 94486449 without problems.
So possible problems for what is not going as expected:
either the cipher is not doing what you expect and cipByte is of different size than expected.
the encoder is not doing what you are expecting. Be carefull that if you call Base64.getEncoder.encode(cipByte), the resulting byte array will not of the size of cipByte, but will have a different size.
Are you sure you are checking the right encryptedFile?
Your snippet enriched with the missing parts produce a valid output.
byte[] dataBytes = "text to be encrypted".getBytes(StandardCharsets.ISO_8859_1);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipByte = cipher.doFinal(dataBytes);
byte[] encr = Base64.getEncoder().encode(cipByte);
File encryptedFile = new File("/tmp/in.enc");
Files.write(Paths.get(encryptedFile.getAbsolutePath()), encr);
System.out.println("encr length: " + encr.length);
System.out.println("file length: " + encryptedFile.length());
output
encr length: 32
file length: 32