I have the following code to define a cipher class
import java.util.*;
import javax.crypto.Cipher;
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
import java.security.AlgorithmParameters;
import javax.crypto.*;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
public class Cipher{
private SecureRandom rand;
private SecretKeyFactory kFact;
private Cipher AESCipher;
private SecretKey key;
public Cipher(char[] mpw, byte[] salt){
try{
kFact = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
rand = SecureRandom.getInstance("SHA1PRNG");
AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
PBEKeySpec spec = new PBEKeySpec(mpw, salt, 1024, 256);
key = new SecretKeySpec(kFact.generateSecret(spec).getEncoded(),"AES");
}catch(Exception e){
System.out.println("no such algorithm");
}
}
/*Henc[k,m] will return c such that Hdec[k,HEnc[k,m]] = m
*/
public ArrayList<byte[]> HEnc(byte[] message) throws Exception{
ArrayList<byte[]> res = new ArrayList<byte[]>(2);
AESCipher.init(Cipher.ENCRYPT_MODE ,key);
AlgorithmParameters params = AESCipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ctxt = AESCipher.doFinal(message);
res.add(0,iv);
res.add(1,ctxt);
return res;
}
public byte[] HDec(byte[] iv, byte[] cipher) throws Exception{
AESCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv) );
System.out.println("decrypting");
return AESCipher.doFinal(cipher);
}
/*public abstract byte[] HDec(SecretKey k, byte[] cipher);
*/
I am interested in decrypting cipher-text with incorrect passwords, to do so i defined the following test class,
import java.util.*;
import java.io.*;
public class testCipher{
public static void main(String[] args) throws Exception{
while(true){
Scanner sc = new Scanner(System.in);
System.out.println("Enter master password");
String pass = sc.nextLine();
System.out.println("Enter incorrect password");
String fakepass = sc.nextLine();
System.out.println("Enter message to encrypt");
String message = sc.next();
String salt = "123";
HCipher goodEnc = new HCipher(pass.toCharArray(),salt.getBytes());
HCipher badEnc = new HCipher(fakepass.toCharArray(),salt.getBytes());
byte[] toEncrypt = message.getBytes();
ArrayList<byte[]> cipher = goodEnc.HEnc(toEncrypt);
byte[] ciphertxt = cipher.get(1);
byte[] iv = cipher.get(0);
while(true){
System.out.println("Enter 1 to decrypt with correct pass, 2 to decrypt with incorrect pass and 0 to end simulation");
int i = sc.nextInt();
if(i == 1){
System.out.println("Decrypting with correct password");
byte[] plaintxt = goodEnc.HDec(iv, ciphertxt);
System.out.println(new String(plaintxt));
}
if(i == 2){
System.out.println("Decrypting with incorrect password");
byte[] plaintxt = badEnc.HDec(iv, ciphertxt);
System.out.println(new String(plaintxt));
}
if(i == 0){
break;
}
}
}
}
}
Encrypting and Decrypting using the correct password works well. However, when I try to decrypt using an incorrect password, I get the follwing error:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:420)
at javax.crypto.Cipher.doFinal(Cipher.java:1966)
at HCipher.HDec(HCipher.java:54)
at testCipher.main(testCipher.java:52)
I am guessing it has something to do with my IV but im not sure how to fix it. Does anyone have any suggestions?
AES is a block cipher that encrypts in blocks of 16 bytes. Padding is used to fill up your last block before encryption so it fits in an even number of blocks.
You are specifying PKCS5Padding with this:
AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
The padding is created in such a way that it can be recognized and removed during decrypt. If you decrypt with the wrong key the Cipher won't be able to identify a valid pad and thus give you the BadPaddingException
If you instantiate your decrypt Cipher without padding (and thus take on that responsibility yourself) you can avoid this exception.
Related
I am kinda new to cryptography, and a requirement needs me to
"Create or retrieve user’s RSA-OAEP key. There should be one
public/private key pair for each user for a device"
and send it to the server in this form:
{"modulus":"qMBRpdYrAy5aMmo31NErUizh5sbweguSmh4wlK6uJEIDl+kwTlROnE34KOFExeTbJSX0WygPi+vWl0yNq7buIMUKpytossAAWut5khO3CQJxTk7G2gnEPNUUXHiExGgNrLzcSLv8YIlfVALhoRWyC67KOL+a+3taNq3h+BHeWhM=","exponent":"AQAB"}
I tried the OpenSSL commands to generate RSA public/private key pair, and it comes out like this:
Public key (have changed the value by a bit for security):
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4NMwqhswK6Py+N1OlPBn3JelqEdZ8YwSn4j1Kvp5HK+pS/5gcABkx/89buDhhtKvZ8mfSNkhKHU2WuBPIikGAvEKbbbQ8DHKubHa07X1xTgY+qMyxTLaHnaEC6oOi6BixPfo6QAm+SnqxBWuvDPBzGqSS+/p5r7aydLBAlkoZ+DzpBbAHIIK72c+xqCL8oOFz4QqsVMakdKQ+fVdM1e8U2ak4ygHOleqJgcl8+xH7TFJsvUOfsgsMlz2FmNXWhCYUdOKglP8ZUVMuiAW9KEjAFta4xEf3bBGRDYss7mLQF5/RHbpzYeNwQ1RVp8bhTumpQytqJZshUj8DA3oqMFUr xyz#xyz.xyz
Private key (have altered the value by a bit for security):
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,67A126EE3266B641AF4AC698AA18FE01
3w4GI7HfymD0A8+LokUbsIiI50CJfszBjO5PR4tW532ccKVMQRKywBMANUWx5B66
Mkr/uY9lH8mJOhWrwwiXCUFKMtDGcC06NHbIWIAu/TP85TidwhtGABqSYkjh+8Hm
SlwTMe2xjPq+X8Xc8+vW6Ng8mvXST0Ezz4DiTKA9yeH0eVxIQ4WIpvO7X9793xSD
FoXQ5sCY7Mr6GBNxln4f9cy5BwEsEGa86dtzXVkK8Gu8xRy28GE4W7D6/eNkgl6B
ovEuuC7IDibP/qrGAq/Nxdrl6QrnFTd2FcQfbR4jeArC+IaeXAxXgqhhTJH9ySk8
ZnEaMIruEGvRbChwzlvqS/sCMcS8eoD22Di94Gmkv4thSIWuk1MTRMTKFTMAgVOb
8shCKgCR5FJXjPHV8sUhIwk4TrQWX70fWM3QmBq3ue2AnGonWXhzXQU7jB36zATm
dhpsHZ2/80BuB/hMnFJpsjcYU16pm9BunSMs7tyMW3X3F91x6liC3j2ItUjEkPME
P6eZE2KDM+QxlDLfebL+bGMN6rYvEmfvKo44nwNIMnJM9J3ZYNM9KGt87B4loVwn
TeWIGrCQ9SRCpiAVbZj+M9DDDuqxSoA0wxSDrcYjWt8trzS20AWj7lsxBQgUvpBX
nuFAQgMgT4DK9X2z9ESplXi/l2uZ0iDBTN4SEHI3oR3ar2rWSjoQrTTfOg7cYlF1
ewLR6toCEEvturC4vLyWyrDIu3P/jiSz6eiSTeI9W02rQ/qILUrouKx1LwviIKR2
OGQnkzm3iiNq0jykzObwCsDLuY6rA4nv/ZBsjLDWB34gveKSzOrtx4dzqmtcv0Kq
ndua6xdaPmpV3n4slRD1PxSwNgKb4qwlYuQMPKLhCXUq4yG59IOoH7yfxS5UZ7wa
yndGMLMPmylcHDLX02U90X3feUcC9IiE7z6pOILy4uC28Z2X5KYjoK07pwA+5lNt
9RvryaK4IXysJZ5zqsBUaeYlqqBATcEPYn3YXbT5cSaxkv4lI36g6iG7/QmA3PGt
1l57kBW2xnUSrqm5XtZZMrsSu2iZ9Hiuh73SRkODjg7ToEMtwLECkN1TRL9PVEQj
QHAxauWleC+2yB0+1XH7/CywkYk2HxeNQJJDsWU+XJM/RFGFNV481LwfU0Hw58sZ
ai4R2LmDDoy4wwtcQGkY13ZHT8h/jxP4/Sr36GJdVkhhUCDnpFfdNHebgflj0PQg
eTHVY/6GqfnKvneOGtDRR4EkBFopUV5OLzuRX3z/rlHRV1iPCaqhooL9XO320JYq
xY5YMWq7tvgzE5jtqo65AwO8WWs12NTzG1KRhcXCyYE4Da1T6k7l8++MOeVGZy1v
qDxEddTfiAzIvCme2lEiYOb2/UUNAhEM+Ave/lfWmirW5dSAOppZenHUnuZh9eVd
iFVswrAxcd4BqA5GGczzu9EIqdzpspTrnG3hxOf+tXEXf3TTAH/sTVfQGQHO1iRd
UTh9FGgHk3WMswBnYyfpbSOR8Mghab966RRYP2xBCVJEvCymYuUE11x6vsvQFpGS
X2SEhOpzgINuKZRTuVmhK1oXRt3BZO8yQ13t+wtQCP6a8azS+Sc436aDqBlWQfJ2
-----END RSA PRIVATE KEY-----
How can I extract the modulus and exponent in the form that server expects from this data?
You can simply get the format from RFC 4253 but you need to find out what the mpint (multi-precission integer) format is from RFC 4251.
Here's the thing in Java (just Java), simply because the JSch library is so horrible.
package nl.owlstead.crypto;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.Base64.Encoder;
public class SSHPublicKeyDecoder {
private static byte[] SSH_RSA_HEADER = "ssh-rsa".getBytes(StandardCharsets.US_ASCII);
private static RSAPublicKey decodeRSAPublicKey(byte[] encodedRSAPublicKey)
throws NoSuchAlgorithmException, InvalidKeySpecException {
ByteBuffer buf = ByteBuffer.wrap(encodedRSAPublicKey);
byte[] header = getSSHEncodedValueFromBuffer(buf);
if (!Arrays.equals(header, SSH_RSA_HEADER)) {
throw new IllegalArgumentException("Not an RSA public key");
}
byte[] eDataSigned = getSSHEncodedValueFromBuffer(buf);
BigInteger e = new BigInteger(eDataSigned);
byte[] nDataSigned = getSSHEncodedValueFromBuffer(buf);
BigInteger n = new BigInteger(nDataSigned);
KeyFactory rsaKeyFactory;
try {
rsaKeyFactory = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException ex) {
throw new IllegalStateException(
"KeyFactory should exist for RSA", ex);
}
RSAPublicKeySpec spec = new RSAPublicKeySpec(n, e);
return (RSAPublicKey) rsaKeyFactory.generatePublic(spec);
}
private static byte[] getSSHEncodedValueFromBuffer(ByteBuffer buf) {
int size = buf.getInt();
if (size < 0) {
throw new IllegalArgumentException("Bad SSH encoded value in format");
}
byte[] data = new byte[size];
buf.get(data);
return data;
}
private static byte[] toUnsigned(BigInteger value) {
if (value.compareTo(BigInteger.ZERO) <= 0) {
throw new IllegalArgumentException("Negative numbers cannot be encoded as unsigned integers");
}
if (value.equals(BigInteger.ZERO)) {
return value.toByteArray();
}
final byte[] signedBigEndian = value.toByteArray();
if (signedBigEndian[0] == 0x00) {
return Arrays.copyOfRange(signedBigEndian, 1, signedBigEndian.length);
}
return signedBigEndian;
}
private SSHPublicKeyDecoder() {
}
public static void main(String[] args) throws Exception {
String[] parts = args[0].split("\\s+");
String part2 = parts[1];
byte[] encodedRSAPublicKey = Base64.getDecoder().decode(part2);
RSAPublicKey pubKey = decodeRSAPublicKey(encodedRSAPublicKey);
String format = encodeServerPublicKey(pubKey);
System.out.println(format);
}
private static String encodeServerPublicKey(RSAPublicKey pubKey) {
byte[] nData = toUnsigned(pubKey.getModulus());
byte[] eData = toUnsigned(pubKey.getPublicExponent());
Encoder base64Encoder = Base64.getEncoder();
String format = String.format(
"{\"modulus\":\"%s\",\"exponent\":\"%s\"}%n",
base64Encoder.encodeToString(nData),
base64Encoder.encodeToString(eData));
return format;
}
}
I got a Private JKS file and a Password file for it. I saw the internet, wrote a java program which will print out the private key as a string.
Similarly I got a public key file with .cer extension. Similarly I printed out the contents of this file too as a string
My idea is to write a java program which has 2 methods encrypt and decrypt.I wrote all the stuff. But when I try to use my encrypt and decrypt function i am seeing InvalidKeyException: Wrong algorithm type. I printed out the algorithm from the jks file and I see it as RSA. In the public certificate the algorithm is printed as SHA1withRSA
here are my programs
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import org.apache.commons.codec.binary.Base64;
public class ExtractKeys {
private static String privateKeyalgorithm = "";
private static String publicKeyAlgorithm = "";
public static void main(String args[]) throws Exception {
String publicCertificate = "C:\\QA\\keys\\sis.cer";
String privateKeyStore = "C:\\QA\\keys\\sis.jks";
String privateKeyStorePassword = "sis";
String alias = "sis";
String aliasPassword = "sis";
ExtractKeys myep = new ExtractKeys();
myep.printPrivateKey(privateKeyStore, privateKeyStorePassword, alias, aliasPassword);
myep.printPublicKey(publicCertificate);
}
public String printPublicKey(String source) throws Exception {
X509Certificate cert = null;
InputStream fis = null;
ByteArrayInputStream bais = null;
Base64 encoder = new Base64(64);
fis = new FileInputStream(source);
byte value[] = new byte[fis.available()];
fis.read(value);
bais = new ByteArrayInputStream(value);
java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
cert = (X509Certificate) cf.generateCertificate(bais);
String cert_begin = "-----BEGIN CERTIFICATE-----\n";
String end_cert = "-----END CERTIFICATE-----";
publicKeyAlgorithm = cert.getSigAlgName();
byte[] derCert = cert.getEncoded();
String pemCertPre = new String(encoder.encode(derCert));
String pemCert = cert_begin + pemCertPre + end_cert;
System.out.println(pemCert);
System.out.println(publicKeyAlgorithm);
return pemCert;
}
public String printPrivateKey(String fileName, String keystorepass, String aliasName, String aliaspass) throws Exception {
KeyStore ks = KeyStore.getInstance("JKS");
Base64 encoder = new Base64(64);
char[] keyStorePassPhrase = keystorepass.toCharArray();
File certificateFile = new File(fileName);
ks.load(new FileInputStream(certificateFile), keyStorePassPhrase);
char[] aliasPassPhrase = aliaspass.toCharArray();
KeyPair kp = getPrivateKey(ks, aliasName, aliasPassPhrase);
PrivateKey privKey = kp.getPrivate();
privateKeyalgorithm = privKey.getAlgorithm();
String b64 = encoder.encodeAsString(privKey.getEncoded());
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(b64);
System.out.println("-----END PRIVATE KEY-----");
System.out.println(privateKeyalgorithm);
return b64;
}
private KeyPair getPrivateKey(KeyStore keystore, String alias, char[] password) {
try {
// Get private key
Key key = keystore.getKey(alias, password);
if (key instanceof PrivateKey) {
// Get certificate of public key
Certificate cert = keystore.getCertificate(alias);
// Get public key
PublicKey publicKey = cert.getPublicKey();
// Return a key pair
return new KeyPair(publicKey, (PrivateKey) key);
}
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return null;
}
public String returnPrivateKeyAlgo() {
return privateKeyalgorithm;
}
public String returnPublicKeyAlgo() {
return publicKeyAlgorithm;
}
The outputs are strings of public key, private key, and their alogorithms
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZehr60/61+4ao
8Bigkamzt3RJZcY9ggE4YuQ1ALY8pDXARDQ3OqPohySw4y+Ebrk4y/Rwzm21mhaU
jC33BNSNUetRAgBDU+/nT3/gRZdIeJRfFdiDtl/Ms2LYxo41nYTeGJEqoW3fivI2
cUG/tDKSPjaoGwnz/kVNIsZXJEcZCAfdIg1UH0wBeQ5qLR4rsseE0I7vVAfvDsMl
-----END PRIVATE KEY-----
RSA
-----BEGIN CERTIFICATE-----
MIIGiTCCBXGgAwIBAgIKYMbAHgAAAAUgKzANBgkqhkiG9w0BAQUFADB5MRMwEQYK
CZImiZPyLGQBGRYDY29tMRYwFAYKCZImiZPyLGQBGRYGc2Nod2FiMRYwFAYKCZIm
-----END CERTIFICATE-----
SHA1withRSA
Now I got the public and private keys as string values. along with their algorithms.
Next I wrote another sample program.I got 2 methods in it. encrypt and decrypt which also accepts these keys.
So ideally i would be passing the public key to encrypt method and the private key to decrypt method
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import **.CryptoService;
import **.CryptoServiceException;
public class CryptoServiceImpl implements CryptoService {
public byte[] encrypt(byte[] data, String key) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA");
Base64 decoder = new Base64(64);
// decode the base64 encoded string
byte[] decodedKey = decoder.decode(key);
// rebuild key using SecretKeySpec
final SecretKeySpec originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "RSA");
cipher.init(Cipher.ENCRYPT_MODE, originalKey);
final String encryptedString = Base64.encodeBase64String(cipher.doFinal(data));
return encryptedString.getBytes();
} catch (Exception e) {
throw new CryptoServiceException("Cannot encrypt data using key '", e);
}
}
public byte[] decrypt(byte[] data, String key) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA");
Base64 decoder = new Base64(64);
// decode the base64 encoded string
byte[] decodedKey = decoder.decode(key);
// rebuild key using SecretKeySpec
final SecretKeySpec originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "RSA");
cipher.init(Cipher.DECRYPT_MODE, originalKey);
final String decryptedString = new String(cipher.doFinal(Base64.decodeBase64(new String(data))));
return decryptedString.getBytes();
} catch (Exception e) {
throw new CryptoServiceException("Cannot decrypt data using key '", e);
}
}
}
Now I got a Junit which when executed throws this exception
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import junit.framework.Assert;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import **.CryptoServiceImpl;
public class TestCryptoService {
String privateKeyStore = "C:\\QA\\keys\\sis.jks";
String privateKeyStorePassword = "sistest";
String alias = "sis";
String aliasPassword = "sistest";
static ExtractKeys myep = new ExtractKeys();
CryptoService service = new CryptoServiceImpl();
String publicCertificate = "C:\\QA\\keys\\sis.cer";;
#BeforeClass
public static void setUpBeforeClass() throws Exception {
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
}
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void testCryptoServiceForAESWithAsymmetricKeys() throws Exception {
String publicKey = myep.printPublicKey(publicCertificate);
byte[] encryptedValue = service.encrypt(new String("abcd").getBytes(), publicKey);
System.out.println(new String(encryptedValue));
String privateKey = myep.printPrivateKey(privateKeyStore, privateKeyStorePassword, alias, aliasPassword);
byte[] decryptedValue = service.decrypt(encryptedValue, privateKey);
System.out.println(new String(decryptedValue));
Assert.assertEquals("abcd", new String(decryptedValue));
}
}
and Here's the exception
*.CryptoServiceException: Cannot encrypt data using key '
at *.impl.CryptoServiceImpl.encrypt(CryptoServiceImpl.java:59)
at *.TestCryptoService.testCryptoServiceForAESWithAsymmetricKeys(TestCryptoService.java:101)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.security.InvalidKeyException: Wrong algorithm type
at com.ibm.crypto.provider.RSAKeyFactory.engineTranslateKey(Unknown Source)
at com.ibm.crypto.provider.RSAKeyFactory.toRSAKey(Unknown Source)
at com.ibm.crypto.provider.RSACipher.engineGetKeySize(Unknown Source)
at javax.crypto.Cipher.b(Unknown Source)
at javax.crypto.Cipher.a(Unknown Source)
at javax.crypto.Cipher.a(Unknown Source)
at javax.crypto.Cipher.a(Unknown Source)
at javax.crypto.Cipher.init(Unknown Source)
at javax.crypto.Cipher.init(Unknown Source)
at *.impl.CryptoServiceImpl.encrypt(CryptoServiceImpl.java:55)
... 28 more
A certificate is not a public key although it contains one; more importantly, either a private key or public key or certificate for a public-key-crypto (aka asymmetric) scheme like RSA is not a symmetric key. Java SecretKeySpec is only for symmetric keys used with symmetric algorithms, like AES.
You need to represent your RSA keys using subtypes of java.security.PrivateKey and java.security.PublicKey. The way you do this is with a KeyFactory for RSA, or a CertificateFactory (as you already did).
For a PKCS#8-encoded private key, which is what you encoded and wrote out, decode it from PEM/base64 to byte[], then:
PKCS8EncodedKeySpec spec = new PKCSEncodedKeySpec (bytearray);
KeyFactory factory = KeyFactory.getInstance("RSA");
PrivateKey privkey = factory.generatePrivate (spec);
// use privkey in a Cipher.getInstance("RSA") to decrypt or sign
For a certificate do basically what you already did:
InputStream is = /* something that returns contents of cert file */;
// you *can* decode from PEM/base64 first, but you don't need to;
// CertificateFactory-X.509 handles both
CertificateFactory cf = CertificateFactory.getInstance ("X.509");
Certificate cert = cf.generateCertificate (is);
// use cert.getPublicKey() for RSA encrypt or verify
Aside: sigAlgName for a certificate does NOT tell about the key in the cert. It is entirely possible for a cert signed SHA1withRSA to contain a DSA or ECC key that cannot be used for RSA, and conversely possible for a cert that contains a perfectly good RSA key to be signed with a different RSA variant (like SHA256withRSA) or an entirely different algorithm (like sha1-DSA or sha2-ECDSA).
Also note: you are explicitly importing java.security.cert.Certificate; that's good. JRE also has an older and deprecated java.security.Certificate which you should not use, but if you just say Certificate some IDEs (like mine) may get confused and give you the wrong one.
I read on this link
AES Encryption/Decryption with Bouncycastle Example in J2ME
about how to encrypt a string using AES as supplied by Bouncy Castle. The encryption method code works fine but decryption doesn't work.
Can anyone suggest how I can decrypt the encrypted string?
I've used the following code to test:
import com.codename1.util.Base64;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
/**
*
* #author SAMUEL
*/
public class Tester {
static String strEnc = "Hi This is my String";
final static String strPassword = "password12345678";
private static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data)throws Exception
{
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
return result;
}
private static byte[] decrypt(byte[] cipher, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(false, ivAndKey);
return cipherData(aes, cipher);
}
private static byte[] encrypt(byte[] plain, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(true, ivAndKey);
return cipherData(aes, plain);
}
public static void main(String [] args) throws Exception{
byte[] enc= encrypt(strEnc.getBytes(),"password12345678".getBytes(), "password12345678".getBytes());
String encrypted = Base64.encode(enc);
System.out.println("Encrypted is:"+encrypted);
byte[] dec= decrypt(encrypted.getBytes(),"password12345678".getBytes() , "password12345678".getBytes());
System.out.println("Decrypted file is:"+dec);
}
}
Output is:
Encrypted is:sw0SrUIKe0DmS7sRd9+XMgtYg+BUiAfiOsdMw/Lo2RA=
And the exception stacktrace is:
Exception in thread "main" org.bouncycastle.crypto.DataLengthException: last block incomplete in decryption
at org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.doFinal(PaddedBufferedBlockCipher.java:281)
at com.mycompany.myapp.Tester.cipherData(Tester.java:28)
at com.mycompany.myapp.Tester.decrypt(Tester.java:40)
at com.mycompany.myapp.Tester.main(Tester.java:57)
You are forgetting to base 64 decode the ciphertext before decryption. You should also create a new String from the decrypted bytes.
When encoding/decoding character strings, always specify the encoding explicitly, otherwise you will be using the platform default, which is not the same on each and every platform.
So use for instance new String(dec, "UTF-8") to recreate the plaintext, and specify "UTF-8" for each and every new String() and toBytes() method.
I'm trying to encrypt and decrypt a string using TrippleDES algorythm and without using Base64 encoding (my app will be talking to another app that has these requirements). Everything worked beautifully when I was testing stuff using Base64 encoding/decoding, but when I switched to doing it plain-text style (like the app I'm calling requires), everything broke.
I've read this post Given final block not properly padded which says the key is wrong on decoding, but that can't be, because these lines actually pass in the same variables for both the key and transformation:
ecipher = Cipher.getInstance(transformation);
dcipher = Cipher.getInstance(transformation);
ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
dcipher.init(Cipher.DECRYPT_MODE, key, iv);
Also, I've printed out the lengths of both the encoded string and the array, their lengths are multiples of 8.
My output with I'm getting:
originalText: Abcdefgh
number of bites: 16
cryptText: d4167d9e2b3b1b2d1f940bc45099da0a
cryptText.length: 32
cryptText.getBytes().length: 32
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.DESedeCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
Java Result: 1
My full code (slightly modified version of this tutorial http://eternusuk.blogspot.com/2008/09/java-triple-des-example.html):
package com.test.encrypt;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.binary.Hex;
public class TrippleDESTest
{
private Cipher ecipher;
private Cipher dcipher;
private String algorithm = "DESede";
private String transformation = "DESede/CBC/PKCS5Padding";
private String keyPhrase = "123456789012345678901234"; //your keyphrase 24 bit
private SecretKey key;
private IvParameterSpec iv;
private static TrippleDESTest cryptoUtil;
private String ENCODING = "UTF-8";
public static TrippleDESTest getInstance() throws Exception
{
if (cryptoUtil == null)
{
cryptoUtil = new TrippleDESTest();
}
return cryptoUtil;
}
private TrippleDESTest() throws Exception
{
DESedeKeySpec keySpec = new DESedeKeySpec(keyPhrase.getBytes());
key = SecretKeyFactory.getInstance(algorithm).generateSecret(keySpec);
iv = new IvParameterSpec(new byte[8]);
ecipher = Cipher.getInstance(transformation);
dcipher = Cipher.getInstance(transformation);
ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
dcipher.init(Cipher.DECRYPT_MODE, key, iv);
}
public String encrypt(String str) throws Exception
{
byte[] utf8 = str.getBytes(ENCODING);
byte[] enc = ecipher.doFinal(utf8);
System.out.println("number of bites: " + enc.length);
return Hex.encodeHexString(enc);
}
public String decrypt(String str) throws Exception
{
byte[] dec = str.getBytes();
byte[] utf8 = dcipher.doFinal(dec);
return Hex.encodeHexString(utf8);
}
public static void main(String[] args) throws Exception
{
TrippleDESTest test = TrippleDESTest.getInstance();
String originalText = "Abcdefgh";
System.out.println("originalText: " + originalText);
String cryptText = test.encrypt(originalText);
System.out.println("cryptText: " + cryptText);
System.out.println("cryptText.length: " + cryptText.length());
System.out.println("cryptText.getBytes().length: " + cryptText.getBytes().length);
System.out.println("decote text: " + test.decrypt(cryptText));
}
}// end class TrippleDESTest
Thanks in advance!
You are performing the hexadecimal encoding in the wrong order. You need to decode the ciphertext, instead of encoding the plain text in your decrypt method.
while encrypting and descripting the string with rsa provider I am getting this error.
RSA Data decryption error.The data to be decrypted exceeds the maximum for this modulus of 64 bytes.
Can any one have idea how to slove this error?
internal sealed class RSAProvider
{
#region key store class
[Serializable]
private struct rsaKey
{
public rsaKey(RSAParameters rsaKeyInfo)
{
D = rsaKeyInfo.D;
DP = rsaKeyInfo.DP;
DQ = rsaKeyInfo.DQ;
Exponent = rsaKeyInfo.Exponent;
InverseQ = rsaKeyInfo.InverseQ;
Modulus = rsaKeyInfo.Modulus;
P = rsaKeyInfo.P;
Q = rsaKeyInfo.Q;
}
public RSAParameters CreateRSAKey()
{
RSAParameters rsaKeyInfo = new RSAParameters();
rsaKeyInfo.D = D;
rsaKeyInfo.DP = DP;
rsaKeyInfo.DQ = DQ;
rsaKeyInfo.Exponent = Exponent;
rsaKeyInfo.InverseQ = InverseQ;
rsaKeyInfo.Modulus = Modulus;
rsaKeyInfo.P = P;
rsaKeyInfo.Q = Q;
return rsaKeyInfo;
}
public byte[] D;
public byte[] DP;
public byte[] DQ;
public byte[] Exponent;
public byte[] InverseQ;
public byte[] Modulus;
public byte[] P;
public byte[] Q;
}
#endregion
private static RSAParameters rsaKeyParameters;
static RSAProvider()
{
string rsaKeyString = System.Configuration.ConfigurationSettings.AppSettings["RSAKey"];
if(rsaKeyString != null)
{
rsaKeyParameters = GetKeyByString(rsaKeyString);
}
}
private RSAProvider()
{
}
private static RSAParameters RSAKeyInfo
{
get
{
return rsaKeyParameters;
}
}
private static bool DoOAEPPadding
{
get
{
return false;
}
}
public static string GenerateKey(int keySize)
{
//Create a new instance of RSACryptoServiceProvider to generate
//public and private key data.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(keySize);
RSAParameters rsaKeyInfo = RSA.ExportParameters(true);
return GetKeyString(rsaKeyInfo);
}
#region Encrypt
public static byte[] Encrypt(byte[] dataToEncrypt, string rsaKeyString)
{
RSAParameters rsaKeyInfo = GetKeyByString(rsaKeyString);
return Encrypt(dataToEncrypt, rsaKeyInfo);
}
public static byte[] Encrypt(byte[] dataToEncrypt, RSAParameters rsaKeyInfo)
{
try
{
//Create a new instance of RSACryptoServiceProvider.
// Common.Identity.ImpersonateValidUser("prana", "eetplpvt", "Avdhoota1985");
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(rsaKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
//return RSA.Encrypt(dataToEncrypt, DoOAEPPadding);
byte[] data = RSA.Encrypt(dataToEncrypt, DoOAEPPadding);
RSA.Clear();
//Common.Identity.UndoImpersonation();
return data;
}
//Catch and display a CryptographicException
//to the console.
catch(CryptographicException e)
{
// Updated By Divya Bhalodia on 27th June 2008 for Localization task
//throw new Exception("Data encryption error.", e);
Common.EnumLocalization.EnumLocalization loc = new Common.EnumLocalization.EnumLocalization(ASP.BL.ApplicationUsers.ApplicationUserController.CurrentUserCulture.Code, ASP.BL.Applications.ApplicationController.CurrentApplicationInfo.ItemId);
throw new Exception(loc.LocalizeString("RSA Data encryption error.") + e.Message, e);
// end Updated - Divya
}
}
public static byte[] Encrypt(byte[] dataToEncrypt)
{
return Encrypt(dataToEncrypt, RSAKeyInfo);
}
#endregion
#region Decrypt
public static byte[] Decrypt(byte[] dataToDecrypt, string rsaKeyString, bool doOAEPPadding)
{
RSAParameters rsaKeyInfo = GetKeyByString(rsaKeyString);
return Decrypt(dataToDecrypt, rsaKeyInfo, doOAEPPadding);
}
public static byte[] Decrypt(byte[] dataToDecrypt, RSAParameters rsaKeyInfo, bool doOAEPPadding)
{
try
{
//Create a new instance of RSACryptoServiceProvider.
Common.Identity.ImpersonateValidUser();
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(rsaKeyInfo);
//Decrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
//return RSA.Decrypt(dataToDecrypt, doOAEPPadding);
byte[] data = RSA.Decrypt(dataToDecrypt, doOAEPPadding);
RSA.Clear();
Common.Identity.UndoImpersonation();
return data;
}
//Catch and display a CryptographicException
//to the console.
catch(CryptographicException e)
{
// Updated By Divya Bhalodia on 27th June 2008 for Localization task
//throw new Exception("Data decryption error.", e);
Common.EnumLocalization.EnumLocalization loc = new Common.EnumLocalization.EnumLocalization(ASP.BL.ApplicationUsers.ApplicationUserController.CurrentUserCulture.Code, ASP.BL.Applications.ApplicationController.CurrentApplicationInfo.ItemId);
throw new Exception(loc.LocalizeString("RSA Data decryption error.") + e.Message, e);
// end Updated - Divya
}
}
public static byte[] Decrypt(byte[] dataToDecrypt)
{
return Decrypt(dataToDecrypt, RSAKeyInfo, DoOAEPPadding);
}
#endregion
#region Additional functions
private static string GetKeyString(RSAParameters rsaKeyInfo)
{
byte[] tmp;
rsaKey k = new rsaKey(rsaKeyInfo);
BinaryFormatter formater = new BinaryFormatter();
using(MemoryStream stream = new MemoryStream())
{
formater.Serialize(stream, k);
tmp = stream.ToArray();
}
Code(tmp);
return Convert.ToBase64String(tmp);
}
private static RSAParameters GetKeyByString(string rsaKeyString)
{
rsaKey k;
byte[] tmp = Convert.FromBase64String(rsaKeyString);
Code(tmp);
BinaryFormatter formater = new BinaryFormatter();
using(MemoryStream stream = new MemoryStream(tmp))
{
k = (rsaKey)formater.Deserialize(stream);
}
return k.CreateRSAKey();
}
private static void Code(byte[] tmp)
{
byte mask1 = 0x55;
byte mask3 = 0xB9;
byte mask4 = 0xCF;
for(int i = 0; i
I've encoutered similar problems but you can do two things to help yourself overcome them.
You need to ensure that hte data you are encrypting is shorter than the key that you are using. so if your key is 1024 bits then make sure that you are only bassing in say 1000 bits. To do this you need to get chunk your byte array into smaller chunks, encrypt each chunk and then store the encrypeted value in an array or a string. So instead of encrypting 1 string you encrypt say 5 strings.
When storing this information as a string make sure that all numbers are the same length, so if the formatter returns 15 you store the string with 015 so that you just divide by 3 later to get the byte to then put into the array.
To decrypt your data you need to simply read the length of the string and determine how many chunks to decrypt. Decrupt these one by one and then you can recreate the object with the decrupted byte array.
if you would like actual code please contact me personally and I'll be able to help you better with some script that can do this for you.