Encryption using PKCS#7 - java

I am using Bouncy Castle provided library to encrypt,decrypt,sign and verify sign.
I am doing this as
1. Encrypt data
2. Sign data
3. Write signed byte to a file
4. Read signed byte from file
5. Verify signature
6. Decrypt data
I have taken reference from Beginning Cryptography with Java
My problem is in step 5 when i am verifying data i am getting
org.bouncycastle.cms.CMSException: message-digest attribute value does
not match calculated value
My code is below
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import javax.security.auth.x500.X500Principal;
import javax.security.auth.x500.X500PrivateCredential;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSEnvelopedDataParser;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.RecipientId;
import org.bouncycastle.cms.RecipientInformation;
import org.bouncycastle.cms.RecipientInformationStore;
import org.bouncycastle.cms.SignerId;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
public class Test {
private static final char[] KEY_STORE_PASSWORD = "123456".toCharArray();
private static final long VALIDITY_PERIOD = 365 * 24 * 60 * 60 * 1000;
private static final char[] KEY_PASSWORD = "keyPassword".toCharArray();
public static String ROOT_ALIAS = "root";
public static String INTERMEDIATE_ALIAS = "intermediate";
public static String END_ENTITY_ALIAS = "end";
public static String PLAIN_TEXT = "Hello World!123";
public static void main(String[] args) {
try{
// CREATE KEY STORE
KeyStore keyStore = createKeyStore();
// STEP 1. ENCRYPT AND SIGN
byte[] step1Data = encryptData(keyStore, PLAIN_TEXT.getBytes());
CMSSignedData cmsSignedData = signData(keyStore,step1Data);
new File("D:\\pkcs7\\encrypted-file.p7b");
FileOutputStream fileOuputStream = new FileOutputStream("D:\\pkcs7\\encrypted-file.p7b");
fileOuputStream.write(cmsSignedData.getEncoded());
fileOuputStream.flush();
fileOuputStream.close();
// STEP 2. READ ENCRYPTED DATA AND VERIFY SIGN AND DECRYPT IT
File file =new File("D:\\pkcs7\\encrypted-file.p7b");
FileInputStream fileInputStream = new FileInputStream(file);
byte[] encryptedAndSignedByte = new byte[(int)file.length()];
fileInputStream.read(encryptedAndSignedByte );
fileInputStream.close();
cmsSignedData = new CMSSignedData(encryptedAndSignedByte);
if( verifyData(keyStore, cmsSignedData) == true ){
decryptData(keyStore,encryptedAndSignedByte);
}
}catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* This method will encrypt data
*/
private static byte[] encryptData(KeyStore keyStore, byte[] plainData) throws Exception {
PrivateKey key = (PrivateKey) keyStore.getKey(END_ENTITY_ALIAS,
KEY_PASSWORD);
Certificate[] chain = keyStore.getCertificateChain(END_ENTITY_ALIAS);
X509Certificate cert = (X509Certificate) chain[0];
// set up the generator
CMSEnvelopedDataGenerator gen = new CMSEnvelopedDataGenerator();
gen.addKeyTransRecipient(cert);
// create the enveloped-data object
CMSProcessable data = new CMSProcessableByteArray(plainData);
CMSEnvelopedData enveloped = gen.generate(data,
CMSEnvelopedDataGenerator.AES128_CBC, "BC");
return enveloped.getEncoded();
// recreate
}
private static byte[] decryptData(KeyStore keyStore,byte[] encryptedData) throws Exception{
CMSEnvelopedDataParser envelopedDataParser = new CMSEnvelopedDataParser(new ByteArrayInputStream(encryptedData));
PrivateKey key = (PrivateKey) keyStore.getKey(END_ENTITY_ALIAS,KEY_PASSWORD);
Certificate[] chain = keyStore.getCertificateChain(END_ENTITY_ALIAS);
X509Certificate cert = (X509Certificate) chain[0];
CMSEnvelopedData enveloped = new CMSEnvelopedData(encryptedData);
// look for our recipient identifier
RecipientId recId = new RecipientId();
recId.setSerialNumber(cert.getSerialNumber());
recId.setIssuer(cert.getIssuerX500Principal().getEncoded());
RecipientInformationStore recipients = enveloped.getRecipientInfos();
RecipientInformation recipient = recipients.get(recId);
if (recipient != null) {
// decrypt the data
byte[] recData = recipient.getContent(key, "BC");
System.out.println("----------------------- RECOVERED DATA -----------------------");
System.out.println(new String(recData));
System.out.println("--------------------------------------------------------------");
return recData;
} else {
System.out.println("could not find a matching recipient");
}
return null;
}
private static CMSSignedData signData(KeyStore keyStore,byte[] encryptedData ) throws Exception {
// GET THE PRIVATE KEY
PrivateKey key = (PrivateKey) keyStore.getKey(END_ENTITY_ALIAS,
KEY_PASSWORD);
Certificate[] chain = keyStore.getCertificateChain(END_ENTITY_ALIAS);
CertStore certsAndCRLs = CertStore.getInstance("Collection",
new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
X509Certificate cert = (X509Certificate) chain[0];
// set up the generator
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA224);
gen.addCertificatesAndCRLs(certsAndCRLs);
// create the signed-data object
CMSProcessable data = new CMSProcessableByteArray(encryptedData);
CMSSignedData signed = gen.generate(data, "BC");
// recreate
signed = new CMSSignedData(data, signed.getEncoded());
// ContentInfo conInf = signed.getContentInfo();
// CMSProcessable sigContent = signed.getSignedContent();
return signed;
}
private static boolean verifyData(KeyStore keyStore, CMSSignedData signed)
throws Exception {
// verification step
X509Certificate rootCert = (X509Certificate) keyStore.getCertificate(ROOT_ALIAS);
if (isValidSignature(signed, rootCert)) {
System.out.println("verification succeeded");
return true;
} else {
System.out.println("verification failed");
}
return false;
}
/**
* Take a CMS SignedData message and a trust anchor and determine if the
* message is signed with a valid signature from a end entity entity
* certificate recognized by the trust anchor rootCert.
*/
private static boolean isValidSignature(CMSSignedData signedData,
X509Certificate rootCert) throws Exception {
boolean[] bArr = new boolean[2];
bArr[0] = true;
CertStore certsAndCRLs = signedData.getCertificatesAndCRLs(
"Collection", "BC");
SignerInformationStore signers = signedData.getSignerInfos();
Iterator it = signers.getSigners().iterator();
if (it.hasNext()) {
SignerInformation signer = (SignerInformation) it.next();
SignerId signerConstraints = signer.getSID();
signerConstraints.setKeyUsage(bArr);
PKIXCertPathBuilderResult result = buildPath(rootCert,
signer.getSID(), certsAndCRLs);
return signer.verify(result.getPublicKey(), "BC");
}
return false;
}
/**
* Build a path using the given root as the trust anchor, and the passed in
* end constraints and certificate store.
* <p>
* Note: the path is built with revocation checking turned off.
*/
public static PKIXCertPathBuilderResult buildPath(X509Certificate rootCert,
X509CertSelector endConstraints, CertStore certsAndCRLs)
throws Exception {
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC");
PKIXBuilderParameters buildParams = new PKIXBuilderParameters(
Collections.singleton(new TrustAnchor(rootCert, null)),
endConstraints);
buildParams.addCertStore(certsAndCRLs);
buildParams.setRevocationEnabled(false);
return (PKIXCertPathBuilderResult) builder.build(buildParams);
}
/**
* Create a KeyStore containing the a private credential with certificate
* chain and a trust anchor.
*/
public static KeyStore createKeyStore() throws Exception {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.load(null, null);
X500PrivateCredential rootCredential = createRootCredential();
X500PrivateCredential interCredential = createIntermediateCredential(
rootCredential.getPrivateKey(), rootCredential.getCertificate());
X500PrivateCredential endCredential = createEndEntityCredential(
interCredential.getPrivateKey(),
interCredential.getCertificate());
keyStore.setCertificateEntry(rootCredential.getAlias(),
rootCredential.getCertificate());
keyStore.setKeyEntry(
endCredential.getAlias(),
endCredential.getPrivateKey(),
KEY_PASSWORD,
new Certificate[] { endCredential.getCertificate(),
interCredential.getCertificate(),
rootCredential.getCertificate() });
keyStore.store(new FileOutputStream("d:\\pkcs7\\KeyStore.jks"),
KEY_STORE_PASSWORD);
return keyStore;
}
/**
* Create a random 1024 bit RSA key pair
*/
public static KeyPair generateRSAKeyPair() throws Exception {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
kpGen.initialize(1024, new SecureRandom());
return kpGen.generateKeyPair();
}
/**
* Generate a sample V1 certificate to use as a CA root certificate
*/
public static X509Certificate generateCertificate(KeyPair pair)
throws Exception {
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(1));
certGen.setIssuerDN(new X500Principal("CN=Test CA Certificate"));
certGen.setNotBefore(new Date(System.currentTimeMillis()
- VALIDITY_PERIOD));
certGen.setNotAfter(new Date(System.currentTimeMillis()
+ VALIDITY_PERIOD));
certGen.setSubjectDN(new X500Principal("CN=Test CA Certificate"));
certGen.setPublicKey(pair.getPublic());
certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
return certGen.generateX509Certificate(pair.getPrivate(), "BC");
}
/**
* Generate a sample V1 certificate to use as a CA root certificate
*/
public static X509Certificate generateRootCert(KeyPair pair)
throws Exception {
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(1));
certGen.setIssuerDN(new X500Principal("CN=Test CA Certificate"));
certGen.setNotBefore(new Date(System.currentTimeMillis()
- VALIDITY_PERIOD));
certGen.setNotAfter(new Date(System.currentTimeMillis()
+ VALIDITY_PERIOD));
certGen.setSubjectDN(new X500Principal("CN=Test CA Certificate"));
certGen.setPublicKey(pair.getPublic());
certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
return certGen.generateX509Certificate(pair.getPrivate(), "BC");
}
/**
* Generate a sample V3 certificate to use as an end entity certificate
*/
public static X509Certificate generateEndEntityCert(PublicKey entityKey,
PrivateKey caKey, X509Certificate caCert) throws Exception {
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(1));
certGen.setIssuerDN(caCert.getSubjectX500Principal());
certGen.setNotBefore(new Date(System.currentTimeMillis()
- VALIDITY_PERIOD));
certGen.setNotAfter(new Date(System.currentTimeMillis()
+ VALIDITY_PERIOD));
certGen.setSubjectDN(new X500Principal("CN=Test End Certificate"));
certGen.setPublicKey(entityKey);
certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(caCert));
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
new SubjectKeyIdentifierStructure(entityKey));
certGen.addExtension(X509Extensions.BasicConstraints, true,
new BasicConstraints(false));
certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(
KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
return certGen.generateX509Certificate(caKey, "BC");
}
/**
* Generate a X500PrivateCredential for the root entity.
*/
public static X500PrivateCredential createRootCredential() throws Exception {
KeyPair rootPair = generateRSAKeyPair();
X509Certificate rootCert = generateRootCert(rootPair);
return new X500PrivateCredential(rootCert, rootPair.getPrivate(),
ROOT_ALIAS);
}
/**
* Generate a X500PrivateCredential for the intermediate entity.
*/
public static X500PrivateCredential createIntermediateCredential(
PrivateKey caKey, X509Certificate caCert) throws Exception {
KeyPair interPair = generateRSAKeyPair();
X509Certificate interCert = generateIntermediateCert(
interPair.getPublic(), caKey, caCert);
return new X500PrivateCredential(interCert, interPair.getPrivate(),
INTERMEDIATE_ALIAS);
}
/**
* Generate a X500PrivateCredential for the end entity.
*/
public static X500PrivateCredential createEndEntityCredential(
PrivateKey caKey, X509Certificate caCert) throws Exception {
KeyPair endPair = generateRSAKeyPair();
X509Certificate endCert = generateEndEntityCert(endPair.getPublic(),
caKey, caCert);
return new X500PrivateCredential(endCert, endPair.getPrivate(),
END_ENTITY_ALIAS);
}
/**
* Generate a sample V3 certificate to use as an intermediate CA certificate
*/
public static X509Certificate generateIntermediateCert(PublicKey intKey,
PrivateKey caKey, X509Certificate caCert) throws Exception {
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(1));
certGen.setIssuerDN(caCert.getSubjectX500Principal());
certGen.setNotBefore(new Date(System.currentTimeMillis()));
certGen.setNotAfter(new Date(System.currentTimeMillis()
+ VALIDITY_PERIOD));
certGen.setSubjectDN(new X500Principal(
"CN=Test Intermediate Certificate"));
certGen.setPublicKey(intKey);
certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(caCert));
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
new SubjectKeyIdentifierStructure(intKey));
certGen.addExtension(X509Extensions.BasicConstraints, true,
new BasicConstraints(0));
certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(
KeyUsage.digitalSignature | KeyUsage.keyCertSign
| KeyUsage.cRLSign));
return certGen.generateX509Certificate(caKey, "BC");
}
}

