I'm pretty familiar with PGP, and the way it works. I'd like to include some functionality in a project, but so far my research has left my head spinning. What I'd like to do is create a public key with a defined private pass phrase. From there, I'd share the public key with someone where they can then encrypt a message using the key and return it to me where I can decrypt. I envision the code looking something like this.
To generate my private pgp key:
PGPKey key = new PGPKey();
key.setPassPhrase("MySecretPassword!!!1");
key.generateRandomSharedKey();
key.build();
To encrypt I'd give my shared key to a friend:
String encryptedText = PGPTools.Encrypt("Text to encrypt", getSharedKey());
To decrypt the encrypted string after being sent back to me:
String decryptedText = PGPTools.Decrypt(encryptedText, key, "MySecretPassword!!!1")
Obviously I know I'm skipping out on a ton of details. Through my research I've seen references to libraries like Bouncy Castle and Spongy Castle. Any help would be hugely appreciated!
I want to post my solution because A. it was extremely difficult to get this working, and B. If any crypto pro's want to audit my code I'd be eternally grateful.
I included the 4 following libraries:
compile 'com.madgag.spongycastle:core:1.50.0.0'
compile 'com.madgag.spongycastle:pg:1.50.0.0'
compile 'com.madgag.spongycastle:pkix:1.50.0.0'
compile 'com.madgag.spongycastle:prov:1.50.0.0'
Bouncy Castle needs to be added as a security provider. I included this code in a class that initializes some other objects when the app loads.
static {
Security.addProvider(new BouncyCastleProvider());
}
Here's the utils class I created that really contains the nuts and bolts. Edited slightly:
import com.example.Device;
import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.crypto.generators.RSAKeyPairGenerator;
import org.spongycastle.crypto.params.RSAKeyGenerationParameters;
import org.spongycastle.openpgp.PGPCompressedData;
import org.spongycastle.openpgp.PGPCompressedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedDataList;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyPair;
import org.spongycastle.openpgp.PGPKeyRingGenerator;
import org.spongycastle.openpgp.PGPLiteralData;
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyEncryptorBuilder;
import org.spongycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.spongycastle.openpgp.operator.bc.BcPGPKeyPair;
import org.spongycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Iterator;
public class PgpUtils {
private static final String PROVIDER = "SC";
private static final String KEY_RING_ID = "asdf#asdf.com";
public static String decrypt(String encryptedText, String password) throws Exception {
byte[] encrypted = encryptedText.getBytes();
InputStream in = new ByteArrayInputStream(encrypted);
in = PGPUtil.getDecoderStream(in);
PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
while (sKey == null && enc.getEncryptedDataObjects().hasNext()) {
pbe = (PGPPublicKeyEncryptedData)enc.getEncryptedDataObjects().next();
sKey = getPrivateKey(getPGPSecretKeyRing(), pbe.getKeyID(), password.toCharArray());
}
if (pbe != null) {
InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
PGPObjectFactory pgpFact = new PGPObjectFactory(clear);
PGPCompressedData cData = (PGPCompressedData) pgpFact.nextObject();
pgpFact = new PGPObjectFactory(cData.getDataStream());
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
InputStream unc = ld.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int ch;
while ((ch = unc.read()) >= 0) {
out.write(ch);
}
byte[] returnBytes = out.toByteArray();
out.close();
return new String(returnBytes);
}
return null;
}
private static PGPPublicKey getPublicKey(PGPPublicKeyRing publicKeyRing) {
Iterator<?> kIt = publicKeyRing.getPublicKeys();
while (kIt.hasNext()) {
PGPPublicKey k = (PGPPublicKey) kIt.next();
if (k.isEncryptionKey()) {
return k;
}
}
return null;
}
private static PGPPrivateKey getPrivateKey(PGPSecretKeyRing keyRing, long keyID, char[] pass) throws PGPException {
PGPSecretKey secretKey = keyRing.getSecretKey(keyID);
PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass);
return secretKey.extractPrivateKey(decryptor);
}
public static String encrypt(String msgText) throws IOException, PGPException {
byte[] clearData = msgText.getBytes();
PGPPublicKey encKey = getPublicKey(getPGPPublicKeyRing());
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
OutputStream out = new ArmoredOutputStream(encOut);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.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);
lData.close();
comData.close();
PGPEncryptedDataGenerator encGen =
new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom(
new SecureRandom()).setProvider(PROVIDER));
if (encKey != null) {
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider(PROVIDER));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = encGen.open(out, bytes.length);
cOut.write(bytes);
cOut.close();
}
out.close();
return new String(encOut.toByteArray());
}
public final static PGPKeyRingGenerator generateKeyRingGenerator (char[] pass) throws PGPException{
RSAKeyPairGenerator kpg = new RSAKeyPairGenerator();
kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x10001), new SecureRandom(), 2048, 12));
PGPKeyPair rsakp_sign = new BcPGPKeyPair(PGPPublicKey.RSA_SIGN, kpg.generateKeyPair(), new Date());
PGPKeyPair rsakp_enc = new BcPGPKeyPair(PGPPublicKey.RSA_ENCRYPT, kpg.generateKeyPair(), new Date());
PGPSignatureSubpacketGenerator signhashgen = new PGPSignatureSubpacketGenerator();
signhashgen.setKeyFlags(false, KeyFlags.SIGN_DATA|KeyFlags.CERTIFY_OTHER|KeyFlags.SHARED);
signhashgen.setPreferredSymmetricAlgorithms(false, new int[]{SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, SymmetricKeyAlgorithmTags.AES_128});
signhashgen.setPreferredHashAlgorithms(false, new int[]{HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, HashAlgorithmTags.SHA224});
signhashgen.setFeature(false, Features.FEATURE_MODIFICATION_DETECTION);
PGPSignatureSubpacketGenerator enchashgen = new PGPSignatureSubpacketGenerator();
enchashgen.setKeyFlags(false, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE);
PGPDigestCalculator sha1Calc = new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1);
PGPDigestCalculator sha256Calc = new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA256);
PBESecretKeyEncryptor pske = (new BcPBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha256Calc, 0xc0)).build(pass);
PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator (PGPSignature.POSITIVE_CERTIFICATION, rsakp_sign,
KEY_RING_ID, sha1Calc, signhashgen.generate(), null, new BcPGPContentSignerBuilder(rsakp_sign.getPublicKey().getAlgorithm(),
HashAlgorithmTags.SHA1), pske);
keyRingGen.addSubKey(rsakp_enc, enchashgen.generate(), null);
return keyRingGen;
}
private static PGPPublicKeyRing getPGPPublicKeyRing() throws IOException {
ArmoredInputStream ais = new ArmoredInputStream(new ByteArrayInputStream(Device.getDevice().getPgpPublicKey().getBytes()));
return (PGPPublicKeyRing) new PGPObjectFactory(ais).nextObject();
}
private static PGPSecretKeyRing getPGPSecretKeyRing() throws IOException {
ArmoredInputStream ais = new ArmoredInputStream(new ByteArrayInputStream(Device.getDevice().getPgpSecretKey().getBytes()));
return (PGPSecretKeyRing) new PGPObjectFactory(ais).nextObject();
}
public final static String genPGPPublicKey (PGPKeyRingGenerator krgen) throws IOException {
ByteArrayOutputStream baosPkr = new ByteArrayOutputStream();
PGPPublicKeyRing pkr = krgen.generatePublicKeyRing();
ArmoredOutputStream armoredStreamPkr = new ArmoredOutputStream(baosPkr);
pkr.encode(armoredStreamPkr);
armoredStreamPkr.close();
return new String(baosPkr.toByteArray(), Charset.defaultCharset());
}
public final static String genPGPPrivKey (PGPKeyRingGenerator krgen) throws IOException {
ByteArrayOutputStream baosPriv = new ByteArrayOutputStream ();
PGPSecretKeyRing skr = krgen.generateSecretKeyRing();
ArmoredOutputStream armoredStreamPriv = new ArmoredOutputStream(baosPriv);
skr.encode(armoredStreamPriv);
armoredStreamPriv.close();
return new String(baosPriv.toByteArray(), Charset.defaultCharset());
}
}
Here is how I create the private and public keys:
final PGPKeyRingGenerator krgen = PgpUtils.generateKeyRingGenerator("password".toCharArray());
String pgpPublicKey = PgpUtils.genPGPPublicKey(krgen);
String pgpSecretKey = PgpUtils.genPGPPrivKey(krgen);
And finally encrypting and decrypting using your own public key:
String encrypted = PgpUtils.encrypt("message text");
String decrypted = PgpUtils.decrypt(encrypted, "Password");
I don't have enough rep to comment on joey_g216 excellent answer above. Initially it worked for me, but then failed on decrypting various files. This is because the structure of a PGPObject can change.
To get decryption to work I had to adjust:
public static String decrypt(String encryptedText, String password) throws Exception {
to include:
// Could be
// signature + compressed -> data
// signature + data
// data
// compressed -> data
Object z = pgpFact.nextObject();
while (!(z instanceof PGPLiteralData))
{
if (z instanceof PGPCompressedData) {
PGPCompressedData cData = (PGPCompressedData) z;
pgpFact = new PGPObjectFactory(cData.getDataStream(), bcKeyFingerprintCalculator);
}
if (z instanceof PGPOnePassSignatureList) {
// ignore for now!
}
z = pgpFact.nextObject();
}
PGPLiteralData ld = (PGPLiteralData) z;
Looks like you want to generate a public key pair using BouncyCastle?
This one asks how to do it without a password, but you can take a look how to do it with a password too:
How to generate OpenPGP KeyPair without passphrase using BouncyCastle?
Related
I was given a task to build a java method to encrypt data (String or InputStream) using PGP. I have generated a test public key, private key with passphrase following the guide here. I then exported the public key using the command below and copy and pasted it to my java code.
gpg --armor --output pubkey.txt --export 'Your Name'
I am able to encrypt a file using the command below
gpg --encrypt --armor -r 'Your Name' plaintext.txt
And I get the below content which is what I'm trying to achieve in my java program. I might need to sign it later as part of the requirement but all I want to do for now is to be able to successfully encrypt it like this.
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.22 (GNU/Linux)
hQEMA0PxXau0Q30VAQf/RuWsN3f4L2HW2GJWOZUjetJsw0odXYbDc7Sug1gZULP8
I0KRrvxnHgiiJgSlBZsws8E8iB1/LDCYJ8oJGj6olicz83iUT8VLdzdJZlc0+96/
BHAvtSTtEv2PWZlh307nU+Zn9cuGAccaijyekCosS5/0JpDyXSFefsLTexMgphAL
veXsxtsISyUU6S0xUux6Ac9HgUWTpCrlNaSdqBN1bk7y8YuvbZgbQ5akwY5FEbq1
f9rxmgXgEgz3N+7f8n5yN2OvWiEyXb+qngVgDLzysD8NTtKDqtw5nViscvVF1h3v
AebdxYxOKGYnWk6XAWhpIgIZdY0ZXG0yu9NJH5VfLtJSAc3c6d2/Nhb7g+k+f2Mn
srZW6XzHCeyGQQqSfr5YJfyUVdsW12udmhnc+ErbRkz84oDkMvFaxes6+2AAKrP/
jdWXsp4fTPl454m+tG5ec/Kn0Q==
=cZH2
-----END PGP MESSAGE-----
The java method I need to build accepts a Public Key as a String parameter where I then use the following method to convert it to a PGPPublicKey.
private static PGPPublicKey getPublicKey(String keyAscii) throws IOException, PGPException, Exception {
InputStream encodedKey = new ByteArrayInputStream(keyAscii.getBytes());
InputStream decodedKey = PGPUtil.getDecoderStream(encodedKey);
JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(decodedKey);
decodedKey.close();
PGPPublicKey key = null;
Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext()) {
PGPPublicKeyRing kRing = rIt.next();
Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext()) {
PGPPublicKey k = kIt.next();
if (k.isEncryptionKey()) {
key = k;
}
}
}
if (key == null) {
throw new Exception("Can't find key");
}
return key;
}
However, when I run the java program, I get an error "exception constructing public key" on the following line of code.
OutputStream cOut = encGen.open(encOut, new byte[4096]);
Complete error below
org.bouncycastle.openpgp.PGPException: exception constructing public key
at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPublicKey(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator.encryptSessionInfo(Unknown Source)
at org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator.generate(Unknown Source)
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at pgp.PgpImpl.encrypt(PgpImpl.java:84)
at pgp.PgpImpl.main(PgpImpl.java:216)
Caused by: java.security.NoSuchProviderException: no such provider: BC
at sun.security.jca.GetInstance.getService(GetInstance.java:83)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
at java.security.KeyFactory.getInstance(KeyFactory.java:211)
at org.bouncycastle.jcajce.util.NamedJcaJceHelper.createKeyFactory(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.OperatorHelper.createKeyFactory(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.implGeneratePublic(Unknown Source)
... 7 more
I followed the sample here but it didn't provide any information on how to construct the publickey coming from a String.
Here's my code so far.
package pgp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Iterator;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
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.PGPUtil;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection;
public class PgpImpl {
public PgpImpl() {
}
private static String encrypt(byte[] data, PGPPublicKey encryptionKey) throws Exception {
String step = "Step-0";
try {
step = "Step-1";
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider("BC"));
step = "Step-2";
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey)
.setSecureRandom(new SecureRandom()).setProvider("BC"));
step = "Step-3";
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
step = "Step-4";
// create an indefinite length encrypted stream
OutputStream cOut = encGen.open(encOut, new byte[4096]);
step = "Step-5";
// write out the literal data
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length,
new Date());
pOut.write(data);
pOut.close();
// finish the encryption
cOut.close();
step = "Step-6";
return new String(encOut.toByteArray());
} catch (Exception e) {
//throw new Exception(String.format("%s: %s", e.getMessage(), step));
e.printStackTrace();
}
return new String(step);
}
private static PGPPublicKey getPublicKey(String keyAscii) throws IOException, PGPException, Exception {
InputStream encodedKey = new ByteArrayInputStream(keyAscii.getBytes());
InputStream decodedKey = PGPUtil.getDecoderStream(encodedKey);
JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(decodedKey);
decodedKey.close();
PGPPublicKey key = null;
Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext()) {
PGPPublicKeyRing kRing = rIt.next();
Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext()) {
PGPPublicKey k = kIt.next();
if (k.isEncryptionKey()) {
key = k;
}
}
}
if (key == null) {
throw new Exception("Can't find key");
}
return key;
}
public static void main(String[] args) {
String publicKey = "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n" + "Version: GnuPG v2.0.22 (GNU/Linux)\r\n"
+ "\r\n" + "mQENBGA1A70BCADK8BnH6GgMbnS1TJSpJvgH+D9VIw0sN8XZWQsUmWWV9WSqhqXt\r\n"
+ "5wNC4XJDcaWtMCapaekQXV5S52T7QCxAz/E5oZzIDe+IUCHQz0WUs37S4Wnw+SZ6\r\n"
+ "QNPXOFaC4nNByRq6gvg0+wtD2Bo/3OJur3f0O0aRSHNiwfd0PdFgG0NU5vGV9PwE\r\n"
+ "xbTMpGssWexIC0MwJaYfJkxzov33CkwLaITvBTCn/J3oeX6JarMkgpurp1FAW0Jk\r\n"
+ "YzgGMOOxwuEVedwP4NtEPce+UtLv2NHHfqsW6xSxjWqsJkMdJ9afzu1jvn9M6e0j\r\n"
+ "MOTmPUCYVCioXK59It8ngN8NLtwaPgfnBwcbABEBAAG0BWFsbGVuiQE5BBMBAgAj\r\n"
+ "BQJgNQO9AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQxzGJxIrjAlxq\r\n"
+ "aggAgoiO82MZZMHyhZ3uLD4qTQ2vsT6+onhCr83kw0eFNM5AH0r3xlVARXHaViWC\r\n"
+ "SFutpb/34lrCTpJfLfKwdFU2bJP2SI3hAujtTg45UFklswu6GZaqQno6JKkZM4hw\r\n"
+ "ltFIXU1dMpIud7nsJ2QU46TI97n+HeD7DvOSGY/CFPnNot0YFHxXCKtHdPHk8JO3\r\n"
+ "JdOG0X90Yi9XSI1USv8HL/WjOTvhSqo7Qps2MpcUZrfNsa0H9Adk9xVYiz0nKNPY\r\n"
+ "qLQxFAiHb34vdav4e28anJ8th93SfiRn5OFK2G6R3DlhLlvn3h1dSAT6vSOrzx80\r\n"
+ "EylyMg2BIbRfp+JEgwCMf2V8X7kBDQRgNQO9AQgA3qV0wYvdH5M4XBzVwDtuGuIs\r\n"
+ "+GRcSRQqmvnt94e8ZE4Kv2w2Pf/JxPMwnPC92lVRypdOjmTZrT3R0z7g+D8mU5A9\r\n"
+ "o/CPvvSShA8Jh3z69S+hLP0nSaajsVsQlBGrI8ehI1EVJDsNh15PZrl27OK0aBb4\r\n"
+ "Fp0BYm0D2HaLnQPD4/jhTR13i1mt5E5hmBwiZiiWr/Wa1i1g1o/XaT4CApu91zgg\r\n"
+ "cmJBz9DL/C2hYC5lkp/cz5IJYp5BsvfA2lwamca33aHxFj8+Bz3+REWa8zvEqQ9U\r\n"
+ "a26RbPVjkeGChwNWLxNTuj1rNDdqB/KZO6iM02orqW86L45SKTBWYqPcpD7GeQAR\r\n"
+ "AQABiQEfBBgBAgAJBQJgNQO9AhsMAAoJEMcxicSK4wJcOLEIAMevvOk9iZ13T3yA\r\n"
+ "+ZW8mWKKE5aXy93VPKAvplP/WlW2VVGeb+6rEkFFsdN4doYIJPEIr+U7K0GDR6XX\r\n"
+ "TKLyI7BtUZPegOdjgcFWVGFnFogDnkrO+IPY+JUy1VMg8fGStThfa2dYEgd7yqpq\r\n"
+ "fZ97q5RQun1B+wyRdPDgC39roSGEwtXbRCZnuSMVNT7J9a2qnXkenvQRSoPjY7wQ\r\n"
+ "tn1wUfnHyjyS9OzfXTSHDi2A5JDRCh5L/V7Q93/P5Isv/U4QzIWudGM6AjuaoZ6i\r\n"
+ "chksRI9EchNKnSut9ebTyTkIJ80sB7Eyfp8TtORAnz8/Xf8A8aYD73r9rD4poSmo\r\n" + "FV15pP8=\r\n" + "=Yc74\r\n"
+ "-----END PGP PUBLIC KEY BLOCK-----";
try {
PGPPublicKey key = getPublicKey(publicKey);
System.out.println(encrypt("Test".getBytes(), key));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (PGPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Appreciate any help.
UPDATE #1: After getting the stacktrace, I found out that the error is due to an invalid provider which I then change using
BouncyCastleProvider provider = new BouncyCastleProvider();
So I had to change all reference to the provider.
private static String encrypt(byte[] data, PGPPublicKey encryptionKey) {
BouncyCastleProvider provider = new BouncyCastleProvider();
String step = "Step-0";
try {
step = "Step-1";
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider(provider));
step = "Step-2";
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey)
.setSecureRandom(new SecureRandom()).setProvider(provider));
step = "Step-3";
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
step = "Step-4";
// create an indefinite length encrypted stream
OutputStream cOut = encGen.open(encOut, new byte[1 << 16]);
step = "Step-5";
// write out the literal data
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length,
new Date());
pOut.write(data);
pOut.close();
// finish the encryption
cOut.close();
step = "Step-6";
return new String(encOut.toByteArray());
} catch (Exception e) {
//throw new Exception(String.format("%s: %s", e.getMessage(), step));
e.printStackTrace();
}
return new String("");
}
But now I'm getting a different error.
org.bouncycastle.openpgp.PGPException: Exception creating cipher
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at pgp.PgpImpl.encrypt(PgpImpl.java:85)
at pgp.PgpImpl.main(PgpImpl.java:217)
Caused by: org.bouncycastle.openpgp.PGPException: invalid key: Illegal key size
at org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder$MyPGPDataEncryptor.<init>(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder.build(Unknown Source)
... 4 more
Caused by: java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1034)
at javax.crypto.Cipher.init(Cipher.java:1367)
at javax.crypto.Cipher.init(Cipher.java:1301)
... 6 more
UPDATE#2: Did a bit of research and came across this. Followed the instructions there and got everything working.
Your modified code works for me: (I have taken out the exception handling, but that should make no difference)
package pgp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Iterator;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
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.PGPUtil;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection;
public class PgpImpl {
public PgpImpl() {
}
private static String encrypt(byte[] data, PGPPublicKey encryptionKey) throws PGPException, IOException {
BouncyCastleProvider provider = new BouncyCastleProvider();
String step = "Step-0";
step = "Step-1";
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider(provider));
step = "Step-2";
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey)
.setSecureRandom(new SecureRandom()).setProvider(provider));
step = "Step-3";
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
step = "Step-4";
// create an indefinite length encrypted stream
OutputStream cOut = encGen.open(encOut, new byte[1 << 16]);
step = "Step-5";
// write out the literal data
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length,
new Date());
pOut.write(data);
pOut.close();
// finish the encryption
cOut.close();
step = "Step-6";
return new String(encOut.toByteArray());
}
private static PGPPublicKey getPublicKey(String keyAscii) throws IOException, PGPException, Exception {
InputStream encodedKey = new ByteArrayInputStream(keyAscii.getBytes());
InputStream decodedKey = PGPUtil.getDecoderStream(encodedKey);
JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(decodedKey);
decodedKey.close();
PGPPublicKey key = null;
Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext()) {
PGPPublicKeyRing kRing = rIt.next();
Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext()) {
PGPPublicKey k = kIt.next();
if (k.isEncryptionKey()) {
key = k;
}
}
}
if (key == null) {
throw new Exception("Can't find key");
}
return key;
}
public static void main(String[] args) throws Exception {
String publicKey = "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n" + "Version: GnuPG v2.0.22 (GNU/Linux)\r\n"
+ "\r\n" + "mQENBGA1A70BCADK8BnH6GgMbnS1TJSpJvgH+D9VIw0sN8XZWQsUmWWV9WSqhqXt\r\n"
+ "5wNC4XJDcaWtMCapaekQXV5S52T7QCxAz/E5oZzIDe+IUCHQz0WUs37S4Wnw+SZ6\r\n"
+ "QNPXOFaC4nNByRq6gvg0+wtD2Bo/3OJur3f0O0aRSHNiwfd0PdFgG0NU5vGV9PwE\r\n"
+ "xbTMpGssWexIC0MwJaYfJkxzov33CkwLaITvBTCn/J3oeX6JarMkgpurp1FAW0Jk\r\n"
+ "YzgGMOOxwuEVedwP4NtEPce+UtLv2NHHfqsW6xSxjWqsJkMdJ9afzu1jvn9M6e0j\r\n"
+ "MOTmPUCYVCioXK59It8ngN8NLtwaPgfnBwcbABEBAAG0BWFsbGVuiQE5BBMBAgAj\r\n"
+ "BQJgNQO9AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQxzGJxIrjAlxq\r\n"
+ "aggAgoiO82MZZMHyhZ3uLD4qTQ2vsT6+onhCr83kw0eFNM5AH0r3xlVARXHaViWC\r\n"
+ "SFutpb/34lrCTpJfLfKwdFU2bJP2SI3hAujtTg45UFklswu6GZaqQno6JKkZM4hw\r\n"
+ "ltFIXU1dMpIud7nsJ2QU46TI97n+HeD7DvOSGY/CFPnNot0YFHxXCKtHdPHk8JO3\r\n"
+ "JdOG0X90Yi9XSI1USv8HL/WjOTvhSqo7Qps2MpcUZrfNsa0H9Adk9xVYiz0nKNPY\r\n"
+ "qLQxFAiHb34vdav4e28anJ8th93SfiRn5OFK2G6R3DlhLlvn3h1dSAT6vSOrzx80\r\n"
+ "EylyMg2BIbRfp+JEgwCMf2V8X7kBDQRgNQO9AQgA3qV0wYvdH5M4XBzVwDtuGuIs\r\n"
+ "+GRcSRQqmvnt94e8ZE4Kv2w2Pf/JxPMwnPC92lVRypdOjmTZrT3R0z7g+D8mU5A9\r\n"
+ "o/CPvvSShA8Jh3z69S+hLP0nSaajsVsQlBGrI8ehI1EVJDsNh15PZrl27OK0aBb4\r\n"
+ "Fp0BYm0D2HaLnQPD4/jhTR13i1mt5E5hmBwiZiiWr/Wa1i1g1o/XaT4CApu91zgg\r\n"
+ "cmJBz9DL/C2hYC5lkp/cz5IJYp5BsvfA2lwamca33aHxFj8+Bz3+REWa8zvEqQ9U\r\n"
+ "a26RbPVjkeGChwNWLxNTuj1rNDdqB/KZO6iM02orqW86L45SKTBWYqPcpD7GeQAR\r\n"
+ "AQABiQEfBBgBAgAJBQJgNQO9AhsMAAoJEMcxicSK4wJcOLEIAMevvOk9iZ13T3yA\r\n"
+ "+ZW8mWKKE5aXy93VPKAvplP/WlW2VVGeb+6rEkFFsdN4doYIJPEIr+U7K0GDR6XX\r\n"
+ "TKLyI7BtUZPegOdjgcFWVGFnFogDnkrO+IPY+JUy1VMg8fGStThfa2dYEgd7yqpq\r\n"
+ "fZ97q5RQun1B+wyRdPDgC39roSGEwtXbRCZnuSMVNT7J9a2qnXkenvQRSoPjY7wQ\r\n"
+ "tn1wUfnHyjyS9OzfXTSHDi2A5JDRCh5L/V7Q93/P5Isv/U4QzIWudGM6AjuaoZ6i\r\n"
+ "chksRI9EchNKnSut9ebTyTkIJ80sB7Eyfp8TtORAnz8/Xf8A8aYD73r9rD4poSmo\r\n" + "FV15pP8=\r\n" +
"=Yc74\r\n"
+ "-----END PGP PUBLIC KEY BLOCK-----";
PGPPublicKey key = getPublicKey(publicKey);
System.out.println(encrypt("Test".getBytes(), key));
}
}
My pom.xml has:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
Can you run that code and see what happens locally?
I want to exactly build a function which produces a HMAC with a secret key like this site provides:
http://www.freeformatter.com/hmac-generator.html
The Java 8 lib only provides MessageDigest and KeyGenerator which both only support up to SH256.
Also, Google doesn't give me any result for an implementation to generate a HMAC.
Does someone know a implementation?
I have this code to generate an ordinary SH256 but I guess this doesn't help me much:
public static String get_SHA_512_SecurePassword(String passwordToHash) throws Exception {
String generatedPassword = null;
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] bytes = md.digest(passwordToHash.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
System.out.println(generatedPassword);
return generatedPassword;
}
The simplest way can be -
private static final String HMAC_SHA512 = "HmacSHA512";
private static String toHexString(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
return formatter.toString();
}
public static String calculateHMAC(String data, String key)
throws SignatureException, NoSuchAlgorithmException, InvalidKeyException
{
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), HMAC_SHA512);
Mac mac = Mac.getInstance(HMAC_SHA512);
mac.init(secretKeySpec);
return toHexString(mac.doFinal(data.getBytes()));
}
public static void main(String[] args) throws Exception {
String hmac = calculateHMAC("data", "key");
System.out.println(hmac);
}
You can change the HMAC_SHA512 variable to any of the Mac algorithm and the code will work the same way.
Hope this helps:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Test1 {
private static final String HMAC_SHA512 = "HmacSHA512";
public static void main(String[] args) {
Mac sha512Hmac;
String result;
final String key = "Welcome1";
try {
final byte[] byteKey = key.getBytes(StandardCharsets.UTF_8);
sha512Hmac = Mac.getInstance(HMAC_SHA512);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA512);
sha512Hmac.init(keySpec);
byte[] macData = sha512Hmac.doFinal("My message".getBytes(StandardCharsets.UTF_8));
// Can either base64 encode or put it right into hex
result = Base64.getEncoder().encodeToString(macData);
//result = bytesToHex(macData);
} catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
} finally {
// Put any cleanup here
System.out.println("Done");
}
}
}
For converting from byte array to hex refer this stackoverflow answer : here
Also you can use a little wrapper by Apache Commons codec:
import static org.apache.commons.codec.digest.HmacAlgorithms.HMAC_SHA_512;
import org.apache.commons.codec.digest.HmacUtils;
public class HmacService {
private String sharedSecret;
public HmacService(String sharedSecret) {
this.sharedSecret = sharedSecret;
}
public String calculateHmac(String data) {
return new HmacUtils(HMAC_SHA_512, sharedSecret).hmacHex(data);
}
public boolean checkHmac(String data, String hmacHex) {
return calculateHmac(data).equals(hmacHex);
}
}
You could use Caesar (version 0.6.0 or later):
int blockSize = 128;
String secretKey = "My secret key";
String message = "Message to hash";
System.out.println(
new Hmac(
new ImmutableMessageDigest(
MessageDigest.getInstance("SHA-512")
),
blockSize,
new PlainText(secretKey),
new PlainText(message)
).asHexString()
);
I have an existing PGP v 1.46 code in maintenance project. now I need to update to 1.56 and it's not working. a lot of classes and methods are changed. I have no idea about PGP.
Here is a sample demo of the exact code.
plugins {
id 'java'
}
group 'com.encryptor.pgp'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
compile fileTree(dir: 'src/main/resources/libs', include: '*.jar')
compile group: 'org.bouncycastle', name: 'bcpg-jdk15on', version: '1.46'
compile group: 'org.bouncycastle', name: 'bcprov-ext-jdk15on', version: '1.46'
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.46'
}
when i update from 1.46 to 1.56, it gives error.
processor
package com.encryptor.pgp;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class PGPFileProcessor {
private String encryptFile;
private String decryptFile;
private String passphrase;
private String publicKeyFile;
private String privateKeyFile;
private String plainTextFile;
private boolean asciiArmored = false;
private boolean integrityCheck = true;
public PGPFileProcessor() {
}
public void setPublicKeyFile(String publicKeyFile) {
this.publicKeyFile = publicKeyFile;
}
public void setPrivateKeyFile(String privateKeyFile) {
this.privateKeyFile = privateKeyFile;
}
public void setEncryptFile(String encryptFile) {
this.encryptFile = encryptFile;
}
public void setDecryptFile(String decryptFile) {
this.decryptFile = decryptFile;
}
public void setPassphrase(String passphrase) {
this.passphrase = passphrase;
}
public void setPlainTextFile(String plainTextFile) {
this.plainTextFile = plainTextFile;
}
public void setAsciiArmored(boolean asciiArmored) {
this.asciiArmored = asciiArmored;
}
public void setIntegrityCheck(boolean integrityCheck) {
this.integrityCheck = integrityCheck;
}
public boolean encrypt() throws Exception {
FileInputStream keyIn = new FileInputStream(publicKeyFile);
FileOutputStream out = new FileOutputStream(encryptFile, true);
PGPUtil.encryptFile(out, plainTextFile, PGPUtil.readPublicKey(keyIn), asciiArmored, integrityCheck);
out.close();
keyIn.close();
return true;
}
public boolean decrypt() throws Exception {
FileInputStream in = new FileInputStream(encryptFile);
FileInputStream keyIn = new FileInputStream(privateKeyFile);
FileOutputStream out = new FileOutputStream(decryptFile);
PGPUtil.decryptFile(in, out, keyIn, passphrase.toCharArray());
in.close();
out.close();
keyIn.close();
return true;
}
}
Main Class
package com.encryptor.pgp;
public class PGPMain {
public static void main(String[] args) throws Exception {
PGPFileProcessor pgpFileProcessor = new PGPFileProcessor();
pgpFileProcessor.setEncryptFile("enc.txt"); pgpFileProcessor.setDecryptFile("dec.txt");
pgpFileProcessor.setPassphrase("pgpencr");
pgpFileProcessor.setInputFile("plain.txt");
private boolean asciiArmored = false;
pgpFileProcessor.setPublicKeyFile("publickey.key");
pgpFileProcessor.setPrivateKeyFile("pivatekey.key");
pgpFileProcessor.encrypt();*/
pgpFileProcessor.encrypt();
pgpFileProcessor.decrypt();
}
}
Util
package com.encryptor.pgp;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import java.io.*;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;
public class PGPUtil {
#SuppressWarnings("unchecked")
public static PGPPublicKey readPublicKey(InputStream in) throws IOException, PGPException {
in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in);
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in);/* we just loop through the collection till we find a key suitable for encryption, in the real world you would probably want to be a bit smarter about this. */
PGPPublicKey key = null;/* iterate through the key rings. */
Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext()) {
PGPPublicKeyRing kRing = rIt.next();
Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext()) {
PGPPublicKey k = kIt.next();
if (k.isEncryptionKey()) key = k;
}
}
if (key == null) throw new IllegalArgumentException("Can't find encryption key in key ring.");
return key;
}
private static PGPPrivateKey findSecretKey(InputStream keyIn, long keyID, char[] pass) throws IOException, PGPException, NoSuchProviderException {
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(org.bouncycastle.openpgp.PGPUtil.getDecoderStream(keyIn));
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) return null;
return pgpSecKey.extractPrivateKey(pass, "BC");
}
#SuppressWarnings("unchecked")
public static void decryptFile(InputStream in, OutputStream out, InputStream keyIn, char[] passwd) throws Exception {
Security.addProvider(new BouncyCastleProvider());
in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in);
PGPObjectFactory pgpF = new PGPObjectFactory(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<PGPPublicKeyEncryptedData> it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
while (sKey == null && it.hasNext()) {
pbe = it.next();
sKey = findSecretKey(keyIn, pbe.getKeyID(), passwd);
}
if (sKey == null) throw new IllegalArgumentException("Secret key for message not found.");
InputStream clear = pbe.getDataStream(sKey, "BC");
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
Object message = plainFact.nextObject();
if (message instanceof PGPCompressedData) {
PGPCompressedData cData = (PGPCompressedData) message;
PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream());
message = pgpFact.nextObject();
}
if (message instanceof PGPLiteralData) {
PGPLiteralData ld = (PGPLiteralData) message;
InputStream unc = ld.getInputStream();
int ch;
while ((ch = unc.read()) >= 0) out.write(ch);
} 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() && !pbe.verify()) throw new PGPException("Message failed integrity check");
}
public static void encryptFile(OutputStream out, String fileName, PGPPublicKey encKey, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException, PGPException {
Security.addProvider(new BouncyCastleProvider());
if (armor) out = new ArmoredOutputStream(out);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
org.bouncycastle.openpgp.PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, withIntegrityCheck, new SecureRandom(), "BC");
cPk.addMethod(encKey);
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes);
cOut.close();
out.close();
}
}
It looks like as that your "old" PGP encryption methods were taken from a Bouncy Castle example, so I used the renewed Bouncy Castle examples in https://github.com/bcgit/bc-java/tree/master/pg/src/main/java/org/bouncycastle/openpgp/examples for a simple test.
You wrote that the problem shows up when updating Bouncy Castle to version 1.56 - this is outdated as well and the actual version is 1.65 and my example works with this version (and OpenJDK 11.0.6). Take my files as a working basis for your maintenance.
First you need a PGP keypair - for my example I generated one with 'RSAKeyPairGenerator.java -a myidentity mypassphrase' to get the files 'secret.asc' (private key) and 'pub.asc' (public key).
For PGP file encryption you need two more files - 'KeyBasedLargeFileProcessor.java' and 'PGPExampleUtil.java.' In class 'KeyBasedLargeFileProcessor.java' I changed the constructor of the methods decryptFile and encryptFile from 'private' to 'public' to get access from the PGPMain.java.
It's just one line of code for pgp file encryption and another line for pgp file decryption. As the original filename can get stored within the encrypted file
I added a "rename-method" to change the original filename 'plain.txt' to 'plain_org.txt'. Be aware that the decryptFile-method will overwrite an existing file without warning or notice and there is no propper exception handling.
The complete set of files including Bouncy Castle library is available here: https://github.com/java-crypto/Stackoverflow/tree/master/PGP_Encryption_after_Update_Not_Working. You need the bcprov-jdk15to18-165.jar and bcpg-jdk15on-165.jar!
PGPMain.java:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchProviderException;
import java.security.Security;
public class PGPMain {
public static void main(String[] args) throws NoSuchProviderException, IOException, PGPException {
System.out.println("https://stackoverflow.com/questions/61927913/bouncycastle-update-from-1-46-to-1-56-not-working");
Security.addProvider(new BouncyCastleProvider()); // get bouncy castle: https://www.bouncycastle.org/latest_releases.html
System.out.println("\nJava version: " + Runtime.version() + " BouncyCastle Version: " + Security.getProvider("BC"));
// create a keypair with RSAKeyPairGenerator.java
// encryption
KeyBasedLargeFileProcessor.encryptFile("enc.txt", "plain.txt", "pub.asc", false, true);
// rename plaintextfile as it will be overwritten by decryptFile (filename is stored within encrypted file)
File file = new File("plain.txt");
file.renameTo(new File("plain_org.txt"));
// decryption will generate the decrypted file with original filename !
KeyBasedLargeFileProcessor.decryptFile("enc.txt", "secret.asc", "mypassphrase".toCharArray(), "defaultfilename.txt");
// return the original filename, to change this behavior change the code in class KeyBasedLargeFileProcessor lines 142-146
}
}
KeyBasedLargeFileProcessor.java
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.util.io.Streams;
/**
* A simple utility class that encrypts/decrypts public key based
* encryption large files.
* <p>
* To encrypt a file: KeyBasedLargeFileProcessor -e [-a|-ai] fileName publicKeyFile.<br>
* If -a is specified the output file will be "ascii-armored".
* If -i is specified the output file will be have integrity checking added.
* <p>
* To decrypt: KeyBasedLargeFileProcessor -d fileName secretKeyFile passPhrase.
* <p>
* Note 1: this example will silently overwrite files, nor does it pay any attention to
* the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
* will have been used.
* <p>
* Note 2: this example generates partial packets to encode the file, the output it generates
* will not be readable by older PGP products or products that don't support partial packet
* encoding.
* <p>
* Note 3: if an empty file name has been specified in the literal data object contained in the
* encrypted packet a file with the name filename.out will be generated in the current working directory.
*/
public class KeyBasedLargeFileProcessor
{ // source: https://github.com/bcgit/bc-java/blob/master/pg/src/main/java/org/bouncycastle/openpgp/examples/KeyBasedLargeFileProcessor.java
// changed from private to public
public static void decryptFile(
String inputFileName,
String keyFileName,
char[] passwd,
String defaultFileName)
throws IOException, NoSuchProviderException
{
InputStream in = new BufferedInputStream(new FileInputStream(inputFileName));
InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName));
decryptFile(in, keyIn, passwd, defaultFileName);
keyIn.close();
in.close();
}
/**
* decrypt the passed in message stream
*/
private static void decryptFile(
InputStream in,
InputStream keyIn,
char[] passwd,
String defaultFileName)
throws IOException, NoSuchProviderException
{
in = PGPUtil.getDecoderStream(in);
try
{
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 it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext())
{
pbe = (PGPPublicKeyEncryptedData)it.next();
sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd);
}
if (sKey == null)
{
throw new IllegalArgumentException("secret key for message not found.");
}
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
InputStream compressedStream = new BufferedInputStream(cData.getDataStream());
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(compressedStream);
Object message = pgpFact.nextObject();
if (message instanceof PGPLiteralData)
{
PGPLiteralData ld = (PGPLiteralData)message;
String outFileName = ld.getFileName();
if (outFileName.length() == 0)
{
outFileName = defaultFileName;
}
InputStream unc = ld.getInputStream();
OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));
Streams.pipeAll(unc, fOut);
fOut.close();
}
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())
{
System.err.println("message failed integrity check");
}
else
{
System.err.println("message integrity check passed");
}
}
else
{
System.err.println("no message integrity check");
}
}
catch (PGPException e)
{
System.err.println(e);
if (e.getUnderlyingException() != null)
{
e.getUnderlyingException().printStackTrace();
}
}
}
// changed from private to public
public static void encryptFile(
String outputFileName,
String inputFileName,
String encKeyFileName,
boolean armor,
boolean withIntegrityCheck)
throws IOException, NoSuchProviderException, PGPException
{
OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName));
PGPPublicKey encKey = PGPExampleUtil.readPublicKey(encKeyFileName);
encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck);
out.close();
}
private static void encryptFile(
OutputStream out,
String fileName,
PGPPublicKey encKey,
boolean armor,
boolean withIntegrityCheck)
throws IOException, NoSuchProviderException
{
if (armor)
{
out = new ArmoredOutputStream(out);
}
try
{
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));
cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
OutputStream cOut = cPk.open(out, new byte[1 << 16]);
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedData.ZIP);
PGPUtil.writeFileToLiteralData(comData.open(cOut), PGPLiteralData.BINARY, new File(fileName), new byte[1 << 16]);
comData.close();
cOut.close();
if (armor)
{
out.close();
}
}
catch (PGPException e)
{
System.err.println(e);
if (e.getUnderlyingException() != null)
{
e.getUnderlyingException().printStackTrace();
}
}
}
public static void main(
String[] args)
throws Exception
{
Security.addProvider(new BouncyCastleProvider());
if (args.length == 0)
{
System.err.println("usage: KeyBasedLargeFileProcessor -e|-d [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
return;
}
if (args[0].equals("-e"))
{
if (args[1].equals("-a") || args[1].equals("-ai") || args[1].equals("-ia"))
{
encryptFile(args[2] + ".asc", args[2], args[3], true, (args[1].indexOf('i') > 0));
}
else if (args[1].equals("-i"))
{
encryptFile(args[2] + ".bpg", args[2], args[3], false, true);
}
else
{
encryptFile(args[1] + ".bpg", args[1], args[2], false, false);
}
}
else if (args[0].equals("-d"))
{
decryptFile(args[1], args[2], args[3].toCharArray(), new File(args[1]).getName() + ".out");
}
else
{
System.err.println("usage: KeyBasedLargeFileProcessor -d|-e [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
}
}
}
Error : javax.crypto.IllegalBlockSizeException: Input length must be
multiple of 16 when decrypting with padded cipher
Tried Solutions: I've tried to to change the padding to "AES/ECB/NoPadding", "AES/ECB/PKCS5", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding" and still received the same error or an error stating only AES or Rijndael required. Then I tried making the key use "AES" parameter and ALGO set to "AES/CBC/PKCS5Padding", but I recieved a missing parameter error which I tried to fix my adding new IvParameterSpec(new byte[16]) to cipher.init. It still resulted into the 16 bit issue. So I'm stuck now.
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.security.Key;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.*;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.util.*;
import java.io.*;
// Don't forget to import any supporting classes you plan to use.
public class Crypto
{
private Scanner fileText;
private PrintWriter fileEncrypt;
private Scanner inputFile;
private PrintWriter outputFile;
private static final String ALGO = "AES/CBC/PKCS5Padding";
private byte[] keyValue;
public Crypto(String key)
{
keyValue = key.getBytes();
}
public String encrypt(String Data) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public String decrypt(String encryptedData) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decodedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
public Key generateKey() throws Exception
{
Key key = new SecretKeySpec(keyValue, "AES");
return key;
}
// encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt" )
// encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt", "CryptoDeciphered.txt")
public void encrypt_decrypt(String function_type , String source_file , String
target_file)
{
String lineValue = "";
String convertedValue = "";
try
{
inputFile = new Scanner(new File(source_file));
}
catch(Exception e)
{
System.out.println("( " + source_file + ") - File Opening Error");
}
try
{
outputFile = new PrintWriter(new FileWriter(target_file));
}
catch(Exception e)
{
System.out.println("( " + target_file + ") - File Opening Error");
}
while(inputFile.hasNext())
{
lineValue = inputFile.nextLine();
System.out.println("Source Line: " + lineValue);
try
{
if (function_type == "ENCRYPT")
{
convertedValue = encrypt(lineValue);
}
else if (function_type == "DECRYPT")
{
convertedValue = decrypt(lineValue);
}
}
catch(Exception e)
{
System.out.println(e);
}
System.out.println("Converted Line : " + convertedValue);
outputFile.write(convertedValue);
}
inputFile.close();
outputFile.close();
}
public static void main( String args[] ) throws IOException
{
// Write your code here...
// You will read from CryptoPlaintext.txt and write to
CryptoCiphertext.txt.
Crypto c = new Crypto("dk201anckse29sns");
c.encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt"
);
c.encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt",
"CryptoDeciphered.txt");
//
// And then read from CryptoCiphertext.txt and write to
CryptoDeciphered.txt.
//
// DON'T forget your comments!
// =============================== DO NOT MODIFY ANY CODE BELOW HERE
==============================
// Compare the files
System.out.println(compareFiles() ? "The files are identical!" : "The
files are NOT identical.");
}
/**
* Compares the Plaintext file with the Deciphered file.
*
* #return true if files match, false if they do not
*/
public static boolean compareFiles() throws IOException
{
Scanner pt = new Scanner(new File("CryptoPlaintext.txt")); // Open the
plaintext file
Scanner dc = new Scanner(new File("CryptoDeciphered.txt")); // Open the
deciphered file
// Read through the files and compare them record by record.
// If any of the records do not match, the files are not identical.
while(pt.hasNextLine() && dc.hasNextLine())
if(!pt.nextLine().equals(dc.nextLine())) return false;
// If we have any records left over, then the files are not identical.
if(pt.hasNextLine() || dc.hasNextLine()) return false;
// The files are identical.
return true;
}
}
There are two errors in your code:
You forgot to generate a random IV and prefix it to your ciphertext (before encoding it to base 64). You'd need to find the IV from your ciphertext and then retrieve it back again during decryption.
Note that CBC code requires an IV indistinguishable from random. You can create it using new SecureRandom (only during encryption, of course) and IvParameterSpec. The code will probably run without this as the default implementation in Java defaults on an all-zero IV. Possibly that is enough for this assignment.
But that's not what generates the error; that's much more of a banality:
You're calling outputFile.write instead of outputFile.println which means that newlines aren't inserted, and all base 64 encodings are put in a single line.
Note that you should not use any classes from sun.misc. Those are private to the Java implementation and are not part of the Java API. The new Java versions have java.util.Base64 for your convenience. Actually, the sun.misc version may insert line endings within the base 64 encoding that will break your code for longer lines.
For example:
package nl.owlstead.stackoverflow;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Key;
import java.util.Base64;
import java.util.Scanner;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
private Scanner inputFile;
private PrintWriter outputFile;
private static final String ALGO = "AES/CBC/PKCS5Padding";
private byte[] keyValue;
public Crypto(String key) {
keyValue = key.getBytes();
}
public String encrypt(String Data) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key,
new IvParameterSpec(new byte[c.getBlockSize()]));
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = Base64.getEncoder().encodeToString(encVal);
return encryptedValue;
}
public String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key,
new IvParameterSpec(new byte[c.getBlockSize()]));
byte[] decodedValue = Base64.getDecoder().decode(encryptedData);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
public Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, "AES");
return key;
}
public void encrypt_decrypt(String function_type, String source_file,
String target_file) {
String lineValue = "";
String convertedValue = "";
try {
inputFile = new Scanner(new File(source_file));
} catch (Exception e) {
System.out.println("( " + source_file + ") - File Opening Error");
}
try {
outputFile = new PrintWriter(new FileWriter(target_file));
} catch (Exception e) {
System.out.println("( " + target_file + ") - File Opening Error");
}
while (inputFile.hasNext()) {
lineValue = inputFile.nextLine();
System.out.println("Source Line: " + lineValue);
try {
if (function_type == "ENCRYPT") {
convertedValue = encrypt(lineValue);
} else if (function_type == "DECRYPT") {
convertedValue = decrypt(lineValue);
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("Converted Line : " + convertedValue);
outputFile.println(convertedValue);
}
inputFile.close();
outputFile.close();
}
public static void main(String args[]) throws IOException {
Crypto c = new Crypto("dk201anckse29sns");
c.encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt",
"CryptoCiphertext.txt");
c.encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt",
"CryptoDeciphered.txt");
System.out.println(compareFiles() ? "The files are identical!"
: "The files are NOT identical.");
}
/**
* Compares the Plaintext file with the Deciphered file.
*
* #return true if files match, false if they do not
*/
public static boolean compareFiles() throws IOException {
Scanner pt = new Scanner(new File("CryptoPlaintext.txt")); // Open the
Scanner dc = new Scanner(new File("CryptoDeciphered.txt")); // Open the
// Read through the files and compare them record by record.
// If any of the records do not match, the files are not identical.
while (pt.hasNextLine() && dc.hasNextLine()) {
String ptl = pt.nextLine();
String dcl = dc.nextLine();
if (!ptl.equals(dcl))
{
System.out.println(ptl);
System.out.println(dcl);
continue;
// return false;
}
}
// If we have any records left over, then the files are not identical.
if (pt.hasNextLine() || dc.hasNextLine())
return false;
// The files are identical.
return true;
}
}
A working solution for you:
Just added a random IV value while initiating your cipher during encrypting and decrypting.
c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[16]));
package com.samples;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.PrintWriter;
import java.io.FileWriter;
// Don't forget to import any supporting classes you plan to use.
public class Crypto
{
private Scanner fileText;
private PrintWriter fileEncrypt;
private Scanner inputFile;
private PrintWriter outputFile;
private static final String ALGO = "AES/CBC/PKCS5Padding";
private byte[] keyValue;
public Crypto(String key)
{
keyValue = key.getBytes();
}
public String encrypt(String Data) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[16]));
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public String decrypt(String encryptedData) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[16]));
byte[] decodedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
public Key generateKey() throws Exception
{
Key key = new SecretKeySpec(keyValue, "AES");
return key;
}
// encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt" )
// encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt", "CryptoDeciphered.txt")
public void encrypt_decrypt(String function_type, String source_file, String target_file)
{
String lineValue = "";
String convertedValue = "";
try
{
inputFile = new Scanner(new File(source_file));
}
catch(Exception e)
{
System.out.println("( " + source_file + ") - File Opening Error");
}
try
{
outputFile = new PrintWriter(new FileWriter(target_file));
}
catch(Exception e)
{
System.out.println("( " + target_file + ") - File Opening Error");
}
while(inputFile.hasNext())
{
lineValue = inputFile.nextLine();
System.out.println("Source Line: " + lineValue);
try
{
if (function_type == "ENCRYPT")
{
convertedValue = encrypt(lineValue);
}
else if (function_type == "DECRYPT")
{
convertedValue = decrypt(lineValue);
}
}
catch(Exception e)
{
System.out.println(e);
}
System.out.println("Converted Line : " + convertedValue);
outputFile.write(convertedValue);
}
inputFile.close();
outputFile.close();
}
public static void main( String args[] ) throws IOException
{
// Write your code here...
// You will read from CryptoPlaintext.txt and write to CryptoCiphertext.txt.
Crypto c = new Crypto("dk201anckse29sns");
c.encrypt_decrypt("ENCRYPT", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoPlaintext.txt", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoCiphertext.txt"
);
c.encrypt_decrypt("DECRYPT", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoCiphertext.txt",
"C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoDeciphered.txt");
//
// And then read from CryptoCiphertext.txt and write to CryptoDeciphered.txt.
//
// DON'T forget your comments!
// =============================== DO NOT MODIFY ANY CODE BELOW HE ==============================
// Compare the files
System.out.println(compareFiles() ? "The files are identical!" : "The files are NOT identical.");
}
/**
* Compares the Plaintext file with the Deciphered file.
*
* #return true if files match, false if they do not
*/
public static boolean compareFiles() throws IOException
{
Scanner pt = new Scanner(new File("C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoPlaintext.txt")); // Open the plaintext file
Scanner dc = new Scanner(new File("C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoDeciphered.txt")); // Open the deciphered file
// Read through the files and compare them record by record.
// If any of the records do not match, the files are not identical.
while(pt.hasNextLine() && dc.hasNextLine())
if(!pt.nextLine().equals(dc.nextLine())) return false;
// If we have any records left over, then the files are not identical.
if(pt.hasNextLine() || dc.hasNextLine()) return false;
// The files are identical.
return true;
}
}
I want to exactly build a function which produces a HMAC with a secret key like this site provides:
http://www.freeformatter.com/hmac-generator.html
The Java 8 lib only provides MessageDigest and KeyGenerator which both only support up to SH256.
Also, Google doesn't give me any result for an implementation to generate a HMAC.
Does someone know a implementation?
I have this code to generate an ordinary SH256 but I guess this doesn't help me much:
public static String get_SHA_512_SecurePassword(String passwordToHash) throws Exception {
String generatedPassword = null;
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] bytes = md.digest(passwordToHash.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
System.out.println(generatedPassword);
return generatedPassword;
}
The simplest way can be -
private static final String HMAC_SHA512 = "HmacSHA512";
private static String toHexString(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
return formatter.toString();
}
public static String calculateHMAC(String data, String key)
throws SignatureException, NoSuchAlgorithmException, InvalidKeyException
{
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), HMAC_SHA512);
Mac mac = Mac.getInstance(HMAC_SHA512);
mac.init(secretKeySpec);
return toHexString(mac.doFinal(data.getBytes()));
}
public static void main(String[] args) throws Exception {
String hmac = calculateHMAC("data", "key");
System.out.println(hmac);
}
You can change the HMAC_SHA512 variable to any of the Mac algorithm and the code will work the same way.
Hope this helps:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Test1 {
private static final String HMAC_SHA512 = "HmacSHA512";
public static void main(String[] args) {
Mac sha512Hmac;
String result;
final String key = "Welcome1";
try {
final byte[] byteKey = key.getBytes(StandardCharsets.UTF_8);
sha512Hmac = Mac.getInstance(HMAC_SHA512);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA512);
sha512Hmac.init(keySpec);
byte[] macData = sha512Hmac.doFinal("My message".getBytes(StandardCharsets.UTF_8));
// Can either base64 encode or put it right into hex
result = Base64.getEncoder().encodeToString(macData);
//result = bytesToHex(macData);
} catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
} finally {
// Put any cleanup here
System.out.println("Done");
}
}
}
For converting from byte array to hex refer this stackoverflow answer : here
Also you can use a little wrapper by Apache Commons codec:
import static org.apache.commons.codec.digest.HmacAlgorithms.HMAC_SHA_512;
import org.apache.commons.codec.digest.HmacUtils;
public class HmacService {
private String sharedSecret;
public HmacService(String sharedSecret) {
this.sharedSecret = sharedSecret;
}
public String calculateHmac(String data) {
return new HmacUtils(HMAC_SHA_512, sharedSecret).hmacHex(data);
}
public boolean checkHmac(String data, String hmacHex) {
return calculateHmac(data).equals(hmacHex);
}
}
You could use Caesar (version 0.6.0 or later):
int blockSize = 128;
String secretKey = "My secret key";
String message = "Message to hash";
System.out.println(
new Hmac(
new ImmutableMessageDigest(
MessageDigest.getInstance("SHA-512")
),
blockSize,
new PlainText(secretKey),
new PlainText(message)
).asHexString()
);