javax.crypto.BadPaddingException: Decryption error - java

Here is the error I have got when run my Encode & Decode Class.
javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291)
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:2087)
at RSAEncDecDemo.decryptData(RSAEncDecDemo.java:64)
at RSAEncDecDemo.main(RSAEncDecDemo.java:47)
java.lang.NullPointerException
at java.lang.String.<init>(String.java:556)
at RSAEncDecDemo.decryptData(RSAEncDecDemo.java:70)
at RSAEncDecDemo.main(RSAEncDecDemo.java:47)
Here is the source code of RSAEncDecDemo.java class file.
public class RSAEncDecDemo {
private static final String PUBLIC_KEY_FILE = "lk.public.key";
private static final String PRIVATE_KEY_FILE = "lk.private.key";
#SuppressWarnings("restriction")
public static void main(String[] args) throws IOException {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
writeStringkey(PUBLIC_KEY_FILE,new BASE64Encoder().encode(publicKey.getEncoded()));
writeStringkey(PRIVATE_KEY_FILE,new BASE64Encoder().encode(privateKey.getEncoded()));
String demoString = "123346";
RSAEncDecDemo rsa = new RSAEncDecDemo();
String decrypted = rsa.decryptData(demoString);
String msisdn = decrypted.substring(0,decrypted.indexOf("|"));
} catch (Exception e) {
e.printStackTrace();
}
}
private String decryptData(String strData) throws IOException {
byte[] data = DatatypeConverter.parseHexBinary(strData);
byte[] descryptedData = null;
try {
PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
descryptedData = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return new String(descryptedData);
}
#SuppressWarnings("restriction")
public PrivateKey readPrivateKeyFromFile(String fileName)throws IOException, NoSuchAlgorithmException,InvalidKeySpecException {
String publicK = readStringKey(fileName);
byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicK);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePrivate(keySpec);
}
public PrivateKey readPrivateKeyFromFileold(String fileName)throws IOException {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(new File(fileName));
ois = new ObjectInputStream(fis);
BigInteger modulus = (BigInteger) ois.readObject();
BigInteger exponent = (BigInteger) ois.readObject();
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privateKey = fact.generatePrivate(rsaPrivateKeySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null) {
ois.close();
if (fis != null) {
fis.close();
}
}
}
return null;
}
public static void writeStringkey(String fileName, String data) {
try {
FileWriter out = new FileWriter(new File(fileName));
out.write(data);
out.close();
} catch (IOException e) {
}
}
public static String readStringKey(String fileName) {
BufferedReader reader = null;
StringBuffer fileData = null;
try {
fileData = new StringBuffer(2048);
reader = new BufferedReader(new FileReader(fileName));
char[] buf = new char[1024];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
reader.close();
} catch (Exception e) {
} finally {
if (reader != null) {
reader = null;
}
}
return fileData.toString();
}
}
Where is mistaken point.? Decryption part is give that error.
Whole class uploaded here
LINK TO SOURCE CODE
-Thanks

In principle a ciphertext should be indistinguishable from random. That said, ciphers do place constraints on the domain (size and possible values). In the case of RSA PKCS#1 - which is the default mode for "RSA" within the Oracle provider - the output must be precisely the key size (in bytes). Furthermore, the value must be smaller than the modulus.
Now assume that you've just shown us a demo value (because the exception doesn't match the input) and the size of the ciphertext is correct. In that case you would get an unpadding exception when either:
the private key doesn't match the public key used;
the wrong padding mode (e.g. OAEP) was used to create the ciphertext;
the ciphertext was altered (e.g. due to an invalid conversion to a string).
You would have to try until you find the culprit, without the required information we cannot test this for you.

Related

Bouncy Castle Java PGP encryption & decryption