In typical usage a .p7b file contains only public key certificates and never a private key. It is often used to store an entire chain of certificates rather than a single certificate. The 'p7b' name comes from the format which is the degenerate form of PKCS#7 SignedData structure. Typically, private keys are stored in a PKCS#12 (often a file that has either a .p12 or a .pfx extension) file but other formats are also common.
To read in the certificates from a p7b file you can use the CertificateFactory class. A PKCS#12 file is directly usable as a keystore.
You mention PKCS#7 frequently. PKCS#7 is an old standard that is extremely large and open ended. These days the standard that is more commonly implemented is an extended subset of PKCS#7 called CMS. It's an IETF standard documented in RFC 5652. The Bouncycastle PKIX/CMS library has extensive support for the CMS specification.

try {
File file = new File("d:\\TESTS\\VG.p7b");
FileInputStream fis = new FileInputStream(file);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection c = cf.generateCertificates(fis);
Iterator i = c.iterator();
while (i.hasNext()) {
X509Certificate cert509 = (X509Certificate) i.next();
System.out.println(cert509);
}
}
catch (Throwable th) {
th.printStackTrace();
}

Related

Apple Pay Payment Token Decryption in Java

I am trying to decrypt the data field inside an Apple Pay Payment Token using ECC algorithm in Java on the server side. How can I implement it?
I've been searching for such an implementation in Java for quite a while and I couldn't find one. Instead, I've found an implementation using Bouncy Castle C# library to decrypt the token:
https://github.com/chengbo/ApplePayAndroidPayDecryption
Although there is also an Bouncy Castle library in Java, but I've found some difference in the implementation between the C# one and the Java one, which lead to the failure of decryption when I try to code in accordance with the C# implementation above.
I've generated my certificate in Apple Dev Center and I'm quite sure that the certificate file needed during the process of decrytion is correct.
Has anyone succeeded in decrypting the token in Java? Any help is appreciated, Thanks a lot!
Here is the key part of the return message from Apple when I did a test payment:
passKit={"version":"EC_v1","data":"AK7UZehTHQRXYzgPCD5ijZfloc9ZfUjAutl+7v/83V7U6YjsWSrBVzILQlp2xLP4E4QXxRwadIh0Y9Vg6297BV2ljginDwoR5nneEIQP6fNCXYwll5hUYYlL0ZO7pD/8KXStAh8pnOAyFtEVrDqIRCWZbftzdsAi76qFMXd3Z2bRSjl5zrt8Qfua6Nu1b3MNNVlPQVMJsskEQFncnViNLDkRulgt5WezVF8N1m62nEqminLBF7m+36/pLi0t9JTfqQ0qNYahczAzyyCJhABkXRXXf9iF3YJ77gBD9mBFRVrePPNW0PnJyoQPvDikGzDTc4k5+NBBSEAJjBLlt94okHmh9eO2A9/xoUh7/ktI+Vjk2k+8PWDOAWIkVM4+7vPCrESYedVzTBd6BYIL7+oPmbAW5EJ1JC2twafmmVhL4lXwdz296aBtNDTIzV+of+Oc6JrEutzjVYm8qGdv4MO0DJ3eWG/r9G1QPaTR84CRXXxmoL/EAH9fLYGfQeJsGHmLKieX2b2IfHwTtTnFVloqwt0ywd47PnqLbZ+pETZgsUegZIUAPH6Hl3WMo2eXKbybyxuY70WV+OoIxKBGHQnPYndPA3aG7XeSiUXF/2vW/Qq+UVfxQc0O4X6A/qTYy5c1HlQVq7PloE2+jkGCtKpuvsuVnnRF7sxxG3Wke7Vlz6at/+CHdT0K91+a29U1E8JVwhjnXvT8E/FcvrwHaCMmK1eK8/sMFGQ=","signature":"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","header":{"ephemeralPublicKey":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFnF0WIB3GTpyaP7rgW0kzUMgqfwsTecb7/JrSQXZSuILCBPBs2YQQXFfIHNYtFFMzMTY24/tgbolbKjkmIUwIw==","applicationData":"5cd2d027aa6372ea5420770272ef47a596e60f4299c16c6591c3e7e532208394","publicKeyHash":"sRANn6djBkx5m//vTDU6HFOX4j1Nn/X4bNlgxJYRZgo=","transactionId":"947a5fc21adcc692bd204fa4e1a7a4f83ab8383283f3fa46b204b514559adede"}}
This Code(JAVA) will decrypt the ApplePay token. For this code to work convert the certificate file to JKS(retrieve merchant ID) and pk8(private key) formates.
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.bouncycastle.asn1.ASN1UTCTime;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Hex;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
import java.io.*;
import java.nio.charset.Charset;
import java.security.*;
import java.security.cert.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
public class ApplePayDecrypt {
public static final String MERCHANT_ID = "merchant.Id";
private static KeyStore keyStore;
private static PrivateKey merchantPrivateKey;
static {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
public static AppleDecryptData decrypt(TokenData tokenData) {
try {
// Load merchant private key
byte[] merchantbyte = IOUtils.toByteArray(Application.class.getResource("/apple_pay.pk8"));
String key = new String(merchantbyte);
key = key.replace("-----BEGIN PRIVATE KEY-----", "");
key = key.replace("-----END PRIVATE KEY-----", "");
key = key.replaceAll("\\s+", "");
byte[] merchantPrivateKeyBytes = Base64.decodeBase64(key);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(merchantPrivateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", PROVIDER_NAME);
merchantPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// Load Apple root certificate
keyStore = KeyStore.getInstance("BKS");
keyStore.load(GoSecureApplication.class.getResourceAsStream("/appleCA-G3"), "apple123".toCharArray());
return unwrap(tokenData);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#SuppressWarnings({ "unused", "unchecked" })
public static AppleDecryptData unwrap(TokenData tokenData) throws Exception {
// Merchants should use the 'version' field to determine how to verify and
// decrypt the message payload.
// At this time the only published version is 'EC_v1' which is demonstrated
// here.
String version = tokenData.version;
byte[] signatureBytes = Base64.decodeBase64(tokenData.signature);
byte[] dataBytes = Base64.decodeBase64(tokenData.data);
// JsonObject headerJsonObject =
// jsonObject.get(PAYMENT_HEADER).getAsJsonObject();
byte[] transactionIdBytes = Hex.decode(tokenData.header.transactionId);
byte[] ephemeralPublicKeyBytes = Base64.decodeBase64(tokenData.header.ephemeralPublicKey);
// Merchants that have more than one certificate may use the 'publicKeyHash'
// field to determine which
// certificate was used to encrypt this payload.
byte[] publicKeyHash = Base64.decodeBase64(tokenData.header.publicKeyHash);
// Application data is a conditional field, present when the merchant has
// supplied it to the iOS SDK.
byte[] applicationDataBytes = null;
byte[] signedBytes = ArrayUtils.addAll(ephemeralPublicKeyBytes, dataBytes);
signedBytes = ArrayUtils.addAll(signedBytes, transactionIdBytes);
signedBytes = ArrayUtils.addAll(signedBytes, applicationDataBytes);
CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(signedBytes), signatureBytes);
// Check certificate path
Store<?> certificateStore = signedData.getCertificates();
List<X509Certificate> certificates = new ArrayList<X509Certificate>();
JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
certificateConverter.setProvider(PROVIDER_NAME);
for (Object o : certificateStore.getMatches(null)) {
X509CertificateHolder certificateHolder = (X509CertificateHolder) o;
certificates.add(certificateConverter.getCertificate(certificateHolder));
}
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", PROVIDER_NAME);
CertPath certificatePath = certificateFactory.generateCertPath(certificates);
PKIXParameters params = new PKIXParameters(keyStore);
params.setRevocationEnabled(false);
// TODO: Test certificate has no CRLs. Merchants must perform revocation checks
// in production.
// TODO: Verify certificate attributes per instructions at
// https://developer.apple.com/library/ios/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html#//apple_ref/doc/uid/TP40014929
CertPathValidator validator = CertPathValidator.getInstance("PKIX", PROVIDER_NAME);
PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) validator.validate(certificatePath, params);
System.out.println(result);
// Verify signature
SignerInformationStore signerInformationStore = signedData.getSignerInfos();
boolean verified = false;
for (Object o : signerInformationStore.getSigners()) {
SignerInformation signer = (SignerInformation) o;
Collection<?> matches = certificateStore.getMatches(signer.getSID());
if (!matches.isEmpty()) {
X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next();
if (signer.verify(
new JcaSimpleSignerInfoVerifierBuilder().setProvider(PROVIDER_NAME).build(certificateHolder))) {
DERSequence sequence = (DERSequence) signer.getSignedAttributes().get(CMSAttributes.signingTime)
.toASN1Primitive();
DERSet set = (DERSet) sequence.getObjectAt(1);
ASN1UTCTime signingTime = (ASN1UTCTime) set.getObjectAt(0).toASN1Primitive();
// Merchants can check the signing time of this payment to determine its
// freshness.
System.out.println("Signature verified. Signing time is " + signingTime.getDate());
verified = true;
}
}
}
if (verified) {
// Ephemeral public key
KeyFactory keyFactory = KeyFactory.getInstance("EC", PROVIDER_NAME);
PublicKey ephemeralPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(ephemeralPublicKeyBytes));
// Key agreement
String asymmetricKeyInfo = "ECDH";
KeyAgreement agreement = KeyAgreement.getInstance(asymmetricKeyInfo, PROVIDER_NAME);
agreement.init(merchantPrivateKey);
agreement.doPhase(ephemeralPublicKey, true);
byte[] sharedSecret = agreement.generateSecret();
byte[] derivedSecret = performKDF(sharedSecret, extractMerchantIdFromCertificateOid());
// Decrypt the payment data
String symmetricKeyInfo = "AES/GCM/NoPadding";
Cipher cipher = Cipher.getInstance(symmetricKeyInfo, PROVIDER_NAME);
SecretKeySpec key = new SecretKeySpec(derivedSecret, cipher.getAlgorithm());
IvParameterSpec ivspec = new IvParameterSpec(new byte[16]);
cipher.init(Cipher.DECRYPT_MODE, key, ivspec);
byte[] decryptedPaymentData = cipher.doFinal(dataBytes);
// JSON payload
String data = new String(decryptedPaymentData, "UTF-8");
// System.out.println(data);
AppleDecryptData decryptDat = ObjMapper.getInstance().readValue(data, AppleDecryptData.class);
return decryptDat;
} else {
return null;
}
}
private static final byte[] APPLE_OEM = "Apple".getBytes(Charset.forName("US-ASCII"));
private static final byte[] COUNTER = { 0x00, 0x00, 0x00, 0x01 };
private static final byte[] ALG_IDENTIFIER_BYTES = "id-aes256-GCM".getBytes(Charset.forName("US-ASCII"));
/**
* 00000001_16 || sharedSecret || length("AES/GCM/NoPadding") ||
* "AES/GCM/NoPadding" || "Apple" || merchantID
*/
private static byte[] performKDF(byte[] sharedSecret, byte[] merchantId) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(COUNTER);
baos.write(sharedSecret);
baos.write(ALG_IDENTIFIER_BYTES.length);
baos.write(ALG_IDENTIFIER_BYTES);
baos.write(APPLE_OEM);
baos.write(merchantId);
MessageDigest messageDigest = MessageDigest.getInstance("SHA256", PROVIDER_NAME);
return messageDigest.digest(baos.toByteArray());
}
#SuppressWarnings("unused")
private static byte[] performKDF(byte[] sharedSecret, String merchantId) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance("SHA256", PROVIDER_NAME);
return performKDF(sharedSecret, messageDigest.digest(merchantId.getBytes("UTF-8")));
}
protected static byte[] extractMerchantIdFromCertificateOid() throws Exception {
KeyStore vkeyStore = KeyStore.getInstance("JKS");
vkeyStore.load(GoSecureApplication.class.getResourceAsStream("/kapple_pay.jks"), "".toCharArray());
Enumeration<String> aliases = vkeyStore.aliases();
String alias = null;
while (aliases.hasMoreElements()) {
alias = aliases.nextElement();
}
X509Certificate cert = (X509Certificate) vkeyStore.getCertificate(alias);
byte[] merchantIdentifierTlv = cert.getExtensionValue("1.2.840.113635.100.6.32");
byte[] merchantIdentifier = new byte[64];
System.arraycopy(merchantIdentifierTlv, 4, merchantIdentifier, 0, 64);
return Hex.decode(merchantIdentifier);
}
}

JAVA API to create a keystore and attaching a csr and keypair to it

I need to attach an existing csr and keypair to a keystore. Given below is an implementation that uses GUI(java swing) to take the input from the user such as keystore name, alias,common name, organization etc.
I try to link the csr to the keystore using keystore.setkeyentry(...), however the keystore is still empty.
I have attached my code below, any help will be very useful:
This code below is used to create a csr
public String getCSR(String cn, String ou, String o, String l,String s) throws Exception {
byte[] csr = generatePKCS10(cn, ou, o, l,s,"US");
return new String(csr);
}
private static byte[] generatePKCS10(String CN, String OU, String O,
String L, String S, String C) throws Exception {
// generate PKCS10 certificate request
String sigAlg = "MD5WithRSA";
PKCS10 pkcs10 = new PKCS10(publicKey);
Signature signature = Signature.getInstance(sigAlg);
signature.initSign(privateKey);
// common, orgUnit, org, locality, state, country
X500Principal principal = new X500Principal( "CN=Ole Nordmann, OU=ACME, O=Sales, C=NO");
// pkcs10CertificationRequest kpGen = new PKCS10CertificationRequest(sigAlg, principal, publicKey, null, privateKey);
// byte[] c = kpGen.getEncoded();
X500Name x500name=null;
x500name= new X500Name(principal.getEncoded());
pkcs10.encodeAndSign(x500name, signature);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs);
pkcs10.print(ps);
byte[] c = bs.toByteArray();
try {
if (ps != null)
ps.close();
if (bs != null)
bs.close();
} catch (Throwable th) {
}
return c;
}
public static X509Certificate generateX509Certificate(String certEntry) throws IOException {
InputStream in = null;
X509Certificate cert = null;
try {
byte[] certEntryBytes = certEntry.getBytes();
in = new ByteArrayInputStream(certEntryBytes);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
cert = (X509Certificate) certFactory.generateCertificate(in);
} catch (CertificateException ex) {
} finally {
if (in != null) {
in.close();
}
}
return cert;
}
In the main method I do the following to create a keystore and attach it to the csr
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
char[] pass = password.toCharArray();
ks.load(null, pass);
ks.store(fos, pass);
fos.close();
GenerateCSR gcsr = GenerateCSR.getInstance();
System.out.println("Public Key:\n"+gcsr.getPublicKey().toString());
System.out.println("Private Key:\n"+gcsr.getPrivateKey().toString());
String csr = gcsr.getCSR(CN,OU,O,L,S);
System.out.println("CSR Request Generated!!");
System.out.println(csr);
X509Certificate[] certChain = new X509Certificate[1];
// certChain[0]= gcsr.generateX509Certificate(csr);
X509Certificate myCert = (X509Certificate) CertificateFactory
.getInstance("X509")
.generateCertificate(
// string encoded with default charset
new ByteArrayInputStream(csr.getBytes())
);
certChain[0]= myCert;
ks.setKeyEntry("alias", (Key)gcsr.getPrivateKey(), pass, certChain);
When I check the contents of the keystore, it is empty.
Any advice will be appreciated
Thank You!!!
You have two main mistakes:
a Certificate Signing Request aka CSR aka PKCS10 is NOT a certificate. CertificateFactory.generateCertificate will only read a certificate and not a CSR, and when you provide it with a CSR it throws an exception which your code cleverly suppresses with no indication to anybody there was a serious problem. The commented-out code you had in your earlier revision was closer to that needed to generate a certificate.
(if you do create/have a valid certificate) KeyStore.set* only sets the entry in the in-memory KeyStore object. If you want the keystore contents saved somewhere like in a file after your program exits, you must store it AFTER doing the 'set'(s).
Here is your code modified enough it works as I believe you want. Except for trivial formatting and scaffolding, spots I changed are marked by //-- for deletions and //** for additions. Even so I do not recommend it because:
I continue your use of the unsupported sun.security classes, even though you are using BC and it has supported classes for PKCS10 and related bits, plus a CSR is only needed if you want to request a certificate from a CA; to generate a cert yourself just generating the cert directly is easier
(less serious) in recent versions of BC pkix has been split to a separate jar and X509V3CertificateGenerator is now deprecated in favor of X509v3CertificateBuilder
//nopackage
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import javax.security.auth.x500.*;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.x509.X509V3CertificateGenerator;
//--import sun.security.pkcs.PKCS10; -- Java7
import sun.security.pkcs10.PKCS10; //** Java8
import sun.security.x509.X500Name;
public class SO40350607GenerateCertIntoKeystoreFile8 {
public static void main (String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//**dummy value for test
KeyPairGenerator kpgen = KeyPairGenerator.getInstance("RSA");
kpgen.initialize(1024); keyPair = kpgen.generateKeyPair();
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
char[] pass = "password".toCharArray();
ks.load(null, pass);
//--ks.store(fos, pass); useless here
//--fos.close();
String csr = new String(generatePKCS10("CommonName","OrgUnit","Org","Locality","State", "US"));
System.out.println("CSR Request Generated!!");
System.out.println(csr);
//--X509Certificate myCert = (X509Certificate) CertificateFactory.getInstance("X509")
//-- .generateCertificate(new ByteArrayInputStream(csr.getBytes()) ); // string encoded with default charset*/
X509Certificate myCert = generateCertificate2 (csr); //**
X509Certificate[] certChain = new X509Certificate[]{myCert};
ks.setKeyEntry("alias", keyPair.getPrivate(), pass, certChain);
FileOutputStream fos = new FileOutputStream ("newksfile");
ks.store(fos,pass); fos.close(); //** NOW store to file
}
private static KeyPair keyPair;
private static byte[] generatePKCS10(String CN, String OU, String O,
String L, String S, String C) throws Exception {
// generate PKCS10 certificate request
String sigAlg = "SHA1WithRSA"; //** don't use "MD5WithRSA" even for CSR
PKCS10 pkcs10 = new PKCS10(keyPair.getPublic());
Signature signature = Signature.getInstance(sigAlg);
signature.initSign(keyPair.getPrivate());
// common, orgUnit, org, locality, state, country
//--X500Principal principal = new X500Principal( "CN=Ole Nordmann, OU=ACME, O=Sales, C=NO");
//--X500Name x500name= new X500Name(principal.getEncoded());
//** can do this directly (and better)
X500Name x500name = new X500Name ("CN="+CN+",OU="+OU+",O="+O+",L="+L+",S="+S+",C="+C);
pkcs10.encodeAndSign(x500name, signature);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs);
pkcs10.print(ps);
byte[] c = bs.toByteArray();
ps.close(); //** bs,ps are never null, ps.close automatically closes underlying bs,
//** and anyway BAOS doesn't need to be closed (although most streams do)
return c;
}
//** (whole) routine to generate an actual (though selfsigned) certificate
public static X509Certificate generateCertificate2 (String csrpem) throws Exception {
String csrtrim = csrpem.replaceAll("-----[^\\n]*\\n","").replaceAll("\\r?\\n","");
//--PKCS10 pkcs10 = new PKCS10 (Base64.decode (csrtrim.toCharArray())); --Java7
PKCS10 pkcs10 = new PKCS10 (Base64.getDecoder().decode (csrtrim.getBytes())); //Java8
// or use the one we had before encoding it -- or the input data directly??
// X509V3CertificateGenerator is deprecated but stay with it for now
X509V3CertificateGenerator cert = new X509V3CertificateGenerator();
cert.setSerialNumber(BigInteger.valueOf(1)); //or generate a random number
cert.setSubjectDN(pkcs10.getSubjectName().asX500Principal());
cert.setIssuerDN(pkcs10.getSubjectName().asX500Principal()); //same since it is self-signed
cert.setPublicKey(pkcs10.getSubjectPublicKeyInfo());
Date now = new Date(); cert.setNotBefore(now);
now.setYear(now.getYear()+1); cert.setNotAfter(now);
cert.setSignatureAlgorithm("SHA1WithRSA");
PrivateKey signingKey = keyPair.getPrivate();
return cert.generate(signingKey, "BC");
}
}

