ECDSA KeyPairGenerator not available (but in JUnit works) - java

I am getting below Exception which I observed when running Android app - it does not occurs when I run the code below as JUnit.
java.security.NoSuchAlgorithmException: ECDSA KeyPairGenerator not available
at java.security.KeyPairGenerator.getInstance(KeyPairGenerator.java:225)
at com.mhamdaoui.smartcardreader.CryptoUtils$Companion.getMerchantEphemeralPublicKey(CryptoUtils.kt:48)
at com.mhamdaoui.smartcardreader.MainActivity.onTagDiscovered(MainActivity.kt:80)
at android.nfc.NfcActivityManager.onTagDiscovered(NfcActivityManager.java:603)
at android.nfc.IAppCallback$Stub.onTransact(IAppCallback.java:83)
at android.os.Binder.execTransact(Binder.java:573)
The code:
Security.addProvider(BouncyCastleProvider())
val generator = KeyPairGenerator.getInstance("ECDSA")
val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
generator.initialize(ecSpec)
val keyPair = generator.generateKeyPair()
val publicKey = keyPair.public as ECPublicKey
return publicKey.q.getEncoded(true)
How to resolve this issue?
UPDATE
When I am creating JUnit in test (I am using Android Studio):
#Test
fun compressedGeneratorTest() {
Security.addProvider(BouncyCastleProvider())
val generator = KeyPairGenerator.getInstance("ECDSA")
val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
generator.initialize(ecSpec)
val keyPair = generator.generateKeyPair()
val publicKey = keyPair.public as ECPublicKey
val encoded = publicKey.q.getEncoded(true)
assert(true)
}
Everything works also. How to resolve this issue on App runtime?

The problem is that it is not possible to use BounceyCastle on Android - instead use SpongyCastle:
implementation 'com.madgag.spongycastle:prov:1.54.0.0'
implementation 'com.madgag.spongycastle:pkix:1.54.0.0'
And then initialize the provider with BouncyCastleProvider instance like below:
Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider())

Latest version of BouncyCastle libraries can be used to generate keypairs using ECDSA algorithm on Android device with the below mentioned steps.
Include the latest bouncy castle library by adding the below dependencies.
implementation "org.bouncycastle:bcprov-jdk15to18:1.68"
implementation "org.bouncycastle:bcpkix-jdk15to18:1.68"
Note: Refer Provider, PKIX to get the latest version details.
After adding the libraries, follow any of the below mentioned approach based on the mentioned need.
Approach 1
If you want to use the provider entire application level, replace the Android OS Bouncycastle provider with the provider from the added library using below line.
// Remove the OS provided bouncy castle provider
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME)
// Add the bouncy castle provider from the added library
Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider())
Approach 2
If you don't want to replace the Provider throughout the application, you can pass the provider instance to the KeyPairGenerator like below.
Java
KeyPairGenerator generator = KeyPairGenerator.getInstance("ECDSA", new org.bouncycastle.jce.provider.BouncyCastleProvider())
Kotlin
val generator = KeyPairGenerator.getInstance("ECDSA", org.bouncycastle.jce.provider.BouncyCastleProvider())

You can use
implementation("org.bouncycastle:bcprov-jdk15on:1.70")

Related

How to initialize the PKCS11 provider without using SunPKCS11?

I have a problem and I tried searching a solution but couldn't find it. Someone please help me, thanks you so much.
String pkcs11Config = "name=CA-Token\nlibrary=C:/java/CA-Token_v2.dll\nslot=1";
InputStream is = new ByteArrayInputStream(pkcs11Config.getBytes())
SunPKCS11 providerPKCS11 = new sun.security.pkcs11.SunPKCS11(is); // (1)
Security.addProvider(providerPKCS11);
For this code, can we initialize the PKCS11 provider without using SunPKCS11?
It's been a while since this question was posted, but if you'd like to use a PKCS11 provider other than SunPKCS11, you can use:
IAIK PKCS11 wrapper https://jce.iaik.tugraz.at/products/core-crypto-toolkits/pkcs11-wrapper/
OpenSC https://github.com/OpenSC/OpenSC-Java/blob/master/pkcs11-test/src/test/java/org/opensc/test/pkcs11/PKCS11ProviderTestCase.java
Build your own provider by following Oracle tutorial https://docs.oracle.com/en/java/javase/17/security/howtoimplaprovider.html#GUID-C485394F-08C9-4D35-A245-1B82CDDBC031
You just need to instantiate them and register with "Security.addProvider(yourProvider)"

SecretKeyFactory.getInstance gives me NoSuchAlgorithmException no matter what algorithm I provide