I am trying to implement PGP encryption in Java using Bouncy Castle, also using some of the examples provided by them.
But if I try and decrypt the message I just encrypted, it does not work. The keys and the decryption method seem to be ok, because I can encrypt using an external tool (link) and then successfully decrypt it here.
public static void main(String[] args) throws PGPException, IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
Security.addProvider(new BouncyCastleProvider());
byte[] msg = ("Test blabla BLA").getBytes();
byte[] encData = encrypt(msg, publicKey);
System.out.println(new String(encData));
System.err.println("DECRYPTED");
System.out.println(decrypt(IOUtils.toInputStream(new String(encData), StandardCharsets.UTF_8), privateKey, passphrase));
System.err.println("DECRYPTED external");
String testEncryptedMsg = "-----BEGIN PGP MESSAGE-----\n" +
"Version: BCPG C# v1.6.1.0\n" +
"\n" +
"hQIMA4p9BgtBOg+BARAAiLdmGZBupsSkrji1qdC/y6KACuaWytcjVg3LWudWRlH8\n" +
"Ye1U0bz+HYc6mLt21RivAZ3p+lPXPzh/h0GVLW/aI2ngJracL+iEA7eam5/H3NQV\n" +
"2o0CR1mjw4xOf0XwDxaLrnivdeuWniXiZyFN7Ud7lmNG+EmQ0d5ZfR7KEnTJNjSe\n" +
"FpzwRffBG5lKB4CxF49jBp+Iupdv4A5JzHuDVBkypPMNhS/UEbuPOt5cfmddYVvW\n" +
"gtDM3rX+ePBhg7d/mVkiDT2KM0Cr7GSrdZ8q83fF4sat3Xp8OHMq61GWriNK4gwb\n" +
"ViT/vmEsY0n55TVgN5VagMZJJlEThkqWE2wpEjq4HM8pNxR4PvP5inqP5oipn8Os\n" +
"Nq2a5f77BS7GB9NQ+hnaLSBsywJkZVKqygN81MeHBnNrVXFQ/Hqg24BLwk49bOuH\n" +
"jTUzorudCnjj/p8/WiyR+PuESkQDLKpo1z9KGEE/rKjTqAwH/fBKJ73XpmAWwd4U\n" +
"1hv/EdF+XDZv7XwxeVjSIK2inAjdNz+way1WNY3qouo7G+gjKf1gbL14q2HVPnd/\n" +
"7mfiW3uWCQ7GhXlHtd1E0WeK2296TdBuSGAvLlVxI4xepsiuVw+zC4BxvAkTXB/a\n" +
"HyJZhKPksHMRCt8ZxitMfhdvMNGjc4MDhv1MLqKijpagKhgrmDTiJRMb3ng6QLvJ\n" +
"L2GICyuS4aIsz6XiCQvZG8ebfb0J4uogbb5HxS2fGFT+Y/VgpCnwhwj6LnLBy1Q3\n" +
"=D/1d\n" +
"-----END PGP MESSAGE-----\n";
System.out.println(decrypt(IOUtils.toInputStream(testEncryptedMsg, StandardCharsets.UTF_8), privateKey, passphrase));
}
I think the problem is on the encryption side, but I cannot figure out what exactly it is. Does anyone have any ideas?
public static byte[] encrypt(byte[] bytes, String publicKey) throws IOException {
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
try {
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_128)
.setSecureRandom(new SecureRandom())
.setWithIntegrityPacket(true)
.setProvider("BC"));
PGPPublicKey encryptionKey = readPublicKey(publicKey);
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey).setProvider("BC"));
ArmoredOutputStream aOut = new ArmoredOutputStream(encOut);
OutputStream cOut = encGen.open(aOut, bytes.length);
// write out the literal data
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(aOut, PGPLiteralData.UTF8, PGPLiteralData.CONSOLE, bytes.length, new Date());
pOut.write(bytes);
pOut.close();
// finish the encryption
cOut.close();
aOut.close();
} catch (PGPException e) {
log.error("Exception encountered while encoding data.", e);
}
return encOut.toByteArray();
}
public static String decrypt(InputStream in, String secretKey, String passphrase) throws IOException {
String content = null;
try {
in = PGPUtil.getDecoderStream(in);
JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
// the first object might be a PGP marker packet.
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
// find the secret key
Iterator<PGPEncryptedData> it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(new ByteArrayInputStream(secretKey.getBytes())), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
sKey = findSecretKey(pgpSec, pbe.getKeyID(), passphrase.toCharArray());
}
if (sKey == null) {
log.error("Secret key for message not found.");
throw new IllegalArgumentException("secret key for message not found.");
}
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
Object message = plainFact.nextObject();
if (message instanceof PGPCompressedData) {
PGPCompressedData cData = (PGPCompressedData) message;
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
message = pgpFact.nextObject();
}
if (message instanceof PGPLiteralData) {
PGPLiteralData ld = (PGPLiteralData) message;
content = new String(ld.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
} else if (message instanceof PGPOnePassSignatureList) {
throw new PGPException("encrypted message contains a signed message - not literal data.");
} else {
throw new PGPException("message is not a simple encrypted file - type unknown.");
}
if (pbe.isIntegrityProtected()) {
if (!pbe.verify()) {
log.error("message failed integrity check");
} else {
log.info("message integrity check passed");
}
} else {
log.warn("no message integrity check");
}
} catch (PGPException e) {
log.error("Exception encountered while decrypting file.", e);
}
return content;
}
private static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass) throws PGPException {
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
}
private static PGPPublicKey readPublicKey(String publicKey) throws IOException, PGPException {
InputStream input = IOUtils.toInputStream(publicKey, StandardCharsets.UTF_8);
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
Iterator<PGPPublicKeyRing> keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext()) {
PGPPublicKeyRing keyRing = keyRingIter.next();
Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext()) {
PGPPublicKey key = keyIter.next();
if (key.isEncryptionKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
Here is the encryption method that eventually worked for me.
It helped debugging together with the examples provided by the BCFipsIn100 book.
public byte[] encrypt(byte[] bytes, String publicKey) throws IOException {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
byte[] compressedData = compress(bytes);
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider(PROVIDER));
PGPPublicKey encryptionKey = readPublicKey(publicKey);
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey).setProvider(PROVIDER));
ArmoredOutputStream aOut = new ArmoredOutputStream(byteArrayOutputStream);
OutputStream cOut = encGen.open(aOut, compressedData.length);
cOut.write(compressedData);
cOut.close();
aOut.close();
return byteArrayOutputStream.toByteArray();
} catch (PGPException e) {
log.error("Exception encountered while encoding data.", e);
}
return new byte[0];
}
private static byte[] compress(byte[] clearData) throws IOException {
try (ByteArrayOutputStream bOut = new ByteArrayOutputStream()) {
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP);
OutputStream cos = comData.open(bOut);
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cos,
PGPLiteralData.BINARY,
PGPLiteralData.CONSOLE,
clearData.length,
new Date());
pOut.write(clearData);
pOut.close();
comData.close();
return bOut.toByteArray();
}
}
There are some errors in your encrypt() method code:
First and foremost, in this line your are opening the literal data stream directly on your armored output stream, while you should open it on your encryption stream:
OutputStream pOut = lData.open(aOut, PGPLiteralData.UTF8, PGPLiteralData.CONSOLE, bytes.length, new Date());
// replace with
OutputStream pOut = lData.open(cOut, PGPLiteralData.UTF8, PGPLiteralData.CONSOLE, bytes.length, new Date());
Furthermore you should replace the line
OutputStream cOut = encGen.open(aOut, bytes.length);
// with
OutputStream cOut = encGen.open(aOut, new byte[1<<9]);
Otherwise you will run into encoding issues.
These changes should make your code run.
I however recommend using a library such as PGPainless (disclaimer: author here) which does all the low level stream wrapping and checking for you. On top of that it does proper signature verification, which most other Bouncycastle based libraries lack.