org.bouncycastle.asn1.DLSequence cannot be cast to org.bouncycastle.asn1.ASN1Integer

I am trying to use BouncyCastle classes to encrypt and decrypt a password. I have written a test program and generated a test key/cert in PEM format as well as DER format. I can read the key/cert into my program and get the public key and encrypt a value. When I try to setup to decrypt the value I am getting the error "org.bouncycastle.asn1.DLSequence cannot be cast to org.bouncycastle.asn1.ASN1Integer" when creating the AsymmetricKeyParameter. It seems that when I am trying to pull in the data from the cert by doing the cert.getEncoded() it pulls in the header values as well. I tried just reading the file and removing the BEGIN and END CERTIFCATE lines, along with the dashes and that netted me the same error. I have tried used the java.security.cert.Certificate as well as the X509Certificate the code below is using. Any help would be greatly appreciated.
I can upload the key file is that would be helpful to you as it is a test key that I generated on my local machine and will be thrown away once I have this working.
package com.cds.test;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
public class RSAEncryptDecrypt {
public X509Certificate cert = null;
//
public void readCertificate() throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
CertificateFactory factory = CertificateFactory.getInstance("X.509", new BouncyCastleProvider());
InputStream fis = new FileInputStream("/opt/temp/keys/openssl_crt.pem");
X509Certificate x509Cert = (X509Certificate) factory.generateCertificate(fis);
this.cert = x509Cert;
System.out.println("issuer: " + x509Cert.getIssuerX500Principal());
}
//
public String encrypt(String inputData) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//
System.out.println("public key: " + new String(Base64.encode(cert.getPublicKey().getEncoded())));
AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(cert.getPublicKey().getEncoded());
AsymmetricBlockCipher cipher = new RSAEngine();
cipher = new org.bouncycastle.crypto.encodings.PKCS1Encoding(cipher);
cipher.init(true, publicKey);
//
byte[] messageBytes = inputData.getBytes();
byte[] hexEncodedCipher = cipher.processBlock(messageBytes, 0, messageBytes.length);
//
return new String(Base64.encode(hexEncodedCipher));
}
//
private String decrypt (String encryptedData) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//
byte[] certData = cert.getEncoded();
//certData = Base64.decode(certData);
AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(cert.getEncoded());
AsymmetricBlockCipher cipher = new RSAEngine();
cipher = new org.bouncycastle.crypto.encodings.PKCS1Encoding(cipher);
cipher.init(false, privateKey);
//
byte[] decoded = Base64.decode(encryptedData.getBytes());
byte[] result = cipher.processBlock(decoded, 0, decoded.length);
//
return new String(result);
}
//
public static void main(String[] args) throws Exception {
String inputData = "This is the message I am trying to encrypt.";
String encrypted = null;
String decrypted = null;
//
RSAEncryptDecrypt rsa = new RSAEncryptDecrypt();
//
rsa.readCertificate();
System.out.println(" input: " + inputData);
encrypted = rsa.encrypt(inputData);
System.out.println("encrypted: " + encrypted);
decrypted = rsa.decrypt(encrypted);
System.out.println("decrypted: " + decrypted);
}
}
A certificate only contains the public key, not a private key. Of course the public key has a private key associated to it, but that is not kept in the certificate. The certificate is what you distribute to other parties.
It could be that you have been working with Microsoft code too much. I'm mentioning Microsoft as in .NET code the certificate class can internally contain the associated private key, making for a rather oversimplified API.
So to decrypt you will have to read the private key separately of your certificate (using PKCS8EncodedKeySpec and an "RSA" KeyFactory).
Another option is to put both in a PKCS#12 key store and read it into Java using KeyStore.load.

