Bug in Keycloak package? ( ECDSA KeyFactory not available ) - java

When running my keycloak application, the following error appears:
java.security.NoSuchAlgorithmException: ECDSA KeyFactory not available
at java.base/java.security.KeyFactory.<init>(KeyFactory.java:138) ~[na:na]
at java.base/java.security.KeyFactory.getInstance(KeyFactory.java:183) ~[na:na]
at org.keycloak.jose.jwk.JWKParser.createECPublicKey(JWKParser.java:107) ~[keycloak-core-15.0.2.jar:15.0.2]
... 61 common frames omitted
After doing some digging, found out KeyFactory cannot settle "ECDSA" as an algorithm and therefore I should use the "EC" algorithm to generate public key.
But if KeyFactory doesnt support "ECDSA" as an algorithm, why does Keycloak-15.0.2 JWKParser class' createECPublicKey func remain trying to generate a public key with ECDSA?
try {
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(name);
ECNamedCurveSpec params = new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN());
ECPoint point = new ECPoint(x, y);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
KeyFactory kf = KeyFactory.getInstance("ECDSA");
return kf.generatePublic(pubKeySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
Is this a bug? or am I juts completely missing something?

Your main problem is that you forgot to tell KeyFactory.getInstance that ECDSA is from BouncyCastle provider.
You add this, KeyFactory.getInstance("ECDSA"); will work:
public static final Provider BC = new BouncyCastleProvider();
...
public static void myMethod() {
...
KeyFactory kf = KeyFactory.getInstance("ECDSA", BC);
}
Alternatively you can add BouncyCastleProvider to your list of providers:
Security.addProvider(new BouncyCastleProvider());

Related

Generate or create p12 file from Android

I have a problem when generating a .pfx certificate that I get from an api. as can be seen in the image.
{
"type": "success",
"code": 0,
"message": "Certificado descargado exitosamente",
"detalle_mensaje": "55g/bNoVn........fHlukJDHhj4=",
"pass": "oz7FkVw1zrHC/Nt+2NQR3arg4Keo409MRbKC6MM3GoE=",
"excepcion": null,
"extension": ".pfx"
}
This is an encrypted code, where the original result is a private key:
MIIM/AIBAzCCDMIGCSqGSIb3DQEHAaCCDLMEggyvMIIMqzCCBzcGCSqGSIb3DQEHBqCCBygwggckAgEAMIIHHQYJKoZI....
So I need to generate this .pfx or .p12 file on the device storage.
I have this code to generate p12 but I don't know where to use the key (MIIM/AIBAzCCD ...)
It is worth mentioning that with this code it generates the .p12 file but when I open the certificate, I copy the password and it cannot open
String storeName = "ruta_del_dispositivo.p12";
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
Certificate trustCert = createCertificate("CN=CA", "CN=CA", publicKey, privateKey);
Certificate[] outChain = { createCertificate("CN=Client", "CN=CA", publicKey, privateKey), trustCert };
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(null);
// GUARDAR archivo p12
OutputStream outputStream = new FileOutputStream(storeName);
ks.store(outputStream, password.toCharArray());
outputStream.flush();
outputStream.close();
--
private static java.security.cert.X509Certificate createCertificate(String dn, String issuer, PublicKey publicKey, PrivateKey privateKey) throws Exception {
X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
certGenerator.setSerialNumber(BigInteger.valueOf(Math.abs(new Random().nextLong())));
certGenerator.setSubjectDN(new X509Name(dn));
certGenerator.setIssuerDN(new X509Name(issuer)); // Set issuer!
certGenerator.setNotBefore(Calendar.getInstance().getTime());
certGenerator.setNotAfter(Calendar.getInstance().getTime());
certGenerator.setPublicKey(publicKey);
certGenerator.setSignatureAlgorithm("SHA1withRSA");
X509Certificate certificate = certGenerator.generate(privateKey, "BC");
return certificate;
}

I need to read a public and private key in java which is already given. I am not able to please advise

The public key is in .csr and private key is in .key extension. The exception I receive is
Exception in thread "main" java.security.cert.CertificateParsingException: java.io.IOException:
ObjectIdentifier() -- data isn't an object ID (tag = 49)
at sun.security.x509.X509CertInfo.<init>(Unknown Source)
at sun.security.x509.X509CertImpl.parse(Unknown Source)
at sun.security.x509.X509CertImpl.<init>(Unknown Source)
at sun.security.provider.X509Factory.engineGenerateCertificate(Unknown Source)
at java.security.cert.CertificateFactory.generateCertificate(Unknown Source)
at com.ebao.gimo.integration.security.RSAEnc.getPublicKey(RSAEnc.java:208)
at com.ebao.gimo.integration.security.RSAEnc.main(RSAEnc.java:37)
Caused by: java.io.IOException: ObjectIdentifier() -- data isn't an object ID (tag = 49)
at sun.security.util.ObjectIdentifier.<init>(Unknown Source)
at sun.security.util.DerInputStream.getOID(Unknown Source)
at sun.security.x509.AlgorithmId.parse(Unknown Source)
at sun.security.x509.CertificateAlgorithmId.<init>(Unknown Source)
at sun.security.x509.X509CertInfo.parse(Unknown Source)
The code I have tried is :
public static PublicKey getPublicKey(String fileName) throws Exception {
FileInputStream fis = new FileInputStream(fileName);
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate xCert = (X509Certificate)cf.generateCertificate(fis);
PublicKey pubKeyVal = xCert.getPublicKey();
return pubKeyVal;
}
Reading Private Key
public static Key getPrivateKey(String filename) throws Exception {
PemReader pemReader = new PemReader(new FileReader(filename));
PemObject pemObject = pemReader.readPemObject();
byte[] der = pemObject.getContent();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(der);
RSAPrivateKey privKey = (RSAPrivateKey)keyFactory.generatePrivate(ks);
return privKey;
}
Kindly help
The public key is
-----BEGIN CERTIFICATE REQUEST-----
MIICwDCCAagCAQAwezELMAkGA1UEBhMCSU4xFDASBgNVBAgMC01haGFyYXNodHJh
MQ8wDQYDVQQHDAZNdW1iYWkxHzAdBgNVBAoMFkViYW90ZWNoIEluZGlhIFB2dCBM
dGQxJDAiBgNVBAsMG0luZGlhIENsb3VkIFJlZmluZW1lbnQgU0JJRzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALhcoHMrt4QroPYeIyr0oYiE1Kjrs7xo
L5eryiOVgJp4ddWGtKy9vVjJJcDhs5D+d78d9wu/4u9ET2LtgOX/99JhbPz6UuVX
UP0vdrfVyWJvbwCrfWPUzW2/vmeP0wXIISzvXghzy/5DhRYfaOlhRHGDl0lRvHgU
DxIWZtl9sNoWO3CRZAO0D5QX0Cq/S+uc9WPXFchdve32DsQ+YFMoBYwli8uH//rB
ZFc95oHo1WEHCrCHHNE6EAgFG/zgBGyEqgSMfOBVt28r89lgZCIoM5zAuVvI/VM2
ROy8pOMoGKNfXlg8rYq/1OljQ1XIIOt/Ir/0T5YDcs771SgNTiVCUicCAwEAAaAA
MA0GCSqGSIb3DQEBBQUAA4IBAQBrz0KUgI3CG8xFVVtiqDOeTqutrvOoRRz5ziiE
uMeGrkN7jlF/EyurReO0TIGzYiQbVnl/XKOhpKIPf8EKI8nN/Idr2dA8z9NrH9gM
Iat6wuSACC6Txb+RbGSYo66FAaJZQU1OJTFtfIP7LfM9mZPA2gi3aKb0sM+VuCph
WpMm0Kjbp9m665hRbJ//nck+os2CxWhRTyuxRbK007IDi/4FNMnlV/2cxMi644m/
++hbFoF0ihZzq+npezh7URU0Oj9aW7YBVXy9110XBX8JfgOJ5pfZxjU6ID+HQdi/
SciHqqv15tKsxxlKOi8Ju2y3g8vW5dcPJOS4/G5QsQqZsPn9
-----END CERTIFICATE REQUEST-----
Let me know if the extension of key affects it
The issue was how the keys were created. Once my keys were exported to .der format the code worked. Below link helped me out.
Load RSA public key from file

Decryption at client side using java

I encypted the session Id at server side but when I am trying to decrypt the session id at client side some error is coming. please can anyone help resolving the error.
public static String decrypt(String sessionId)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
final SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
final String decryptedSessionId = new String(cipher.doFinal(Base64.decodeBase64(sessionId)));
return decryptedSessionId;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
The error that is coming is :
Class 'javax.crypto.Cipher' is not present in JRE Emulation Library so it cannot be used in client code of "some" GWT module.
This inspection reports usages in client code of JDK classes which is not present in JRE Emulation Library.
The method for encryption that I used is :
public static String encrypt(String sessionId)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
final String encryptedSessionId = Base64.encodeBase64String(cipher.doFinal(sessionId.getBytes()));
return encryptedSessionId;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
I am new to this stuff please help me resolving the errors
Well, you cannot use java standard encryption library in GWT coding on client side. It's not supported.
Use gwt-crypto to encrypt/decrypt the necessary stuff.
AES is not be supported on client side for GWT in GWT-crypto, but you can use TripleDES. TripleDES is also very much secure implementation.

ECDH using Android KeyStore generated private key

I'm trying to implement ECDH in Android using a private generated by Android KeyStore Provider.
public byte[] ecdh(PublicKey otherPubKey) throws Exception {
try {
ECPublicKey ecPubKey = (ECPublicKey) otherPubKey;
KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
PrivateKey pk = (PrivateKey) LoadPrivateKey("Backend");
keyAgreement.init(pk);
keyAgreement.doPhase(ecPubKey, true);
return (keyAgreement.generateSecret());
}
catch (Exception e)
{
Log.e("failure", e.toString());
return null;
}
}
However, this exception is catched in keyAgreement.init(pk) :
E/failure: java.security.InvalidKeyException: cannot identify EC private key: java.security.InvalidKeyException: no encoding for EC private key
I generated before successfully the "Backend" Public/Private key pair using:
public void GenerateNewKeyPair(String alias)
throws Exception {
if (!keyStore.containsAlias(alias)) {
// use the Android keystore
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, ANDROID_KEYSTORE);
keyGen.initialize(
new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY | KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA384,
KeyProperties.DIGEST_SHA512)
.setRandomizedEncryptionRequired(true)
.build());
// generates the keypair
KeyPair keyPair = keyGen.generateKeyPair();
}
}
And I load the private key using:
public PrivateKey LoadPrivateKey(String alias) throws Exception {
PrivateKey key = (PrivateKey) keyStore.getKey(alias, null);
return key;
}
Anyone has an idea what is happening and can help me to understand how to fix it? Thanks!
As far as I know through research and trial and error, this is not currently supported.
I believe the best you can do is sign the public key of an EC key pair you generate outside of the AndroidKeyStore with an EC key pair that is stored in AndroidKeyStore. You can then send this signed public key over to the other party with your signing key certificate, generate a shared secret (outside of AndroidKeyStore), then store the SecretKey that is derived using a KDF on the generated secret. I recommend using this non-AndroidKeyStore generated key pair once (so only for the purpose of deriving the secret) and repeating this process to re-key when deemed necessary.
EDIT: When I said 'store the SecretKey', I meant in AndroidKeyStore. That key will initially be in what is called 'normal world' in this context, but its the best you can do for now.
ECDH is supported in API level 23. Please refer android documentation on Android Keystore System
Sample code is also available in this link..