How to read public/private key files for encryption when they are Base64?

I'm trying to learn RSA public/private key-pair encryption in Java.
I have the code below working. It generates a private & public key pair, writes the keys to disk, encrypts the string with the public key from disk, the decrypts with the private key from disk, and then it outputs the decrypted string.
All works great.
The next thing is, I want the key files to be the readable "-----BEGIN RSA PRIVATE KEY-----" type of key files ... so I wrote the method saveKeysToDiskBase64.
The problem is, when I write the files using saveKeysToDiskBase64, the methods that read the key files fail. That is loadPrivateKey and loadPublicKey can't read the Base64 files.
What am I missing?
public class EncryptionTest1 {
public void execute() throws Exception {
String filename = "test1";
KeyPair keyPair = EncryptionUtil.generateKeyPair();
EncryptionUtil.saveKeysToDisk(filename, keyPair);
// EncryptionUtil.saveKeysToDiskBase64(filename, keyPair);
String pvtKeyFilename = filename+".key";
String pubKeyFilename = filename+".pub";
PrivateKey privateKey = EncryptionUtil.loadPrivateKey(pvtKeyFilename);
byte[] bPrivateKey = privateKey.getEncoded();
PublicKey publicKey = EncryptionUtil.loadPublicKey(pubKeyFilename);
byte[] bPublicKey = publicKey.getEncoded();
String sOriginal = "hi this is plain text";
byte[] encryptedData = EncryptionUtil.encrypt(bPublicKey, sOriginal.getBytes());
byte[] decryptedData = EncryptionUtil.decrypt(bPrivateKey, encryptedData);
String sEncrypted = new String(encryptedData);
String sDecrypted = new String(decryptedData);
System.out.println("sOriginal = "+sOriginal);
System.out.println("sEncrypted = "+sEncrypted);
System.out.println("sDecryptedData = "+sDecrypted);
}
public static void main(String[] args) {
try {
new EncryptionTest1().execute();
} catch (Exception x) {
x.printStackTrace();
}
}
}
...
public class EncryptionUtil {
private static final String ALGORITHM = "RSA";
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
// 2048 is keysize
keyGen.initialize(2048, random);
KeyPair generateKeyPair = keyGen.generateKeyPair();
return generateKeyPair;
}
public static void saveKeysToDisk(String name, KeyPair keyPair) {
try {
String privateFileName = name+".key";
FileOutputStream out1 = new FileOutputStream(privateFileName);
out1.write(keyPair.getPrivate().getEncoded());
out1.close();
String publicFileName = name+".pub";
FileOutputStream out2 = new FileOutputStream(publicFileName);
out2.write(keyPair.getPublic().getEncoded());
out2.close();
} catch (Exception x) {
x.printStackTrace();
}
}
public static void saveKeysToDiskBase64(String name, KeyPair keyPair) {
try {
Base64.Encoder encoder = Base64.getEncoder();
String privateFileName = name+".key";
Writer out = new FileWriter(privateFileName);
out.write("-----BEGIN RSA PRIVATE KEY-----\n");
out.write(encoder.encodeToString(keyPair.getPrivate().getEncoded()));
out.write("\n-----END RSA PRIVATE KEY-----\n");
out.close();
String publicFileName = name+".pub";
Writer out2 = new FileWriter(publicFileName);
out2.write("-----BEGIN RSA PUBLIC KEY-----\n");
out2.write(encoder.encodeToString(keyPair.getPublic().getEncoded()));
out2.write("\n-----END RSA PUBLIC KEY-----\n");
out2.close();
} catch (Exception x) {
x.printStackTrace();
}
}
public static PrivateKey loadPrivateKey(String keyFile) {
PrivateKey pvt = null;
try {
/* Read all bytes from the private key file */
Path path = Paths.get(keyFile);
byte[] bytes = Files.readAllBytes(path);
/* Generate private key. */
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
pvt = kf.generatePrivate(ks);
} catch (Exception x) {
x.printStackTrace();
}
return pvt;
}
public static PublicKey loadPublicKey(String keyFile) {
PublicKey pub = null;
try {
/* Read all the public key bytes */
Path path = Paths.get(keyFile);
byte[] bytes = Files.readAllBytes(path);
/* Generate public key. */
X509EncodedKeySpec ks = new X509EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
pub = kf.generatePublic(ks);
} catch (Exception x) {
x.printStackTrace();
}
return pub;
}
public static byte[] encrypt(byte[] publicKey, byte[] inputData) throws Exception {
PublicKey key = KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(publicKey));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(inputData);
return encryptedBytes;
}
public static byte[] decrypt(byte[] privateKey, byte[] inputData) throws Exception {
PrivateKey key = KeyFactory.getInstance(ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(privateKey));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedBytes = cipher.doFinal(inputData);
return decryptedBytes;
}
}
Great thanks to #President James K. Polk who gave me the correct answer in a comment.
Here is the Base64 related code that that worked for me ...
private static String PRIVATE_HEADER = "-----BEGIN PRIVATE KEY-----\n";
private static String PRIVATE_FOOTER = "\n-----END PRIVATE KEY-----\n";
private static String PUBLIC_HEADER = "-----BEGIN PUBLIC KEY-----\n";
private static String PUBLIC_FOOTER = "\n-----END PUBLIC KEY-----\n";
public static void saveKeysToDiskBase64(String name, KeyPair keyPair) {
try {
Base64.Encoder encoder = Base64.getEncoder();
String privateFileName = name+".key";
Writer out = new FileWriter(privateFileName);
out.write(PRIVATE_HEADER);
out.write(encoder.encodeToString(keyPair.getPrivate().getEncoded()));
out.write(PRIVATE_FOOTER);
out.close();
String publicFileName = name+".pub";
Writer out2 = new FileWriter(publicFileName);
out2.write(PUBLIC_HEADER);
out2.write(encoder.encodeToString(keyPair.getPublic().getEncoded()));
out2.write(PUBLIC_FOOTER);
out2.close();
} catch (Exception x) {
x.printStackTrace();
}
}
public static PrivateKey loadPrivateKeyBase64(String keyFile) {
PrivateKey pvt = null;
try {
/* Read all bytes from the private key file */
Path path = Paths.get(keyFile);
byte[] bytes = Files.readAllBytes(path);
String s = new String(bytes);
s = s.replace(PRIVATE_HEADER, "");
s = s.replace(PRIVATE_FOOTER, "");
bytes = Base64.getDecoder().decode(s.getBytes());
/* Generate private key. */
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
pvt = kf.generatePrivate(ks);
} catch (Exception x) {
x.printStackTrace();
}
return pvt;
}
public static PublicKey loadPublicKeyBase64(String keyFile) {
PublicKey pub = null;
try {
/* Read all the public key bytes */
Path path = Paths.get(keyFile);
byte[] bytes = Files.readAllBytes(path);
String s = new String(bytes);
s = s.replace(PUBLIC_HEADER, "");
s = s.replace(PUBLIC_FOOTER, "");
bytes = Base64.getDecoder().decode(s.getBytes());
/* Generate public key. */
X509EncodedKeySpec ks = new X509EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
pub = kf.generatePublic(ks);
} catch (Exception x) {
x.printStackTrace();
}
return pub;
}

