AndroidKeyStore cannot generate certificate - java

I have been trying to solve this issue regarding AndroidKeyStore. My app seems to not getting Android native provider for NONEwithRSA signing algorithm. This is the code reference:
Calendar startDate = Calendar.getInstance();
Calendar endDate = Calendar.getInstance();
endDate.add(Calendar.YEAR, 30);
KeyPairGeneratorSpec keyPairGeneratorSpec = new KeyPairGeneratorSpec.Builder(context)
.setAlias("aliasName")
.setSubject(new X500Principal("CN=aliasName"))
.setSerialNumber(BigInteger.TEN)
.setStartDate(startDate.getTime())
.setEndDate(endDate.getTime())
.build();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
keyPairGenerator.initialize(keyPairGeneratorSpec);
keyPairGenerator.generateKeyPair();
Once generateKeyPair() gets called, I got the following exception stack trace.
Caused by: java.security.SignatureException: java.security.ProviderException: No provider for NONEwithRSA
at com.google.android.gms.org.conscrypt.OpenSSLSignature.engineSign(:com.google.android.gms#12673012#12.6.73 (020408-194189626):6)
at java.security.Signature$SignatureImpl.engineSign(Signature.java:672)
at java.security.Signature.sign(Signature.java:381)
at com.android.org.bouncycastle.x509.X509Util.calculateSignature(X509Util.java:248)
at com.android.org.bouncycastle.x509.X509V3CertificateGenerator.generate(X509V3CertificateGenerator.java:434)
at com.android.org.bouncycastle.x509.X509V3CertificateGenerator.generate(X509V3CertificateGenerator.java:412)
at android.security.AndroidKeyPairGenerator.generateKeyPair(AndroidKeyPairGenerator.java:133)
... 26 more
Caused by: java.security.ProviderException: No provider for NONEwithRSA
at java.security.Signature$SignatureImpl.getSpi(Signature.java:734)
at java.security.Signature$SignatureImpl.engineInitSign(Signature.java:692)
at java.security.Signature.initSign(Signature.java:343)
at com.google.android.gms.org.conscrypt.CryptoUpcalls.rawSignDigestWithPrivateKey(:com.google.android.gms#12673012#12.6.73 (020408-194189626):11)
at com.google.android.gms.org.conscrypt.NativeCrypto.EVP_DigestSignFinal(Native Method)
at com.google.android.gms.org.conscrypt.OpenSSLSignature.engineSign(:com.google.android.gms#12673012#12.6.73 (020408-194189626):2)
... 32 more
No solution is found related to my issue. Does anyone have any idea on how to solve this?

You can replace the line with
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
As it is showing in logs that No provider for NONEwithRSA
Updated
You can try the below code for generating key pair in Androidkeystore and android version should be greater than 18
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
// generator.initialize(spec);
generator.initialize(new KeyGenParameterSpec.Builder(
alias ,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.setCertificateSubject(new X500Principal("CN=aliasName" ))
.setCertificateNotBefore(start.getTime())
.setCertificateNotAfter(end.getTime())
.setCertificateSerialNumber(BigInteger.ONE)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.build());
KeyPair keyPair = generator.generateKeyPair();

Related

Interpreting tpm-tools tpm_getpubek output

The output of tpm_getpubek is of the form:
http://trousers.sourceforge.net/man/tpm_getpubek.8.html
Key Size: 2048 bits
Public Key:
be262286 b51d0a21 88860ae7 32db7478 503c9213 bbb5545a 7e5d7c5f 30ff83da
37c5b548 fee21fd1 650181e8 3401a86b 1462e94e 118fc7f3 eb976b4c eb3a091f
6c5ea72c 527711dc ffbf1ae5 51fcbe1a aec95c64 7e2ac0eb 93484551 339f4959
6332b500 024cfe5c e08697cb 7431b3f4 328b4569 5e2e3eed 93a962d9 8387a58c
df15ecd1 9d01dd08 e2e60002 2baa6197 485dfbfc dd2f1898 fdff3913 7cc3bdc1
cc8bcb04 19e26ac8 466b6daf 4d53e9ea 88e45364 d029c1af b035a354 0f2e4484
e51bc0aa d216cdb6 71f50abb 44a0fdba 38715a6c 0c97d45d 5f3c08ab e7a46117
3666e6b0 d840ee54 4c617388 1714f0a1 acded3bd fc3ea323 8e7d1fcb 9fe74340
1) I am having a hard time to understand how to use it. I am trying to convert it to a java PublicKey object via the code:
byte[] derPublicKey = DatatypeConverter.parseHexBinary(keyBloc);
X509EncodedKeySpec x509publicKey = new X509EncodedKeySpec(derPublicKey);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(x509publicKey);
But this returns the following error:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
[java] at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
tpm_getpubek returns the hex-encoded public key modulus in its raw form, not an X509 encoded blob. Assuming you saved the returned data into a string called keyBlock (with whitespace removed) you would generate the public key like this:
PublicKey pk = KeyFactory.getInstance("RSA").generatePublic(
new RSAPublicKeySpec(new BigInteger(keyBlock, 16), new BigInteger("65537")));

Issue with Generating self-signed Certificate(X509), Private and Public key in Java Programatically

I am facing issues when i tried generating the certificate using BouncyCastle or Sun.Security.*
Requirements-
Android API support - For API 15 and API 8
I tried following ways to do it..
1) I tried using BouncyCastle jar with the following code
X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
v3CertGen.setSerialNumber(BigInteger.valueOf(new SecureRandom().nextInt()));
v3CertGen.setIssuerDN(new X509Principal("CN=" + domainName + ", OU=None, O=None L=None, C=None"));
v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365*10)));
v3CertGen.setSubjectDN(new X509Principal("CN=" + domainName + ", OU=None, O=None L=None, C=None"));
//
v3CertGen.setPublicKey(KPair.getPublic());
v3CertGen.setSignatureAlgorithm("MD5WithRSAEncryption");
X509Certificate PKCertificate = v3CertGen.generateX509Certificate(KPair.getPrivate());
issues faced with this code:
CertificateGenerator is depricated
X509V3CertificateGenerator class is not identified
tried with different versions of bouncycastle jars (1.45, 1.46, 1.47 & 1.57)
tried using CertificateBuilder (code is below)
SubjectPublicKeyInfo this class is not identified when i used this code.
SubjectPublicKeyInfo publicKeyInfo =
SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());
X509v3CertificateBuilder myX509v3CertificateBuilder = new X509v3CertificateBuilder(new X500Name("c=sree"), BigInteger.valueOf(new Random().nextInt(1000000)), new Date(System.currentTimeMillis()), new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 *365 * 100)), new X500Name("c=sree"), publicKeyInfo);
ContentSigner signer = new JcaContentSignerBuilder("Sha256withRSA").build(myCAPrivateKey);
X509CertificateHolder certHolder = myX509v3CertificateBuilder.build(signer);
X509Certificate cert = (new JcaX509CertificateConverter().getCertificate(certHolder));
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
Certificate certcert = cf.generateCertificate(new ByteArrayInputStream(cert.getEncoded()));
2) I tried with Sun.Security.* package with the below code
import java.security.cert.X509Certificate;
import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.X500Name;
public class SelfSignedCertificateGeneration {
public static void main(String[] args){
try{
CertAndKeyGen keyGen=new CertAndKeyGen("RSA","SHA1WithRSA",null);
keyGen.generate(1024);
//Generate self signed certificate
X509Certificate[] chain=new X509Certificate[1];
chain[0]=keyGen.getSelfCertificate(new X500Name("CN=ROOT"), (long)365*24*3600);
System.out.println("Certificate : "+chain[0].toString());
}catch(Exception ex){
ex.printStackTrace();
}
}
}
Issues faced with this code:
CertAndKeyGen and few other class are not accessible
**
Is there any other way? please suggest me.
**
Old versions of android are shipped with a cut-down version of bouncycastle. So you can not trust that the functionality you need is complete. Try to include https://rtyley.github.io/spongycastle/, a repackage of Bouncy Castle for Android.
Specify dependencies in gradle
compile 'com.madgag.spongycastle:core:1.56.0.0'
compile 'com.madgag.spongycastle:prov:1.56.0.0'
compile 'com.madgag.spongycastle:pkix:1.56.0.0'
compile 'com.madgag.spongycastle:pg:1.56.0.0'
Package names have changed from org.bouncycastle.* to org.spongycastle.* and provider name from BC to SC
Here you have an example of using spongycastle to create a selfsigned certificate

