Encryption and Decryption with BouncyCastle PKCS7 - CMS in java - java

I want to use BouncyCastle to encrypt and decrypt with pkcs7 format. I have a hardware token. when I use Keypair in jks file in my hard drive it work fine but when i use key pair in token
its not work. this is my exception:
Exception in thread "main" org.bouncycastle.cms.CMSException: cannot create cipher: No such algorithm: 2.16.840.1.101.3.4.1.2
at org.bouncycastle.cms.jcajce.EnvelopedDataHelper.createCipher(Unknown Source)
at org.bouncycastle.cms.jcajce.EnvelopedDataHelper$1.doInJCE(Unknown Source)
at org.bouncycastle.cms.jcajce.EnvelopedDataHelper.execute(Unknown Source)
at org.bouncycastle.cms.jcajce.EnvelopedDataHelper.createContentCipher(Unknown Source)
at org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient.getRecipientOperator(Unknown Source)
at org.bouncycastle.cms.KeyTransRecipientInformation.getRecipientOperator(Unknown Source)
at org.bouncycastle.cms.RecipientInformation.getContentStream(Unknown Source)
at org.bouncycastle.cms.RecipientInformation.getContent(Unknown Source)
at pktb.PKTB.CmsDecrypt(PKTB.java:288)
at pktb.PKTB.main(PKTB.java:419)
Caused by: java.security.NoSuchAlgorithmException: No such algorithm: 2.16.840.1.101.3.4.1.2
at javax.crypto.Cipher.getInstance(DashoA13*..)
at javax.crypto.Cipher.getInstance(DashoA13*..)
at org.bouncycastle.jcajce.NamedJcaJceHelper.createCipher(Unknown Source)
... 10 more
Java Result: 1
this is my Encryption code:
public byte[] CmsEncrypt(byte[] message, KeyContainer keyContainer) throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, IOException
{
Security.addProvider(new BouncyCastleProvider());
X509Certificate cert = (X509Certificate) keyContainer.certificate;
CMSEnvelopedDataGenerator gen = new CMSEnvelopedDataGenerator();
gen.addKeyTransRecipient(cert);
CMSProcessable data = new CMSProcessableByteArray(message);
CMSEnvelopedData enveloped = gen.generate(data,
CMSEnvelopedDataGenerator.AES128_CBC, "BC");
return enveloped.getEncoded();
}
and this is my decryption code:
public byte[] CmsDecrypt(byte[] cipher, KeyContainer keyContainer) throws CMSException, IOException, NoSuchProviderException
{
Security.addProvider(new BouncyCastleProvider());
byte[] contents=null;
CMSEnvelopedDataParser envelopedDataParser = new CMSEnvelopedDataParser(new ByteArrayInputStream(cipher));
PrivateKey key = keyContainer.privateKey;
X509Certificate cert = keyContainer.certificate;
CMSEnvelopedData enveloped = new CMSEnvelopedData(cipher);
Collection recip = enveloped.getRecipientInfos().getRecipients();
KeyTransRecipientInformation rinfo = (KeyTransRecipientInformation) recip
.iterator().next();
if(keyContainer.provider.equals("Software"))
contents = rinfo.getContent(
new JceKeyTransEnvelopedRecipient(key).setProvider("BC"));
else
contents = rinfo.getContent(
new JceKeyTransEnvelopedRecipient(key).setProvider("SunPKCS11-" + keyContainer.provider));
System.out.println(new String(contents));
return contents;
}
I must say that i use this token provider for cmsSign and cmsVerify and it works fine therefore i think the problem isn't for provider.

You can use PKCS#11 to extract private and public keys from hardware token and then use these extracted public and private keys to encrypt and decrypt data with BouncyCastle PKCS7. which token you are using ? Also I cannot find the code to extract keys from hardware token. Go through the answer in following Link for extracting keys from hardware token. Click here

Related

Error with BouncyCastle library 1.59 (NoSuchAlgorithmException)

