Difference between these two HMAC excamples? - java

I have to calc HMAC signature to compare to the one from a message.
I come to two different results and do not understand the difference nor which one is correct.
I have even tested different online HMAC validators and get both version from different web sites.
the message: 7914073381342284::TestMerchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true
the key: 44782def547aaa06c910c43932b1eb0c71fc68d9d0c057550c48ec2acf6ba056
result 1: /b1O7eDkBtlZ3I1xH+qMl/I1aRBDel8Y4sbLZXnDKEI=
result 2: coqCmt/IZ4E3CzPvMY8zTjQVL5hYJUiBRg8UU+iCWo0=
I guess that result 2 is the correct one.
Java code calculating the first result:
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class HMAC {
static public byte[] calcHmacSha256(byte[] secretKey, byte[] message) {
byte[] hmacSha256 = null;
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "HmacSHA256");
mac.init(secretKeySpec);
hmacSha256 = mac.doFinal(message);
} catch (Exception e) {
throw new RuntimeException("Failed to calculate hmac-sha256", e);
}
return hmacSha256;
}
public static void main(String[] args) {
String message = "7914073381342284::TestMerchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true";
String key = "44782def547aaa06c910c43932b1eb0c71fc68d9d0c057550c48ec2acf6ba056";
try {
byte[] hmacSha256 = HMAC.calcHmacSha256(key.getBytes("UTF-8"), message.getBytes("UTF-8"));
//Output of HEX
System.out.println(String.format("Hex: %064x", new BigInteger(1, hmacSha256)));
System.out.println("Base64: " + Base64.getEncoder().encodeToString(hmacSha256));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
Java code comming to the second result
import java.nio.charset.StandardCharsets;
import java.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
public class HMACValidator {
public static void main(String[] args) throws IllegalArgumentException, SignatureException {
String message = "7914073381342284::TestMerchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true";
String key = "44782def547aaa06c910c43932b1eb0c71fc68d9d0c057550c48ec2acf6ba056";
HMACValidator demo = new HMACValidator();
String result = demo.calculateHMAC(message, key);
System.out.println(result);
}
public static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
// To calculate the HMAC SHA-256
public String calculateHMAC(String data, String key) throws IllegalArgumentException, SignatureException {
try {
if (data == null || key == null) {
throw new IllegalArgumentException();
}
byte[] rawKey = Hex.decodeHex(key.toCharArray());
// Create an hmac_sha256 key from the raw key bytes
SecretKeySpec signingKey = new SecretKeySpec(rawKey, HMAC_SHA256_ALGORITHM);
// Get an hmac_sha256 Mac instance and initialize with the signing ey
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
// Compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
// Base64-encode the hmac
return new String(Base64.encodeBase64(rawHmac));
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Missing data or key.");
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
}
}
Could someone please point me in the right direction?
Websites
https://www.devglan.com/online-tools/hmac-sha256-online is doing it "wrong"
https://cryptii.com/ is doing it "correct"

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.

How to use Java encrypt Json by HmacSHA256

I have such a Json :
{
"idcardno":"510525198803154232",
"name":"丁品"
}
If I use HmacSHA256 encrypt it with key
252c04cdb0d047f8ab9a1eb49b1db1686e321104756ff792779a4d40d94f0dfd70a8b9ffa6d6d930e57d0e7206d26d13
Then I should get such result:
cd1fe72697a832d57198b8c0d00289309dffe6f05750aa2a145f9359e41f1843
I need to encrypt this json object in java environemnt, so I use below java code to achieve this:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONObject;
public class EncryptUtil {
// Charset to use when encrypting a string.
private static final String UTF_8 = "UTF-8";
// Encrypt key
private static final String APP_SECRET = "252c04cdb0d047f8ab9a1eb49b1db1686e321104756ff792779a4d40d94f0dfd70a8b9ffa6d6d930e57d0e7206d";
public static void main(String[] args) throws Exception {
//build json object
JSONObject object = new JSONObject();
object.put("idcardno", "510525198803154232");
object.put("name", "丁品");
String result = enCode(object.toString());
//print encrpted result
System.out.println(result);
}
public static String enCode(String orginalMsg) throws Exception {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(APP_SECRET.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(orginalMsg.getBytes(UTF_8)));
return hash;
}
catch (Exception e){
throw new Exception(e);
}
}
}
But the encypted result is :
i2hF1WyxmS9MctkFLxBM2mgXeicraH9DhR9P9JySDFk=
How can get the correct result by Java code?

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.)

GPG decryptor doesn't work properly

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);

What is wrong with this code?

