GPG decryptor doesn't work properly - java

I'm trying to write gpg encryptor/decryptor (code below). In first step program encrypts "#data1\n#data2\n#data3\n" string and in next step decrypts the array of bytes that decryptor returns. But... why text from decryptor is not the same as "#data1\n#data2\n#data3\n" ? Where did I missed something ? Thanks for your help.
package tests.crypto;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.util.Iterator;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
import Decoder.BASE64Encoder;
public class GPGTest {
char[] pass = { 'p', 'a', 's', 's' };
public static void main(String[] args) throws Exception {
GPGTest gTest = new GPGTest();
gTest.setUpCipher();
}
public void setUpCipher() throws NoSuchAlgorithmException,
InvalidKeyException, IllegalBlockSizeException,
NoSuchProviderException, BadPaddingException,
NoSuchPaddingException {
System.out.println("--- setup cipher ---");
// public key
String publicKeyFilePath = "E:/Programs/Keys/GPG/Public/public.key";
File publicKeyFile = new File(publicKeyFilePath);
// secret key
String secretKeyFilePath = "E:/Programs/Keys/GPG/Secret/private.key";
File secretKeyFile = new File(secretKeyFilePath);
// security provider
Security.addProvider(new BouncyCastleProvider());
try {
// Read the public key
FileInputStream pubIn = new FileInputStream(publicKeyFile);
PGPPublicKey pgpPubKey = readPublicKey(pubIn);
PublicKey pubKey = new JcaPGPKeyConverter().getPublicKey(pgpPubKey);
// Read the private key
FileInputStream secretIn = new FileInputStream(secretKeyFile);
PGPSecretKey pgpSecretKey = readSecretKey(secretIn);
PGPPrivateKey pgpPrivKey = pgpSecretKey
.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(
new BcPGPDigestCalculatorProvider()).build(pass));
PrivateKey privKey = new JcaPGPKeyConverter()
.getPrivateKey(pgpPrivKey);
Cipher cipher = Cipher.getInstance("RSA");
// Encrypt data
byte[] encData = encryptData(cipher, pubKey, new String(
"#data1\n#data2\n#data3\n").getBytes());
String cryptString = new BASE64Encoder().encode(encData);
System.out.println("\n\nEncrypted data=" + cryptString);
// Decrypt data
byte[] decData = decryptData(cipher, privKey, encData);
String decryptString = new BASE64Encoder().encode(decData);
System.out.println("\n\nDecrypted data=" + decryptString);
} catch (Exception e) {
System.out.println("Setup cipher exception");
System.out.println(e.toString());
}
}
public byte[] encryptData(Cipher cipher, PublicKey pubKey, byte[] clearText) {
byte[] encryptedBytes = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
encryptedBytes = cipher.doFinal(clearText);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return encryptedBytes;
}
public byte[] decryptData(Cipher cipher, PrivateKey privKey, byte[] encryptedText) {
byte[] decryptedBytes = null;
try {
cipher.init(Cipher.DECRYPT_MODE, privKey);
decryptedBytes = cipher.doFinal(encryptedText);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decryptedBytes;
}
private static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException {
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input));
Iterator<?> keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext()) {
PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next();
Iterator<?> keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext()) {
PGPPublicKey key = (PGPPublicKey) keyIter.next();
if (key.isEncryptionKey()) {
return key;
}
}
}
throw new IllegalArgumentException(
"Can't find encryption key in key ring.");
}
private static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input));
Iterator<?> keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRingIter.next();
Iterator<?> keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
PGPSecretKey key = (PGPSecretKey) keyIter.next();
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalArgumentException(
"Can't find signing key in key ring.");
}
}

They aren't the same because you are base-64 encoding the results of the decryption, rather than decoding it as text. Do this instead:
byte[] decData = decryptData(cipher, privKey, encData);
System.out.println("\n\nDecrypted data=" + new String(decData));
It is poor practice to use the platform default character encoding. Instead, you should convert text to bytes with with specific encoding, and use the same coding when decoding the bytes.
byte[] plaintext = "#data1\n#data2\n#data3\n").getBytes(StandardCharsets.UTF_8);
...
String recovered = new String(decData, StandardCharsets.UTF_8);

Related

got AEADBadTagException while trying to decrypt message in GCM mode