Bouncy Castle J2ME load existing private key

I have a PEM or DER private key, an existing key. How can I load this key with
PrivateKeyFactory.createKey or into an AsymmetricCipherKeyPair ?
I tried this:
InputStream inKey = getClass().getResourceAsStream("/samsjava/user_key_pk8.der");
byte[] binKey = new byte[inKey.available()];
inKey.read(binKey, 0, binKey.length);
inKey.close();
privKey = PrivateKeyFactory.createKey(binKey);
keyPair = new AsymmetricCipherKeyPair(new AsymmetricKeyParameter(false), privKey);
rsaPriv = (RSAPrivateCrtKeyParameters)keyPair.getPrivate();
rsaPub = (RSAPrivateCrtKeyParameters)keyPair.getPublic();
What can I try next?
I tried the thing in Java, which should get me on the right track for J2ME. Here is the code:
public class EncrypDecrypt {
private RSAPrivateCrtKey rsaPriv;
private RSAPublicKey rsaPub;
private BASE64Decoder decoder;
private BASE64Encoder encoder;
public EncrypDecrypt(){
decoder = new BASE64Decoder();
encoder = new BASE64Encoder();
byte[] buffer;
try {
FileInputStream in = new FileInputStream("pathtofile.pfx");
KeyStore kStore = KeyStore.getInstance("PKCS12");
kStore.load(in, null);
PrivateKey privKeyEntry = (PrivateKey)kStore.getKey("Key Alias", null);
rsaPriv = (RSAPrivateCrtKey) privKeyEntry;
} catch (Exception ex) {
Logger.getLogger(EncrypDecrypt.class.getName()).log(Level.SEVERE, null, ex);
}
}
public String encrypt(String data){
try{
AsymmetricBlockCipher eng = new RSAEngine();
eng = new PKCS1Encoding(eng);
RSAKeyParameters publicKey = new RSAKeyParameters(true, rsaPriv.getModulus(), rsaPriv.getPublicExponent());
eng.init(true, publicKey);
byte[] encrypted = eng.processBlock(data.getBytes(), 0, data.getBytes().length);
return encoder.encode(encrypted);
}
catch(Exception err){
return "";
}
}
public String decrypt(String data){
try
{
byte[] encrypted = decoder.decodeBuffer(data);
AsymmetricBlockCipher eng = new RSAEngine();
eng = new PKCS1Encoding(eng);
RSAKeyParameters privateKey = new RSAKeyParameters(true, rsaPriv.getModulus(), rsaPriv.getPrivateExponent());
eng.init(false, privateKey);
byte[] decrypted = eng.processBlock(encrypted, 0, encrypted.length);
return new String(decrypted);
}
catch(Exception err){
return "";
}
}
}