Read Original Data from Signed content java

I want to extract original data from signed content.
In the following code, the signed data is "CMSSignedData signed"
I found several similar answers from the StackOverflow, but all the answers cannot
state how to extract original data from signed content.
regards
package chapter9;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.*;
import java.util.Arrays;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
/**
* Example of generating a detached signature.
*/
public class SignedDataExample
extends SignedDataProcessor
{
public static void main(String[] args)
throws Exception
{
KeyStore credentials = Utils.createCredentials();
PrivateKey key = (PrivateKey)credentials.getKey(Utils.END_ENTITY_ALIAS, Utils.KEY_PASSWD);
Certificate[] chain = credentials.getCertificateChain(Utils.END_ENTITY_ALIAS);
CertStore certsAndCRLs = CertStore.getInstance("Collection",
new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
X509Certificate cert = (X509Certificate)chain[0];
// set up the generator
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA256);
gen.addCertificatesAndCRLs(certsAndCRLs);
// create the signed-data object
CMSProcessable data = new CMSProcessableByteArray("Hello World!".getBytes());
CMSSignedData signed = gen.generate(data, "BC");
// recreate
signed = new CMSSignedData(data, signed.getEncoded());
//extract public key
CertStore cs = signed.getCertificatesAndCRLs("Collection", "BC");
//signed.signedContent
//signed.g
CMSProcessable S = signed.getSignedContent();
String aaa = S.getContent().toString();
//byte[] K = Base64.decodeBase64((S.getContent()).toString());
//
//String K = Base64.decodeBase64(S.getContent());
//BASE64Decoder.decoder.decodeBuffer()
//
//byte[] array = asString.getBytes("UTF8");
//String s = new String(array, "UTF8");
// verification step
X509Certificate rootCert = (X509Certificate)credentials.getCertificate(Utils.ROOT_ALIAS);
if (isValid(signed, rootCert))
{
System.out.println("verification succeeded");
//System.out.println(K);
//String asString = new String((byte[])data.getContent());
//String asString1 = new String(cs.toString());
//System.out.println(asString);
//System.out.println(asString1);
//System.out.println(aaa);
}
else
{
System.out.println("verification failed");
}
}
}
You need to use String aaa = new String(s); instead of String aaa = S.getContent().toString(); although you should also specify an encoding, e.g. String aaa = new String(s, Charset.forName("UTF-8"));. Please do the same for your toBytes() methods.
Use new String((byte[])S.getContent()); to get the original content