I'm writing an app which got a lot of security constraints:
It needs to store files securely encrypted, and must be able to decrypt them. Also, an Operator needs to be able to decrypt the file without the app.
To archive this, I generated a KeyPair on my PC, put the public part in my app, generate an AES SecretKey Key inside the app, encrypt and save it with my public key (for operator purposes), and put the unencrypted key in AndroidKeyStore.
To Encrypt a message, I receive the SecretKey from KeyStore, encrypt my message, get the IV I used as well as the encryptedSecretKey, and write them in a defined order to a byte array (iv->encryptedSecretKey->encryptedMessage).
To Decrypt I try the same in reverse: get the byte array, read the iv and encryptedSecretKey, and pass the rest (encryptedMessage) to my cypher to decrypt.
The problem is, that cipher.doFinal(encryptedMessage) is throwing an
javax.crypto.AEADBadTagExceptionwhich is caused by android.security.KeyStoreException: Signature/MAC verification failed.
I already checked that the encrypted message and the one I want to decrypt are exactly the same. I'm having no idea what I am doing wrong.
The class I use is the following:
package my.company.domain;
import android.content.Context;
import android.content.SharedPreferences;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.support.annotation.NonNull;
import android.util.Base64;
import android.util.Log;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CryptoHelper {
public static final String TAG = CryptoHelper.class.getSimpleName();
private static final String KEY_ALIAS = "OI1lTI1lLI1l0";
private static final char[] KEY_PASSWORD = "Il0VELI1lO".toCharArray();
private static final String PREF_NAME = "CryptoPrefs";
private static final String KEY_ENCRYPTED_SECRET = "encryptedSecret";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final int IV_SIZE = 12;
private static final int IV_BIT_LEN = IV_SIZE * 8;
//generate 128 bit key (16), other possible values 192(24), 256(32)
private static final int AES_KEY_SIZE = 16;
private static final String AES = KeyProperties.KEY_ALGORITHM_AES;
private static final String AES_MODE = AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE;
private static final String RSA = KeyProperties.KEY_ALGORITHM_RSA;
private static final String RSA_MODE = KeyProperties.KEY_ALGORITHM_RSA + "/" + KeyProperties.BLOCK_MODE_ECB + "/" + KeyProperties.ENCRYPTION_PADDING_NONE;
private static final String RSA_PROVIDER = "AndroidOpenSSL";
private final Context mContext;
private final SharedPreferences mPrefs;
private SecureRandom mSecureRandom;
private KeyStore mAndroidKeyStore;
private PublicKey mPublicKey;
private byte[] mEncryptedSecretKey;
public CryptoHelper(Context context) {
mContext = context;
mSecureRandom = new SecureRandom();
mPrefs = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
try {
mAndroidKeyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
mAndroidKeyStore.load(null);
} catch (KeyStoreException e) {
Log.wtf(TAG, "Could not get AndroidKeyStore!", e);
} catch (Exception e) {
Log.wtf(TAG, "Could not load AndroidKeyStore!", e);
}
}
public void reset() throws KeyStoreException {
mAndroidKeyStore.deleteEntry(KEY_ALIAS);
}
public byte[] encrypt(byte[] message){
SecretKey secretKey = getSecretKey();
try {
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
byte[] cryptedBytes = cipher.doFinal(message);
byte[] iv = cipher.getIV();
byte[] encryptedSecretKey = getEncryptedSecretKey();
ByteBuffer buffer = ByteBuffer.allocate(IV_BIT_LEN + encryptedSecretKey.length + cryptedBytes.length);
buffer
.put(iv)
.put(encryptedSecretKey)
.put(cryptedBytes);
return buffer.array();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
public byte[] encrypt(String message){
return encrypt(message.getBytes(StandardCharsets.UTF_8));
}
public byte[] decrypt(byte[] bytes){
ByteBuffer buffer = ByteBuffer.wrap(bytes);
byte[] iv = new byte[IV_SIZE];
buffer.get(iv);
byte[] unused = getEncryptedSecretKey();
buffer.get(unused);
byte[] encryptedMessage = new byte[bytes.length - IV_SIZE - unused.length];
buffer.get(encryptedMessage);
try {
Cipher cipher = Cipher.getInstance(AES_MODE);
GCMParameterSpec parameterSpec = new GCMParameterSpec(IV_BIT_LEN, iv);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), parameterSpec);
byte[] decryptedMessage = cipher.doFinal(encryptedMessage);
return decryptedMessage;
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}
public String decryptToString(byte[] bytes){
return new String(decrypt(bytes), StandardCharsets.UTF_8);
}
public byte[] decrypt(FileInputStream fileToDecrypt){
byte[] buffer = null;
try {
buffer = new byte[fileToDecrypt.available()];
fileToDecrypt.read(buffer);
buffer = decrypt(buffer);
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
public PublicKey getPublicKey() {
if (null == mPublicKey) {
mPublicKey = readPublicKey();
}
return mPublicKey;
}
public byte[] getEncryptedSecretKey() {
if (null == mEncryptedSecretKey){
mEncryptedSecretKey = Base64.decode(mPrefs.getString(KEY_ENCRYPTED_SECRET, null), Base64.NO_WRAP);
}
return mEncryptedSecretKey;
}
private void saveEncryptedSecretKey(byte[] encryptedSecretKey){
String base64EncryptedKey = Base64.encodeToString(encryptedSecretKey, Base64.NO_WRAP);
mPrefs.edit().putString(KEY_ENCRYPTED_SECRET, base64EncryptedKey).apply();
}
protected SecretKey getSecretKey(){
SecretKey secretKey = null;
try {
if (!mAndroidKeyStore.containsAlias(KEY_ALIAS)){
generateAndStoreSecureKey();
}
secretKey = (SecretKey) mAndroidKeyStore.getKey(KEY_ALIAS, KEY_PASSWORD);
} catch (KeyStoreException e) {
Log.wtf(TAG, "Could not check AndroidKeyStore alias!", e);
secretKey = null;
} catch (GeneralSecurityException e) {
e.printStackTrace();
secretKey = null;
}
return secretKey;
}
private void generateAndStoreSecureKey()
throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, KeyStoreException, BadPaddingException, IllegalBlockSizeException {
SecretKey secretKey = generateSecureRandomKey();
PublicKey publicKey = getPublicKey();
Cipher keyCipher = Cipher.getInstance(RSA_MODE, RSA_PROVIDER);
keyCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedSecretKeyBytes = keyCipher.doFinal(secretKey.getEncoded());
saveEncryptedSecretKey(encryptedSecretKeyBytes);
KeyProtection keyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_VERIFY)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
mAndroidKeyStore.setEntry(KEY_ALIAS, new KeyStore.SecretKeyEntry(secretKey), keyProtection);
}
protected PublicKey readPublicKey() {
DataInputStream dis = null;
PublicKey key = null;
try {
dis = new DataInputStream(mContext.getResources().getAssets().open("public_key.der"));
byte[] keyBytes = new byte[dis.available()];
dis.readFully(keyBytes);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory facotory = KeyFactory.getInstance(RSA);
key = facotory.generatePublic(spec);
} catch (Exception e) {
key = null;
} finally {
if (null != dis) {
try {
dis.close();
} catch (IOException e) {
Log.wtf(TAG, "Cannot Close Stream!", e);
}
}
}
return key;
}
#NonNull
protected SecretKey generateSecureRandomKey() {
return new SecretKeySpec(generateSecureRandomBytes(AES_KEY_SIZE), AES);
}
#NonNull
protected byte[] generateSecureRandomBytes(int byteCount) {
byte[] keyBytes = new byte[byteCount];
mSecureRandom.nextBytes(keyBytes);
return keyBytes;
}
}
And I Test it like this:
#Test
public void testCrypto() throws Exception {
CryptoHelper crypto = new CryptoHelper(InstrumentationRegistry.getTargetContext());
crypto.reset();
String verySecretOpinion = "we're all doomed";
byte[] encrypt = crypto.encrypt(verySecretOpinion);
Assert.assertNotNull("Encrypted secret is Null!", encrypt);
Assert.assertFalse("encrypted Bytes are the same as Input!", new String(encrypt, StandardCharsets.UTF_8).equals(verySecretOpinion));
String decryptedString = crypto.decryptToString(encrypt);
Assert.assertNotNull("Decrypted String must be Non-Null!", decryptedString);
Assert.assertEquals("Decrypted String doesn't equal encryption input!", verySecretOpinion, decryptedString);
}
By the way minSdkVersion is 25, so higher than Marshmallow
UPDATE:
Fixed Cipher.DECRYPT_MODE to ENCRYPT_MODE on saving the SecretKey thx to James K Polk's comment
it works If I switch from BlockMode GCM to BlockMode CBC (and changing the GCMParameterSpec to IvParamterSpec but loose the verification of the GCM Mode.
There are at least two problems with the Operator interface. First, you RSA encrypt the secret key using the wrong Cipher mode: you used DECRYPT mode when you should have used encrypt. Secondly, you are using RSA without any padding. You need to use a real padding mode, one of the OEAP padding modes is recommended.
An error in the encryption side occurs when sizing the buffer used to hold the result:
ByteBuffer buffer = ByteBuffer.allocate(IV_BIT_LEN + encryptedSecretKey.length + cryptedBytes.length);
allocates too much space. IV_BIT_LEN should probably be changed to IV_SIZE to get the correctly sized ByteBuffer.
The last mistake is the failure to account for the GCM authentication tag length when setting the GCMParameterSpec on the decrypt side. You initialized the tag length in this line
GCMParameterSpec parameterSpec = new GCMParameterSpec(IV_BIT_LEN, iv);
but that's incorrect, the tag length is unrelated to the IV. Since you did not explicitly set the GCMParameterSpec on the encrypt side you got the default tag length, which happens to be 128.
You can retrieve the tag length on the encrypt side by calling
cipher.getParameters().getParameterSpec(GCMParameterSpec.class) to get the parameter spec. From this you can retrieve both the tag length and the iv. You should probably consider the tag length, 16 bytes = 128 bits, to be a hard-coded constant and not transmit it. The receiver should similar assume the tag length is 128 bits.

Java AES encryption example

when I tried to implement this code which is (AES algorithm written in Java), I found an error in these lines:
import org.apache.commons.codec.binary.Base64;
setEncryptedString(Base64.encodeBase64String(cipher.doFinal(strToEncrypt.getBytes("UTF-8"))));
setDecryptedString(new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt))));
The main code is :
package trytry;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;
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 javax.print.DocFlavor.STRING;
import org.apache.commons.codec.binary.Base64;
public class AES
{
private static SecretKeySpec secretKey ;
private static byte[] key ;
private static String decryptedString;
private static String encryptedString;
public static void setKey(String myKey){
MessageDigest sha = null;
try {
key = myKey.getBytes("UTF-8");
System.out.println(key.length);
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
System.out.println(key.length);
System.out.println(new String(key,"UTF-8"));
secretKey = new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String getDecryptedString() {
return decryptedString;
}
public static void setDecryptedString(String decryptedString) {
AES.decryptedString = decryptedString;
}
public static String getEncryptedString() {
return encryptedString;
}
public static void setEncryptedString(String encryptedString) {
AES.encryptedString = encryptedString;
}
public static String encrypt(String strToEncrypt)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
setEncryptedString(Base64.encodeBase64String(cipher.doFinal(strToEncrypt.getBytes("UTF-8"))));
}
catch (Exception e)
{
System.out.println("Error while encrypting: "+e.toString());
}
return null;
}
public static String decrypt(String strToDecrypt)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
setDecryptedString(new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt))));
}
catch (Exception e)
{
System.out.println("Error while decrypting: "+e.toString());
}
return null;
}
public static void main(String args[])
{
final String strToEncrypt = "My text to encrypt";
final String strPssword = "encryptor key";
AES.setKey(strPssword);
AES.encrypt(strToEncrypt.trim());
System.out.println("String to Encrypt: " + strToEncrypt);
System.out.println("Encrypted: " + AES.getEncryptedString());
final String strToDecrypt = AES.getEncryptedString();
AES.decrypt(strToDecrypt.trim());
System.out.println("String To Decrypt : " + strToDecrypt);
System.out.println("Decrypted : " + AES.getDecryptedString());
}
}
just to know I tried to add: JRE System Library but does not work.
Perhaps
setDecryptedString(new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt))));
should be
setDecryptedString(new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt)),
Charset.forName("UTF-8")));
I doubt it will make a difference, but if you're explicit in encryption (and you should be), then you should be explicit with the decryption.
In any case, something more descriptive than "I found an error" or "I have errors" would be very helpful. (Exceptions and stacktraces or the Eclipse and/or compiler error messages.)