Using openssh public key (ecdsa-sha2-nistp256) with Java Security

Is there a Java library/example to read an openssh format ecdsa public key to a JCE PublicKey in Java? I want to use EC for JWT .
The format I'm trying to read is as per authorized_keys, or Github API (e.g. https://api.github.com/users/davidcarboni/keys): ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK8hPtB72/sfYgNw1WTska2DNOJFx+QhUxuV6OLINSD2ty+6gxcM8yZrvMqWdMePGRb2cGh8L/0bGOk+64IQ/pM=
I've found this answer, which is fine for RSA and DSS:
Using public key from authorized_keys with Java security, and this discussion of the openssh format for ECDSA: https://security.stackexchange.com/questions/129910/ecdsa-why-do-ssh-keygen-and-java-generated-public-keys-have-different-sizes
However I'm getting lost trying to adapt the RSS/DSA code for ECDSA - I'm not sure how to set up an ECPublicKeySpec. It needs ECPoint, EllipticCurve, ECParameterSpec, ECField. The openssh format only contains two integers, which makes sense for ECPoint, but I don't know how to set up the rest.
I've been poking around a bunch of libraries, including jsch, sshj, ssh-tools and good old Bouncycastle. The closest I have is:
com.jcraft.jsch.KeyPair load = com.jcraft.jsch.KeyPair.load(jsch, null, bytes[openSshKey]);
Which loads the key fine, but doesn't get me to a JCE PublicKey - just a byte[] getPublicKeyBlob() method.
Am I missing something obvious?
I've found a way to do this using Bouncycastle (but would like to find a JCE way).
Adapting the code from Using public key from authorized_keys with Java security, and refering to RFC 5656, section 3.1, the following block added to decodePublicKey will parse the single BigInt value Q, which is "the public key encoded from an elliptic curve point":
if (type.startsWith("ecdsa-sha2-") &&
(type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
// Based on RFC 5656, section 3.1 (https://www.rfc-editor.org/rfc/rfc5656#section-3.1)
// The string [identifier] is the identifier of the elliptic curve
// domain parameters. The format of this string is specified in
// Section 6.1 (https://www.rfc-editor.org/rfc/rfc5656#section-6.1).
// Information on the REQUIRED and RECOMMENDED sets of
// elliptic curve domain parameters for use with this algorithm can be
// found in Section 10 (https://www.rfc-editor.org/rfc/rfc5656#section-10).
String identifier = decodeType();
if (!type.endsWith(identifier)) {
throw new IllegalArgumentException("Invalid identifier " + identifier + " for key type " + type + ".");
}
// Q is the public key encoded from an elliptic curve point into an
// octet string as defined in Section 2.3.3 of [SEC1];
// (https://www.rfc-editor.org/rfc/rfc5656#ref-SEC1)
// point compression MAY be used.
BigInteger q = decodeBigInt();
ECPublicKey keyBC = getKeyBC(q, identifier);
return keyBC;
}
The solution I've found for getting from Q to an ECPublicKey is the following, using the Bouncycastle API (credit to Generate ECPublicKey from ECPrivateKey for providing the starting point):
ECPublicKey getKeyBC(BigInteger q, String identifier) {
// https://stackoverflow.com/questions/42639620/generate-ecpublickey-from-ecprivatekey
try {
// This only works with the Bouncycastle library:
Security.addProvider(new BouncyCastleProvider());
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
String name = identifier.replace("nist", "sec") + "r1";
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, ecSpec);
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(pubSpec);
return publicKey;
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
throw new RuntimeException(e);
}
}
That gets you from an openssh format elliptic curve public key (ssh-keygen -t ecdsa -b [256|384|521]) to a JCE ECPublicKey.
For completeness, here's the code I've gone with. It's nearly-pure JCE, with a sprinkling of Bouncycastle inside helper methods (this updates the example code in Using public key from authorized_keys with Java security):
...
} else if (type.startsWith("ecdsa-sha2-") &&
(type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
// Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1)
String identifier = decodeType();
BigInteger q = decodeBigInt();
ECPoint ecPoint = getECPoint(q, identifier);
ECParameterSpec ecParameterSpec = getECParameterSpec(identifier);
ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
return KeyFactory.getInstance("EC").generatePublic(spec);
} ...
/**
* Provides a means to get from a parsed Q value to the X and Y point values.
* that can be used to create and ECPoint compatible with ECPublicKeySpec.
*
* #param q According to RFC 5656:
* "Q is the public key encoded from an elliptic curve point into an octet string"
* #param identifier According to RFC 5656:
* "The string [identifier] is the identifier of the elliptic curve domain parameters."
* #return An ECPoint suitable for creating a JCE ECPublicKeySpec.
*/
ECPoint getECPoint(BigInteger q, String identifier) {
String name = identifier.replace("nist", "sec") + "r1";
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
org.bouncycastle.math.ec.ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
BigInteger x = point.getAffineXCoord().toBigInteger();
BigInteger y = point.getAffineYCoord().toBigInteger();
System.out.println("BC x = " + x);
System.out.println("BC y = " + y);
return new ECPoint(x, y);
}
/**
* Gets the curve parameters for the given key type identifier.
*
* #param identifier According to RFC 5656:
* "The string [identifier] is the identifier of the elliptic curve domain parameters."
* #return An ECParameterSpec suitable for creating a JCE ECPublicKeySpec.
*/
ECParameterSpec getECParameterSpec(String identifier) {
try {
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
String name = identifier.replace("nist", "sec") + "r1";
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(name));
return parameters.getParameterSpec(ECParameterSpec.class);
} catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
throw new IllegalArgumentException("Unable to get parameter spec for identifier " + identifier, e);
}
}