Thanx to evry one help me ..but still there is 2 problem after editing the code
import java.io.*;
import java.math.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RCC4 {
public RCC4(){}
public static void main(String[] args)throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException{
String test = "testisperfect";
System.out.println(RCC4.keyGet());
byte b[] = RCC4.keyGet().getBytes();
byte plain[] = test.getBytes();
**byte c[] = RCC4.encrypt(plain,b);**
**byte p[] = RCC4.decrypt(c,b);**
**System.out.println(new String(c)) ;
System.out.println(new String(p));**
}
public static byte[] encrypt(byte[] plaintext,byte[] keyBytes)
{
byte[] e = null;
try
{
Key key = new SecretKeySpec(keyBytes,"RC4");
Cipher enCipher = Cipher.getInstance("RC4");
**enCipher.init(Cipher.ENCRYPT_MODE ,key);**
e = enCipher.doFinal(plaintext);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return e;
}
public static byte[] decrypt(byte[] ciphertext,byte[] keyBytes)
{
byte de[] = null;
try
{
Key key = new SecretKeySpec(keyBytes,"RC4");
Cipher deCipher = Cipher.getInstance("RC4");
**deCipher.init(Cipher.DECRYPT_MODE, key);**
de = deCipher.doFinal(ciphertext);
}
catch(Exception e)
{
e.printStackTrace();
}
return de;
}
public static Key getKey()
{
Key key = null;
try
{
SecureRandom sr = new SecureRandom();
KeyGenerator kg = KeyGenerator.getInstance("RC4");
kg.init(128,sr);
key = kg.generateKey();
}catch(Exception e)
{
e.printStackTrace();
}
return key;
}
public static String keyGet()
{
Key k = RCC4.getKey();
byte[] b = k.getEncoded();
BigInteger big = new BigInteger(b);
String s = big.toString();
return s;
}
}
When I press "Build file" it says process completed but at running file a message says
112670544188765215715791498302542646231
java.security.InvalidKeyException: Illegal key size or default parameters
at RCC4.encrypt(RCC4.java:37)
at RCC4.main(RCC4.java:23)
java.security.InvalidKeyException: Illegal key size or default parameters
at RCC4.decrypt(RCC4.java:53)
at RCC4.main(RCC4.java:24)
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:479)
at RCC4.main(RCC4.java:26)
Process completed.
These Lines are indicated as *
Answer to original question:
Key key = new SecretKeySpec(byte[]keyBytes,RC4);
should be
Key key = new SecretKeySpec(keyBytes, "RC4");
Also,
deCipher.init(Cipher.WHATEVER, keyBytes);
should be
deCipher.init(Cipher.WHATEVER, key);
Then it compiles, however there's still some issue with the application logic. That's up to you again :).
Answer to new question:
The problem was the unneeded usage of SecretKeySpec. Somewhere between getKey(), keyGet() all the byte[] games and SecretKeySpec it got wrong somehow. I didn't have the patience to track it, so I just deleted it and made the code somewhat more readable to make sure I didn't miss anything. I think you will still understand it since it still is basically your code and it is much simpler now.
import java.security.*;
import javax.crypto.*;
public class RCC4 {
public static void main(String[] args) throws Exception {
String plain = "testisperfect";
Key key = RCC4.getKey();
String encrypted = RCC4.encrypt(plain, key);
String decrypted = RCC4.decrypt(encrypted, key);
System.out.println(encrypted);
System.out.println(decrypted);
}
private static String rc4(String plaintext, int mode, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(mode, key);
return new String(cipher.doFinal(plaintext.getBytes()));
}
public static String encrypt(String plaintext, Key key) throws Exception {
return rc4(plaintext, Cipher.ENCRYPT_MODE, key);
}
public static String decrypt(String ciphertext, Key key) throws Exception {
return rc4(ciphertext, Cipher.DECRYPT_MODE, key);
}
public static Key getKey() throws Exception {
KeyGenerator kg = KeyGenerator.getInstance("RC4");
SecureRandom sr = new SecureRandom();
kg.init(128, sr);
return kg.generateKey();
}
}
You need import SecretKeySpec which is under package javax.crypto.spec.
You're not calling the method correctly in that you're passing in the parameter type with the parameter. Parameter types are only shown when declaring a method, not when calling the method.
In other words, it's not
Key key = new SecretKeySpec(byte[] keyBytes, RC4);
it's instead
Key key = new SecretKeySpec(keyBytes, RC4);
You will of course need to have a keyBytes variable declared and initialized before trying to pass it into the parameter of this method.
package test;
import java.io.*;
import java.math.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RCC4 {
public RCC4() {
}
public static void main(String[] args) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IOException {
String test = "testisperfect";
System.out.println(RCC4.keyGet());
byte b[] = RCC4.keyGet().getBytes();
byte plain[] = test.getBytes();
byte c[] = RCC4.encrypt(plain, b);
byte p[] = RCC4.decrypt(c, b);
System.out.println(new String(c));
System.out.println(new String(p));
}
public static byte[] encrypt(byte[] plaintext, byte[] keyBytes) {
byte[] e = null;
try {
Key key = new SecretKeySpec(keyBytes, "RC4");
Cipher enCipher = Cipher.getInstance("RC4");
enCipher.init(Cipher.ENCRYPT_MODE, key);
e = enCipher.doFinal(plaintext);
} catch (Exception ex) {
ex.printStackTrace();
}
return e;
}
public static byte[] decrypt(byte[] ciphertext, byte[] keyBytes) {
byte de[] = null;
try {
Key key = new SecretKeySpec(keyBytes, "RC4");
Cipher deCipher = Cipher.getInstance("RC4");
deCipher.init(Cipher.DECRYPT_MODE, RCC4.getKey());
de = deCipher.doFinal(ciphertext);
} catch (Exception e) {
e.printStackTrace();
}
return de;
}
public static Key getKey() {
Key key = null;
try {
SecureRandom sr = new SecureRandom();
KeyGenerator kg = KeyGenerator.getInstance("RC4");
kg.init(128, sr);
key = kg.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
return key;
}
public static String keyGet() {
Key k = RCC4.getKey();
byte[] b = k.getEncoded();
BigInteger big = new BigInteger(b);
String s = big.toString();
return s;
}
}

Categories