Decrypt java (DESede/ECB/PKCS5Padding) cipher using python - java

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

Related

AES encryption in python and decryption in java not working

I have Java based Web API which receives AES encrypt user credentials and let the user get the session token. This is working fine with AES encryption on client side with CryptoJS. But the same throws bad padding exception while trying to access this API from Python.
In Java I've used PKCS5Padding padding. I have tried this with NoPadding as well, but in that case the de-crypted text is simply empty. Also, when trying with NoPadding, CryptoJS code is not working properly. As, this API should work for any client side program (Later I'm planning to expand this to PHP, .Net and R as well), I want to have a common, working mechnism for encryption of passwords thru AES. I'm pretty new to python and I have tried various programs provided in stack overflow as well as in other blogs on this subject.
Here is the java part
public String decrypto(String cipherText, String secret) {
byte[] cipherData = java.util.Base64.getDecoder().decode(cipherText);
byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);
String decryptedText = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes(StandardCharsets.UTF_8),
md5);
SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);
byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decryptedData = aesCBC.doFinal(encrypted);
decryptedText = new String(decryptedData, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
And this line send the encrypted password from CrptoJS without any issues which gets de-crypted properly in Java
encKey = CryptoJS.AES.encrypt(this.logingrp.value['loginpass'], this.localPublicKey).toString();
this.localLogin(encKey);
LocalLogin is an AJAX function to call the API
Python code is below. I'm using Pycryptodome
import requests, json
import base64
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto import Random
from urllib.parse import urlencode
from urllib.request import Request, urlopen
from hashlib import sha256
BS = 16
pad = lambda s: bytes(s + (BS - len(s) % BS) * chr(BS - len(s) % BS), 'utf-8')
unpad = lambda s : s[0:-ord(s[-1:])]
class AESCipher:
def __init__( self, key ):
self.key = bytes(key, 'utf-8')
def encrypt( self, raw ):
raw = pad(raw)
iv = Random.new().read( AES.block_size )
cipher = AES.new(self.key, AES.MODE_CBC )
return base64.b64encode( iv + cipher.encrypt( raw ) )
def decrypt( self, enc ):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return unpad(cipher.decrypt( enc[16:] )).decode('utf8')
header = {"Content-type": "application/json",
"Authorization": "Bearer CT9797"
}
password = 'stone#123'
keyphrase = '9DA538D0HMQXQRGI';
cipher = AESCipher(keyphrase)
encrypted = cipher.encrypt(password).decode('utf8')
payload={'userId':'CT9797','userData':encrypted,'encKey':''}
response_decoded_json = requests.post(url=_base_URL+'eLogin', data=json.dumps(payload), headers=header)
print(response_decoded_json.status_code)
The below exception occurs while trying the above program on java side
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:10
Appreciate your time in reading and helping me out.

unable to decrypt in java if encrypted with aes-256-cfb nodejs [duplicate]

I'm using openssl's aes-256-cfb algorithm (from NodeJS's crypto module).
While both the NodeJS and the Java code successfully encrypt and decrypt data, the ciphertext is different, even when the iv, key and plaintext are all identical.
openssl/NodeJS cipherText:
05c2aad7bac42ed0846e9a52ce73df9ff9d7ff914feea49fed27d55ad690782a43107914c1b307ec92753227728c95b8e59c546d
Java cipherText:
05C2AAD7BAC42ED084739340D47CEC9F03D8E94AC7B1E11A56A6654F76AD2C8076BCA162303E39B44D043732E98FDD28C52D
I have guessed that openssl's aes-256-cfb translates to Java's AES/CFB/NoPadding.
The ciphertexts both share the same initial 9 bytes, which is odd - I would have expected them to share the first 16 bytes if there had been some difference in the common mode used. (I hope that "common mode" is the collective term for CFB/CBC/CTR/etc.)
Is Java's AES/CFB/NoPadding the correct translation of OpenSSL's aes-256-cfb?
Does the existence of the common first nine bytes imply that Java's AES/CFB/NoPadding is at least using AES256, as opposed to AES128?
If so, what else might account for the differing ciphertext?
Test cases follow:
OpenSSL/NodeJS:
var assert = require('assert');
var crypto = require('crypto');
describe('crypto', function() {
it('should work', function () {
var plainText = new Buffer('a secret plainText which has more than sixteen bytes');
var key = new Buffer('fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210', 'hex');
var iv = new Buffer('0123456789abcdef0123456789abcdef', 'hex');
var cipher = crypto.createCipheriv('aes-256-cfb', key, iv);
var decipher = crypto.createDecipheriv('aes-256-cfb', key, iv);
var cipherText = cipher.update(plainText);
cipher.final(); // no need to use this value with cfb, it seems to always be empty?
assert.equal(plainText.length, cipherText.length);
assert.equal('05c2aad7bac42ed0846e9a52ce73df9ff9d7ff914feea49fed27d55ad690782a43107914c1b307ec92753227728c95b8e59c546d', cipherText.toString('hex'));
var deciphered = decipher.update(cipherText);
decipher.final(); // no need to use value this with cfb, it seems to always be empty?
assert.equal(plainText, deciphered.toString('utf8'));
});
});
Java/Android:
import android.test.InstrumentationTestCase;
import com.google.protobuf.ByteString;
import bit.Twiddling;
import java.security.AlgorithmParameters;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CryptoTest extends InstrumentationTestCase {
public void test_encrypt_and_decrypt() throws Exception {
byte[] plainText = "a secret message which has more than sixteen bytes".getBytes();
byte[] key = Twiddling.hexStringBEToBytes("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210");
byte[] iv = Twiddling.hexStringBEToBytes("0123456789abcdef0123456789abcdef");//0123456789abcdef0123456789abcdef");
SecretKeySpec aesSecret = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
Cipher decipher = Cipher.getInstance("AES/CFB/NoPadding");
IvParameterSpec ivps = new IvParameterSpec(iv);
assertEquals(16, iv.length);
cipher.init(Cipher.ENCRYPT_MODE, aesSecret, ivps);
byte[] cipherText = cipher.doFinal(plainText);
assertEquals(plainText.length, cipherText.length);
assertEquals("05C2AAD7BAC42ED084739340D47CEC9F03D8E94AC7B1E11A56A6654F76AD2C8076BCA162303E39B44D043732E98FDD28C52D", Twiddling.bytesToHexStringBE(cipherText));
decipher.init(Cipher.DECRYPT_MODE, aesSecret, ivps);
byte[] deciphered = decipher.doFinal(cipherText);
assertEquals(new String(plainText), new String(deciphered));
}
}
It was a find/replace error - the two plainTexts differ after the first nine bytes.
Java's name for OpenSSL's aes-256-cfb is AES/CFB/NoPadding.

Blowfish encryption - encrypted in php and java, I got different encrypted values

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=

Convert Java code to NodeJS - Encryption method

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.

AES/CBC/PKCS5Padding encrypt in java decrypt in ruby

I am trying to encrypt data in java and decrypt data in ruby.
I found almost same asks, but my case is little bit different.
Encrypt in Ruby and Decrypt in Java - Why is it not working?
AES/CBC encrypt in Java, decrypt in Ruby
My code is ...
Encrypt in java
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Hex;
class Crypt {
public static void main(String[] args) throws Exception {
Map<String, String> node = new HashMap<String, String>();
node.put("timestamp", "1377499097199");
JSONObject jsonObject = JSONObject.fromObject(node);
String json = jsonObject.toString();
System.out.println(json);
//key
String skeyString = "97128424897797a166913557a6f4cc8e";
byte[] skey = Hex.decodeHex(skeyString.toCharArray());
System.out.println("key : " + skeyString);
//iv
String ivString = "84e8c3ea8859a0e293941d1cb00a39c3";
byte[] iv = Hex.decodeHex(ivString.toCharArray());
System.out.println("iv : " + ivString);
//encrypt
SecretKeySpec skeySpec1 = new SecretKeySpec(skey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec1, new IvParameterSpec(iv));
byte[] encrypted = cipher.doFinal(json.getBytes());
String encryptedString = Hex.encodeHexString(encrypted);
System.out.println("=============>");
System.out.println("encrypted string: " + encryptedString);
}
}
Result is
{"timestamp":"1377499097199"}
key : 97128424897797a166913557a6f4cc8e
iv : 84e8c3ea8859a0e293941d1cb00a39c3
=============>
encrypted string: 395f6c0e8ad27f57c4a5a8975aa633e5b26f288d37ce18c6971779951f3b3527
and I hope to decrypt (encrypted string) in Ruby
Ruby code is ...(got error)
require 'openssl'
key = "97128424897797a166913557a6f4cc8e"
iv = "84e8c3ea8859a0e293941d1cb00a39c3"
encrypted_string = "395f6c0e8ad27f57c4a5a8975aa633e5b26f288d37ce18c6971779951f3b3527"
de_cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
de_cipher.decrypt
de_cipher.key = key
de_cipher.iv = iv
de_cipher.update(encrypted_string) << de_cipher.final
I expected to get
{"timestamp":"1377499097199"}
But it returns error
`final': bad decrypt (OpenSSL::Cipher::CipherError)
I think the problem is cipher.padding and type of key/iv.
But I don't know exactly how to complete ruby code.
Please let me know How to complete this code.
Thank you.
There's two problems with your Ruby code.
First, you're using AES 256 when you should be using AES 128. Java uses AES 128 or 256 based on the size of the key you use, and you're using a 128 bit key.
Second, you need to Hex decode your key, iv, and encrypted_string values in Ruby. OpenSSL Cipher is expecting binary, not hex strings.
require 'openssl';
key = "97128424897797a166913557a6f4cc8e";
iv = "84e8c3ea8859a0e293941d1cb00a39c3";
encrypted_string = "395f6c0e8ad27f57c4a5a8975aa633e5b26f288d37ce18c6971779951f3b3527";
de_cipher = OpenSSL::Cipher::Cipher.new("AES-128-CBC");
de_cipher.decrypt;
de_cipher.key = [key].pack('H*');
de_cipher.iv = [iv].pack('H*');
puts de_cipher.update([encrypted_string].pack('H*')) << de_cipher.final;
Output:
{"timestamp":"1377499097199"}

Categories

Resources