The encryption test data:
key: 'ABC';
data:'1234567';
algorithm: MCRYPT_BLOWFISH;
mode: MCRYPT_MODE_ECB;
PHP code
$key = 'ABC';
$data = '1234567';
$alg = MCRYPT_BLOWFISH;
$mode = MCRYPT_MODE_ECB;
$encrypted_data = mcrypt_encrypt($alg, $key, $data, $mode);
$phpgeneratedtoken = base64_encode($encrypted_data);
print "PHP generated token: " . $phpgeneratedtoken." ";
// return
// In6uDpDqt1g=
// Decode the token just generated by php
$decoded = mcrypt_decrypt($alg,$key,base64_decode("In6uDpDqt1g="),$mode);
print "Decoded from php generated token:" . $decoded." ";
//return
//1234567
// This is the encrypted token generated by java with same key and value
$javageneratedtoken = "Cg8qY4gRMaI=";
// Decode the token generated by Java
$decoded = mcrypt_decrypt($alg,$key,base64_decode("Cg8qY4gRMaI="),$mode);
print "Decoded from Java Generated token: " . $decoded." ";
// return
// 1234567
// Both tokens generated by java and php, are decrypted back to the same value.
Java Code:
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class BlowfishTest {
public static void main(String[] args) throws Exception {
encrypt("1234567");
decrypt("In6uDpDqt1g=");
}
private static void encrypt(String password) throws Exception {
byte[] keyData = ("ABC").getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyData, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] hasil = cipher.doFinal(password.getBytes());
System.out.println(new BASE64Encoder().encode(hasil));
}
private static void decrypt(String string) throws Exception {
byte[] keyData = ("ABC").getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyData, "Blowfish");
Cipher cipher = Cipher.getInstance("blowfish/ecb/nopadding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] hasil = cipher.doFinal(new BASE64Decoder().decodeBuffer(string));
System.out.println(new String(hasil));
}
}
The PHP generated encrypted value is: In6uDpDqt1g=.
The Java generated encrypted value is: Cg8qY4gRMaI=.
The issue is at Java Code's
Cipher cipher = Cipher.getInstance("blowfish");
I need to find a way to make my PHP generated encrypted value the same as the Java generated encrypted value.
Both encrypted values I can decrypt them back in PHP. Both encrypted values I could decrypt them back in java too, ONLY IF I set,
Cipher cipher = Cipher.getInstance("blowfish/ecb/nopadding");
But when I try to decrypt PHP encrypted value, In6uDpDqt1g=, in Java.
If I set,
Cipher cipher = Cipher.getInstance("blowfish");
I got the error:
"Given final block not properly padded".
The problem is I am supposed to use PHP to encrypt value, and my client would use java to decrypt value. With the setup Cipher cipher = Cipher.getInstance("blowfish") to decrypt my value.
So I want to find a way that I should use PHP to get the same encrypted value as Java, with Cipher cipher = Cipher.getInstance("Blowfish"), would get.
If there is no such solution, then I would have to ask my client to change his java codes to use
Cipher cipher = Cipher.getInstance("blowfish/ecb/nopadding");
OK, I find my answer. I need to change my php code to
$key = 'ABC';
$data = '1234567';
$alg = MCRYPT_BLOWFISH;
$mode = MCRYPT_MODE_ECB;
$blocksize = mcrypt_get_block_size('blowfish', 'ecb'); // get block size
$pkcs = $blocksize - (strlen($data) % $blocksize); // get pkcs5 pad length
$data.= str_repeat(chr($pkcs), $pkcs);
$encrypted_data = mcrypt_encrypt($alg, $key, $data, $mode);
$phpgeneratedtoken = base64_encode($encrypted_data);
print "PHP generated token: " . $phpgeneratedtoken." ";
// return
// Cg8qY4gRMaI=
Related
Is it possible to implement like this technique in java (encryption and Decryption) using python ?
Here the 3DES is using in this java code.
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
String keytext = "key......";
byte[] keyArray = keytext.getBytes("utf-8");
SecretKey key = new SecretKeySpec(keyArray, "DESede");
String mytext = "anytext......";
Cipher.init(1, key);
byte[] enc = cipher.doFinal(plaintext.getBytes("utf-8"));
String value = Base64.getUrlEncode().encodeToString(enc);
return value;
Hope someone can assist me with this, to implement this using python2 if possible or python3
EDIT:
from Crypto.Cipher import DES3
from Crypto.Random import get_random_bytes
while True:
try:
key = DES3.adjust_key_parity(get_random_bytes(24))
break
except ValueError:
pass
cipher = DES3.new(key, DES3.MODE_CFB)
plaintext = b'We are no longer the knights who say ni!'
msg = cipher.iv + cipher.encrypt(plaintext)
print(msg)
Taken from the PyCryptodome manual itself: Link
I have encrypt the file using node.js and decrypt in JAVA. Decryption is done in JAVA using "AES/GCM/Nopadding" algorithm and it is third party app hence I cannot see the JAVA code.
I am encrypting the payload in node.js using "aes-128-gcm" algorithm.
for this, I am try mimicking a working java encryption code
I have tried with crypto and node-forge.
iam getting the output but am getting an error "Bad encryption - payload is not encrypted properly" when submitting payload.
pleas help me to find what I did wrong in this code.
working code in java
public void encrypt(#NonNull final byte[] payload, #NonNull final byte[] key) throws GeneralSecurityException
{
SecretKeySpec codingKey = new SecretKeySpec(key, AES);
Cipher cipher = AEC_GCM_THREAD_CIPHER.get();
byte[] iv = new byte[cipher.getBlockSize()];
RANDOM.nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, codingKey, new IvParameterSpec(iv));
final byte[] encryptedPayload = cipher.doFinal(payload);
byte[] encryptMerchantKey = encryptMerchantKey(key);
String payloadFinal = encodeToUrlString(encryptedPayload); // final payload
String ivFinal = encodeToUrlString(iv); // final iv
String keyFinal = encodeToUrlString(encryptMerchantKey); // final key
System.out.println("Payload");
System.out.println(payloadFinal);
System.out.println("iv");
System.out.println(ivFinal);
System.out.println("key");
System.out.println(keyFinal);
}
code iam tried in node js
function encrypt(payload) {
let key = forge.random.getBytesSync(16);
let iv = forge.random.getBytesSync(16);
let cipher = forge.cipher.createCipher("AES-GCM", key);
cipher.start({ iv: iv});
cipher.update(forge.util.createBuffer(payload));
cipher.finish();
let encrypted = forge.util.encode64(cipher.output.getBytes());
let tag = forge.util.encode64(cipher.mode.tag.getBytes());
let iv64 = forge.util.encode64(iv);
let encryptedPayload = encrypted+tag;
//RSA Encryption
encryptedkey = RSAencrypt(forge.util.encode64(key));
return {
"payload" : base64url.fromBase64(encryptedPayload) ,
"iv" : base64url.fromBase64(iv64).length,
"key" : base64url.fromBase64(encryptedkey)
};
}
Rsa description is working fine abling to decrypt the key.
some problem with aes encryption. as see the code, I added auth tag and encrypted data together but no use.
I have complete example of encryption and decryption in angular and java you can take this example as it is and make changes according to you.
Install node-forge with command "npm install node-forge".
encrypt(msg, pass) {
const key = CryptoJS.lib.WordArray.random(8).toString();
const iv = CryptoJS.lib.WordArray.random(8).toString();
// encrypt some bytes using GCM mode
const cipher = forge.cipher.createCipher('AES-GCM', key);
cipher.start({
iv: iv,
additionalData: 'nvn', // optional
tagLength: 128 // optional, defaults to 128 bits
});
cipher.update(forge.util.createBuffer(msg));
cipher.finish();
const encrypted = cipher.output;
const encodedB64 = forge.util.encode64(encrypted.data);
const tag = cipher.mode.tag;
const tagB64 = forge.util.encode64(tag.data);
// outputs encrypted hex
const trasmitmsg = key+iv+tagB64+encodedB64;
return trasmitmsg
}
I have used CryptoJS to generate random string because random of node-forge giving nontransferable strings.
java code to decrypt this trasmitmsg is
public String getDecrypt(String transmsg) throws Exception {
String keyString = transmsg.substring(0, 16);
String ivString = transmsg.substring(16, 32);
String additionalString = transmsg.substring(32, 56);
String cipherString = transmsg.substring(56);
byte[] keyBytes = keyString.getBytes();
SecretKey key = new SecretKeySpec(keyBytes, "AES");
byte[] ivBytes = ivString.getBytes();
byte[] one = Base64.getDecoder().decode(cipherString);
byte[] two = Base64.getDecoder().decode(additionalString);
byte[] cipherText = ArrayUtils.addAll(one, two);
return decrypt(cipherText, key, ivBytes);
}
public static String decrypt(byte[] cipherText, SecretKey key, byte[] IV) throws Exception {
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// Create SecretKeySpec
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH , IV);
// Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
cipher.updateAAD("nvn".getBytes());
byte[] decryptedText = cipher.doFinal(cipherText);
return new String(decryptedText);
}
Cheers!!!
The problem was with forge buffer it need to convert to node buffer
this code is working now. thanks, #Maarten Bodewes for the advice.
function encrypt(payload) {
//initialize forge random buffer
var key = forge.random.getBytesSync(16);
var iv = forge.random.getBytesSync(16);
let cipher = forge.cipher.createCipher("AES-GCM", key);
cipher.start({iv : iv});
cipher.update(forge.util.createBuffer(payload));
cipher.finish();
let encrypted = cipher.output.data;
let tag = cipher.mode.tag.data;
let encryptedLoad = encrypted+tag;
// node buffer and forge buffer differ, so the forge buffer must be converted to node Buffer
iv = Buffer.from(iv, "binary");
encryptedLoad = Buffer.from(encryptedLoad, "binary");
//Calling RSA Encryption
encryptedKey = RSAencrypt(key);
return {
"payload" : base64url(encryptedLoad) ,
"iv" : base64url(iv),
"key" : base64url.fromBase64(encryptedKey)
};
}
I have a Java code to encrypt(AES encryption with key) a JSON and store it in Oracle database LONG RAW column.
I have a python code to read the data from that column and decrypt. Below is the code i am using for decryption.
The code is running fine but i am not able to see the JSON after decryption instead some unreadable string is getting printed.
c = conn.cursor()
c.execute(u'select KEY_VALUE from TEST1')
encoded = "";
for row in c:
encoded = base64.b64encode(row[0])
print(encoded)
key = 'F50D518354690A8630BCE683B7AC8F55'
aes = AES.new(key, AES.MODE_CBC, 16 * b'\0')
print(aes.decrypt(encoded))
conn.close()
Can you please point where am i wrong.
Also the Encoded String is getting printed fine and matches the value in Oracle database.
I tried using AES.MODE_ECB since the java code was not iv to encrypt but still the same issue
Below is the Encryption and Decryption Code in java. I want to replicate the decrypt in python.
decrypt
public static String decryptText(byte[] byteCipherText, SecretKey secKey) throws Exception {
// AES defaults to AES/ECB/PKCS5Padding in Java 7
System.out.println(secKey.toString());
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, secKey);
byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
return new String(bytePlainText);
}
encrypt
public static byte[] encryptText(String plainText, String key) throws Exception {
// AES defaults to AES/ECB/PKCS5Padding in Java 7
System.out.println("key is "+key);
SecretKey secKey=decodeKeyFromString(key);
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
return byteCipherText;
}
The decodeKeyFromString method has just the below line :
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
I Even tried writing the encrypted value as blob in oracle and then doing decryption but still the same garbage values.
for row in c:
encoded=row[0]
encrypted= open(blobpath,'wb')
encrypted.write(encoded.read())
encrypted.close()
with open('encrypted.txt', 'r') as myfile:
data=myfile.read().replace('\n', '')
key='F50D518354690A8630BCE683B7AC8F55'
aes = AES.new(key, AES.MODE_ECB)
e=unpad(aes.decrypt(base64.b64encode(data)))
I have a node module that can both encrypt and decrypt with AES-256 GCM. Now I am also trying to decrypt with Java whatever the node module encrypts, but I keep getting a AEADBadTagException.
I have tested the node module by itself and can confirm that it works as intended. I know that Java assumes the authentication tag is the last part of the message, so I ensured that the tag is the last thing appended in the node module.
Right now I'm just testing with the word, "hello". This is the encrypted message from node:
Q10blKuyyYozaRf0RVYW7bave8mT5wrJzSdURQQa3lEqEQtgYM3ss825YpCQ70A7hpq5ECPafAxdLMSIBZCxzGbv/Cj4i6W4JCJXuS107rUy0tAAQVQQA2ZhbrQ0gNV9QA==
The salt is not really being used right now because I am trying to keep things simple for testing purposes
Node module:
var crypto = require('crypto');
var encrypt = function(masterkey, plainText) {
// random initialization vector
var iv = crypto.randomBytes(12);
// random salt
var salt = crypto.randomBytes(64);
var key = masterkey;
// AES 256 GCM Mode
var cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// encrypt the given text
var encrypted = Buffer.concat([cipher.update(plainText, 'utf8'), cipher.final()]);
// extract the auth tag
var tag = cipher.getAuthTag();
return Buffer.concat([salt, iv, encrypted, tag]).toString('base64');
};
var decrypt = function(masterkey, encryptedText) {
// base64 decoding
var bData = new Buffer(encryptedText, 'base64');
// convert data to buffers
var salt = bData.slice(0, 64);
var iv = bData.slice(64, 76);
var tag = bData.slice(bData.length - 16, bData.length);
var text = bData.slice(76, bData.length - 16);
var key = masterkey;
// AES 256 GCM Mode
var decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
// encrypt the given text
var decrypted = decipher.update(text, 'binary', 'utf8') + decipher.final('utf8');
return decrypted;
};
module.exports = {
encrypt: encrypt,
decrypt: decrypt
}
Java Class:
The main method is just there for testing right now and will be removed later.
package decryption;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class DecryptAES256 {
private static String salt;
private static byte[] ivBase64;
private static String base64EncryptedText;
private static String key;
public static void main(String[] args) {
String key = "123456789aabbccddeefffffffffffff";
String sourceText = "Q10blKuyyYozaRf0RVYW7bave8mT5wrJzSdURQQa3lEqEQtgYM3ss825YpCQ70A7hpq5ECPafAxdLMSIBZCxzGbv/Cj4i6W4JCJXuS107rUy0tAAQVQQA2ZhbrQ0gNV9QA==";
System.out.println(decrypt(key, sourceText));
}
public static String decrypt(String masterkey, String encryptedText) {
byte[] parts = encryptedText.getBytes();
salt = new String(Arrays.copyOfRange(parts, 0, 64));
ivBase64 = Arrays.copyOfRange(parts, 64, 76);
ivBase64 = Base64.getDecoder().decode(ivBase64);
base64EncryptedText = new String(Arrays.copyOfRange(parts, 76, parts.length));
key = masterkey;
byte[] decipheredText = decodeAES_256_CBC();
return new String(decipheredText);
}
private static byte[] decodeAES_256_CBC() {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] text = base64EncryptedText.getBytes();
GCMParameterSpec params = new GCMParameterSpec(128, ivBase64, 0, ivBase64.length);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, params);
return cipher.doFinal(Base64.getDecoder().decode(text));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to decrypt");
}
}
}
The exception thrown is normal, you have 2 problems in your Java code:
1- your AES key is not decoded correctly: it is wrapped in hexadecimal representation and you decode it as if it was not. You need to convert it from the hexadecimal representation to bytes, when calling SecretKeySpec().
Replace the following line:
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
By this one:
SecretKeySpec skeySpec = new SecretKeySpec(Hex.decodeHex(key.toCharArray()), "AES");
Note that to get access to the Hex class, you need to import org.apache.commons.codec.binary.Hex in your class file and include the corresponding Apache commons-codec library in your project.
2- you split your base64 cipher text before having converted it to base64, this is not the correct order to do things:
At the start of your decrypt() method, you need to first call Base64.getDecoder().decode() on your cipher text (sourceText) before splitting it into the corresponding fields.
If you want an example of using AES-256-GCM in Java, you can look at the following example I had written some months ago: https://github.com/AlexandreFenyo/kif-idp-client
The source code to encrypt and decrypt is in the following file: https://github.com/AlexandreFenyo/kif-idp-client/blob/master/src/kif/libfc/Tools.java
See the methods named encodeGCM() and decodeGCM().
Those methods are called by the main class here: https://github.com/AlexandreFenyo/kif-idp-client/blob/master/src/kif/libfc/CommandLine.java
I want to duplicate the JAVA encryption code in NodeJS.
private String DEFAULT_KEY = "abcdwAYserXbzcSeqL/zPg==";
private String text = "abc";
Base64 base64decoder = new Base64();
byte[] raw = base64decoder.decode(key);
SecretKeySpec fSecretKeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, fSecretKeySpec);
byte[] encrypted = cipher.doFinal(text.getBytes());
Base64 base64encoder = new Base64();
result = base64encoder.encodeToString(encrypted);
System.out.println("result: "+ result);
The above code generate the encrypted code as: ZkojvMTW+9EEK0owxMuA7A==
I have tried few ways in NodeJS. It is not generating same code for me.
I have tried the following code.
var bKey = new Buffer('abcdwAYserXbzcSeqL/zPg==', 'base64');
var cipher = crypto.createCipher('aes-128-ecb',bKey);
//cipher.setAutoPadding(auto_padding=false);
var crypted = cipher.update('abc',null,'base64');
crypted+=cipher.final('base64');
console.log(crypted);
Can someone help me out?
You probably are running into the issue that createCipher with two arguments takes a password, not a key. This password is first run through a key derivation function before it becomes a key.
Try to use the createCipheriv method instead, using any value for the IV. ECB mode doesn't take an IV, but at least you would be using a key instead of a password.