Determine certificate key type (RSA vs EC) in .NET or BouncyCastle? - rsa

Currently we have a routine that Signs a byte[] given a certificate (and it's private key). However, the type of certificate/keys is hardcoded as "Certificate with RSA keys". That code is :
public byte[] Sign(byte[] bytesToSign, bool fOAEP, X509Certificate2 certificate)
{
using (RSACryptoServiceProvider provider = new RSACryptoServiceProvider())
{
// HACK: Round-trip the key to XML and back, to get provider type working
// as 'Microsoft Enhanced RSA and AES Cryptographic Provider' (for
// SHA256/SHA512 signing hash) instead of 'Microsoft Enhanced
// Cryptographic Provider v1.0' (that limits us to SHA1)
string publicKeyXml = certificate.PrivateKey.ToXmlString(true);
provider.FromXmlString(publicKeyXml);
// We use the private key to sign.
return provider.SignData(bytesToSign, CryptoConfig.MapNameToOID("SHA512"));
}
}
We would like to make it more flexible where if the certificate uses RSA keys, we process it one way but if it uses EC keys, then we process it differently. Basically the Crypto Service Provider type would be of a different type.
So the core question is:
Given a certificate with public+private keys (for signing) OR a certificate with just public keys (for verifying), how do you determine the types of keys used by the certificate?
I'm open to standard .NET libs or even BouncyCastle.Org libs.

You can check key type (algorithm) via certificate.PublicKey.Oid.
Here you can see supported by Microsoft OIDs: http://msdn.microsoft.com/en-us/library/ff635835.aspx
Other OIDs can be checked at oid-info.com

Related

How do you set permissions on a certificate in the Windows Certificate Store through PowerShell 7?

Every resource I've found so far, such as this question, boils down to:
Get the certificate as an X509Certificate2
Cast the PrivateKey property to RSACryptoServiceProvider
Do stuff involving CspKeyContainerInfo property on the private key
This works in PowerShell 5, but in PowerShell 7, the PrivateKey property is an RSACng, not an RSACryptoServiceProvider, and so step 2 doesn't work.
FYI, PrivateKey was deprecated. You are now required to use the GetRSAPrivateKey extension method.
I cannot find any documentation, but it appears that .Net Framework used to return an RSA that also implemented RSACryptoServiceProvider which is where we could get the CspKeyContainerInfo, but now we are required to grab the key RSA derived type RSACng which is returned by the extension method. From here you can grab properties like the $cert.Key.UniqueName

ACM PCA Issue certificate for client authentication and signing data

I'm trying to implement MTLS client authentication using AWS ACM Private CA to issue X.509 client certificates.
The certificate and the correlating private key is supposed to be stored in a password protected PKCS#12 file.
The private key will also be used by the client to sign data.
If I request a new certificate using aws-acm-sdk:
RequestCertificateResult response = acm.requestCertificate(new RequestCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withIdempotencyToken("1234")
.withDomainName("localhost.com"));
return response.getCertificateArn();
And then export the it using the arn, I get a certificate, certificateChain and a privateKey as strings.
ExportCertificateResult response = acm.exportCertificate(new ExportCertificateRequest()
.withCertificateArn(certificateArn)
.withPassphrase(ByteBuffer.wrap(password.getBytes())));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
String privateKey = response.getPrivateKey();
But I'm not able to add any type of identifier that let's me tie the certificate to a user during authentication (I'm using Java and Spring security x509 authentication, which extracts e.g. the subject CN (Common Name) from the certificate which then can be used to identify a user).
If I want to add custom attributes to the certificate, I need to issue a certificate through the aws-acm-pca-sdk:
IssueCertificateRequest request = new IssueCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCsr(stringToByteBuffer(getCSR()))
.withTemplateArn("arn:aws:acm-pca:::template/EndEntityClientAuthCertificate_APIPassthrough/V1")
.withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA)
.withValidity(new Validity()
.withValue(365L)
.withType(ValidityPeriodType.DAYS))
.withIdempotencyToken(userId)
.withApiPassthrough(new ApiPassthrough()
.withSubject(new ASN1Subject()
.withCustomAttributes(List.of(
new CustomAttribute()
.withObjectIdentifier("1.3.6.1.4.1") // CustomOID
.withValue("userId")))));
return acmPca.issueCertificate(request).getCertificateArn();
But if I use the sdk to get the certificate, it doesn't contain any private key.
GetCertificateResult response = acmPca.getCertificate(new GetCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCertificateArn(certificateArn));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
So, when I read documentation I found that I need to import it to ACM in order to export it and get the private key.
But in order to import it to ACM I also need to provide the private key..
But as I understand it, the private key should be used when issuing the certificate in the first place?
Should I create a new public/private key pair using KMS or what am I supposed to do?
Im confused.. Please help!
I had misinterpreted the responsibility of the PCA.
The PCA is only responsible for issuing certificates, not keys or even CSR (Certificate Signing Requests).
I assumed that the CSR were created by PCA, so the getCSR() method actually fetched the CA's CSR from PCA, while the actual CSR should be generated internally using a private key which has been generated either programmatically or using KMS.

How to encrypt JWT secret code for protect it in case of APK decompilation?

I have a problem with JWT. If someone decompiles my APK, they can see the secret code I used to create my token. Example code, the code is secret:
String originalInput = "secret";
String encodedString =Base64Utils.encode(originalInput.getBytes());
String jwt = Jwts.builder().claim("emailId","test123#gmail.com").claim("user", "123456")
.claim("phoneNo", "1111111111")
.signWith(SignatureAlgorithm.HS256, encodedString)
.compact();
As there are a client (the APK) and a backend, you should use an asymmetric algorithm such as RS256, PS256 or ES256, not a symmetric one (HS256).
If the issuer of the token is your backend, you only need the public key on client side (your APK). This key can safely be shipped as it is public.
If the client is the issuer, key should not be shipped with your application but generated on the device and securely stored using the Keystore API (https://developer.android.com/training/articles/keystore). The associated public key should be sent to the backend. This means that each client has a uniquely generated private key.

How to get publicKey in RSA_encrypt key-pair generation algorithm in STRING format in flutter

I am currently working on encryption in my flutter app wherein I am using RSA key-pair generator to get public and private key using the following code-
import 'package:rsa_encrypt/rsa_encrypt.dart';
import 'package:pointycastle/api.dart' as crypto;
//Future to hold our KeyPair
Future<crypto.AsymmetricKeyPair> futureKeyPair;
//to store the KeyPair once we get data from our future
crypto.AsymmetricKeyPair keyPair;
Future<crypto.AsymmetricKeyPair<crypto.PublicKey, crypto.PrivateKey>> getKeyPair()
{
var helper = RsaKeyHelper();
return helper.computeRSAKeyPair(helper.getSecureRandom());
}
Now I want to get the keyPair.publicKey in string format but if i print keyPair.publicKey, it shows "Instance of RSA publicKey" . How can I get it in string format??
It is always best to use standardized formats when saving public keys. For RSA public keys you can store them in layers, much like a Matroesjka doll.
Encode the public key in the ASN.1 / DER format specified in the PKCS#1 RSA standard;
Encode that public key in a format called SubjectPublicKeyInfo which is part of the X.509 specifications - it indicates that this is indeed an RSA key;
Apply so called PEM "ASCII armor", which consists of a header & footer line indicating the generic SubjectPublicKeyFormat (just PUBLIC KEY), with a multi-line base 64 encoding of the public key from step 2 in between.
Sounds like a lot of work, but if you look here you'll find handy methods called encodePublicKeyToPem and parsePublicKeyFromPem that do these 3 steps for you (it actually does both 1 and 2 in the same function, which is a bit of a shame but not that important).
These keys are rather portable and are also usable by e.g. OpenSSL or PGP.

Decryption with the public key in iphone

I have a public key and an encrypted string. I could encrypt with the publickey successfully.But when i try to decrypt using the publickey it fails. I mean when i pass the publickey toseckeyDecrypt it fails.
I have Googled and found out that, by default kSecAttrCanDecrypt is false for public keys.So When i import the public key, i have added this particular line ,
[publicKeyAttr setObject:(id)kCFBooleanTrue forKey:(id)kSecAttrCanDecrypt];
But there is no improvement it still fails. Please somebody help.
EDIT:
Apple's Certificate,Key and Trust Services Says,
kSecAttrCanEncrypt Default false for private keys, true for public keys.
kSecAttrCanDecrypt Default true for private keys, false for public keys.
Which means, the values can be changed right?. My server does not sign(Convert as a digest) the content. They just encrypt using the private key which is to be decrypted at my(in iphone) end. Is that possible?.
The point of asymmetric cryptography is that you encrypt with the public key and decrypt with the private key.
EDIT: If you're signing and verifying, you should use the associated APIs. For example, you can check this capability with kSecAttrCanSign and kSecAttrCanVerify.