So I have been looking at this page: https://developer.android.com/reference/javax/crypto/SecretKeyFactory.html
They appear to claim that any of those algorithms should work with SecretKeyFactory in Android-Studio but when I put in this code:
SecretKeyFactory key = SecretKeyFactory.getInstance("Algorithm-Name");
No matter what algorithm name I put in that is listed on that android website, it always gives me
Unhandled exception: java.security.NoSuchAlgorithmException
I tried it in eclipse with a standard Java project and it worked fine.
I tried using spongycastle too but that didn't seem to work either.
There seems to be something wrong with your provider configuration. You could try and list which algorithms are available using the following code:
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
boolean printedProvider = false;
Set<Service> services = provider.getServices();
for (Service service : services) {
String algorithm = service.getAlgorithm();
String type = service.getType();
if (type.equalsIgnoreCase("SecretKeyFactory")) {
if (!printedProvider) {
System.out.printf("%n === %s ===%n%n", provider.getName());
printedProvider = true;
}
System.out.printf("Type: %s alg: %s%n", type, algorithm);
}
}
}
If this doesn't print anything then create an empty project for the same runtime, and run it again. If it does show an algorithm - and it should - then you should make sure that the printed provider is available in your project configuration.
If it doesn't, you should really reinstall the SDK or runtimes, as there is something seriously wrong with the project setup.

difference in xamarin vs java documentation for ECPublicKey

in andorid xamarin project I am generating key pair using EC curves
generator = KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmEc, AndroidKeyStoreContants.AndroidKeyStore);
paramSpec = new KeyGenParameterSpec.Builder(
alias,
KeyStorePurpose.Sign | KeyStorePurpose.Verify)
.SetAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.SetDigests(KeyProperties.DigestSha256)
.Build();
generator.Initialize(paramSpec);
var keyPair = generator.GenerateKeyPair();
which is fine, problem starts when I want to access the public key, keyPair.Public. This gives me an IPublicKey interface. On java, you will just cast it to ECPublicKey and on Xamarin you just can't do it.
I also noticed there is a missing member - the importat one for me - getW()- on xamarin representation of ECPublicKey vs java ECPublicKey.
xamarin ECPublicKey
java ECPublicKey
My question is - how to access - and cast the public key to ECPublicKey in Xamarin? I want to access the X and Y coordinates.
Is there a way to add this missing declaration?
Instead of casting to ECPublicKey, cast it to ECPublicKeySpec. IE,
var pubKeySpec = (Java.Security.Spec.ECPublicKeySpec)keyPair.Public;
var w = pubKeySpec.GetW();
I've just run into the same issue, except in my case I was already trying to cast it to IECPublicKey (as suggested in the deprecation message for ECPublicKey). I kept getting an InvalidCastException, even though this is seemingly the correct way to do it in native Java/Android. I also got the same exception when trying to cast it to ECPublicKeySpec instead as suggested in the other answer here.
After a lot of searching and not finding anything relevant except this question, I've now found one method which works (adapted from this post), but I'm not sure why it's necessary to do it this way.
KeyFactory keyFactory = KeyFactory.GetInstance(KeyProperties.KeyAlgorithmEc);
ECPublicKeySpec publicKeySpec = (ECPublicKeySpec)keyFactory.GetKeySpec(keyPair.Public, Java.Lang.Class.ForName("java.security.spec.ECPublicKeySpec"));
You can then use publicKeySpec.GetW() to access the coordindates.

Java use SecureRandom with SunPKCS11 provider

I would like to use my PKCS#11 enabled device as a source of SecureRandom.
So I have done the following:
Provider pkcs11provider = new sun.security.pkcs11.SunPKCS11(pkcs11config);
Security.addProvider(pkcs11provider);
byte[] rb = new byte[100];
SecureRandom sr = SecureRandom.getInstance("PKCS11", pkcs11provider);
sr.nextBytes(rb);
And I always get an exception:
Exception in thread "main" java.security.NoSuchAlgorithmException: no such algorithm: PKCS11 for provider SunPKCS11-HSM
at sun.security.jca.GetInstance.getService(GetInstance.java:101)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:218)
at java.security.SecureRandom.getInstance(SecureRandom.java:383)
What I am doing wrong? According JDK PKCS#11 Reference Guide "PKCS11" should be supported algorithm for SecureRandom.
"PKCS11" doesn't sound like an algorithm name. It is the provider name. A provider can have their own algorithm names for specific crypto operations. To see what all algorithms they have, you can run this code snippet to see them.
Set<Provider.Service> services = pkcs11provider.getServices();
services.forEach(service ->
{
// System.out.println(service.getType()); // --> Look for 'SecureRandom' type
System.out.println(service.getAlgorithm());
});
Look for 'SecureRandom' type, and that's the algorithm you have to pass in as the first argument in SecureRandom.getInstance(.., ..).