I have updated BouncyCastle library 1.49 to version 1.59 and I am getting the following error:
exception unwrapping private key - java.security.NoSuchAlgorithmException: Cannot find any provider supporting 2.16.840.1.101.3.4.1.42
java.io.IOException: exception unwrapping private key - java.security.NoSuchAlgorithmException: Cannot find any provider supporting 2.16.840.1.101.3.4.1.42
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.unwrapKey(Unknown Source)
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineLoad(Unknown Source)
at java.security.KeyStore.load(KeyStore.java:1226)
The code implemented is as follows:
KeyStore keystore = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());
keystore.load(new ByteArrayInputStream(hexStringToByteArray(privKey)), passphrase.toCharArray());
Enumeration<String> aliases = keystore.aliases();
String keyAlias = "";
while (aliases.hasMoreElements()) {
keyAlias = (String) aliases.nextElement();
}
PrivateKey key = (PrivateKey) keystore.getKey(keyAlias, passphrase.toCharArray());
final Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding", new BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] arr = hexStringToByteArray(encriptedPin);
byte[] decryptedTextBytes = cipher.doFinal(arr);
return new String(decryptedTextBytes);
I have updated JCE Policy and it still does not work, as well as the .pk8 certificate.
Has anyone had this problem? Any additional information tell me.
Thanks in advance,
Regards.

Signing file with hardware token

I'm trying to sign some files with SafeNet eToken5110. I have managed to get certificate from it but found out that i can't export PrivateKey. I developed some code to encrypt/decrypt files with common certificate, now my issue is to do the same with eToken. But i can't find any info how to do that.
Any tips? Is there any API for that? (and documentation/examples)
Ok, I've found out how to sign smtx with hardware token, and I hope someone will find it usefull. Need to use Signature class and SunPKCS11 provider
public static byte[] sign(byte[] file) throws Exception {
char password[] = "12345678".toCharArray();
Provider userProvider = new sun.security.pkcs11.SunPKCS11("C:\\ForJava\\eToken.cfg");
KeyStore ks = KeyStore.getInstance("PKCS11", userProvider);
ks.load(null, password);
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Security.addProvider(userProvider);
//Working only with the first alias on the token
String alias = (String)ks.aliases().nextElement();
Signature signature = Signature.getInstance("SHA256withRSA");
PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password);
signature.initSign(privateKey);
signature.update(file);
byte[] result = signature.sign();
//System.out.println("result coding: \n" +new BASE64Encoder().encode(result));
return result;
}
To verify signed data u can use the following code
public static void verify(byte[] sig, byte[] original) throws Exception {
Keystore keystore = initKeystore();
PublicKey key = keystore.getCertificate(getCertAlias()).getPublicKey();
Signature s = Signature.getInstance("SHA256withRSA");
s.initVerify(key);
s.update(original);
if ( ! s.verify(sig)) {
System.out.println("Signature check FAILED");
return;
}
System.out.println("Signature check PASSED");
}
Please add initKeysStore() method into it. It will be more useful then.

FipsUnapprovedOperationError while creating CMS message with BouncyCastle

