I'm encrypt data using triple DES. It works fine, but I have a question.
Where can I see the initialization vector (IV)?
It's 3des encyption with BASE64Decoder.
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class Crypter {
Cipher ecipher;
Cipher dcipher;
Crypter(String as_Phrase)
throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException {
this.ecipher = Cipher.getInstance("DESede");
this.dcipher = Cipher.getInstance("DESede");
this.ecipher.init(1, getSecretKey(as_Phrase));
this.dcipher.init(2, getSecretKey(as_Phrase));
}
public String encrypt(String as_valueToEncrypt)
throws BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, IOException {
byte[] lbarr_utf8 = as_valueToEncrypt.getBytes("UTF8");
byte[] lbarr_enc = this.ecipher.doFinal(lbarr_utf8);
return new BASE64Encoder().encode(lbarr_enc);
}
public String decrypt(String as_valueToDecrypt)
throws BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, IOException {
byte[] lbarr_enc = new BASE64Decoder().decodeBuffer(as_valueToDecrypt);
byte[] lbarr_utf8 = this.dcipher.doFinal(lbarr_enc);
return new String(lbarr_utf8, "UTF8");
}
private SecretKey getSecretKey(String as_Phrase)
throws UnsupportedEncodingException {
return new SecretKeySpec(as_Phrase.getBytes("UTF8"), "DESede");
}
}
You can get the IV from the cipher:
ecipher.getIV();
The problem is that the IV is generated during init. Since you init in the constructor you would run into the problem of using the same IV for every encryption of different ciphertexts. It's always best to generate a new Cipher and init it for every encryption and decryption operation separately.
You use the DESede cipher which is actually DESede/ECB/PKCS5Padding. Note that the mode is ECB which doesn't use an IV. So the above call returns null. Although this is the default mode, it is not recommended. It's safer to use DESede/CBC/PKCS5Padding which actually uses an IV.
So when you decrypt in CBC mode you need to pass that IV in:
dcipher.init(2, new SecretKeySpec(key, "DESede"), new IvParameterSpec(ecipher.getIV()));
To reduce the burden of passing the IV around you could then append the IV to the front of the ciphertext before encoding it and slice it off before decrypting the ciphertext. DES is a 64-bit cipher so your IV will be 8 bytes long.
Cipher has getIV() method, which returns initialization vector.
Related
I have written this code in Angular to encrypt a string:
import { Injectable } from '#angular/core';
import * as CryptoJS from 'crypto-js';
#Injectable({
providedIn: 'root',
})
export class CryptoService {
encrypt(message: string, clef: string): string {
const salt = CryptoJS.SHA256("123456789123");
const key = CryptoJS.PBKDF2(clef, salt, {
keySize: 128 / 32,
iterations: 1000
});
// var key = CryptoJS.enc.Utf8.parse(clef);
let iv = CryptoJS.enc.Utf8.parse(clef);
let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(message.toString()), key,
{
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// var encryptedMessage = CryptoJS.AES.encrypt(message.trim(), key).toString();
return encrypted.toString();
}
generateKey(): string {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < 16) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
}
I transfer my key and encriptedMessage to the back for the decryption.
I code dat on java:
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
public class AESUtilService {
protected static final String salt = "123456789123";
public SecretKey getKeyFromPassword(String password)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 1000, 128/32);
SecretKey secret = factory.generateSecret(spec);
return secret;
}
public String decrypt(String cipherText, SecretKey key)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
String algorithm = "AES/CBC/PKCS7Padding";
IvParameterSpec iv = new IvParameterSpec("MnTQLHcWumIKTXpQ".getBytes());
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(plainText);
}
}
My issue is the following.
The part of the code Cipher cipher = Cipher.getInstance(algorithm); crashes in java, if I use String algorithm = "AES/CBC/PKCS7Padding";
However it would pass with String algorithm = "AES/CBC/PKCS5Padding";, but this time it's angular that would crash. padding: CryptoJS.pad.Pkcs5
I can't find a solution for this problem, and that's why I ask for your help.
As per your code seems like, There is a issue with your PBEKeySpec and key length specification.
JAVA: you must need to use "AES/CBC/PKCS5Padding" instead of "AES/CBC/PKCS7Padding"
Angular: Make changes on key length and PBEKeySpec
let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse("hasan test"), key,
{
keySize: 16,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
I finaly find a post who sayd they pkcs5 in java are the same as pkcs7 in angular
-->padding (128)
source:
https://crypto.stackexchange.com/questions/9043/what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding
Java encryption code.
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.json.simple.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jarvis.accountopeningv2.model.PartChanRequestDTO;
import com.jarvis.accountopeningv2.model.TemplateDTO;
public class SecurityService {
private static final String ALGORITHM = "AES/CBC/PKCS5PADDING";
public static String encryptpayload(String value, String key) {
String encryptedData = null;
try {
IvParameterSpec iv = new IvParameterSpec(key.substring(0, 16).getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.substring(0, 32).getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
encryptedData = Base64.getEncoder().encodeToString(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
encryptedData = null;
}
return encryptedData;
}
}
This is what I have tried.
function SecurityFunc(request) {
const digest = 'SHA256';
var secretkey = 'fgbnhgfcjhgfcvjkhgfcvjkhgfcvbjbnvcjhnbvcfghjnbvc'; // 256 character
var iv = Buffer.from(secretkey.substring(0,16), 'utf-8', 'aes');
const key = crypto.pbkdf2Sync(secretkey, 'boooooo!!', 65536, 32, digest);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(`${request}`, 'ascii', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
I have searched a lot about this. I got these questions on stack overflow
Difference in key lengths between crypto.pbkdf2 (node.js) and PBEKeySpec, AES/CBC/PKCS5PADDING IV - Decryption in NodeJs (Encrypted in Java) I have tried both of them but none of them resolved my query.
Any help will be highly appreciated.
Are you trying to make the 2 compatible or just port the code from Java to JavaScript?
Update: apparently PKCS#5 will work the same as for PKCS#7 so that isn't your issue.
The key length should be 32-bytes in both cases.
If you don't need backwards compatibility, I'd recommend using AES in GCM mode rather than CBC as it includes tamper protection.
I want to encrypt my password in angular side before sending it to Springboot API. My idea is to do:-
Generate public key and private key in java
Do a base64 encoding on both public key and private key
Use encoded public key in node (angular) side, this will be used for encryption
Use encoded private key in springboot rest api, this will be used for decryption
Below is my java code which generates, encrypts and decrypts password
RSAKeyPairGenerator.java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class RSAKeyPairGenerator {
private static String privateKeyString = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALyR1WRqVBuvdmXmgrcZ4VMY4hIFTYt63NGEN9atlgnngNliMasvzBofnjRtk5mukezUKujtON6mPnAjKJoEDdiaw3Rk0hKvgW5MszyUBE5bLThexVLbi+nQYSf2GSvd0fjdZn6KjhgVOdbYe+JduU/iPD3/Ti5p+w3MewgZpy2RAgMBAAECgYAqWdqCXfsb6LF/u2C6PN7Faf5EK9q5q9NyXu6nkX70JIFk0U/0cZy2dUlz3vRafMGbXh9xBu5R2yaEyvCwfp6ZF26A8MbS/IaI53LMKmyclhES2f3tZLKUPkg6fntz+e6e/6oSDdQPHP3J2QrpuwzyW+UZJQmmYYj7f9sq/+dawQJBAOnkHWkLuIZNIgLzV0TuHA6fcOXrqrSlS1/Q0qLyaQEZOObocXDvWaCSP+8RXiqZSwAnMJbrGHQA5ULXLWI4GjkCQQDOZP6bfn2VV3m8JSlYL9Uz4TrRYb8Qe3/mohhMsyDB7Ua/6d9BV7JZgbYiXP0utobKVWLxD49OFMkgEs20qY4ZAkB4dJsQ9pBZ2m+hxWE0hsy8WzDxuKV504c2GX3hnaamgi7j/OIvn5UxNSDoJrGwjrIpqgVENF+rnqpz+g3Nf8dBAkBV/op+6yMUGFBmbe1eCwAAD7XcC6f6DBrsU1lgi7n4Uw6JY75bkViEJqFmi+wJjI94uj7xRZRl6g8qx+rhfUvxAkEArD1we6ZLTWz73D8z+4Boj7Su7b5LhfgvXVL5V4Zdog3X58pHK+dYppapDh5KjZZdor+y/6uz1PqIs2dmFy/xtQ==";
private static String publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8kdVkalQbr3Zl5oK3GeFTGOISBU2LetzRhDfWrZYJ54DZYjGrL8waH540bZOZrpHs1Cro7Tjepj5wIyiaBA3YmsN0ZNISr4FuTLM8lAROWy04XsVS24vp0GEn9hkr3dH43WZ+io4YFTnW2HviXblP4jw9/04uafsNzHsIGactkQIDAQAB";
private static PrivateKey privateKey;
private static PublicKey publicKey;
public void generateKeys() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair pair = keyGen.generateKeyPair();
RSAKeyPairGenerator.privateKey = pair.getPrivate();
RSAKeyPairGenerator.publicKey = pair.getPublic();
}
public void readKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
byte [] encoded = Base64.getDecoder().decode(privateKeyString);
PKCS8EncodedKeySpec keySpec1 = new PKCS8EncodedKeySpec(encoded);
RSAKeyPairGenerator.privateKey = kf.generatePrivate(keySpec1);
encoded = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpec2 = new X509EncodedKeySpec(encoded);
RSAKeyPairGenerator.publicKey = kf.generatePublic(keySpec2);
}
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException {
RSAKeyPairGenerator keyPairGenerator = new RSAKeyPairGenerator();
// Next line is for testing with encrypted text generated by nodejs code with genrated keys
// keyPairGenerator.generateKeys();
keyPairGenerator.readKeys();
System.out.println("-----Private----------");
System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
System.out.println("Encoding : "+ privateKey.getFormat());
System.out.println("----------------------");
System.out.println("-----Public----------");
System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("Encoding : "+ publicKey.getFormat());
System.out.println("----------------------");
String secretMessage = "Test";
System.out.println(secretMessage);
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] secretMessageBytes = secretMessage.getBytes(StandardCharsets.UTF_8);
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
// Next lines are for testing decryption with encrypted text generated by nodejs code with generated keys
// byte[] encryptedMessageBytes = "B��u���<⌂�lǚm0�W������1�%EN�7��‼��l��l�<�����k;�������GĦ9D8��Z��I�Oɺ♫��→P'�§�{k�Ɋ+-}?��rZ".getBytes();
// byte[] encryptedMessageBytes = Base64.getDecoder().decode("woboAUytDXJLlKm7zbqNdxVORG+kio9kZxvMPOHruQfxwNEx7SVFTsw3oeETqbRs4NZskjzO2Nzjyms73vv758Dcy0fEpjlEOKmrWuG62knOT8m6DqGDGlAn1hXpe2u6yYorLX0/6fhyWg1C/JR1sbaKPH/Xt+Fsx5ptMONX0uw=");
System.out.println(new String(encryptedMessageBytes));
Cipher decryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);
System.out.println(decryptedMessage);
}
}
This gives me following output
-----Private----------
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMv+t+D6/7ZY6m+CjD97NB989P2YjmGcE2yHUokyjmxVi/SxIu9MboiVNewR+mFjTFYPGgMWHz1/XeVGlinjN/5+0fdiO/JEvEUilFmkkIF3My11I09b9NZ9RJmpCNCbqOg7NSt6VD8IC/w19N25xwcofc3qbgfEjKSs0CgxfahrAgMBAAECgYEAiyLlEBKiryDeZchJGFNULdXw07dmBbWKmg+CgAl3kvSWTQM0rLsY+Rese6OXfy1XN6t9NnW0QSHKTUNj0JYl7btKEblVHERbjwavUe83tcNIc3o0xrGoBAzma14ZicPYm70JWixTO778lm5AXKl504+oOQyVYmfgXcevPXwdIkECQQDvO3DBuu6wp5nbwR4t0736HOH9jVIjJOS8oABUARDhNt1fkb8uEptDr5EomVRMqarJMAjSMpYxrUCpvgtf4nZ5AkEA2ksDr8pbbFvZPaAe0F43LmJtFM3PvCz87S93p20YjwVMmGV17sJ5t7a26HtubgRLEWq4z6rxq2oXPv4y1lstAwJAbj9cVUtKWIrEcutqdwAPmsXYt7p60ctcxjiOLihXmRJprnNCQX89olG0eZs/qBzAofrK9eNuJ/KJzC/SmhuJMQJAAz9gc6oQCCGprrgGHVV5frAqLUgOkh8dOC4fmpcN6XrLs+y2f3HXO7t1JypG704TC9RJoZVKeSFf7Sj8+qFqnwJBALRiQc9SG5Ht5TLo12W4l3bRaxpbo597BgKRjz3hqiySdqjZA9Qe84qmEKveZ9eWehbfqwzKmCbW43I1ZEFZ95o=
Encoding : PKCS#8
----------------------
-----Public----------
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL/rfg+v+2WOpvgow/ezQffPT9mI5hnBNsh1KJMo5sVYv0sSLvTG6IlTXsEfphY0xWDxoDFh89f13lRpYp4zf+ftH3YjvyRLxFIpRZpJCBdzMtdSNPW/TWfUSZqQjQm6joOzUrelQ/CAv8NfTduccHKH3N6m4HxIykrNAoMX2oawIDAQAB
Encoding : X.509
----------------------
Test
�N::�`��\A���ƈ�~��5s���
�0�I�C�uƹx2�Z&Kں�"ьC�$
q��K���h�^<�5�E�Ɨ0B�͒Z�{��EDbDH�.��#:�e��h~j���������q�c��R�
Test
In the Nodejs side I am using the above public to encrypt my text.
index.js
const crypto = require("crypto");
var pubkey = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL/rfg+v+2WOpvgow/ezQffPT9mI5hnBNsh1KJMo5sVYv0sSLvTG6IlTXsEfphY0xWDxoDFh89f13lRpYp4zf+ftH3YjvyRLxFIpRZpJCBdzMtdSNPW/TWfUSZqQjQm6joOzUrelQ/CAv8NfTduccHKH3N6m4HxIykrNAoMX2oawIDAQAB\n-----END PUBLIC KEY-----";
var plaintext = "Test"
var buffer = new Buffer.from(plaintext, "utf8");
var enc = crypto.publicEncrypt(pubkey, buffer);
var bs64 = enc.toString('base64');
console.log(enc.toString());
console.log(enc.toString('base64'));
this gives me following output
B��u���<⌂�lǚm0�W������1�%EN�7��‼��l��l�<�����k;�������GĦ9D8��Z��I�Oɺ♫��→P'�§�{k�Ɋ+-}?��rZ
woboAUytDXJLlKm7zbqNdxVORG+kio9kZxvMPOHruQfxwNEx7SVFTsw3oeETqbRs4NZskjzO2Nzjyms73vv758Dcy0fEpjlEOKmrWuG62knOT8m6DqGDGlAn1hXpe2u6yYorLX0/6fhyWg1C/JR1sbaKPH/Xt+Fsx5ptMONX0uw=
Now I tried using both the strings in java side for decryption.
When I try decoding the string, it gives me following error
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:346)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391)
at javax.crypto.Cipher.doFinal(Cipher.java:2168)
at com.mindtree.starr.wsr.RSAKeyPairGenerator.main(RSAKeyPairGenerator.java:90)
And, when I try decoding the base64 string, it gie me following error
Exception in thread "main" javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:379)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:290)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:365)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391)
at javax.crypto.Cipher.doFinal(Cipher.java:2168)
at com.mindtree.starr.wsr.RSAKeyPairGenerator.main(RSAKeyPairGenerator.java:90)
What am I doing wrong?
The problem was clearly described in the first comment and the solution is in second comment.
Correct transformation string for Cipher instance that worked for me is RSA/ECB/OAEPWithSHA-1AndMGF1Padding
So below instantiation for decryption Cipher works perfectly.
Cipher decryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
In Java, the code below can encrypt strings of any length and decrypt without any problem.
Java code:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class AesEncryption {
public static void main(String[] args) throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {
AesEncryption ae = new AesEncryption();
byte[] secret = ae.encrypt("Hello World!");
for (byte b : secret)
System.out.print(String.format("%d, ", b));
System.out.print("\n");
System.out.print(String.format("%s\n", ae.decrypt(secret)));
}
private final IvParameterSpec iv;
private final SecretKeySpec keySpec;
public AesEncryption() throws NoSuchAlgorithmException {
byte[] key = "thisisasecretkey".getBytes(StandardCharsets.UTF_8);
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(key);
this.iv = new IvParameterSpec(md.digest());
this.keySpec = new SecretKeySpec(key, "AES");
}
public byte[] encrypt(String content) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, this.keySpec, this.iv);
return cipher.doFinal(content.getBytes());
}
public String decrypt(byte[] secret) throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, this.keySpec, this.iv);
return new String(cipher.doFinal(secret));
}
}
Python code:
import array
import hashlib
from Crypto.Cipher import AES
class AesEncryption:
def __init__(self):
key = 'thisisasecretkey'.encode('UTF-8')
md = hashlib.md5()
md.update(key)
iv = md.digest()
self.__cryptor = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
def encrypt(self, content):
return self.__cryptor.encrypt(AesEncryption.r_pad(content.encode('UTF-8')))[:len(content.encode('UTF-8'))]
def decrypt(self, secret):
return self.__cryptor.decrypt(secret)
#staticmethod
def r_pad(payload):
length = 16 - (len(payload) % 16)
return payload + (chr(length) * length).encode('UTF-8')
if __name__ == '__main__':
secretstr = array.array('b', [-108, 20, -91, -103, 13, 59, 94, -51, 17, -104, -30, -83]).tostring()
ae = AesEncryption()
print(ae.decrypt(secretstr).decode('UTF-8'))
However when I pass the secret byte array produced by the Java code to PyCrypto, the decryption fails. The Python code uses AES.MODE_CFB and segment_size = 128 to match the AES mode in Java, but the length of the plain text won't meet the 16-byte-block requirement. Changing the segment_size never produces the same result either. So I figure NoPadding may be the problem. What is the algorithm used by AES/CFB/NoPadding mode in Java? And how is it different from the algorithm used in PyCrypto? Thanks.
Edit:
Thanks to Topaco and Robert. As a stream cipher, CFB mode with segment_size=128 should work correctly. The problem is caused by the bug in an outdated version of PyCrypto. Use latest PyCryptodome instead.
I am trying to generate a shared key from Alice and Bob. I used a key generator to get public and private keys for Bob and Alice. Then, I generated a secret key using AES. What I am supposed to do is encrypt the secret key then decrypt it, and it should be the same as the original secret key. However, my code is giving me an exception that says "decryption error". And I cannot figure out why. Can anyone help me? Thank you!
Also, decodeBytes and generateSharedKey are supposed to be equal and I was having trouble with that as well.
import java.security.*;
import java.util.UUID;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
public class rsa {
static SecretKey sharedKey = null;
public static void main(String[] args) throws NoSuchAlgorithmException,
NoSuchProviderException, InvalidKeyException, NoSuchPaddingException,
IllegalBlockSizeException, BadPaddingException {
//Generates Key Pair -> a private and public key for both Alice and
Bob
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
//Alice's key pair
KeyPair aliceKey = keyGen.genKeyPair();
PublicKey pubAlice = aliceKey.getPublic(); //alice's public key
PrivateKey privAlice = aliceKey.getPrivate();//alice's private key
//Bob's key pair
KeyPair bobKey = keyGen.genKeyPair();
PublicKey pubBob = bobKey.getPublic(); //bob's public key
PrivateKey privBob = bobKey.getPrivate();// bob's private key
//Generates a random key and encrypt with Bob's public Key
System.out.println(generateSharedKey());
byte[] keyEncrypted = encrypt(sharedKey, pubBob);
byte[] decodeBytes = decrypt(sharedKey, privBob);
System.out.println(decodeBytes);
}
public static SecretKey generateSharedKey() throws
NoSuchAlgorithmException{
KeyGenerator sharedKeyGen = KeyGenerator.getInstance("AES");
sharedKey = sharedKeyGen.generateKey();
return sharedKey;
}
public static byte[] encrypt(SecretKey sharedKey, PublicKey pubKey)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
//System.out.println(inputBytes);
return cipher.doFinal(generateSharedKey().getEncoded());
}
public static byte[] decrypt(SecretKey sharedKey, PrivateKey privKey)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privKey);
return cipher.doFinal(generateSharedKey().getEncoded());
}
}
Please carefully read your code before posting... You are generating a new shared key and then trying to decrypt that in your decrypt method...
You should be passing in a byte[] to decrypt and returning a SecretKey, not the other way around.