difference in xamarin vs java documentation for ECPublicKey - java

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.

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)"

ECDSA KeyPairGenerator not available (but in JUnit works)

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")

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(.., ..).

Bouncy Castle Getting FipsSecureRandom

I'm trying to use Bouncy Castle in approved mode (CryptoServicesRegistrar.SetApprovedOnlyMode(true);) and am having some trouble generating RSA keys. I keep throwing exceptions on the following line.
var generator = CryptoServicesRegistrar.CreateGenerator(new FipsRsa.KeyGenerationParameters(BigInteger.ValueOf(65537L), 3072), FipsSecureRandom.GetInstance(FipsDrbg.CtrAes256.Algorithm.Name));
I have debugged the constructor, looked at the source code, and so on, but I can't figure out how to get an FSR object. All the builder methods for the object are internal to the BC library so I can't get to them. The methods provided in the FipsDrbg class are all internal as well and the provided stubs (such as CtrAes256 in my example) don't expose it either. I've tried passing a string of a PRNG method directly to the constructor from the values I've found in the documentation such as "SHA256PRNG." This gives the following exception:
attempt to create key pair with unapproved RNG: RSA
Looking in the source, the method throwing this exception comes from a ValidateRandom method that checks to make sure the random instance is a FipsSecureRandom so it doesn't get me anywhere.
Lastly, trying to backtrack the Builder : IDrbgBuilder<FipsSecureRandom> class doesn't lead anywhere. They're wholly used in the Base : Org.BouncyCastle.Crypto.Parameters.Parameters<FipsAlgorithm>, IDrbgBuilderService<FipsSecureRandom> class which is completely internal. While the Builder's Build method is public, it's not static and the constructor is internal so I can't create an instance of it to build anything.
What am I missing?
Update:
I was asked to split out the failing line so here is that line split.
var rsaParams = new FipsRsa.KeyGenerationParameters(BigInteger.ValueOf(65537L), 3072);
var fipsRandom = FipsSecureRandom.GetInstance("SHA256PRNG");
var generator = CryptoServicesRegistrar.CreateGenerator(rsaParams, fipsRandom);
The line throwing the exception is the var generator = line. The full exception details are such.
Source: "bc-fips-1.0.1"
Message: attempt to create key pair with unapproved RNG: RSA
at Org.BouncyCastle.Crypto.Fips.Utils.ValidateRandom(SecureRandom random, Int32 securityStrength, FipsAlgorithm algorithm, String message)
at Org.BouncyCastle.Crypto.Fips.FipsRsa.KeyPairGenerator..ctor(KeyGenerationParameters keyGenParameters, SecureRandom random)
at Org.BouncyCastle.Crypto.Fips.FipsRsa.KeyGenerationParameters.<>c.<Org.BouncyCastle.Crypto.IGenerationService<Org.BouncyCastle.Crypto.Fips.FipsRsa.KeyPairGenerator>.GetFunc>b__17_0(IParameters`1 parameters, SecureRandom random)
at Org.BouncyCastle.Security.SecurityContext.CreateGenerator[A](IGenerationServiceType`1 type, SecureRandom random)
at Org.BouncyCastle.Crypto.CryptoServicesRegistrar.CreateGenerator[A](IGenerationServiceType`1 type, SecureRandom random)
No inner exception, no exception data.

How to find keylength of SSH RSA keys using java

I am using JSCH API to find length of RSA SSH keys .
I use the following code to do that:
KeyPairRSA KPR = (KeyPairRSA) KeyPairRSA.load(jsch, keypath);
System.out.println("size " +KPR.getKeySize());
This returns me always length 1024 .I think its bug with API itself.
Can anyone please tell me how to find length of RSA/DSA SSH keys?
Thanks a lot in advance.
I'm the author of JSch.
It is a bug or the incompleteness of KeyPair* classes.
They had been just introduced for the key-pair generation purposes.
But, in our internal development version, KeyPair* classes have been overhauled, and
that method has worked well.
# This is off-topic, but we have added the support for Putty's private key format, as a bonus! :-)
Anyway, the fix will be available in the next release, and if you can't wait for it,
replace KeyPairRSA#getKeySize() with the following,
public int getKeySize(){
return (new java.math.BigInteger(n_array)).bitLength();
}

Categories