How to sign string with private key

How can I get the signature of a string using SHA1withRSA if I already have the Private Key as byte[] or String?
I guess what you say is you know the key pair before hand and want to sign/verify with that.
Please see the following code.
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import sun.misc.BASE64Encoder;
public class MainClass {
public static void main(String[] args) throws Exception {
KeyPair keyPair = getKeyPair();
byte[] data = "test".getBytes("UTF8");
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initSign(keyPair.getPrivate());
sig.update(data);
byte[] signatureBytes = sig.sign();
System.out.println("Signature:" + new BASE64Encoder().encode(signatureBytes));
sig.initVerify(keyPair.getPublic());
sig.update(data);
System.out.println(sig.verify(signatureBytes));
}
private static KeyPair getKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
return kpg.genKeyPair();
}
}
Here you need to change the method getKeyPair() to supply your known key pair. You may load it from a java key store [JKS].
You can't just have an arbitrary byte array either as your public key or private key. They should be generated in relation.
public static String sign(String plainText, PrivateKey privateKey) throws Exception {
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes(UTF_8));
byte[] signature = privateSignature.sign();
return Base64.getEncoder().encodeToString(signature);
}
public static boolean verify(String plainText, String signature, PublicKey publicKey) throws Exception {
Signature publicSignature = Signature.getInstance("SHA256withRSA");
publicSignature.initVerify(publicKey);
publicSignature.update(plainText.getBytes(UTF_8));
byte[] signatureBytes = Base64.getDecoder().decode(signature);
return publicSignature.verify(signatureBytes);
}
I use bouncy-castle to sign data and verify it.
you should add maven dependency:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.56</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.56</version>
</dependency>
Load RSA private or public key from a disk file into a Java object
First, we need to be able to load RSA private or public key from a disk file into a Java object of a proper class from Bouncy Castle
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.lang3.Validate;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
public class KeyUtil {
public static AsymmetricKeyParameter loadPublicKey(InputStream is) {
SubjectPublicKeyInfo spki = (SubjectPublicKeyInfo) readPemObject(is);
try {
return PublicKeyFactory.createKey(spki);
} catch (IOException ex) {
throw new RuntimeException("Cannot create public key object based on input data", ex);
}
}
public static AsymmetricKeyParameter loadPrivateKey(InputStream is) {
PEMKeyPair keyPair = (PEMKeyPair) readPemObject(is);
PrivateKeyInfo pki = keyPair.getPrivateKeyInfo();
try {
return PrivateKeyFactory.createKey(pki);
} catch (IOException ex) {
throw new RuntimeException("Cannot create private key object based on input data", ex);
}
}
private static Object readPemObject(InputStream is) {
try {
Validate.notNull(is, "Input data stream cannot be null");
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
PEMParser pemParser = new PEMParser(isr);
Object obj = pemParser.readObject();
if (obj == null) {
throw new Exception("No PEM object found");
}
return obj;
} catch (Throwable ex) {
throw new RuntimeException("Cannot read PEM object from input data", ex);
}
}
}
Creation of an RSA digital signature
// GIVEN: InputStream prvKeyInpStream
AsymmetricKeyParameter privKey = KeyUtil.loadPrivateKey(prvKeyInpStream);
// GIVEN: byte[] messageBytes = ...
RSADigestSigner signer = new RSADigestSigner(new SHA512Digest());
signer.init(true, privKey);
signer.update(messageBytes, 0, messageBytes.length);
try {
byte[] signature = signer.generateSignature();
} catch (Exception ex) {
throw new RuntimeException("Cannot generate RSA signature. " + ex.getMessage(), ex);
}
Verification of an RSA digital signature
// GIVEN: InputStream pubKeyInpStream
AsymmetricKeyParameter publKey = KeyUtil.loadPublicKey(pubKeyInpStream);
// GIVEN: byte[] messageBytes
RSADigestSigner signer = new RSADigestSigner(new SHA512Digest());
signer.init(false, publKey);
signer.update(messageBytes, 0, messageBytes.length);
// GIVEN: byte[] signature - see code sample above
boolean isValidSignature = signer.verifySignature(signature);
public static String sign(String samlResponseString, String keystoreFile, String keyStorePassword, String privateKeyPassword, String alias)
throws NoSuchAlgorithmException, UnsupportedEncodingException,
InvalidKeyException, SignatureException {
PrivateKey pkey=getPrivateKey( keystoreFile, keyStorePassword, privateKeyPassword, alias);
String signedString = null;
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(pkey);
signature.update(samlResponseString.getBytes());
byte[] signatureBytes = signature.sign();
byte[] encryptedByteValue = Base64.encodeBase64(signatureBytes);
signedString = new String(encryptedByteValue, "UTF-8");
System.out.println(signedString);
return signedString;
}
You first must create a public key from array of bytes
byte publicKeyBytes[] = .... your public key in bytes ...
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes));
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
and after using the publicKey to encrypt
String data = "... data to be encrypted ....";
String alg = "RSA/ECB/PKCS1Padding";
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte encryptedBytes[] = cipher.doFinal(data.getBytes());
Now only who have the privateKey can read your data
#rczajka: a publicKey is a key. You can use it to sign somethig that only the owner (that have the privateKey) can read.

Categories

Resources