I have a .gpg file and a RSA private key. How can I programatically decrypt it without using operating system? e.g. without using something like Runtime.getRuntime().exec("gpg -decrypt.....");
Libraries I've found all run operating system. Like GnuPG or gnugpg-for-java.
As Skyr mentioned: Bouncy Castle is the way to go.
What do you want to do with this key? If your goal is to en- or decrypt files you might want to take a look at bouncy-gpg (shameless plug: I wrote it).
Using secret keys is actually three steps
Parse the key and put it into a PGPSecretKeyRing
Extract the secret key from the keyring
Decrypt it with the password
1. Parsing the exported key
In any case look here for the part that parses keys:
class ...
private PGPSecretKeyRingCollection secretKeyRings = new PGPSecretKeyRingCollection(EMPTY_LIST);
...
/**
* Add a new secret keyring to the public keyrings.
* .
* Can read the result of "gpg --export" and "gpg --export -a keyid"
* .
* E.g. "gpg --export-secret-key -a keyid":
* addSecretKey("-----BEGIN PGP PRIVATE KEY BLOCK----- ....".getBytes("US-ASCII")
* <p>
* The password is queried via the callback (decryptionSecretKeyPassphraseForSecretKeyId).
*
* #param encodedPrivateKey the key ascii armored or binary
* #throws IOException IO is dangerous
* #throws PGPException E.g. this is nor a valid key
*/
public void addSecretKey(byte[] encodedPrivateKey) throws IOException, PGPException {
if (encodedPrivateKey == null) {
throw new NullPointerException("encodedPrivateKey must not be null");
}
try (
final InputStream raw = new ByteArrayInputStream(encodedPrivateKey);
final InputStream decoded = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(raw)
) {
PGPSecretKeyRing pgpPrivate = new PGPSecretKeyRing(decoded, getKeyFingerPrintCalculator());
this.secretKeyRings = PGPSecretKeyRingCollection.addSecretKeyRing(this.secretKeyRings, pgpPrivate);
}
}
2. Getting the key from the keyring
final PGPSecretKeyRingCollection pgpSec = ...
final PGPSecretKey encryptedKey = pgpSec.getSecretKey(keyID);
3. Decrypting the key
Later you have to decrypt the key using a password like so:
/**
* Decrypt an encrypted PGP secret key.
*
* #param encryptedKey An encrypted key
* #param passphrase The passphrase for the key
* #return the decrypted secret key
* #throws PGPException E.g. wrong passphrase
*/
public static PGPPrivateKey extractPrivateKey(PGPSecretKey encryptedKey, final char[] passphrase) throws PGPException {
LOGGER.debug("Extracting secret key with key ID '0x{}'", Long.toHexString(encryptedKey.getKeyID()));
PGPDigestCalculatorProvider calcProvider = new JcaPGPDigestCalculatorProviderBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build();
PBESecretKeyDecryptor decryptor = new JcePBESecretKeyDecryptorBuilder(
calcProvider).setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(passphrase);
return encryptedKey.extractPrivateKey(decryptor);
}
there are too many examples that I've tried on Bouncy Castle with PGP. The common issue is keyID can't be found in KeyRing.
So, I found #Jens' bouncy-gpg (not sure if he still maintains it.)
Here is his documentation from github.io. It's simple to follow and works!
https://neuhalje.github.io/bouncy-gpg/
The Bouncy Castle library provides (among other features) an OpenPGP implementation. The package org.bouncycastle.openpgp.examples contains several usage examples, one of them showing how to encrypt/decrypt a file using a public/secret key pair (you can have a look at the examples on GrepCode or on the project's Github mirror).
Related
Its best to show my problem and explain it after (I am using KeyStore Explorer to peek into my .pfx files):
Basically, I want the result on the right, but I get the result on the left.
To be more precise: The KeyStore should contain the private key and certs chain (KeyPair), in one entry.
I somehow couldn't get it working in java. This is what I tried to get the result on the left:
The problem with the code below is, that its not verifing the certs and adding them as trusted certs.
/**
* Creates and returns a new {#link KeyStore} from the provided information.
* #param keystoreType The {#link KeyStore}s type. Recommended: "pkcs12".
* Check {#link KeyStore#getInstance(String)} for details.
* #param passwordAsCharArray Password to encrypt this {#link KeyStore} and its keys.
* #param certificateChain The certificate chain is simply an array of {#link X509Certificate}s.
* #param privateKey The {#link PrivateKey}.
* #param publicKey The {#link PublicKey}.
* #throws KeyStoreException
*/
public KeyStore buildAndGetKeystore(String keystoreType, char[] passwordAsCharArray,
X509Certificate[] certificateChain, PrivateKey privateKey, PublicKey publicKey)
throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, EmptyStringException, EmptyCharArrayException, EmptyCertificateChainException {
// Check for null parameters
Objects.requireNonNull(keystoreType);
Objects.requireNonNull(passwordAsCharArray);
Objects.requireNonNull(certificateChain);
Objects.requireNonNull(privateKey);
Objects.requireNonNull(publicKey);
// Check for empty parameters
if (keystoreType.isEmpty()) throw new EmptyStringException("Parameter 'keystoreType' should NOT be empty!");
if (passwordAsCharArray.length==0) throw new EmptyCharArrayException("Parameter 'passwordAsCharArray' should NOT be empty!");
if (certificateChain.length==0) throw new EmptyCertificateChainException("Parameter 'certificateChain' should NOT be empty!");
// Initialise a new keystore
KeyStore keystore = KeyStore.getInstance(keystoreType);
keystore.load(null, passwordAsCharArray); // Pass null to tell java this is a new keystore
// Insert certificates
for (int i = 0; i < certificateChain.length; i++) {
keystore.setCertificateEntry(""+i, certificateChain[i]);
}
// Write private key (with password protection) to keystore.
// NOTE: I tried this before and it only writes
// the private key to the .pfx file and ignores the domain chain
//keystore.setKeyEntry("sso-signing-key", privateKey, passwordAsCharArray, certificateChain);
return keystore;
}
Some extra details:
The KeyStore on the right was created like this: First generated the certs at sslforfree.com and then converted them to a PKCS12 KeyStore with https://decoder.link/converter
I created my own certificate chain and used this structure for the certificateChain:
X509Certificate[] certificateChain = new X509Certificate[3];
certificateChain[0] = topCertificate;
certificateChain[1] = middleCertificate;
certificateChain[2] = rootCertificate;
The keystore creation part is as simple like this (I left out the "notNull checks"):
KeyStore keystore = KeyStore.getInstance(keystoreType);
keystore.load(null,null);
keystore.setKeyEntry("use_your_own_alias", privateKey, passwordAsCharArray, certificateChain);
return keystore;
Kindly note that the publicKey is NOT part of the storage process as it is available with
certificateChain[0].getPublicKey()
Checking the keystore (I used a PKCS12 one) in KeyStoreExplorer gives this output:
and the key chain:
You guys won't believe this, but... The problem was the alias name 'priv-key'. Just removed the hyphen '-' and changed the alias name to 'myKey' like in https://stackoverflow.com/a/67147429/13600212 and voila it works...
So many hours lost for such a stupid thing...
I want to send an encrypted mail in java. BouncyCastle (Release 1.6.4) seems to be popular to do so. In their example "CreateLargeEncryptedMail.java" you find:
/**
* a simple example that creates a single encrypted mail message.
* <p>
* The key store can be created using the class in
* org.bouncycastle.jce.examples.PKCS12Example - the program expects only one
* key to be present in the key file.
* <p>
* Note: while this means that both the private key is available to
* the program, the private key is retrieved from the keystore only for
* the purposes of locating the corresponding public key, in normal circumstances
* you would only be doing this with a certificate available.
*/
public class CreateLargeEncryptedMail
{
public static void main(
String args[])
throws Exception
{
if (args.length != 3)
{
System.err.println("usage: CreateLargeEncryptedMail pkcs12Keystore password inputFile");
System.exit(0);
}
//
// Open the key store
//
KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
String keyAlias = ExampleUtils.findKeyAlias(ks, args[0], args[1].toCharArray());
Certificate[] chain = ks.getCertificateChain(keyAlias);
But ks.getCertificateChain() does not work without the private key and usually I do not have the private key of a recipient.
In my tries it returned null. From documentation
Returns the certificate chain associated with the given alias. The certificate chain must have been associated with the alias by a call to setKeyEntry, or by a call to setEntry with a PrivateKeyEntry.
But I do not have the private key.
An other way would be to use CertificateFactory.getInstance("X.509"); is there a way to decrypt smime public key data.
But I only come to
java.security.cert.CertificateParsingException: signed fields invalid
Found stackoverflow to that exception, but the solution uses KeyStore.getCertificate() again.
I have: A certificat suitable for SMIME in Windows trust store. The certificat works in outlook. I can export the certificat to a file.
I want: A java object of type Certificate (X509Certificate) working for SMIME with BounceCastle.
So what kind of file do I have to create with which tool and what to do in Java to get this X509Certificate initialized? Do I need the single certificat or a chain in that file? The certificat is self signed.
BouncyCastle not only supports SMIME encryption but also contains a CertificateFactory which can load a p7b-file I exported from Windows certmgr. For export I chose without private key and with key-chain. That file worked for me using:
import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
...
/**
* Reads the Certificate from the file with filename.
* Works for p7b-files.
* #param filename the name and path of a key-file.
* #return a Certificate
*/
public static Certificate getCertificate(String filename) {
Certificate cert = null;
try (InputStream is = new FileInputStream(filename)) {
CertificateFactory fact = new CertificateFactory();
cert = fact.engineGenerateCertificate(is);
}
catch (Exception ex) {
ex.printStackTrace();
}
return cert;
}
I'm looking for an implementation of Bouncy Castle PGP 'sign and encrypt'. Ideally in one operation, if that makes any difference.
I've taken the encrypt example and the signing example and tried to turn it into a 'one pass' encrypt and sign operation.
I see this relatively dated implementation Boncode. It seems to show that the two operations are just linked together.
I'm not getting the consumer to decrypt the code. The signature seems to be able to be verified. This is true whether I use the merged operations or separate encrypt then sign.
Is there a better Bouncy Castle PGP implementation?
Here is my current implementation of a one pass, Bouncy Castle PGP encrypt+sign. The signature seems to verify, but the payload is not decrypted.
public class SinglePassSignedEncryptedFileProcessor {
private static final Logger logger = LoggerFactory.getLogger(SinglePassSignedEncryptedFileProcessor.class);
/*
* This is the primary function that will create encrypt a file and sign it
* with a one pass signature. This leans on an C# example by John Opincar
* #author Bilal Soylu
* #param targetFileName
* -- file name on drive systems that will contain encrypted content
* #param embeddedFileName
* -- the original file name before encryption
* #param secretKeyRingInputStream
* -- Private Key Ring File
* #param targetFileStream
* -- The stream for the encrypted target file
* #param secretKeyPassphrase
* -- The private key password for the key retrieved from
* collection used for signing
* #param signPublicKeyInputStream
* -- the public key of the target recipient to be used to
* encrypt the file
* #throws Exception
*/
public void encryptOnePassSign(
String fileName,
InputStream keyIn,
OutputStream out,
char[] pass,
PGPPublicKey encryptionKey,
boolean armor,
boolean withIntegrityCheck,
String providerName)
throws IOException, NoSuchAlgorithmException, NoSuchProviderException, PGPException, SignatureException {
if (armor) {
out = new ArmoredOutputStream(out);
}
// Compress
byte[] bytes = PGPEncryptUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP);
// Encryption process.
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey).setProvider("BC"));
ByteArrayOutputStream encryptedOutputStream = new ByteArrayOutputStream();
OutputStream encryptedOut = encGen.open(encryptedOutputStream, bytes);
encryptedOut.write(bytes);
encryptedOut.close();
byte[] bytesEncrypted = encryptedOutputStream.toByteArray();
encryptedOutputStream.close();
// Signing process.
PGPSecretKey pgpSec = PGPEncryptUtil.readSecretKey(keyIn);
PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1).setProvider("BC"));
sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
Iterator it = pgpSec.getPublicKey().getUserIDs();
if (it.hasNext()) {
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String) it.next());
sGen.setHashedSubpackets(spGen.generate());
}
PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator(
PGPCompressedData.UNCOMPRESSED);
// Write to the output stream.
BCPGOutputStream bOut = new BCPGOutputStream(cGen.open(out));
sGen.generateOnePassVersion(false).encode(bOut);
File file = new File(fileName);
PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();
// file is encoding name.
Date lastModified = new Date(file.lastModified());
OutputStream lOut = lGen.open(bOut, PGPLiteralData.BINARY, fileName, lastModified, bytesEncrypted);
//FileInputStream fIn = new FileInputStream(file);
//int ch;
//while ((ch = fIn.read()) >= 0) {
lOut.write(bytesEncrypted);
sGen.update(bytesEncrypted);
// }
// ?
lGen.close();
sGen.generate().encode(bOut);
cGen.close();
if (armor) {
out.close();
}
// close everything down we are done
/*
literalOut.close();
literalDataGenerator.close();
signatureGenerator.generate().encode(compressedOut);
compressedOut.close();
compressedDataGenerator.close();
encryptedOut.close();
encryptedDataGenerator.close();
*/
// if (armor) targetFileStream.close();
}
}
Latest answer is to use BouncyGPG
Works as per the test cases. Kotlin
val encryptionStream = BouncyGPG
.encryptToStream()
.withConfig(keyringConfig)
.withStrongAlgorithms()
.toRecipient("recipient#example.com")
.andSignWith("sender#example.com")
.armorAsciiOutput()
.andWriteTo(cipherText)
encryptionStream.write(expectedPlaintext)
encryptionStream.close()
cipherText.close()
This question already has answers here:
one way SHA1 hash javascript implementation?
(3 answers)
Closed 8 years ago.
I am writing a JavaScript Client Application that needs to communicate with Server. I tried to implement the API, but i stuck on one method and I need help.
Infect i don't know how to translate this from Java to JavaScript (I don't know where to find analog libraries written in javascript that are used in this method):
import java.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* This class defines common routines for generating
* authentication signatures for AWS requests.
*/
public class Signature {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
/**
* Computes RFC 2104-compliant HMAC signature.
* * #param data
* The data to be signed.
* #param key
* The signing key.
* #return
* The Base64-encoded RFC 2104-compliant HMAC signature.
* #throws
* java.security.SignatureException when signature generation fails
*/
public static String calculateRFC2104HMAC(String data, String key)
throws java.security.SignatureException
{
String result;
try {
// get an hmac_sha1 key from the raw key bytes
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
// get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes());
// base64-encode the hmac
result = Encoding.EncodeBase64(rawHmac);
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
}
This method is from AWS Documentations:
Java Sample Code for Calculating HMAC-SHA1 Signatures
I am asking if someone can give me some references (websites) where I can find solution or analog libraries, written in javascript.
I searched AWS Documentation and SDK for JavaScript and I couldn't find translation in JS.
Thanks very much in advance.
Hi i think this might be helpful for you.
Here you can find out the link to calculate hmac sha1:
http://caligatio.github.io/jsSHA/
Here you can find the source code in javascript.
https://github.com/Caligatio/jsSHA/releases/tag/v1.5.0
I'm trying to make use of elliptic curve crypto. I need two implementations of the same thing, one in Java and one in C. I'm testing them using two key pairs which were generated using the curve secp256k1. When I generate the derived secret in Java I always get a different number from what I get from OpenSSL.
Java code:
/* privateKey and peerPublicKey are generated with the following parameters */
ECParameterSpec paramSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
/* ... */
Provider BC = new BouncyCastleProvider();
KeyAgreement agr = KeyAgreement.getInstance("ECDH", BC);
agr.init(privateKey);
agr.doPhase(peerPublicKey, true);
byte[] secret = agr.generateSecret();
C code
/* pkey and peerkey are generated using EC_KEY_new_by_curve_name(NID_secp256k1) */
/* and than wrapped in an EVP_PKEY */
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
uint8_t *secret = NULL;
size_t secret_len;
EVP_PKEY_derive_init(ctx);
EVP_PKEY_derive_set_peer(ctx, peerkey);
EVP_PKEY_derive(ctx, NULL, &secret_len);
secret = malloc(secret_len);
EVP_PKEY_derive(ctx, secret, &secret_len);
I'm sure that the keys are valid and that they are the same both in C and in Java code, but I don't understand why the derived secret is different. Am I missing something?
Thanks
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
uint8_t *secret = NULL;
size_t secret_len;
EVP_PKEY_derive_init(ctx);
EVP_PKEY_derive_set_peer(ctx, peerkey);
EVP_PKEY_derive(ctx, NULL, &secret_len);
secret = malloc(secret_len);
EVP_PKEY_derive(ctx, secret, &secret_len);
This code looks like its missing a few steps. For example, EVP_PKEY_paramgen_init is not present.
The OpenSSL wiki has an example at Elliptic Curve Diffie-Hellman. I'm going to copy/paste it below to avoid the link-only answer, but I believe its the work of Matt Caswell.
EVP_PKEY_CTX *pctx, *kctx;
EVP_PKEY_CTX *ctx;
unsigned char *secret;
EVP_PKEY *pkey = NULL, *peerkey, *params = NULL;
/* Create the context for parameter generation */
if(NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) handleErrors();
/* Initialise the parameter generation */
if(1 != EVP_PKEY_paramgen_init(pctx)) handleErrors();
/* We're going to use the ANSI X9.62 Prime 256v1 curve */
if(1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)) handleErrors();
/* Create the parameter object params */
if (!EVP_PKEY_paramgen(pctx, ¶ms)) handleErrors();
/* Create the context for the key generation */
if(NULL == (kctx = EVP_PKEY_CTX_new(params, NULL))) handleErrors();
/* Generate the key */
if(1 != EVP_PKEY_keygen_init(kctx)) handleErrors();
if (1 != EVP_PKEY_keygen(kctx, &pkey)) handleErrors();
/* Get the peer's public key, and provide the peer with our public key -
* how this is done will be specific to your circumstances */
peerkey = get_peerkey(pkey);
/* Create the context for the shared secret derivation */
if(NULL == (ctx = EVP_PKEY_CTX_new(pkey, NULL))) handleErrors();
/* Initialise */
if(1 != EVP_PKEY_derive_init(ctx)) handleErrors();
/* Provide the peer public key */
if(1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) handleErrors();
/* Determine buffer length for shared secret */
if(1 != EVP_PKEY_derive(ctx, NULL, secret_len)) handleErrors();
/* Create the buffer */
if(NULL == (secret = OPENSSL_malloc(*secret_len))) handleErrors();
/* Derive the shared secret */
if(1 != (EVP_PKEY_derive(ctx, secret, secret_len))) handleErrors();
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(peerkey);
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(kctx);
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(pctx);
/* Never use a derived secret directly. Typically it is passed
* through some hash function to produce a key */
return secret;
When I generate the derived secret in Java I always get a different number from what I get from OpenSSL.
Each run of the protocol will produce different results. That's because each party picks a random value for each run of the protocol. That is, the a in g^a is random and different for each run, so the public key A = g^a is different for each run.
If everything is working correctly, you'll never see the parties use the same values, or one party to reuse a past value. Independent executions will never produce the same result. It does not matter if its OpenSSL ↔ OpenSSL, OpenSSL ↔ Java, or Java ↔ Java. They will always produce different results.