RSA Signature having public key as text not verified in java

This issue is generated in continuation of past question How to RSA verify a signature in java that was generated in php . That code work for simple text. But Now I have requirement for signing and verifying the text which also have a public key ( other than verification key ) in format.
text1:text2:exported-public-key
Example :
53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:MIIBCgKCAQEAxWg6ErfkN3xu8rk9WsdzjL5GpjAucMmOAQNeZcgMBxN+VmU43EnvsDLSxUZD1e/cvfP2t2/dzhtV6N2IvT7hveuo/zm3+bUK6AnAfo6pM1Ho0z4WetoYOrHdOVNMMPaytXiVkNlXyeWRF6rl9JOe94mMYWRJzygntiD44+MXsB6agsvQmB1l8thg/8+QHNOBBU1yC4pLQwwO2cb1+oIl0svESkGpzHk8xJUl5jL6dDnhqp8+01KE7AGHwvufrsw9TfVSAPH73lwo3mBMVXE4sfXBzC0/YwZ/8pz13ToYiN88DoqzcfD3+dtrjmpoMpymAA5FBc5c6xhPRcrn24KaiwIDAQAB
PHP Code :
$rsa = new Crypt_RSA();
$keysize=2048;
$pubformat = "CRYPT_RSA_PUBLIC_FORMAT_PKCS1";
$privformat = "CRYPT_RSA_PRIVATE_FORMAT_PKCS8";
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
$Kp = $d['publickey'];
$Ks = $d['privatekey'];
$rsa = new Crypt_RSA();
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
$Kver = $d['publickey'];
$KSign = $d['privatekey'];
$plainText = "53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:".$Kp;
// Signing
$hash = new Crypt_Hash('sha256');
$rsa = new Crypt_RSA();
$rsa->loadKey($KSign);
$rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setHash('sha256');
$signature = $rsa->sign($plainText);
$signedHS = base64_encode($signature);
// Verification
$signature = base64_decode($signedHS);
$rsa->loadKey($Kver);
$status = $rsa->verify($plainText, $signature);
var_dump($status);
JAVA Code
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.math.BigInteger;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
//import java.util.Base64;
//import java.util.Base64.Decoder;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class VerifySig {
public static RSAPublicKey fromPKCS1Encoding(byte[] pkcs1EncodedPublicKey) {
// --- parse public key ---
org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey;
try {
pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey
.getInstance(pkcs1EncodedPublicKey);
} catch (Exception e) {
throw new IllegalArgumentException(
"Could not parse BER PKCS#1 public key structure", e);
}
// --- convert to JCE RSAPublicKey
RSAPublicKeySpec spec = new RSAPublicKeySpec(
pkcs1PublicKey.getModulus(), pkcs1PublicKey.getPublicExponent());
KeyFactory rsaKeyFact;
try {
rsaKeyFact = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("RSA KeyFactory should be available", e);
}
try {
return (RSAPublicKey) rsaKeyFact.generatePublic(spec);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(
"Invalid RSA public key, modulus and/or exponent invalid", e);
}
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
String pkey = "MIIBCgKCAQEA+8fKYCT4QiFUdsJ7VdF4xCkVmq/Kwc/10Jl3ie6mvn8hEsC3NAtMJu+Od12gyWYsS0zBDiQ8h2pGZ7p4uWqenc01dRRrq+g968zmoCKPUllPUuR6v9o+wYTX/os4hgaQSBg7DQn4g3BEekcvyk6e6zAMvuhHjeqnrinhCMFgJUhFL8zFNoyaH559C0TNbR6BTKzOoikah8cKhu4UOga0tWDC0I2Ifus/sHOwVaOBkDFIzD6jBxDH/QF8FsrLLTocuIb7Y6lVxFPPtgiUJku6b7wKExV0bPJvm6/Xhv1GX1FpMrA0Ylzj5IFviuviwgo534EcZQ/Hx3aIf4oPG8jVTQIDAQAB";
byte[] dpkey = Base64.decodeBase64(pkey);
RSAPublicKey publicKey = fromPKCS1Encoding(dpkey);
String plainData = "53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:MIIBCgKCAQEArszIunGg3ievJOpgesYQsp3nPGgrW+3VwkivkkktOXUBRzb3G3mZzidEjG6LxNe/rrNe0UczmnSHQoSBxJCHyUnCWNfScBD66CFG4hLo5Z1gxrP8D2M2lCa6ap2PWcsKiWqlu38EinMeBjBvB4aYpF7+FkFy64ObxR4pfVZxnxradkD0HvvMPLMbyeHxeGqYf8orERf9jfuKTdY8V44rxht2D2fg2WhB1+XL0JulsPvgOaSK3RPnwi+RQAJbihCIh5Zznn0KQCs5pIWoT3XKe1DMpQuEmphSOY9ZUg3AwlOrpRV+565x6GCSc615/6nowmqKzE4T7qT5nbH+ctiEHQIDAQAB";
String data = "iD96rNeR51BF2TUZSaw+QhW8SnsMXE5AdJiDVmJk6LL55jC26PBCnqXrFo2lsQt8aWRsZc0bHFGCcuIbhHA+Duo1/PwrxTqC5BZFL/frqsRSVa+vpvGEnj3xe4iImTEasMicQzzaAG9IWIgkRZ272lUZ8PqdtTuqAsRIwir6fEsfVs5uIErEWM18R4JxlFBc3LDIjFOFemEPSVIEBHwWht1c/CrdTtxPRIiugEb1jdofEBUNcWPZgfvApVx5+0aS9WTl31AY+RMlvp+13P/FQgAMnH9rvBdopRIVsZUNlMf8AOE2afhLPfOgx+41rzCB2wGCrRGELbml466WJ3wYNQ==";
byte[] ciphertext = Base64.decodeBase64(data);
System.out.println(new String(plainData.getBytes(), UTF_8));
verifyBC(publicKey, plainData, ciphertext);
System.out.flush();
}
private static void verifyBC(PublicKey publicKey, String plainData,
byte[] ciphertext) throws Exception {
// what should work (for PKCS#1 v1.5 signatures), requires Bouncy Castle provider
//Signature sig = Signature.getInstance( "SHA256withRSAandMGF1");
Signature sig = Signature.getInstance( "SHA256withRSA");
sig.initVerify(publicKey);
sig.update(plainData.getBytes(UTF_8));
System.out.println(sig.verify(ciphertext));
}
}
It not gave any error but just return false when using public key in plainText. If try after removing with public key, It works and return true.
PHP is working fine and signature is verified in all cases.
I suspecting if java is unable to verify data having base 64 text/public key as text ?
UPDATE : I compare binary bytes of both two times and result show minor difference.
First Case
PHP -> ��#C:���sQ
JAVA -> ��/#C:���sQ
Second Case
PHP -> ��]Q0l�O+
JAVA -> ��]Q0l�
If php base64 is not compatible with apache base 64 ?
When I run the PHP code, I'm noticing that the $Kp variable contains a key in the wrong format:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAqCJ/2E+YZvXJyabQmi0zZlaXXGbfXHt8KYS27i+PAJKBODmevTrS
w59S5AOy2l7lB4z5mYHuwdT6bm6YYXgE0gnoX/b2L65xdD9XtlenS4Zm15TVTdR5
zde4nBa0QPKfhFvthOmdPr9xDhDb8Rojy/phX+Ftva33ceTXoB+CtLyidMWbQmUh
ZufnI7MwIOPAIzXNJJ85eyUjBdoNMwlAPZo9vYQWeiwYGyP1fjQwEWZgjCH/LJjl
sNR1X9vp5oi8/4omdnFRvKLpkd5R7WMmMfAyAXe7tcfMSXuVAgMWEj9ZG0ELpXbG
S3CK6nvOp2gFF+AjHo9bCrh397jYotE3HQIDAQAB
-----END RSA PUBLIC KEY-----
When I strip out all the extra formatting and export the key as a single line of base64, it works.
PHP code:
function extract_key($pkcs1) {
# strip out -----BEGIN/END RSA PUBLIC KEY-----, line endings, etc
$temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $pkcs1, 1);
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
return str_replace(array("\r", "\n", ' '), '', $temp);
}
$rsa = new Crypt_RSA();
$keysize=2048;
$pubformat = "CRYPT_RSA_PUBLIC_FORMAT_PKCS1";
$privformat = "CRYPT_RSA_PRIVATE_FORMAT_PKCS8";
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
$Kp = $d['publickey'];
$Ks = $d['privatekey'];
$rsa = new Crypt_RSA();
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
$Kver = $d['publickey'];
$KSign = $d['privatekey'];
file_put_contents("pub_verify_key.txt",extract_key($Kver));
$plainText = "53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:".extract_key($Kp);
file_put_contents("plain.txt",$plainText);
// Signing
$hash = new Crypt_Hash('sha256');
$rsa = new Crypt_RSA();
$rsa->loadKey($KSign);
$rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setHash('sha256');
$signature = $rsa->sign($plainText);
$signedHS = base64_encode($signature);
file_put_contents("signedkey.txt", $signedHS);
// Verification
$signature = base64_decode($signedHS);
$rsa->loadKey($Kver);
$status = $rsa->verify($plainText, $signature);
var_dump($status);
Java code:
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.File;
import java.io.FileReader;
import java.math.BigInteger;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class VerifySig {
public static RSAPublicKey fromPKCS1Encoding(byte[] pkcs1EncodedPublicKey) {
// --- parse public key ---
org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey;
try {
pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey
.getInstance(pkcs1EncodedPublicKey);
} catch (Exception e) {
throw new IllegalArgumentException(
"Could not parse BER PKCS#1 public key structure", e);
}
// --- convert to JCE RSAPublicKey
RSAPublicKeySpec spec = new RSAPublicKeySpec(
pkcs1PublicKey.getModulus(), pkcs1PublicKey.getPublicExponent());
KeyFactory rsaKeyFact;
try {
rsaKeyFact = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("RSA KeyFactory should be available", e);
}
try {
return (RSAPublicKey) rsaKeyFact.generatePublic(spec);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(
"Invalid RSA public key, modulus and/or exponent invalid", e);
}
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
String pkey = fromFile("pub_verify_key.txt");
byte[] dpkey = Base64.decodeBase64(pkey);
RSAPublicKey publicKey = fromPKCS1Encoding(dpkey);
String plainData = fromFile("plain.txt");
String data = fromFile("signedkey.txt");
byte[] ciphertext = Base64.decodeBase64(data);
System.out.println(new String(plainData.getBytes(), UTF_8));
verifyBC(publicKey, plainData, ciphertext);
System.out.flush();
}
private static void verifyBC(PublicKey publicKey, String plainData,
byte[] ciphertext) throws Exception {
// what should work (for PKCS#1 v1.5 signatures), requires Bouncy Castle provider
//Signature sig = Signature.getInstance( "SHA256withRSAandMGF1");
Signature sig = Signature.getInstance( "SHA256withRSA");
sig.initVerify(publicKey);
sig.update(plainData.getBytes(UTF_8));
System.out.println(sig.verify(ciphertext));
}
private static String fromFile(String filename) {
StringBuilder builder = new StringBuilder(8000);
try {
FileReader reader = new FileReader(new File(filename));
int c;
while((c = reader.read()) != -1) {
builder.append((char)c);
}
} catch(IOException ioe) {
throw new RuntimeException(ioe);
}
return builder.toString();
}
}