I am trying to create a CMS Enveloped encrypted message using BouncyCastle FIPS 1.0.0 for Java. I receive the following error indicating that it is trying to use AES for random number generation (which is not an approved algorithm for FIPS mode).
Exception in thread "main" org.bouncycastle.crypto.fips.FipsUnapprovedOperationError: Attempt to create key with unapproved RNG: AES
at org.bouncycastle.crypto.fips.Utils.validateRandom(Unknown Source)
at org.bouncycastle.crypto.fips.Utils.validateKeyGenRandom(Unknown Source)
at org.bouncycastle.crypto.fips.FipsAES$KeyGenerator.<init>(Unknown Source)
at org.bouncycastle.crypto.fips.FipsAES$KeyGenerator.<init>(Unknown Source)
at org.bouncycastle.jcajce.provider.ProvAES$39$1.createInstance(Unknown Source)
at org.bouncycastle.jcajce.provider.BaseKeyGenerator.engineInit(Unknown Source)
at javax.crypto.KeyGenerator.init(KeyGenerator.java:510)
at org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder$CMSOutputEncryptor.<init>(Unknown Source)
at org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder.build(Unknown Source)
First, I make sure BouncyCastle is loaded as a JCE provider and then I make sure that it is running in FIPS approved only mode.
if(!CryptoServicesRegistrar.isInApprovedOnlyMode()) {
CryptoServicesRegistrar.setApprovedOnlyMode(true);
}
After that I am basically just using code like the example in the BC FIPS in 100 mini-book. The code I have so far is as follows:
private static final String FIPS_PROVIDER = "BCFIPS";
public byte[] encrypt(X509Certificate cert, byte[] dataToEncrypt) throws CertificateEncodingException, CMSException, IOException, InvalidAlgorithmParameterException {
CMSEnvelopedDataGenerator envelopedGen = new CMSEnvelopedDataGenerator();
JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
AlgorithmIdentifier algId = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, OAEPParameterSpec.DEFAULT);
JceKeyTransRecipientInfoGenerator recipientInfo = new JceKeyTransRecipientInfoGenerator(cert, algId);
recipientInfo.setProvider(FIPS_PROVIDER);
envelopedGen.addRecipientInfoGenerator(recipientInfo);
CMSProcessableByteArray processableArray = new CMSProcessableByteArray(dataToEncrypt);
JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC);
encryptorBuilder.setProvider(FIPS_PROVIDER);
OutputEncryptor outputEncryptor = encryptorBuilder.build();
return envelopedGen.generate(processableArray, outputEncryptor).getEncoded();
}
If I do not put BouncyCastle into the FIPS approved only mode then this code works fine, but I need to be able to run in this mode. Is there some way to tell the CMSOutputEncryptor to use a different RNG algorithm?
Have you tried setting up a FIPS-approved SecureRandom?
CryptoServicesRegistrar.setSecureRandom(
new FipsDRBG.Builder(
new BasicEntropySourceProvider(new SecureRandom(), true))
.build(FipsDRBG.SHA512_HMAC, null, false)
);
then on your builder (and wherever else you may need it):
encryptorBuilder.setSecureRandom(CryptoServicesRegistrar.getSecureRandom());

Race Condition in Java 8 PKCS11 KeyStore

I've been experimenting with an SafeNet (Aladdin) eToken and Java 8's PKCS11 interface. I noticed that when I was debugging the following code snippet it would work. If I ran it without the debugger I got an exception. I introduced an artificial delay and suddenly it worked without the debugger. This leads me to believe there is a race condition in my code. Is there a better way to be doing this? Or is this specific to my token? Or is this a new bug in Java 8 x64 for debian based systems?
public class CertificteRequestTest {
public static void main(String[] args) throws Exception{
KeyStore keyStore = getPKCS11Keys();
PrivateKey privateKey = (PrivateKey)keyStore.getKey("onekey",null);
PublicKey publicKey = ((KeyStore.PrivateKeyEntry)keyStore.getEntry("onekey",null)).getCertificate().getPublicKey();
X500Principal principal = new X500Principal("CN=onesubject");
PKCS10CertificationRequestBuilder builder
= new JcaPKCS10CertificationRequestBuilder(principal,publicKey);
ContentSigner signer
= new JcaContentSignerBuilder("SHA256withRSA").build(privateKey);
/* Removing this causes the Signer to think the token is not logged in */
Thread.sleep(1000);
PKCS10CertificationRequest csr = builder.build(signer);
PEMWriter writer = new PEMWriter(new PrintWriter(System.out));
writer.writeObject(csr);
writer.close();
}
public static KeyStore getPKCS11Keys() throws KeyStoreException {
SunPKCS11 provider = new SunPKCS11ProviderFactory()
.withDescription("PKCS11TestProvider - libeToken 8")
.withName("PKCS11TestProvider")
.withLibrary("/lib64/libeToken.so.8").build();
Security.addProvider(provider);
KeyStore.CallbackHandlerProtection pinHandler
= new KeyStore.CallbackHandlerProtection(new TextCallbackHandler());
return KeyStore.Builder.newInstance("PKCS11",provider,pinHandler).getKeyStore();
}
}
The exception that is thrown seems to indicate that I've not logged into the token, but I have done so. Entering the wrong PIN results in a failed login attempt.
$ java ... com.test.CertificteRequestTest
PKCS11 Token [SunPKCS11-PKCS11TestProvider] Password:
Exception in thread "main" java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_USER_NOT_LOGGED_IN
at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:588)
at java.security.Signature$Delegate.engineSign(Signature.java:1162)
at java.security.Signature.sign(Signature.java:554)
at org.bouncycastle.operator.jcajce.JcaContentSignerBuilder$SignatureOutputStream.getSignature(Unknown Source)
at org.bouncycastle.operator.jcajce.JcaContentSignerBuilder$1.getSignature(Unknown Source)
at org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder.build(Unknown Source)
...
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_USER_NOT_LOGGED_IN
at sun.security.pkcs11.wrapper.PKCS11.C_Sign(Native Method)
at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:579)
With the artificial delay installed this is the result of a successful run:
$ java ... com.test.CertificteRequestTest
PKCS11 Token [SunPKCS11-PKCS11TestProvider] Password:
-----BEGIN CERTIFICATE REQUEST-----
MIICW...
-----END CERTIFICATE REQUEST-----

