Related
tldr: generated rsa key pair using node-forge, encrypted hello and converted it to base64 in order to decrypt it using the same key pair (imported using pem files) in java but it throws an exception while the key pair is working fine with data encrypted by java
I am generating a key pair in node which works fine for decrypting and encrypting in both java and node, but I am unable to decrypt the encrypted value from node in java
the key pair is generated using the following nodejs code
var bip39 = require("bip39");
var forge = require("node-forge");
async function test() {
var mnemonic = "fever draw mind boil renew fire sleep palace useful ritual wood snake april polar brown off round zebra swallow health grass drink jelly beef";
console.log(mnemonic)
let seed = await bip39.mnemonicToSeed(mnemonic);
console.log(seed.toString("hex"))
const prng = forge.random.createInstance();
prng.seedFileSync = () => seed
const {
privateKey,
publicKey
} = forge.pki.rsa.generateKeyPair({
bits: 1024,
prng,
workers: 2
})
console.log(await forge.pki.publicKeyToRSAPublicKeyPem(publicKey));
console.log(await forge.pki.privateKeyToPem(privateKey));
let encrypted = publicKey.encrypt("hello");
var previousBase ="WTq03NoOtGHX+Xs1Mu6bbQmjQ+xSssj2mSeRf55+lw/tVaGRTI7KQZzu8DFqNJS4kzu6iJjqKTmnvtAMzPOo4KAmEtZAMDEZw7D1Y5ptb0cDP0SgROsZgZr5XpGbifQMDGT+rZr/5EfFOXdwDvUy1rUABAKpSbXFZTF64UFM4lk=";
var previous = atob(previousBase);
let base = btoa(encrypted);
console.log(base);
var x = new TextEncoder().encode(previousBase);
var all = "";
for (var i = 0; i < x.length; i++) {
all += x[i] + ", ";
}
console.log(all.substring(0, all.length - 2))
console.log(await privateKey.decrypt(previous));
console.log(await privateKey.decrypt(encrypted));
};
test();
since I am trying to decrypt/encrypt using the same private/public key in Java I decided to add a few logs so I have a base to work with
fever draw mind boil renew fire sleep palace useful ritual wood snake april polar brown off round zebra swallow health grass drink jelly beef
8f445e53ea42708dd4be30c646261c9fc3352125c42f8f5ead86d44c15adbac4a46ffe1dca758f99bf46c7b939fd3db0f2f3000b792bc9192156e5ef5936a732
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAK0HXXtavoJkYXYSBFvb+JINZ9MFZANLWRVOu69iiP6PgILqEbV8ybFm
vdSCuZu0BB/P5f0uW/0fw0149UZxXltrkPZHqYLPckXOxgRD3LAWbI+vwV0UqU0X
597hg5E8UnV+2S5VG4/QxpAS5iiAPwT96dxjxEhZ3mRqLX74BsrDAgMBAAE=
-----END RSA PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCtB117Wr6CZGF2EgRb2/iSDWfTBWQDS1kVTruvYoj+j4CC6hG1
fMmxZr3UgrmbtAQfz+X9Llv9H8NNePVGcV5ba5D2R6mCz3JFzsYEQ9ywFmyPr8Fd
FKlNF+fe4YORPFJ1ftkuVRuP0MaQEuYogD8E/encY8RIWd5kai1++AbKwwIDAQAB
AoGAFDPb8l8yBz95MbQA1kjkyQjPqo/ikY/motpCh8PVgwN2WdLCppIfaps4Zuus
iEWIhb5ceCdFjlR7FTyeRs9N2OTC2Mcp1n1sxfHNFMGPOsxyMAaIw9UhFzpr2cHy
PXiPbyg+y4EMwEbB2js7Zf2A2wNSda4VBkYUZIkBXIxmUwECQQD9a70jjdfN6Ldj
M6ZqPPg/V5GGsEohfsmsSJKUxzZ3AmFqrwzDmclbfviVmqTiULPDbl4Tb6qvhLc3
Qk//DUijAkEArsosXFv7DkZmMA3MTE8lURgOD509Ts1+4wWIDsbP54pvFoIPX7eG
6NR48SEvjAmZfGgwi6gbwUdBbRFFQwP3YQJAfuPmdZn9V5XR1XM0PXe/2X+QV3+H
7tOcSY6hDqvdIqPngVKbMombYBvofohLTSKZkB6ALn04WuA6GQo0IgJVvwJARvsH
JMKdo2BnYyBXVK3XY6U3IJQkL3o4Cw1WAVovV8HZ9vP+NkqbWLXgH1vwqRfE4saU
4EH2c3jyUs5uqBZWQQJAajdCCVRyPghnfqhzWl68gfvrEATDTWRt4UKY46IP+QUx
islQ2e9ZU+wbjBmqM5zd1oG9yUsxD8c5X0mCyZ1wSg==
-----END RSA PRIVATE KEY-----
HWqv4dvDtLPc8ZhBbTI4JJ89XgxASKacZKuaz+0HF0kInt9R/tDgv2lkNPl7RWC/SNacqY0DnBL1uAQvg8r75nVo7sZ29hhjph5n5ucBNXcT9OSYgGY4fjSmMLvLY3qVSYItSLsIbXrfemWDF2jaV2FbDb4dBCaeC02PjIJQGnw=
87, 84, 113, 48, 51, 78, 111, 79, 116, 71, 72, 88, 43, 88, 115, 49, 77, 117, 54, 98, 98, 81, 109, 106, 81, 43, 120, 83, 115, 115, 106, 50, 109, 83, 101, 82, 102, 53, 53, 43, 108, 119, 47, 116, 86, 97, 71, 82, 84, 73, 55, 75, 81, 90, 122, 117, 56, 68, 70, 113, 78, 74, 83, 52, 107, 122, 117, 54, 105, 74, 106, 113, 75, 84, 109, 110, 118, 116, 65, 77, 122, 80, 79, 111, 52, 75, 65, 109, 69, 116, 90, 65, 77, 68, 69, 90, 119, 55, 68, 49, 89, 53, 112, 116, 98, 48, 99, 68, 80, 48, 83, 103, 82, 79, 115, 90, 103, 90, 114, 53, 88, 112, 71, 98, 105, 102, 81, 77, 68, 71, 84, 43, 114, 90, 114, 47, 53, 69, 102, 70, 79, 88, 100, 119, 68, 118, 85, 121, 49, 114, 85, 65, 66, 65, 75, 112, 83, 98, 88, 70, 90, 84, 70, 54, 52, 85, 70, 77, 52, 108, 107, 61
hello
hello
the first challenge was to actually get the rsa key objects in Java to initialize without any exceptions, which in fact required me to add the dependency
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
now within java I am able to encrypt and decrypt using the keys, but I am unable to decrypt anything that was generated within nodejs as it throws this exception
javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:344)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at Test.main(Test.java:44)
my current code for reference looks like this
import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;
import java.io.File;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class Test {
static {
java.security.Security.addProvider(
new org.bouncycastle.jce.provider.BouncyCastleProvider()
);
}
public static void main(String[] args) {
try {
RSAPrivateKey privateKey = parsePrivateKey(Files.readAllBytes(Paths.get("pri.pem")));
RSAPublicKey pub = readPublicKey(new File("pub.pem"));
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, pub);
String test = "hello";
byte[] testBytes = test.getBytes(StandardCharsets.UTF_8);
byte[] encryptedMessageBytes = encryptCipher.doFinal(testBytes);
String base64 = "WTq03NoOtGHX+Xs1Mu6bbQmjQ+xSssj2mSeRf55+lw/tVaGRTI7KQZzu8DFqNJS4kzu6iJjqKTmnvtAMzPOo4KAmEtZAMDEZw7D1Y5ptb0cDP0SgROsZgZr5XpGbifQMDGT+rZr/5EfFOXdwDvUy1rUABAKpSbXFZTF64UFM4lk=";
byte[] decodedBytes = Base64.getDecoder().decode(base64);
String decodedString = new String(decodedBytes);
byte[] secretMessageBytes = decodedString.getBytes(StandardCharsets.UTF_8.name());
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
System.out.println(new String(decryptCipher.doFinal(encryptedMessageBytes)));
byte[] decryptedMessageBytes = decryptCipher.doFinal(secretMessageBytes);
System.out.println(new String(decryptedMessageBytes));
} catch (Exception e) {
e.printStackTrace();
}
}
public static RSAPrivateKey parsePrivateKey(byte[] b) throws InvalidKeySpecException, NoSuchAlgorithmException {
byte[] privateKeyBytes = parseDERFromPEM(b);
return generatePrivateKeyFromDER(privateKeyBytes);
}
public static byte[] parseDERFromPEM(byte[] b) {
return DatatypeConverter.parseBase64Binary(parseKeyData(b));
}
public static String parseKeyData(byte[] b) {
String data = new String(b);
String[] tokens = data.split("-----BEGIN RSA PRIVATE KEY-----");
tokens = tokens[1].split("-----END RSA PRIVATE KEY-----");
return tokens[0];
}
public static RSAPrivateKey generatePrivateKeyFromDER(byte[] b) throws InvalidKeySpecException, NoSuchAlgorithmException {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) factory.generatePrivate(spec);
}
public static RSAPublicKey readPublicKey(File file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
String publicKeyPEM = key
.replace("-----BEGIN PUBLIC KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
}
is it somehow impossible todo what I am trying todo or am I just missing something somewhere since the keys are working with java for encryption and decryption as long as it was encrypted using java.
I believe all data required to replicate my issue is included in this post - if any further information is needed please let me know and I will provide
Encrypted data using modern (computer) ciphers is not text. And the data that can be encrypted can be any bits, not just text, although they are still called 'ciphertext' and 'plaintext' following a historical tradition from past centuries where they actually were text. Neither is other cryptographic data, such as digital signatures, hashes, keys, certificates, and such, although some of them are converted to and from text forms such as (several variants of) base64, hex, and PEM. Your node/forge code represents the RSA-encrypted data in base64, as is common to handle this, but your Java code after decoding the base64 correctly does the following
String decodedString = new String(decodedBytes);
byte[] secretMessageBytes = decodedString.getBytes(StandardCharsets.UTF_8.name());
which tries to treat it as text. This does not work, and turns much of your data into garbage, which also happens to make it longer and trigger the exception you got. You need to use the result of the base64 decoding directly in the decrypt call.
In addition your posted Java code doesn't and can't work on the public-key format you posted. You need to either use forge's publicKeyToPem (which produces the correct 'generic' PUBLIC KEY format -- not RSA PUBLIC KEY) or convert your posted output with something like openssl rsa -RSAPublicKey_in; I did the latter.
Finally, it isn't sufficient to just add Bouncy to the provider list. You must either:
specify the actual provider object in KeyFactory.getInstance
have Bouncy in the list (anywhere) and specify "BC" in KeyFactory.getInstance
put Bouncy at the beginning of the list with insertProviderAt(new org.bouncy...,1)
With those three changes, and some trivial simplification and hardcoded data for convenience, the following gives hello as expected:
String pubbad = "-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAK0HXXtavoJkYXYSBFvb+JINZ9MFZANLWRVOu69iiP6PgILqEbV8ybFm\n"
+"vdSCuZu0BB/P5f0uW/0fw0149UZxXltrkPZHqYLPckXOxgRD3LAWbI+vwV0UqU0X\n"
+"597hg5E8UnV+2S5VG4/QxpAS5iiAPwT96dxjxEhZ3mRqLX74BsrDAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n";
String pubfix = "-----BEGIN PUBLIC KEY-----\n"
+"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtB117Wr6CZGF2EgRb2/iSDWfT\n"
+"BWQDS1kVTruvYoj+j4CC6hG1fMmxZr3UgrmbtAQfz+X9Llv9H8NNePVGcV5ba5D2\n"
+"R6mCz3JFzsYEQ9ywFmyPr8FdFKlNF+fe4YORPFJ1ftkuVRuP0MaQEuYogD8E/enc\n"
+"Y8RIWd5kai1++AbKwwIDAQAB\n"
+"-----END PUBLIC KEY-----\n";
String prvpem = "-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICWwIBAAKBgQCtB117Wr6CZGF2EgRb2/iSDWfTBWQDS1kVTruvYoj+j4CC6hG1\n"
+"fMmxZr3UgrmbtAQfz+X9Llv9H8NNePVGcV5ba5D2R6mCz3JFzsYEQ9ywFmyPr8Fd\n"
+"FKlNF+fe4YORPFJ1ftkuVRuP0MaQEuYogD8E/encY8RIWd5kai1++AbKwwIDAQAB\n"
+"AoGAFDPb8l8yBz95MbQA1kjkyQjPqo/ikY/motpCh8PVgwN2WdLCppIfaps4Zuus\n"
+"iEWIhb5ceCdFjlR7FTyeRs9N2OTC2Mcp1n1sxfHNFMGPOsxyMAaIw9UhFzpr2cHy\n"
+"PXiPbyg+y4EMwEbB2js7Zf2A2wNSda4VBkYUZIkBXIxmUwECQQD9a70jjdfN6Ldj\n"
+"M6ZqPPg/V5GGsEohfsmsSJKUxzZ3AmFqrwzDmclbfviVmqTiULPDbl4Tb6qvhLc3\n"
+"Qk//DUijAkEArsosXFv7DkZmMA3MTE8lURgOD509Ts1+4wWIDsbP54pvFoIPX7eG\n"
+"6NR48SEvjAmZfGgwi6gbwUdBbRFFQwP3YQJAfuPmdZn9V5XR1XM0PXe/2X+QV3+H\n"
+"7tOcSY6hDqvdIqPngVKbMombYBvofohLTSKZkB6ALn04WuA6GQo0IgJVvwJARvsH\n"
+"JMKdo2BnYyBXVK3XY6U3IJQkL3o4Cw1WAVovV8HZ9vP+NkqbWLXgH1vwqRfE4saU\n"
+"4EH2c3jyUs5uqBZWQQJAajdCCVRyPghnfqhzWl68gfvrEATDTWRt4UKY46IP+QUx\n"
+"islQ2e9ZU+wbjBmqM5zd1oG9yUsxD8c5X0mCyZ1wSg==\n"
+"-----END RSA PRIVATE KEY-----\n";
//RSAPrivateKey privateKey = parsePrivateKey(Files.readAllBytes(Paths.get("pri.pem")));
byte[] prvder = Base64.getDecoder().decode( prvpem.replaceAll("-----(BEGIN|END) RSA PRIVATE KEY-----","").replaceAll("\n","") );
RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA","BC") .generatePrivate(new PKCS8EncodedKeySpec(prvder) );
// actually not PKCS8, but BCprov handles this as a special case
//RSAPublicKey pub = readPublicKey(new File("pub.pem"));
byte[] pubder = Base64.getDecoder().decode( pubfix.replaceAll("-----(BEGIN|END) PUBLIC KEY-----","").replaceAll("\n","") );
RSAPublicKey pub = (RSAPublicKey) KeyFactory.getInstance("RSA") .generatePublic(new X509EncodedKeySpec(pubder) );
String base64 = "WTq03NoOtGHX+Xs1Mu6bbQmjQ+xSssj2mSeRf55+lw/tVaGRTI7KQZzu8DFqNJS4kzu6iJjqKTmnvtAMzPOo4KAmEtZAMDEZw7D1Y5ptb0cDP0SgROsZgZr5XpGbifQMDGT+rZr/5EfFOXdwDvUy1rUABAKpSbXFZTF64UFM4lk=";
byte[] decodedBytes = Base64.getDecoder().decode(base64);
//BAD String decodedString = new String(decodedBytes);
//BAD byte[] secretMessageBytes = decodedString.getBytes(StandardCharsets.UTF_8.name());
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedMessageBytes = decryptCipher.doFinal(decodedBytes);
System.out.println(new String(decryptedMessageBytes));
And merry Xmas, until someone edits this out because Stack is supposed to be impersonal.
So, I am trying to store 3 longs to a file, but it will a lot of data so I convert them to byte arrays and save them. My current method for saving them:
try (FileOutputStream output = new FileOutputStream(path, true)) {
//Put the data into my format
byte[] data = new byte[24];
main.getLogger().log(Level.INFO, "Saving most sig bits");
System.arraycopy(ByteUtils.longToBytes(uuid.getMostSignificantBits()), 0, data, 0, 8);
System.arraycopy(ByteUtils.longToBytes(uuid.getLeastSignificantBits()), 0, data, 8, 8);
System.arraycopy(ByteUtils.longToBytes(player.getTokens()), 0, data, 16, 8);
//Write data in the format
output.write(data);
}
longToBytes method:
private static ByteBuffer buffer = ByteBuffer.allocate(8);
public static byte[] longToBytes(long x) {
System.out.println(x);
buffer.putLong(0, x);
return buffer.array();
}
The byte array gets saved to the file, but the first byte gets truncated. the print statement in longToByes prints 8 three times.
The original longs are:
-9089798603852198353, -5339652910133477779, 5992
If I print the byte array I get:
-127, -38, -116, 84, 97, -116, 78, 47, -75, -27, -67, -8, 11, -100, -2, 109, 0, 0, 0, 0, 0, 0, 23, 104 (24 bytes)
But in the file I see:
ÚŒTaŒN/µå½ø(VT symbol)œþm(nul)(nul)(nul)(nul)(nul)(nul)(etb)h
which is 23 bytes (the first box doesn't show in notepad++)
but if I read it using
bytes = IOUtils.toByteArray(new FileReader(file));
I see:
64, -38, -116, 84, 97, -116, 78, 47, -75, -27, -67, -8, 11, -100, -2, 109, 0, 0, 0, 0, 0, 0, 23, 104 (24 bytes)
-127 is replaced with 64 somehow.
I concat the byte with "" to print it btw.
Do not use FileReader to read raw bytes from file. Use FileInputStream instead.
The problem with FileReader is that it reads chars, not bytes, from the file, by trying to decode the bytes using some character encoding (the default one if none was given).
bytes = IOUtils.toByteArray(new FileInputStream(file));
Alternatively you can use DataOutputStream to write long directly to an output stream and use DataInputStream to read from an input stream.
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) {
out.writeLong(uuid.getMostSignificantBits());
out.writeLong(uuid.getLeastSignificantBits());
out.writeLong(player.getTokens());
}
try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
long uuidMSB = in.readLong();
long uuidLSB = in.readLong();
long tokens = in.readLong();
}
Using the following code, I am doing AES encrypt operation, I am passing the same input at different instances but I am getting different Cipher. Why does this happen?
public static byte[] encrypt(byte[] plainText, byte[] key)
{
byte[] passwordKey128 = Arrays.copyOfRange(key, 0, 16);
SecretKeySpec secretKey = new SecretKeySpec(passwordKey128, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(plainText);
return cipherText;
}
Input is
encrypt(new byte[]{-17, -60, -70, 24, 80, 35, 2, -62, -79, 19, -55, -50, -62, -69, -80, -96} ,new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} );
At one instance cipher is - [0, 91, -96, 80, -44, -93, 107, 62, 4, -10, 103, 119, 109, 4, 25, 68]
At another instance cipher is - [87, 109, 20, 69, 18, 6, 103, 92, -57, 62, -41, -103, -18, -19, 74, 87]
What can be the reason?
CBC mode requires an IV and the init method may generate a random IV if none is specified (from the documentation):
If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values) if it is being initialized for encryption or key wrapping, and raise an InvalidKeyException if it is being initialized for decryption or key unwrapping. The generated parameters can be retrieved using getParameters or getIV (if the parameter is an IV).
To avoid that specify an IV explicitly.
I did a POC using apache codec base64 library, where I encrypted a string using SHA. (This can be ignored).
Step 1 - I printed byte array for that string.
Step 2 - Encoded the byte array and printed its value.
Step 3 - Decoded the encoded value and printed it.
public static void main(String[] args)
{
MessageDigest messageDigest = null;
String ALGORITHM = "SHA";
try
{
messageDigest = MessageDigest.getInstance(ALGORITHM);
byte[] arr = "admin1!".getBytes();
byte[] arr2 = messageDigest.digest(arr);
System.out.println(arr2);
String encoded = Base64.encodeBase64String(arr2);
System.out.println(encoded);
byte[] decoded = Base64.decodeBase64(encoded);
System.out.println(decoded);
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
Expected result : Step 1 and Step 3 should produce same output. But I am not getting that.
Output :
[B#5ca801b0
90HMfRqqpfwRJge0anZat98BTdI=
[B#68d448a1
Your program is all good and fine. Just one mistake.
System.out.println(byteArray); prints hashCode of byte array object. (Note: Arrays are object in Java not primitive type)
You should use System.out.println(Arrays.toString(byteArray)); instead and you will get same value for both steps 1 and 3.
As per javadocs Arrays.toString(byte[] a) returns a string representation of the contents of the specified array.
Your code after changes will be :
public static void main(String[] args)
{
MessageDigest messageDigest = null;
String ALGORITHM = "SHA";
try
{
messageDigest = MessageDigest.getInstance(ALGORITHM);
byte[] arr = "admin1!".getBytes();
byte[] arr2 = messageDigest.digest(arr);
System.out.println(Arrays.toString(arr2));
String encoded = Base64.encodeBase64String(arr2);
System.out.println(encoded);
byte[] decoded = Base64.decodeBase64(encoded);
System.out.println(Arrays.toString(decoded));
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
and output will be :
[-9, 65, -52, 125, 26, -86, -91, -4, 17, 38, 7, -76, 106, 118, 90, -73, -33, 1, 77, -46]
90HMfRqqpfwRJge0anZat98BTdI=
[-9, 65, -52, 125, 26, -86, -91, -4, 17, 38, 7, -76, 106, 118, 90, -73, -33, 1, 77, -46]
Note value of byte array is same.
I am trying to read data of a .wav file both in java and matlab and save as an array of bytes.
In java the code looks as follows:
public byte[] readWav2(File file) throws UnsupportedAudioFileException, IOException {
AudioFormat audioFormat;
AudioInputStream inputAIS = AudioSystem.getAudioInputStream(file);
audioFormat = inputAIS.getFormat();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Read the audio data into a memory buffer.
int nBufferSize = BUFFER_LENGTH * audioFormat.getFrameSize();
byte[] abBuffer = new byte[nBufferSize];
while (true) {
int nBytesRead = inputAIS.read(abBuffer);
if (nBytesRead == -1) {
break;
}
baos.write(abBuffer, 0, nBytesRead);
}
byte[] abAudioData = baos.toByteArray();
return abAudioData;
}
In matlab I am using the wavread function:
[Y, FS] = wavread('sound.wav', 'native');
But the results I am getting are different.
In java the first 20 bytes:
53, 0, 19, 0, -71, -1, -80, -1, -99, -1, 10, 0, 87, 0, -69, -1, 123, -1, -77, -1
In matlab:
53, 19, -71, -80, -99, 10, 87, -69, -133, -77, 38, 143, 13, -100, 39, 45, -52, -83, -82, 56
Why every second byte in java is 0 or -1 where in matlab there isn't? Even though I skip the 0's and -1's where in java there is 123 for matlab there is -133? Why is it different?
Java is returning you 16-bit signed PCM data. Since each sample is 16 bits and a byte holds 8 bits, each sample spans two bytes in Java. What Matlab returns you is an array of the 16-bit samples directly.
Basically, the data is the same. It's just laid out differently in memory.
To access the samples in an easier way from Java you could do some bitwise arithmetic, like this:
int firstSample = (abAudioData[0]&0xFF) | (abAudioData[1]<<8);
Another way to read the samples is with the java.nio buffers:
ByteBuffer bb = ByteBuffer.wrap(abAudioData);
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
int firstSample = sb.get();