Java 7 : output from encryption with public RSA key using cipher "RSA/ECB/OAEPWithSHA1AndMGF1Padding" does not match with openssl command

We have to encrypt our data with HMAC-SHA256 that needs randomly generated salt. We are generating the salt this way:
public String generateSalt() throws Exception
{
KeyGenerator keyGen;
String salt = null;
try
{
keyGen = KeyGenerator.getInstance( "HmacSHA256" );
keyGen.init( 128 );
SecretKey key = keyGen.generateKey();
byte[] encodedKey = key.getEncoded();
salt = Base64.encodeBase64String( key.getEncoded() );
LOG.info( "Salt : " + salt );
}
catch ( NoSuchAlgorithmException )
{
e.printStackTrace();
throw e;
}
return salt;
}
According to our test this salt generation part is right. I have issue with the next part:
Now I have to write this salt in binary format in a file ( say named as pie_raw) and that's been done as:
private void writeToFile( byte[] saltBytes, String fileName ) throws FileNotFoundException, IOException
{
DataOutputStream out = new DataOutputStream( new FileOutputStream( enviro.getOutputFilePath()
+ fileName ) );
out.write( saltBytes );
out.close();
LOG.info( " Raw file created : " + enviro.getOutputFilePath() + fileName );
}
And then, I have to encrypt this salt with a supplied public RSA key in ".pem" and for Java implementation, the cipher will be "RSA/ECB/OAEPWithSHA1AndMGF1Padding". And finally the binary ciphertext should be written to a file named "pie_key". This part has been implemented this way:
private byte[] encryptSalt( String salt ) throws Exception
{
byte[] cipheredKey = null;
try
{
String keyString= readKeyFile( enviro.getPublicKeyFile() );
byte[] pem = pemToDer(keyString);
PublicKey publicKey = derToPublicKey(pem);
//PublicKey publicKey = getPublicKey( enviro.getPublicKeyFile() );
// Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
rsaCipher.init( Cipher.ENCRYPT_MODE, publicKey );
cipheredKey = rsaCipher.doFinal( salt.getBytes( "UTF-8" ) );//"UTF-8"
LOG.info( "Cyphered key : " + cipheredKey.toString() );
}
catch ( IOException | GeneralSecurityException e )
{
e.printStackTrace();
throw e;
}
return cipheredKey;
}
static String readKeyFile( String path )
throws IOException
{
String line = null;
try (BufferedReader br =
new BufferedReader( new FileReader( path ) ))
{
StringBuilder sb = new StringBuilder();
line = br.readLine();
while ( line != null )
{
sb.append( line );
sb.append( "\n" );
line = br.readLine();
}
return sb.toString();
}
}
public static byte[] pemToDer( String pemKey ) throws GeneralSecurityException
{
String[] parts = pemKey.split( "-----" );
return DatatypeConverter.parseBase64Binary( parts[ parts.length / 2 ] );
}
public static PublicKey derToPublicKey( byte[] asn1key ) throws GeneralSecurityException
{
X509EncodedKeySpec spec = new X509EncodedKeySpec( asn1key );
KeyFactory keyFactory = KeyFactory.getInstance( "RSA" );
return keyFactory.generatePublic( spec );
}
Writing this encrypted salt to a file named as "pie_key" in binary format by calling the "writeToFile" method above.
Now the content of the file "pie_key" should match the out put of the cmd :
openssl rsautl -encrypt -pubin -inkey wrap_pie_key_rsa.pem -oaep -in pie_key.raw -out pie_key
But whatever I tried ( you may find some signs of the ways, I tried ) did not work means that the final binary-encrypted-salt did not match with the output of openssl cmd.
Any idea what I am doing wrong?
I am using Java 7. And the .pem (partial) looks like
-----BEGIN PUBLIC KEY-----
MIIBIjANBgk345iG9w0BAQEFAA54328AMIIBCgKCAQEAt4GLJGPmvYdxwwAe59n3
.
.
.
.
7QIDNQAB
-----END PUBLIC KEY-----
Thanks in advance.
First of all, as Artjom already mentioned, the padding for OAEP or PKCS#1 v1.5 compatible padding is randomized. So even if you encrypt the same salt multiple times you would not get the same value. You can only decrypt the result to see if encryption succeeded.
Furthermore, you say you need a binary salt, but you first encode the salt to base64. It's unlikely that your encryption should contain an encoded salt. Maybe you need to encode the output of the encryption, not the salt.
The spurious encoding happens in the following line:
salt = Base64.encodeBase64String( key.getEncoded() );
Finally, although a new HMAC key generally consists of fully random bytes, I would say that it is not the right way to generate a salt. Instead just use:
SecureRandom rngForSalt = new SecureRandom();
byte[] salt = new byte[SALT_SIZE];
rngForSalt.nextBytes(salt);
Note too that the Bouncy Castle lightweight API (i.e. calling org.bouncycastle functionality directly) contains a PEM codec. No need to program or hack that yourself.
Try this Java 8 code. Bouncy castle provider classes required (no need to register the provider, this is just for the PEM handling).
package nl.maartenbodewes.stackoverflow;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.io.pem.PemWriter;
public class GenerateAndWrapHMACKey {
public static SecretKey generateHMACKey() throws Exception {
final KeyGenerator keyGen;
try {
keyGen = KeyGenerator.getInstance("HmacSHA256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("HMAC KeyGeneration should be available");
}
keyGen.init(128);
SecretKey key = keyGen.generateKey();
return key;
}
public static void writeToFile(SecretKey key, String filename)
throws IOException {
// file handling probably should be in a separate class
Files.write((new File(filename)).toPath(), key.getEncoded());
}
public static RSAPublicKey readRSAPublicKey(String filename) throws IOException, InvalidKeySpecException {
try (PemReader reader = new PemReader(new FileReader(filename))) {
PemObject pemObject = reader.readPemObject();
KeyFactory kf;
try {
kf = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("RSA key factory not available", e);
}
KeySpec keySpec = new X509EncodedKeySpec(pemObject.getContent());
try {
return (RSAPublicKey) kf.generatePublic(keySpec);
} catch (ClassCastException e) {
throw new InvalidKeySpecException("That's no RSA key", e);
}
}
}
public static byte[] wrapKey(Key key, RSAPublicKey wrappingKey) throws InvalidKeyException, IllegalBlockSizeException {
Cipher rsaWrapper;
try {
rsaWrapper = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
rsaWrapper.init(Cipher.WRAP_MODE, wrappingKey);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
throw new RuntimeException("RSA OAEP should be available for RSA public key", e);
}
return rsaWrapper.wrap(key);
}
public static void main(String[] args) throws Exception {
// we need an RSA PEM key first I guess :)
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024, new SecureRandom());
KeyPair kp = kpg.generateKeyPair();
String publicKeyFilename = "rsa_pub.pem";
try (PemWriter pemWriter = new PemWriter(new FileWriter(publicKeyFilename))) {
pemWriter.writeObject(new PemObject("PUBLIC KEY", kp.getPublic().getEncoded()));
}
RSAPublicKey wrappingRSAPublicKey = readRSAPublicKey(publicKeyFilename);
SecretKey hmacKey = generateHMACKey();
byte[] wrappedKey = wrapKey(hmacKey, wrappingRSAPublicKey);
System.out.println(Base64.getEncoder().encodeToString(wrappedKey));
}
}