junit java.security.NoSuchAlgorithmException: Cannot find any provider supporting

I'm using JUnit 4 [C:\eclipse\plugins\org.junit_4.11.0.v201303080030\junit.jar] in combination with Eclipse (MARS, Version: Mars Milestone 3 (4.5.0M3) Build id: 20141113-0320.
I have some tests that test a simple class and which work well. But now arrived at the point where I wanted to test my encryption class, which implements the following encrypt function:
public String encrypt(String data) {
try {
SecretKeySpec KS = new SecretKeySpec(mKeyData, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding"); // PKCS5Padding
cipher.init(Cipher.ENCRYPT_MODE, KS, new IvParameterSpec(mIv));
return bytesToHex(cipher.doFinal(data.getBytes()));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}
The Crypto class is not sub classed...
public class Crypto {
So to test this Class and more the encrypt function I have designed the following unit test:
package my.junit4.example;
import static org.junit.Assert.*;
import org.junit.Test;
public class CryptoTest {
#Test
public void testEncryption() {
Crypto myCrypto = new Crypto();
String encodedString = myCrypto.encrypt("Secret");
assertTrue("The decrypted encrypted word should deliver the original string", encodedString.equals(myCrypto.decrypt(encodedString)));
}
}
This test is failing with a stack trace:
java.security.NoSuchAlgorithmException: Cannot find any provider supporting Blowfish/CBC/ZeroBytePaddingnull
at javax.crypto.Cipher.getInstance(Cipher.java:535) at
my.junit.example.encrypt(Crypto.java:35) at
my.junit.example.CryptoTest.testEncrypt(CryptoTest.java:14) at
This didn't make much sense to me. But being relatively new to JUnit I suspect the issue is with me not understanding how to formulate these tests. The code works well encryption - decryption in my debugger is giving me the desired outcome. But how can I get this to work with JUnit. What obvious mistake I have made?
The problem is with this line:
Cipher cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding");
The algorithm you're requesting is not supported on your system. Any particular reason you want that specific one?
The docs specify the following default implementations:
AES/CBC/NoPadding (128)
AES/CBC/PKCS5Padding (128)
AES/ECB/NoPadding (128)
AES/ECB/PKCS5Padding (128)
DES/CBC/NoPadding (56)
DES/CBC/PKCS5Padding (56)
DES/ECB/NoPadding (56)
DES/ECB/PKCS5Padding (56)
DESede/CBC/NoPadding (168)
DESede/CBC/PKCS5Padding (168)
DESede/ECB/NoPadding (168)
DESede/ECB/PKCS5Padding (168)
RSA/ECB/PKCS1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
You need to add the Bouncy Castle provider to the Java runtime. You can see how to install the provider by looking at the Bouncy Castle wiki page. Neither the Blowfish algorithm nor zero padding is supported out of the box by Java installations.
The following runs fine on my box:
Security.addProvider(new BouncyCastleProvider());
byte[] mKeyData = new byte[16];
byte[] mIv = new byte[8];
SecretKeySpec KS = new SecretKeySpec(mKeyData, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding");
cipher.init(Cipher.ENCRYPT_MODE, KS, new IvParameterSpec(mIv));
Make sure that the provider is also available to the test framework when it is run. You'll need to put the bcprov-jdk15on-[version].jar in the class path of the runtime before you can install the provider.

Categories