Decrypted string not the same as pre encrypted string

I have the following pieces of code:
Globals
public static PublicKey pubKey;
public static PrivateKey privKey;
public static Cipher cip;
Main
public static void main(String[] args) throws Exception {
//Generate the keys
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
cip = Cipher.getInstance("RSA/ECB/NoPadding");
// Store Public Key.
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream("public.key");
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
// Store Private Key.
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
fos = new FileOutputStream("private.key");
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
//Get the public and private keys out of their files
getPubAndPrivateKey();
//Check if the keys gotten out of the files are the same as the generated files (this returns truetrue)
System.out.print(publicKey.equals(pubKey));
System.out.print(privateKey.equals(privKey));
byte[] text = "This is my super secret secret".getBytes();
encryptToFile("encrypted.txt", text );
decryptToFile("encrypted.txt", "decrypted.txt");
}
Getting the keys from the files
private static void getPubAndPrivateKey() throws IOException, Exception {
// Read Public Key.
File filePublicKey = new File("public.key");
FileInputStream fis = new FileInputStream("public.key");
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
// Read Private Key.
File filePrivateKey = new File("private.key");
fis = new FileInputStream("private.key");
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
encodedPublicKey);
pubKey = keyFactory.generatePublic(publicKeySpec);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
encodedPrivateKey);
privKey = keyFactory.generatePrivate(privateKeySpec);
}
Encrypting
public static void encryptToFile(String fileName, byte[] data)
throws IOException {
try {
cip.init(Cipher.ENCRYPT_MODE, privKey);
byte[] cipherData = cip.doFinal(data);
String encryptedData = cipherData.toString();
BufferedWriter out = new BufferedWriter(new FileWriter(fileName));
out.write(encryptedData);
out.close();
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
}
}
Decrypting
private static void decryptToFile(String string, String string2)
throws Exception {
try {
File encryptedFile = new File("encrypted.txt");
byte[] encrypted = getContents(encryptedFile).getBytes();
cip = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cip.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherData = cip.doFinal(encrypted);
String decryptedData = cipherData.toString();
BufferedWriter out = new BufferedWriter(new FileWriter(
"decrypted.txt"));
out.write(decryptedData);
out.close();
} catch (Exception e) {
throw e;
}
}
Things I already checked
The data used in the decryption is the same as in the encrypted file
The generated keys are the same as the ones gotten from the file
The encryption and decryption both don't give errors
Results
Original string:
My super secret secret
The encryption results in:
[B#1747b17
The decryption results in:
[B#91a4fb
If you print out a byte array via toString() method you are getting a value that is totally independent of the content.
Therefore the values [B#1747b17 [B#91a4fb are just garbage that does not tell you anything.
If you want to print the content of a byte array convert it to Base64 or hex-string.
System.out.println(new sun.misc.BASE64Encoder().encode(myByteArray));
A hex string can be generated by using org.apache.commons.codec.binary.Hex from Apache Commons Codec library.
I agree with the above answer.
I would like to add that in your case, you can simply use FileOutputStream, write the bytes to a file -
For example:
public static void encryptToFile(String fileName, byte[] data)
throws IOException {
FileOutputStream out = null;
try {
cip.init(Cipher.ENCRYPT_MODE, privKey);
byte[] cipherData = cip.doFinal(data);
out = new FileOutputStream(fileName);
out.write(cipherData);
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException ex) {
}
}
}
}

How to encrypt decrypt with RSA keys in java

I need to replace the encrypt and decrypt step from Unix to java code with the rsaprivatekey.pem and rsapublickey.pem keys generated with openssl
I generate the keys
openssl genrsa -out /tmp/rsaprivatekey.pem -des3 1024
openssl rsa -in /tmp/rsaprivatekey.pem -pubout -out /tmp/rsapublickey.pem
i use the keys in unix (i need do it in java)
echo "Text to encript"| openssl rsautl -encrypt -inkey /tmp/rsapublickey.pem -pubin -out out.enc
openssl rsautl -decrypt -inkey /tmp/rsaprivatekey.pem -in out.enc
This was my attempt to do it
public static void main(String[] args) {
Base64 base64 = new Base64();
String TextStream = "this is the input text";
byte[] Cipher;
System.out.println("input:\n" + TextStream);
Cipher = encrypt(TextStream);
System.out.println("cipher:\n" + base64.encodeAsString(Cipher));
System.out.println("decrypt:\n" + decrypt(Cipher));
}
private static byte[] encrypt(String Buffer) {
try {
Cipher rsa;
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, getPrivateKey(PRIVATE_PATH));
return rsa.doFinal(Buffer.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String decrypt(byte[] buffer) {
try {
Cipher rsa;
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.DECRYPT_MODE, getPrivateKey(PUBLIC_PATH));
byte[] utf8 = rsa.doFinal(buffer);
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static PrivateKey getPrivateKey(String filename) throws Exception {
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
public static PublicKey getPublicKey(String filename) throws Exception {
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
but it not works, the PKCS8EncodedKeySpec/X509EncodedKeySpec are not correct... but i do not know what to put
Solution:
Thanks to #Sanjeev, using the bouncy castle API, I was able to encrypt/decrypt with the keys generated by openssl
public static void main(String[] args) throws IOException {
Security.addProvider(new BouncyCastleProvider());
KeyPair keyPair = readKeyPair(new File(PRIVATE_PATH), "pass");
// if the private key is not encripted, pass can be anything.
Key publickey = readPublicKey(new File(PUBLIC_PATH), "pass");
Base64 base64 = new Base64();
String text = "this is the input text";
byte[] encripted;
System.out.println("input:\n" + text);
encripted = encrypt(keyPair.getPublic(), text);
System.out.println("cipher:\n" + base64.encodeAsString(encripted));
System.out.println("decrypt:\n" + decrypt(keyPair.getPrivate(), encripted));
}
private static byte[] encrypt(Key pubkey, String text) {
try {
Cipher rsa;
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, pubkey);
return rsa.doFinal(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String decrypt(Key decryptionKey, byte[] buffer) {
try {
Cipher rsa;
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.DECRYPT_MODE, decryptionKey);
byte[] utf8 = rsa.doFinal(buffer);
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static KeyPair readKeyPair(File privateKey, String keyPassword) throws IOException {
FileReader fileReader = new FileReader(privateKey);
PEMReader r = new PEMReader(fileReader, new DefaultPasswordFinder(keyPassword.toCharArray()));
try {
return (KeyPair) r.readObject();
} catch (IOException ex) {
throw ex;
} finally {
r.close();
fileReader.close();
}
}
private static Key readPublicKey(File privateKey, String keyPassword) throws IOException {
FileReader fileReader = new FileReader(privateKey);
PEMReader r = new PEMReader(fileReader, new DefaultPasswordFinder(keyPassword.toCharArray()));
try {
return (RSAPublicKey) r.readObject();
} catch (IOException ex) {
throw ex;
} finally {
r.close();
fileReader.close();
}
}
I think you're having problems reading PEM files. The JPA doesn't directly support the PEM format. You have two options, either convert them to DER encoded files (you can use openSSL to do this) or the you can use the bouncy castle API to read (or write) PEM files. the class you'd be interested in is called PEMReader (and maybe also PEMWriter). Here is the Javadoc on the bouncycastle website.

Categories

Resources