How to find out what algorithm [ encryption ] are supported by my JVM?

I am using Jasypt for encryption. This is my code:
public class Encryptor {
private final static StandardPBEStringEncryptor pbeEncryptor = new StandardPBEStringEncryptor();
private final static String PASSWORD = "FBL";
private final static String ALGORITHM = "PBEWithMD5AndTripleDES";
static{
pbeEncryptor.setPassword( PASSWORD );
//pbeEncryptor.setAlgorithm( ALGORITHM );
}
public static String getEncryptedValue( String text ){
return pbeEncryptor.encrypt( text );
}
public static String getDecryptedValue( String text ){
return pbeEncryptor.decrypt( text );
}
}
Uncomment the setAlgorithm line and it will throw an exception
org.jasypt.exceptions.EncryptionOperationNotPossibleException:
Encryption raised an excep tion. A
possible cause is you are using strong
encryption algorithms and you have not
installed the Java Cryptography Ex
tension (JCE) Unlimited Strength
Jurisdiction Policy Files in this Java
Virtual Machine
api says:
Sets the algorithm to be used for
encryption Sets the algorithm to be
used for encryption, like
PBEWithMD5AndDES.
This algorithm has to be supported by
your JCE provider (if you specify one,
or the default JVM provider if you
don't) and, if it is supported, you
can also specify mode and padding for
it, like ALGORITHM/MODE/PADDING.
refer: http://www.jasypt.org/api/jasypt/apidocs/org/jasypt/encryption/pbe/StandardPBEStringEncryptor.html#setAlgorithm%28java.lang.String%29
Now, when you comment 'setAlgorithm' it will use the default Algorithm [ i guess it is md5 ], and it will work fine. That means md5 is supported by my JVM. Now, how to find out what other encryption algorithms are supported by my JVM.
Thanks,
The following will list all the providers and the algorithms supporter. What version of Java are you using? Unless you're on an old version JCE should be included as standard.
import java.security.Provider;
import java.security.Security;
public class SecurityListings {
public static void main(String[] args) {
for (Provider provider : Security.getProviders()) {
System.out.println("Provider: " + provider.getName());
for (Provider.Service service : provider.getServices()) {
System.out.println(" Algorithm: " + service.getAlgorithm());
}
}
}
}
Edit:
Any reason why you don't use the standard stuff from the javax.crypto package?
1) Generate a Key using
Key key = SecretKeyFactory.getInstance(algorithm).generateSecret(new PBEKeySpec(password.toCharArray()));
2) Create a Cipher using
cipher = Cipher.getInstance(algorithm);
3) Init your cipher with the key
cipher.init(Cipher.ENCRYPT_MODE, key);
4) Do the encrypting with
byte[] encrypted = cipher.doFinal(data)
The Jasypt command line tool now comes with a script for doing this called listAlgorithms.bat for windows and listAlgorithms.sh for Linux.
You can find instructions on how to download and use it here: http://www.jasypt.org/cli.html#Listing_algorithms
If you don't have it installed already, then you need to install the JCE (Java Cryptography Extension) which provides support for the algorithms.
You can see how to install here:
http://download.oracle.com/javase/1.4.2/docs/guide/security/CryptoSpec.html#ProviderInstalling
The library can be found here:
http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136007.html
I tried the code posted by #Qwerky, but it's not very helpful. I had added the latest BouncyCastle provider, and the results I got were very confusing. This shows in better detail who's the provider, version, and the algorithm type and name.
for (Provider provider : Security.getProviders()) {
System.out.println("Provider: " + provider.getName() + " version: " + provider.getVersion());
for (Provider.Service service : provider.getServices()) {
System.out.printf(" Type : %-30s Algorithm: %-30s\n", service.getType(), service.getAlgorithm());
}
}
There is still a 'pending' question asked by Qwerky: why using Jasypt instead of using javax.crypto?
Well, I would recommend using Jasypt as it is a simple way to crypto for beginners and highly configurable for experienced users.
With Jasypt, you can start taking benefit of javax.crypto quickly with a little knowledge of JCE and the cryptography. Whether you want to manage user passwords or encrypt/decrypt data, the framework provides a simple abstraction to the question.
In the same time, the framework exposes all the possibilities of the JCE specification to allow experienced users to be in full control.
In addition to this, Jasypt provides many more features out-of-the-box for well known questions (dealing with sensitive data stored in the database, ...)
Using Java 8 and above,
Stream.of(Security.getProviders()).flatMap(mapper -> Stream.of(mapper.getServices())).flatMap(Set::stream)
.map(Provider.Service::getAlgorithm).distinct().sorted().forEach(System.out::println);

Categories