I need to encrypt a string using SuiteScript, send it to a web service written in Java, and decrypt it there.
Using SuiteScript I'm able to encrypt and decrypt without any issue. But when I use the same key in java, I get different errors.
var x = "string to be encrypted";
var key = 'EB7CB21AA6FB33D3B1FF14BBE7DB4962';
var encrypted = nlapiEncrypt(x,'aes',key);
var decrypted = nlapiDecrypt(encrypted ,'aes',key);
^^works fine^^
The code in Java
final String strPassPhrase = "EB7CB21AA6FB33D3B1FF14BBE7DB4962"; //min 24 chars
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(strPassPhrase.getBytes()));
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, key);
String encrypted = "3764b8140ae470bda73f7ebed3c33b0895f70c3497c85f39043345128a4bc3b3";
String decrypted = new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(encrypted)));
System.out.println("Text Decryted : " + decrypted);
With the above code, I get an exception javax.crypto.BadPaddingException: Given final block not properly padded
The key was generated using openssl
openssl enc -aes-128-ecb -k mypassphrase -P
it looks like you are encrypting with AES, and decrypting with DES. I think the ciphertext needs to be decrypted with the same symmetric algorithm that you used to encrypt.
Looks like currently you have to use Suitescript to decrypt messages if it was encrypted using SuiteScript.
See suiteanswers: 35099
The workaround suggested is to use an external javascript library to encrypt/decrypt. We ended up using OpenJS on the javascript, but on the java side had to make sure the defaults were adjusted according to what is setup on the javascript side. The Java APIs were more flexible in this regard than the javascript ones.
Related
I need to encrypt a value in Java using AES CBC 256 but I am unable to decrypt it in NodeJS:
The cyphered string is generated with the following code:
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
String result = DatatypeConverter.printHexBinary(cipher.doFinal(test));
and decrypted with this one:
var crypto = require('crypto');
var mykey = crypto.createDecipher('aes-256-cbc', key);
var mystr = mykey.update(value, 'hex', 'utf8')
but the code returns an error:
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
at Decipher.final (internal/crypto/cipher.js:104:26)
at evalmachine.<anonymous>:12:16
at Script.runInContext (vm.js:74:29)
at Object.runInContext (vm.js:182:6)
at evaluate (/run_dir/repl.js:133:14)
at ReadStream.<anonymous> (/run_dir/repl.js:116:5)
at ReadStream.emit (events.js:180:13)
at addChunk (_stream_readable.js:274:12)
at readableAddChunk (_stream_readable.js:261:11)
at ReadStream.Readable.push (_stream_readable.js:218:10)
I assume it has something to do with the padding strategy but I can not find any documentation on the one applied by NodeJS.
What is the equivalent padding in Java Cypher corresponging to the one provided by the cripto package in NodeJS?
CBC mode requires an Initialization Vector (IV) to be pressent when encryptin the first block. In the Java implementation of AES you can provide this when you Initialize the Cipher, or you can let Java generate one for you. In your case Java have genereted an IV for you. As this is needed when you decrypt, you need to grab this and pass it along with the encrypted data (this ought to be random, but don't need to be kept secret). Use the Cipher.getIV() methode to get it.
In NodeJS there is a variant of the crypto.createDecipher() where you can provide this IV called crypto.createDecipheriv()
I have inheritied Java web application and am supposed to convert that to node.js.
Part of that is encryption of data. In Java it is done like in attached code. How would I do that in node using crypto?
I am not strong in cryptography at all, sorry if this is really basic question and thanks in advance.
private final String ALGORITHM = "PBEWITHSHA1ANDDESEDE";
private final int ITERATION_COUNT = 20;
private final byte[] SALT = {
(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
and later...
PBEKeySpec pbeKeySpec = new PBEKeySpec("password".toCharArray());
SecretKeyFactory keyFac = SecretKeyFactory.getInstance(ALGORITHM);
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(SALT, ITERATION_COUNT);
// Create PBE Cipher
Cipher pbeCipher = Cipher.getInstance(ALGORITHM);
// Initialize PBE Cipher with key and parameters
pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
byte[] encrypted = pbeCipher.doFinal("text to be encrypted");
Edit:
This is my failed attempt to implement that in node.js based on various searches:
var crypto = require('crypto');
var SALT = new Buffer('c773218c7ec8ee99', 'hex');
var pass = new Buffer('password');
//digest is by default SHA-1 thats what I need
var key = crypto.pbkdf2Sync(pass, SALT, 20, 56); //[, digest]
//var cipher = crypto.createCipher('des-ede-cbc', key);
var cipher = crypto.createCipher('des-ede', key);
//var cipher = crypto.createCipheriv('des-ede-cbc', key, new Buffer('00000000', 'binary'));
cipher.update(new Buffer('This is to be encoded'));
var encrypted = cipher.final('binary');
console.log(encrypted);
fs.writeFileSync('encrypted.file', encrypted);
When I am trying to use crypto.createCipheriv I have no idea what to put there as IV.
When used without IV, it produces some 'encrypted' gibberish however when saved to file, it can't be read and decoded on Java side. Sigh.
The reason that you can't get these to interoperate is the Java side is using PBE and the node.js side is using PBKDF2, which serve similar purposes and come from the same standards document (PKCS #5), but have very different mechanisms under the hood.
Because these are different key generation algorithms, you generate different keys on each end, and thus get different results when you decrypt.
There is also something of an mismatch in the level of abstraction between java and node.js in your code. the Java API you are using is very high level, and uses OpenSSL-like constructs. Meanwhile, the node.js code is at a much lower level, gluing pieces together bit-by-bit. This can cause issues when, for example, the java code introduces a particular padding structure or cipher mode of operation.
If this is just for learning or something non-critical, I would recommend changing the java code to be at the same lower level as the node.js code, and put pieces together one by one: generate the key on both sides and make sure they are the same, ecrypt on both sides and get the same output, etc. If you can't change the java code, use something like forge to get your node.js code at the same higher level as the java code. But as the comments on this question indicate, you may not be able to do PBE anyways.
If this is for something "real" where you actually want the files saved to be secure, call out to an external program like gpg to handle the encryption, instead of "rolling your own" file encryption system.
I need to encrypt some values in Java application using AES algorithm, and decrypt the same in my Javascript module of my application.
I saw some examples over the internet but it seems there's some differences in compatibility.
like below issue :
AES encryption in javascript and decrypting in java
Can someone please point me some code examples to solve this issue.
Thanks.
AES is an exactly specified algorithm, so all AES implementations must be "compatible". Having said that, AES is a variable-key-length block-cipher, operating on 128-bit blocks. To actually use this in a piece of software, you have to make a bunch of other choices: how to deal with input consisting of more than 1 block (this is called the "mode"), in some modes you need an initialization vector, you need to deal with input not consisting of an exact number of blocks (padding), how to encode characters into bytes, and how to represent bytes in a context (like a source file) that doesn't support that. All those things need to be compatible.
Below is a tested example. It uses the standard Java crypto functions (and Apache Commons Codec), and JavaScript crypto library crypto-js. Choices are as follows: 128-bit key, cipher-block-chaining mode (which needs an initialization vector), PKCS5/7 padding, UTF-8 for character encoding, Base64 to represent byte arrays.
This piece of Java will output Base64-encoded ciphertext:
String plainText = "Hello, World! This is a Java/Javascript AES test.";
SecretKey key = new SecretKeySpec(
Base64.decodeBase64("u/Gu5posvwDsXUnV5Zaq4g=="), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec(
Base64.decodeBase64("5D9r9ZVzEYYgha93/aUK2w=="));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
System.out.println(Base64.encodeBase64String(cipher.doFinal(
plainText.getBytes("UTF-8"))));
This piece of JavaScript correctly decrypts it:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script>
var encrypted = CryptoJS.enc.Base64.parse('3Q7r1iqtaRuJCo6QHA9/GhkTmbl4VkitV9ZsD3K2VB7LuBNg4enkJUA1cF8cHyovUH2N/jFz3kbq0QsHfPByCg==');
var key = CryptoJS.enc.Base64.parse('u/Gu5posvwDsXUnV5Zaq4g==');
var iv = CryptoJS.enc.Base64.parse('5D9r9ZVzEYYgha93/aUK2w==');
document.write(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(
{ ciphertext: encrypted },
key,
{ mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: iv, })));
</script>
I'm writing a program which does both encryption and decryption in DES. The same key used during the encryption process should be used while decrypting too right? My problem is encryption and decryption are run on different machines. This is how the key is generated during the encryption process.
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
So ,I thought I'll write the key to a file. But looks like I can typecast a SecretKey object to a String but not vice-versa! So, how do I extract the key contained in a text file? And pass as an input to this statement?
decipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
Or else is it possible to take the key as an input from the user during both the encryption and decryption process?
Do this:
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
byte[] encoded = key.getEncoded();
// save this somewhere
Then later:
byte[] encoded = // load it again
SecretKey key = new SecretKeySpec(encoded, "DES");
But please remember that DES is unsecure today (it can be relatively easily bruteforced). Strongly consider using AES instead (just replace "DES" with "AES).
I am currently devloping a Windows application using C# and looking at developing a mobile app using Java.
The windows software and the mobile app will work together, the windows app will store information and encrypt certain information before storing it in an online database.
The mobile app will pull the information from the online database and will need to decrypt the encrypted string that is retrieved from the datbase.
The encryption method I am using in C# is below
byte[] clearTextBytes = Encoding.UTF8.GetBytes(encryptionString);
SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
MemoryStream ms = new MemoryStream();
byte[] rgbIV = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo");
CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV), CryptoStreamMode.Write);
cs.Write(clearTextBytes, 0, clearTextBytes.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
The Windows method works fine.
The code I am using in Java is as follows:
KeySpec ks = new DESKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("UTF-8"));
SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(ks);
String ivString = "ryojvlzmdalyglrj";
byte[] ivByte = ivString.getBytes("UTF-8");
IvParameterSpec iv = new IvParameterSpec(ivByte);
//RC5ParameterSpec iv = new RC5ParameterSpec(ivByte);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(Base64.decodeBase64("iNtaFme3B/e6DppNSp9QLg=="));
Log.d("Decoded Password", encoded.toString());
As both methods need to encrypt and decrypt the same string together it has to use the same key and IV. The only problem that I am having is in the java method the IVParameterSpec is going into the catch with an error that says IV must be 8 bytes long.
How can I resolve this to ensure that I have the same IV as C#.
Thanks for the help
The problem is that you are encrypting (in C#) with AES (also known as Rjindael), but trying to decrypt in Java with DES. If you change your Java code to use AES then it should all work fine.
DES uses an 8-byte IV because it works on 64-bit blocks. AES uses a 16-byte IV because it works on 128-bit blocks.
You should also make sure you use the same character encoding. In C# you are using ASCII, but in java you're using UTF-8. In your case they will be the same, but you should really fix it now to prevent strange bugs in future. You can change the character set name in Java to "US-ASCII" and it'll work.
You have to use the same algorithm of course. The default algorithm is for .NET is AES, so that is what you should be using on the Java side as well.