I am trying to simulate asymmetric key system. I use following code to generate key pairs, encrypt, decrypt passwords. I have a distributed environment and for the moment I save the keys generated in a file system. I know that is not secure but its just for testing purposes.
private static SecureRandom random = new SecureRandom();
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
protected synchronized void generateKeys() throws InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException,
NoSuchPaddingException {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
generator.initialize(256, random);
KeyPair pair = generator.generateKeyPair();
Key pubKey = pair.getPublic();
Key privKey = pair.getPrivate();
//store public key
try {
storeKey(pubKey, Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-publickey")));
} catch (Exception e) {
e.printStackTrace();
DBLogger.logMessage(e.toString(), Status.KEY_GENERATION_ERROR);
}
//store private key
try {
storeKey(privKey, Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-privatekey")));
} catch (Exception e) {
e.printStackTrace();
DBLogger.logMessage(e.toString(), Status.KEY_GENERATION_ERROR);
}
}
protected synchronized String encryptUsingPublicKey(String plainText) throws IllegalBlockSizeException, BadPaddingException,
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException,
FileNotFoundException, IOException, ClassNotFoundException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, readKey(Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-publickey"))), random);
byte[] cipherText = cipher.doFinal(plainText.getBytes());
System.out.println("cipher: " + new String(cipherText));
return new String(cipherText);
}
protected synchronized String decryptUsingPrivatekey(String cipherText) throws NoSuchAlgorithmException,
NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, FileNotFoundException,
IOException, ClassNotFoundException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, readKey(Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-privatekey"))));
byte[] plainText = cipher.doFinal(cipherText.getBytes());
System.out.println("plain : " + new String(plainText));
return new String(plainText);
}
public static void main(String[] args) {
KeyGenerator keyGenerator = new KeyGenerator();
try {
keyGenerator.deleteAllKeys(Constants.KEY_PATH);
keyGenerator.generateKeys();
String cipherText = keyGenerator.encryptUsingPrivateKey("dilshan");
keyGenerator.decryptUsingPublickey(cipherText);
// String cipherText = keyGenerator.encryptUsingPublicKey("dilshan1");
// keyGenerator.decryptUsingPrivatekey(cipherText);
} catch (Exception e) {
e.printStackTrace();
DBLogger.logMessage(e.toString(), Status.KEY_GENERATION_ERROR);
}
}
This works perfectly well in most of the time. But some times it generates following error. This happens occasionally. Most of the time this works so I have no issue is with the code. I belive this is something to do with the serialization/serialization process to file system. Help is appreciated.
Note : I am using bouncycastle.
Error is as follows,
javax.crypto.BadPaddingException: unknown block type
at org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at com.dilshan.ttp.web.KeyGenerator.decryptUsingPublickey(KeyGenerator.java:105)
at com.dilshan.ttp.web.KeyGenerator.main(KeyGenerator.java:150)
Happens at,
byte[] plainText = cipher.doFinal(cipherText.getBytes());
in decryptUsingPrivatekey method.
The cipher text is binary data. If you convert it to a String using the default encoding it is very likely that you encounter byte sequences that cannot be represented by a character. Thus, during decryption when you convert the String back to a byte array you don't end up with the same bytes and the decryption fails.
To solve that, don't convert the cipher text to a string, instead carry the byte[] around.
Related
everyone.
I am trying to encrypt and decrypt a string with an AES symmetric key, generated with a password. My current code for generating this follows below:
public class AESUtils {
public static SecretKey getKeyFromPassword(String password, String salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);
return new SecretKeySpec(factory.generateSecret(spec)
.getEncoded(), "AES");
}
public static IvParameterSpec generateIv() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
public static String encryptPasswordBased(String plainText, SecretKey key, IvParameterSpec iv)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes()));
}
public static String decryptPasswordBased(String cipherText, SecretKey key, IvParameterSpec iv)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
}
}
The code to generate the encrypted string:
AESUtils.encryptPasswordBased(string_content_plain, AESUtils.getKeyFromPassword("password", "salt"), AESUtils.generateIv());
The code to generate the decrypted string:
AESUtils.decryptPasswordBased(string_content_encrypted, AESUtils.getKeyFromPassword("password", "salt"), AESUtils.generateIv());
The encryptPasswordBased works fine, but when I use the decryptPasswordBased, it always raises javax.crypto.BadPaddingException with the message: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
What can I do? The generated key is always the same. I have compared it with both byte arrays.
Thanks
As #Topaco said, the solution was to use the same IV when decrypting the content. The generation of a new one would make it impossible to decrypt.
I got an error Input length must be multiple of 16 when decrypting with padded cipher when trying to decrypt my encrypted message.
What I encrypt is this:
{
"guid": "d123-231s-2314w123-21312-2312312",
"userid": "000123",
"channel": "TESTINGCHANNELTEST"
}
but when I decrypt it I got that error. But when I decrypt this message
{
"guid": "00",
"userid": "00",
"channel": "TEST"
}
It works.
What make this issue?
Heres my code to encrypt and decrypt:
public class EncryptDecryptModel {
private static final String key = "aesEncryptionKey";
private static final String initVector = "encryptionIntVec";
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
//original = Base64.decodeBase64(encrypted);
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
This is to encrypt:
#PostMapping("/getEncrypt")
public String getEncrypt(#RequestBody OpenMediaModel openMediaModel) throws UnsupportedEncodingException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
EncryptDecryptModel encryptDecryptModel=new EncryptDecryptModel();
MessageDigest digest = MessageDigest.getInstance("SHA-256");
String message = openMediaModel.getGuid() + "|" + openMediaModel.getCif()
+ "|" + openMediaModel.getChannel();
byte[] encodedhash = digest.digest(
message.getBytes(StandardCharsets.UTF_8));
message = message + "|" + new String(encodedhash);
return encryptDecryptModel.encrypt(message);
}
And this is how I decrypt my message:
#GetMapping("/getDecrypt")
public String getDecrypt(#RequestParam String encrypt) throws NoSuchPaddingException, UnsupportedEncodingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
EncryptDecryptModel encryptDecryptModel=new EncryptDecryptModel();
String plainMessage = encryptDecryptModel.decrypt(encrypt);
String[] splitMessage = plainMessage.split("\\|");
MessageDigest digest = MessageDigest.getInstance("SHA-256");
String message = splitMessage[0] + "|" + splitMessage[1]
+ "|" + splitMessage[2];
//byte[] encodedhash = digest.digest(
// message.getBytes(StandardCharsets.UTF_8));
//return new String(encodedhash).equals(splitMessage[3]);
return splitMessage[0]+"-"+splitMessage[1]+"-"+splitMessage[2];
}
The Issue is when I put long json format like the first one, I got exception:
javax.crypto.IllegalBlockSizeException: Input length must be multiple
of 16 when decrypting with padded cipher
Sorry this is my first time do this encrypt. So got no clue when I decrypt long message. since It work well when I do short message. and I tried use that decodeBase64 but no value
Need help with this.
Thanks in advance.
I have created following to method
public static PublicKey readPublicKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
PublicKey key = null;
CertificateFactory fact;
try {
// MBFS certificate to be used
FileInputStream is = new FileInputStream(filename);
fact = CertificateFactory.getInstance("X.509");
System.out.println(is.toString());
X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
key = cer.getPublicKey();
System.out.println(key.getAlgorithm());
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return key;
}
for encryption
public static byte[] encrypt(PublicKey key, byte[] plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plaintext);
}
I have long xml string and using these both method as following
byte[] message = xmlMessage.getBytes();
byte[] secret = encrypt(publicKey, message);
But it is giving me Data must not be longer than 256 bytes when using rsa
Certificate is shard by client it is saying Signature algorithm sha256RS.
Typically, you would use a symmetric cipher to encrypt the document (with a random secret key) and then just encrypt the key with RSA. This does not only overcome the length problem but is also much faster.
This question already has answers here:
IllegalBlockSizeException when trying to encrypt and decrypt a string with AES
(4 answers)
Closed 6 years ago.
I am trying to encode the passphase into a properties file so that I don't have to type in the passphase to make an SSH connection. But I am facing the following error :
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.test.ssh.SSH_Public_Private.deCryptPwd(SSH_Public_Private.java:191)
at com.test.ssh.SSH_Public_Private.checkHostName(SSH_Public_Private.java:227)
at com.test.ssh.SSH_Public_Private.checkHostName(SSH_Public_Private.java:223)
at com.test.ssh.SSH_Public_Private.connectToSSH(SSH_Public_Private.java:64)
at com.test.ssh.SSH_Public_Private.main(SSH_Public_Private.java:124)
My code is as follows:
private String checkHostName(String hostUserName) throws IOException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
String deCrypted = null;
FileInputStream is = new FileInputStream(new File("C:\\test\\SSH\\PrivateKey\\keystore.properties"));
Properties properties = new Properties();
properties.load(is);
ssh_Public_Private = new SSH_Public_Private();
boolean isHostNameExist = false;
if (properties.getProperty(hostUserName) == null) {
OutputStream outputStream = new FileOutputStream(
"C:\\test\\SSH\\PrivateKey\\keystore.properties");
String passPhraseStored = new String(enCryptPwd());
properties.setProperty(hostUserName,passPhraseStored );
properties.store(outputStream, null);
outputStream.close();
is.close();
return checkHostName(hostUserName);
}else{
System.out.println(properties.getProperty(hostUserName));
String passPhrase = properties.getProperty(hostUserName);
deCrypted = deCryptPwd(passPhrase); //isHostNameExist = true;
}
return deCrypted;
}
My encryption and decryption piece of code is as follow :
private static String enCryptPwd() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
String decrypted = null;
byte[] encrypted = null;
try {
String text = "";
Scanner sc = new Scanner(System.in);
System.out.println("Enter your passphrase : " );
text = sc.next();
String key = "Bar12345Bar12345"; // 128 bit key
//String key = "AesSEcREtkeyABCD";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
System.out.println(aesKey.getFormat());
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
encrypted = cipher.doFinal(text.getBytes("UTF-8"));
System.err.println(new String(encrypted));
System.err.println(encrypted.length);
} catch (Exception e) {
e.printStackTrace();
}
return new String(encrypted);
}
private static String deCryptPwd(String encrypted) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
String originalString = "";
try {
String key = "Bar12345Bar12345"; // 128 bit key
//String key = "AesSEcREtkeyABCD";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES");
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
byte[] encryptBytes = new byte[encrypted.length()];
encryptBytes = encrypted.getBytes();
byte[] decrypted = cipher.doFinal(encryptBytes);
originalString = new String(decrypted, "UTF-8");
System.out.println(originalString);
System.err.println(decrypted);
} catch (Exception e) {
e.printStackTrace();
}
return originalString;
}
I have been trying to read up and I have tried many other ways by including no padding Algorithms as well. My code writes the output into a property file as :
abced=Y\u201Eh\uFFFD\u00EC-:\u00F9\u00F8mC\u0160\u0002\u00F3#\u00DE
My console outputs are :
Enter your passphrase :
abc!##
After encryption >> Y„h?ì-:ùømCŠó#Þ
16
Read from property file >> Y„h?ì-:ùømCŠó#Þ
Generate key using KeyGenerator
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, new SecureRandom());
SecretKeySpec aesKey = new SecretKeySpec(kg.generateKey().getEncoded(), "AES");
Use AES/CBC/PKCS5Padding to get cipher instance.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
This should work.
I'm trying to encrypt data with RSA public key in Java and decrypt it in Crypto++. It results in an error:
"RSA/EME-PKCS1-v1_5: ciphertext length of 24 doesn't match the required length of 128 for this key"
What am I doing wrong?
Java:
String cipher = Encryption.encryptStrRSA(txt, pubKeyk);
public static String encryptStrRSA(String str, PublicKey pubKey)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encryptedAesKey = cipher.doFinal(str.getBytes());
String cipherStr = new String(encryptedAesKey);
System.out.println(cipherStr);
return cipherStr;
}
public static PublicKey strToPublicKey(String key64) throws GeneralSecurityException {
byte[] data = Base64.getDecoder().decode(key64);
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePublic(spec);
}
public static String publicKeyToStr(PublicKey publ) throws GeneralSecurityException {
KeyFactory fact = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = fact.getKeySpec(publ, X509EncodedKeySpec.class);
return Base64.getEncoder().encode(spec.getEncoded()).toString();
}
Crypto++:
using namespace CryptoPP;
RSAES_PKCS1v15_Decryptor priv(privString);
StringSource( cipher, cipherSize, true, new
Base64Decoder( new PK_DecryptorFilter(randPool, priv, new StringSink(sdata))));
It is dangerous to use String instances for keeping binary data -- you should use byte[] instead.
Additionally, in the java code there is no Base64 wrapping of the resulting ciphertext, but in the C++ code it is being unwrapped from Base64.
Modified your code to return byte[] and encode the result using Base64:
public static byte[] encryptRSA(String str, PublicKey pubKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(str.getBytes());
}
String cipher = Base64.getEncoder().encodeToString(Encryption.encryptRSA("0123456789ABCDEF", pubKeyk));
Then you can decrypt in Crypto++ the same way you did.
Good luck!