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());
Related
I have two text files, one with a "-----BEGIN CERTIFICATE-----" header, one with a "-----BEGIN RSA PRIVATE KEY-----" header. I need to use CXF ClientBuilder to make a REST service call to a remote host.
I think my loading of the cert file is ok, but I can't figure out how to handle the private key file properly.
I have the following tentative code (which doesn't quite compile yet, as you'll see) to initialize the Client object (with some minor elisions):
private Certificate buildCertFromFile(String fileName) throws CertificateException {
return CertificateFactory.getInstance("X.509").generateCertificate(ClassLoaderUtils.getResourceAsStream(fileName, <ThisClass>.class));
}
#PostConstruct
public void init() {
try {
KeyStore trustStore = KeyStore.getInstance("jks");
trustStore.load(null, null);
trustStore.setCertificateEntry("cert", buildCertFromFile("<path to cert file>"));
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(null, "abc".toCharArray());
// Need something here.
keyStore.setKeyEntry("key", key, "abc", chain);
ClientBuilder builder = ClientBuilder.newBuilder();
builder.trustStore(trustStore);
builder.keyStore(keyStore, "abc");
builder.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String host, SSLSession session) {
try {
Certificate[] certs = session.getPeerCertificates();
return certs != null && certs[0] instanceof X509Certificate;
}
catch (SSLException ex) {
return false;
}
}
});
client = builder.build();
}
catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException ex) {
ex.printStackTrace();
}
}
Update:
I'm experimenting with the following method to load the private key file:
public static PrivateKey getPrivateKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
String contents = IOUtils.toString(ClassLoaderUtils.getResourceAsStream(filename, TguardService.class), "UTF-8");
contents = contents.replaceAll("-----[A-z ]+-----", "").trim();
System.out.println("contents[" + contents + "]");
byte[] bytes = Base64.getDecoder().decode(contents);
System.out.println("decoded[" + new String(bytes) + "]");
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
However, this is giving me the following error:
Caused by: java.lang.IllegalArgumentException: Illegal base64 character a
at java.util.Base64$Decoder.decode0(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at com.att.detsusl.tguardrest.TguardService.getPrivateKey(TguardService.java:58)
The debugging output shows that "contents" looks somewhat like this:
contents[MIIEp....
...
...
...kdOA=]
Update:
Ok, I managed to figure out that I had to remove ALL the newlines from the encoded string, so now it gets through base64 decode, but now it fails on the call to "generatePrivate()", with the following:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(Unknown Source)
at java.security.KeyFactory.generatePrivate(Unknown Source)
at com.att.detsusl.tguardrest.TguardService.getPrivateKey(TguardService.java:63)
I've seen some notes that imply that I must have a "PKCS#1" format, instead of "PKSC#8" and talk about calling "openssl" to convert the file. I'd really rather not do that. Is there a straightforward way to do this conversion (assuming this is what I need) in Java? I intend this code to execute only once at application startup.
Update:
Ok, after considering the alternatives, I used openssl to convert the file to PKCS#8 format. After that, I was able to complete the construction of the Client object, but I get another error while trying to make a connection. I considered it possible that this is a related but different problem (and I wanted to reduce the number of "Updates" on a single posting), so I posted that as a separate question at CXF REST client call with 2-way auth failing with "unable to find valid certification path to requested target" .
Also note that I've converted the key file from PKCS#1 to PKCS#8, but I never did anything with the cert file.
In the meantime, I could use a little more background on PKCS#1 vs. PKCS#8. How "legacy" is PKCS#1? I note that the original name of the key file that was given to me used an acronym representing the previous name of our organization, which changed several years ago.
I got the following error and I got a little stuck:
Exception in thread "main"
java.security.InvalidKeyException: Illegal key size or default parameters
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1011)
at javax.crypto.Cipher.implInit(Cipher.java:786)
at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
at javax.crypto.Cipher.init(Cipher.java:1213)
at javax.crypto.Cipher.init(Cipher.java:1153)
at net.nakou.indie.wtext.engineClass.Session.cryptString(Session.java:52)
I'm stuck because all the answers I've found talk about the Java Cryptography Extension (JCE) which be normally included into the android SDK. So I think my problem is not this one.
I must have forgotten something, but I can't find what. Maybe my code is wrong (it's my first approach of cryptography in Java, I'm not an expert, and the following code is mostly some copy-pastes of tutorials).
I use this code to crypt and decrypt a String :
public String cryptString(String s) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException {
byte[] KeyData = this.cryptKey.getBytes();
SecretKeySpec KS = new SecretKeySpec(KeyData, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, KS);
String ret = new String(cipher.doFinal(s.getBytes("UTF-8")));
return ret;
}
public String decryptString(byte[] s) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] KeyData = this.cryptKey.getBytes();
SecretKeySpec KS = new SecretKeySpec(KeyData, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, KS);
String ret = new String(cipher.doFinal(s));
return ret;
}
And the following key :
private String cryptKey = "qkjll5#2md3gs5Q#FDFqf";
Thank you guys.
private String cryptKey = "qkjll5#2md3gs5Q#FDFqf";
By default Java supports only 128-bit encryption
128bits == 16Bytes == 16 Chars.
So cryptKey cannot exceed 16 characters.
If you want to exceed more than 16 character you have to install Java Cryptography Extension (JCE) Unlimited Strength.
Why 128bits?
There have been updates since Java 8/9
The Unlimited Strength Jurisdiction Policy Files are included with Java 9 and used by default
Starting with Java 8 Update 161, Java 8 defaults to the Unlimited Strength Jurisdiction Policy.
Starting with Java 8 Update 151, the Unlimited Strength Jurisdiction Policy is included with Java 8 but not used by default. To enable it, you need to edit the java.security file in <java_home>/jre/lib/security (for JDK) or <java_home>/lib/security (for JRE). Uncomment (or include) the line
crypto.policy=unlimited
Make sure you edit the file using an editor run as administrator.
The policy change only takes effect after restarting the JVM
Before Java 8 Update 151 you have to download JCE Unlimited Strength Jurisdiction Policy files and replace.
For more details see How to install Java Cryptography Extension (JCE) unlimited strength jurisdiction policy files
PS: Above link goes to my personal blog that has additional details.
Default JDK supports encryption only through 128 bit keys becuase of American restrictions. So to support encryption from 256 bit long key we have to replace local_policy.jar and US_export_policy.jars in $JAVA_HOME/java-8-oracle/jre/lib/security folder otherwise it will give java.security.InvalidKeyException: Illegal key size or default
This is a code only solution. No need to download or mess with configuration files.
It's a reflection based solution, tested on java 8
Call this method once, early in your program or while application is being started.
//Imports
import javax.crypto.Cipher;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
//method
public static void fixKeyLength() {
String errorString = "Failed manually overriding key-length permissions.";
int newMaxKeyLength;
try {
if ((newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES")) < 256) {
Class c = Class.forName("javax.crypto.CryptoAllPermissionCollection");
Constructor con = c.getDeclaredConstructor();
con.setAccessible(true);
Object allPermissionCollection = con.newInstance();
Field f = c.getDeclaredField("all_allowed");
f.setAccessible(true);
f.setBoolean(allPermissionCollection, true);
c = Class.forName("javax.crypto.CryptoPermissions");
con = c.getDeclaredConstructor();
con.setAccessible(true);
Object allPermissions = con.newInstance();
f = c.getDeclaredField("perms");
f.setAccessible(true);
((Map) f.get(allPermissions)).put("*", allPermissionCollection);
c = Class.forName("javax.crypto.JceSecurityManager");
f = c.getDeclaredField("defaultPolicy");
f.setAccessible(true);
Field mf = Field.class.getDeclaredField("modifiers");
mf.setAccessible(true);
mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.set(null, allPermissions);
newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES");
}
} catch (Exception e) {
throw new RuntimeException(errorString, e);
}
if (newMaxKeyLength < 256)
throw new RuntimeException(errorString); // hack failed
}
You can remove the maximum key restriction by replacing the existing JCE jars with unlimited strength policy jars.
For JAVA 8 the download JCE Jar from link - https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
(/usr/libexec/java_home -v to find Java_HOME in Mac)
Copy local_policy.jar and US_export_policy.jar extracted from above zip file to the $JAVA_HOME/jre/lib/security
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-----
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
I have a big and strange problem with PKCS7 securities files.
I create a p7s file like what is suggested in http://www.thatsjava.com/java-tech/85019/ where it creatse the file and validates it using only sun libraries. It works fine.
The problem starts when I want to validate this file. It returns this exception:
java.security.SignatureException: Signature encoding error
at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:185)
at java.security.Signature$Delegate.engineVerify(Signature.java:1140)
at java.security.Signature.verify(Signature.java:592)
at sun.security.pkcs.SignerInfo.verify(SignerInfo.java:374)
at sun.security.pkcs.PKCS7.verify(PKCS7.java:494)
at sun.security.pkcs.PKCS7.verify(PKCS7.java:511)
at sun.security.pkcs.PKCS7.verify(PKCS7.java:533)
at firma.FirmaDigitalImpl.firmarCadenaSun(FirmaDigitalImpl.java:553)
at firma.FirmaDigitalImpl.firmarCadena(FirmaDigitalImpl.java:249)
at firma.FirmaDigitalImpl.firmarCadena(FirmaDigitalImpl.java:147)
at firma.TestFirma.main(TestFirma.java:75)
Caused by: java.io.IOException: Sequence tag error
at sun.security.util.DerInputStream.getSequence(DerInputStream.java:280)
at sun.security.rsa.RSASignature.decodeSignature(RSASignature.java:209)
at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:174)
... 10 more
But the problems don't appear always, just only with a type of certificates used to sign. I will explain better.
I have two certificates (stored into smartcard) and the first works fine; I create the p7s and next I validate correctly, but the second certificate allows me to create the p7s, file but when I validate it, it returns the SignatureException. I thought the p7s file was wrong, but I tested it with others' applications, and it looks correct. Besides, this file is sent throws webservice and it returns that it is ok!
And for more information, if the p7s file is created with different tools (.net and capicom) and the same certificate, then I can validate correctly.
I have looked for the solution, but nothing. I have found the same exception in similar situations, but either the solution suggested doesn't work for me, or it doesn't appear.
Any advice to find the solution will be very appreciated.
It might be encoding problem: text vs. binary. PKCS7 can be in either DER-encoded binary format or PEM-format (which is base64 encoded DER). Open the files in a text editor (e.g. notepad) and see whether the one which works is binary or text.
After more than two weeks, I have noticed what was the problem, although I didn't find the full solution.
First, I extracted the problem out of the PKCS7 file, and I reproduced the exception with the following source code:
import diz.firma.keyStore.SmartCard;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
public class TestFirma3 {
public static void main(String args[]) throws Exception {
//Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
SmartCard sm = new SmartCard();
KeyStore ks = sm.loadKeyStore("1234");
//KeyPair keyPair = generateKeyPair(999);
byte[] data = "original".getBytes("UTF-8");
//byte[] data = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 };
//byte[] digitalSignature = signData(data, keyPair.getPrivate());
byte[] digitalSignature = signData(data,
(PrivateKey)ks.getKey(sm.getAlias(), null),ks.getProvider());
boolean verified;
//verified = verifySig(data, keyPair.getPublic(), digitalSignature);
verified = verifySig(data, ks.getCertificate(sm.getAlias()).
getPublicKey(),ks.getProvider(), digitalSignature);
System.out.println("verified:" + verified) ;
//keyPair = generateKeyPair(888);
//verified = verifySig(data, keyPair.getPublic(), digitalSignature);
//System.out.println(verified);
}
public static byte[] signData(byte[] data, PrivateKey key,Provider p) throws Exception {
Signature signer = Signature.getInstance("SHA1withRSA",p);
//Signature signer = Signature.getInstance("SHA1withRSA",Security.getProviders()[10]);
signer.initSign(key);
signer.update(data);
return (signer.sign());
}
public static boolean verifySig(byte[] data, PublicKey key, Provider p, byte[] sig) throws Exception {
Signature signer = Signature.getInstance("SHA1withRSA",p);
//Signature signer = Signature.getInstance("SHA1withRSA");
signer.initVerify(key);
signer.update(data);
boolean valido = false;
try{
valido = signer.verify(sig);
}catch(Exception e){
e.printStackTrace();
valido = false;
}
return valido;
}
public static KeyPair generateKeyPair(long seed) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("DSA");
SecureRandom rng = SecureRandom.getInstance("SHA1PRNG", "SUN");
rng.setSeed(seed);
keyGenerator.initialize(1024, rng);
return (keyGenerator.generateKeyPair());
}
}
In this code, (extracted from an example in the net), I changed the generators key and took it from my card. I got the exception again, without using PKCS7 files.
Looking at all providers (with Security.getProviders() you can get all of them; they are defined in java.security file, but it can be added to or taken from in runtime), and I used everyone to sign and validate, I found out that:
If no one provider is selected when Signature is instantiated, it uses SunRsaSign by default.
My Signature is validated with 2 providers:
a) With SunMSCAPI provider, which uses Microsoft Crypt API.
b) With the provider created by smart card reader, in my case Siemens.
Reading another smart card that does not belong to Siemens, it is validated with SunRsaSign and SunJSSE.
At this moment, I find out the problem and a workarournd using SunMSCAPI to validate, but I have to validate into an IBM machine. Siemens software provides an option to install into Unix, but I cannot get it to work. And using SunMSCAPI, I suppose it isn't available for IBM.
So, I have to find out a provider that validates correctly in IMB the Signature that SunRsaSign returns SignatureException.