Bouncycastle X509 certificate chain generation with valid Root certificate :unknown object in getInstance

Trying to generate a X509 with BouncyCastle api. Here is my piece of code.
try {
Security.addProvider(new BouncyCastleProvider()); // adding provider to
String pathtoSave = "D://sureshtest.cer";
KeyPair keyPair = generateKeypair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
X509Certificate trustCert = createCertificate(null,"CN=DigiCorp",
"CN=Nextenders", publicKey, privateKey);
// Create an input stream from the file containing the certificate.
InputStream is =new FileInputStream(new File("D://validcertFormCa.pfx"));
/*
* CertificateFactory object is used for reading Certificates, CRL and
* CertPaths. Create a factory object using the standard SPI pattern
* used in JCA.
*/
CertificateFactory factory =
CertificateFactory.getInstance("X.509", "BC");
/*
* Generate a X509 Certificate initialized with the data read from the
* input stream.
*/
X509Certificate mastercert =
(X509Certificate) factory.generateCertificate(is);
java.security.cert.Certificate[] outChain = { trustCert,mastercert };
trustCert.checkValidity();
mastercert.checkValidity();
KeyStore outStore = KeyStore.getInstance("PKCS12");
outStore.load(null, null);
outStore.setKeyEntry("my own certificate", privateKey,
"admin123".toCharArray(), outChain);
OutputStream outputStream = new FileOutputStream(pathtoSave);
outStore.store(outputStream, "admin123".toCharArray());
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
And run into the exception
org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory$ExCertificateException
at org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory.engineGenerateCertificate(Unknown Source)
at java.security.cert.CertificateFactory.generateCertificate(Unknown Source)
at com.nextenders.certificategeenrator.CertificateGenerator.testGenerateSignCertWithKeyStore(CertificateGenerator.java:119)
at com.nextenders.facadeimplementation.facade.JUnitFacade.main(JUnitFacade.java:11)
Caused by: java.lang.IllegalArgumentException: unknown object in getInstance: org.bouncycastle.asn1.ASN1Integer
at org.bouncycastle.asn1.ASN1Sequence.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.TBSCertificate.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.Certificate.<init>(Unknown Source)
at org.bouncycastle.asn1.x509.Certificate.getInstance(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory.readDERCertificate(Unknown Source)
... 4 more
What is mastercert supposed to be?
According to the docs for generateCertificate(), it expects that a "certificate provided in inStream must be DER-encoded and may be supplied in binary or printable (Base64) encoding". In other words, a DER or PEM encoded X509 certificate.
What you're providing it via that InputStream is a PFX file (a PKCS#12 file), not a DER or PEM encoded certificate.
My advice is to use openssl pkcs12 to extract the necessary certificate from the PKCS#12 file, and place it into a separate file, then change the code to load that instead of your PFX file.

Categories

Resources