3DES Encryption Oracle/JAVA equivalent

I'm trying to migrate the oracle method dbms_obfuscation_toolkit.DES3Encrypt to a Java Function. My problem is that I don't get the same encrypted value in both scenes.
For this procedure in Oracle:
set serveroutput on;
declare
input raw(128);
encrypted raw(2048);
cadena varchar2(60);
begin
dbms_obfuscation_toolkit.DES3Encrypt(
input => utl_raw.cast_to_raw('TESTDATATESTDATATESTDATA'),
key => utl_raw.cast_to_raw('GD6GTT56HKY4HGF6FH3JG9J5F62FT1'),
encrypted_data => encrypted
);
dbms_output.put_line(rawtohex(encrypted));
end;
I get this output:
8A2E6792E39B0C850377F9A0E054033963F979E4A3FBA25B
However, with this Java class:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
public class TripleDes2
{
private static final String PLAIN_TEXT = "TESTDATATESTDATATESTDATA";
private static final String SHARED_KEY = "GD6GTT56HKY4HGF6FH3JG9J5F62FT1";
public static void main(String args []) throws Exception
{
String algorithm = "DESede";
String transformation = "DESede/CBC/PKCS5Padding";
byte[] keyValue = SHARED_KEY.getBytes("UTF-8");
DESedeKeySpec keySpec = new DESedeKeySpec(keyValue);
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
SecretKey key = SecretKeyFactory.getInstance(algorithm).generateSecret(keySpec);
Cipher encrypter = Cipher.getInstance(transformation);
encrypter.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] input = PLAIN_TEXT.getBytes("UTF-8");
byte[] encrypted = encrypter.doFinal(input);
System.out.println(new String(Hex.encodeHex(encrypted)).toUpperCase());
}
}
I'm getting this value:
82EBC149F298DE55E4FF1540615E60ACDB7743FE79CD2CF4BB6FD232893F83D0
I'm not sure if my Java Code is right. Can you help me?
Thank you very much.
This is my final code, it works like a charm:
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
public class TripleDes3 {
private Cipher cipher = null;
private SecretKey key = null;
private byte[] bytes = null;
private IvParameterSpec iv = null;
public static void main(String[] args) throws Exception {
try {
String hexKey = "GD6GTT56HKY4HGF6FH3JG9J5";
//TripleDes3 encryptor = new TripleDes3(new String(Hex.decodeHex(hexKey.toCharArray())));
TripleDes3 encryptor = new TripleDes3(hexKey);
String original = "ABC";
System.out.println("Oringal: \"" + original + "\"");
String enc = encryptor.encrypt(original);
System.out.println("Encrypted: \"" + enc.toUpperCase() + "\"");
String dec = encryptor.decrypt(enc);
System.out.println("Decrypted: \"" + dec.toUpperCase() + "\"");
if (dec.equals(original)) {
System.out.println("Encryption ==> Decryption Successful");
}
} catch (Exception e) {
System.out.println("Error: " + e.toString());
}
}
public TripleDes3(String encryptionKey) throws GeneralSecurityException, DecoderException {
cipher = Cipher.getInstance("DESede/CBC/NoPadding");
try {
key = new SecretKeySpec(encryptionKey.getBytes("ISO8859_15"), "DESede");
iv = new IvParameterSpec(Hex.decodeHex("0123456789abcdef".toCharArray()));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String encrypt(String input) throws GeneralSecurityException, UnsupportedEncodingException {
bytes = input.getBytes("ISO8859_15");
bytes = Arrays.copyOf(bytes, ((bytes.length+7)/8)*8);
return new String(Hex.encodeHex(encryptB(bytes)));
}
public String decrypt(String input) throws GeneralSecurityException, DecoderException, UnsupportedEncodingException {
bytes = Hex.decodeHex(input.toCharArray());
String decrypted = new String(decryptB(bytes), "ISO8859_15");
if (decrypted.indexOf((char) 0) > 0) {
decrypted = decrypted.substring(0, decrypted.indexOf((char) 0));
}
return decrypted;
}
public byte[] encryptB(byte[] bytes) throws GeneralSecurityException {
cipher.init(Cipher.ENCRYPT_MODE, (Key) key, iv);
return cipher.doFinal(bytes);
}
public byte[] decryptB(byte[] bytes) throws GeneralSecurityException {
cipher.init(Cipher.DECRYPT_MODE, (Key) key, iv);
return cipher.doFinal(bytes);
}
}
And this is the Oracle Code:
DECLARE
v_data VARCHAR2(255);
v_retval RAW(255);
p_str VARCHAR2(255);
p_key RAW(255);
BEGIN
p_str := 'ABC';
p_key := utl_raw.cast_to_raw('GD6GTT56HKY4HGF6FH3JG9J5F62FT1');
v_data := RPAD(p_str, CEIL(LENGTH(p_str)/8)*8, CHR(0));
dbms_obfuscation_toolkit.DES3Encrypt
(
input => utl_raw.cast_to_raw(v_data),
key => p_key,
which => 1,
encrypted_data => v_retval
);
dbms_output.put_line(v_retval);
END;

Categories