How to use Android KeyStore API with API 18? [duplicate]

This question already has answers here:
Android KeyStore implementation for < 4.3
(2 answers)
Closed 4 months ago.
How do I get the equivalent code below when I'm targeting API 18? Code below works only for API 23 and above. Also how secure would the API 18 code be, given that we can't use KeyGenParameterSpec and the API 18 code might use deprecated APIs?
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(new KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setKeySize(256)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(400)
.setRandomizedEncryptionRequired(false)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
SecretKey key = keyGenerator.generateKey();
private final String ENCRYPTION_ALIAS = "anEncryptionAlias"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA, AndroidKeyStore);
generator.initialize(new KeyGenParameterSpec.Builder(
ENCRYPTION_ALIAS,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(
KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.build()
);
generator.generateKeyPair();
} else {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 1);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec
.Builder(YourApplication.getInstance().getApplicationContext())
.setAlias(ENCRYPTION_ALIAS)
.setSubject(new X500Principal("CN=Your Company ," +
" O=Your Organization" +
" C=Your Coountry"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA, AndroidKeyStore);
generator.initialize(spec);
generator.generateKeyPair();
}

Undefined CommonName in certificate

So far, I've been working with a certificate which I added to a SoapUI 5.2 project and which gave me access to a pre-production server. However, now that I'm ready to move to a production environment, I'm trying to check the new production certificate with SoapUI, but I'm getting the next error:
WARN:Using fallback method to load keystore/truststore due to: Invalid keystore format
ERROR:An error occurred [java.lang.NullPointerException], see error log for details
And the error log says:
ERROR:Could not load keystore/truststore
ERROR:java.lang.NullPointerException
java.lang.NullPointerException
at org.apache.commons.ssl.KeyStoreBuilder.build(KeyStoreBuilder.java:176)
at org.apache.commons.ssl.KeyStoreBuilder.build(KeyStoreBuilder.java:97)
at org.apache.commons.ssl.KeyStoreBuilder.build(KeyStoreBuilder.java:88)
at com.eviware.soapui.impl.wsdl.support.wss.crypto.KeyMaterialWssCrypto.fallbackLoad(KeyMaterialWssCrypto.java:206)
at com.eviware.soapui.impl.wsdl.support.wss.crypto.KeyMaterialWssCrypto.load(KeyMaterialWssCrypto.java:168)
at com.eviware.soapui.impl.wsdl.support.wss.crypto.KeyMaterialWssCrypto.getStatus(KeyMaterialWssCrypto.java:216)
at com.eviware.soapui.impl.wsdl.panels.project.WSSTabPanel$CryptoTableModel.getValueAt(WSSTabPanel.java:643)
at javax.swing.JTable.getValueAt(Unknown Source)
at javax.swing.JTable.prepareRenderer(Unknown Source)
...
The only difference I found between the pre-production and production certificates was that the latter did not have the CommonName field defined.
I know that field is not mandatory, so how is that possible? How can I solve this problem without asking for a new certificate? That's not an option.
Any suggestion would be appreciated.
I check the pom.xml of SOAPUI project for 5.2 versión, and it use not-yet-commons-ssl versión 0.3.11:
<dependency>
<groupId>commons-ssl</groupId>
<artifactId>not-yet-commons-ssl</artifactId>
<version>0.3.11</version>
</dependency>
And If you check the build method for org.apache.commons.ssl.KeyStoreBuilder class as the exception thrown in your error log you'll see:
public static KeyStore build(byte[] jksOrCerts, byte[] privateKey,
char[] jksPassword, char[] keyPassword)
throws IOException, CertificateException, KeyStoreException,
NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, ProbablyBadPasswordException,
UnrecoverableKeyException {
...
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, jksPassword);
Iterator keysIt = keys.iterator();
Iterator chainsIt = chains.iterator();
int i = 1;
while (keysIt.hasNext() && chainsIt.hasNext()) {
Key key = (Key) keysIt.next();
Certificate[] c = (Certificate[]) chainsIt.next();
X509Certificate theOne = buildChain(key, c);
String alias = "alias_" + i++;
// The theOne is not null, then our chain was probably altered.
// Need to trim out the newly introduced null entries at the end of
// our chain.
if (theOne != null) {
c = Certificates.trimChain(c);
alias = Certificates.getCN(theOne);
/* line 176 */ alias = alias.replace(' ', '_');
}
ks.setKeyEntry(alias, key, keyPassword, c);
}
return ks;
}
}
So seems that you're right and the problem is that your certificate has no common name, so org.apache.commons.ssl.Certificates.getCN(X509Certificate) returns null as alias and then alias.replace is throwing the NPE.
alias = Certificates.getCN(theOne);
/* line 176 */ alias = alias.replace(' ', '_');
I don't see nothing that says that Common Name is mandatory in RFC5280, however various code/software use it for different purposes as not-yet-commons-ssl does.
Your certificate is probably right but you can't use it with SOAPUI 5.2 version to test your environment if it hasn't the CN, so if you want to use SOAPUI to test your environment I think that you've to reissue the certificate generating a CSR with CN. Or you can report the problem to http://juliusdavies.ca/commons-ssl/ and then ask to SOAPUI to include the latest version...
Hope this helps,

Categories