I'm trying to retrieve a private key, using the Bouncy Castle, Ktor and Kotlin.
fun readPrivateKey(filePath: String): Result<RSAPrivateKey> = runCatching {
val pemParse = PEMParser(FileReader(filePath))
val privateKey = PrivateKeyInfo.getInstance(pemParse.readObject())
JcaPEMKeyConverter().getPrivateKey(privateKey) as RSAPrivateKey
}.onFailure { throw it }
but when testing the function, I get the following error
unknown object in getInstance: org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo
java.lang.IllegalArgumentException: unknown object in getInstance: org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo
the error occurs in this line: privateKey = PrivateKeyInfo.getInstance(pemParse.readObject())
I generated my private key with the following code:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -aes-256-cbc -out development_erp_private.key
what am I doing wrong?
Related
I am using an in-browser library, SSHy, for SSHing to devices. I'm currently working on adding support for publickey authentication, but I keep getting an error from the server about an invalid signature. I'm able to send the first SSH_MSG_USERAUTH_REQUEST without the signature and get back a SSH_MSG_USERAUTH_PK_OK. But when I send the next message with the signature, I always get a SSH_MSG_USERAUTH_FAILURE.
I'm doing the signing with another library (sshpk-browser) and forming the signature below using SSHy based on the SSH schema.
Can anyone see any potential issues with how I am forming the signature?
const decodedPublicKey = config.privateKey.toPublic().toString('ssh', { hashAlgo: 'sha512' }).split(' ')[1];
const publicKey = atob(decodedPublicKey);
var m = new SSHyClient.Message();
m.add_bytes(String.fromCharCode(SSHyClient.MSG_USERAUTH_REQUEST));
m.add_string(this.termUsername);
m.add_string('ssh-connection');
m.add_string('publickey');
m.add_boolean(true); // has signature
m.add_string('rsa-sha2-512'); // public key algorithm name
m.add_string(publicKey); // public key
// Create signature
var sigMsg = new SSHyClient.Message();
sigMsg.add_string(SSHyClient.kex.sessionId);
sigMsg.add_bytes(String.fromCharCode(SSHyClient.MSG_USERAUTH_REQUEST));
sigMsg.add_string(this.termUsername);
sigMsg.add_string('ssh-connection');
sigMsg.add_string('publickey');
sigMsg.add_boolean(true); // has signature
sigMsg.add_string('rsa-sha2-512');
sigMsg.add_string(publicKey);
const sigMsgString = sigMsg.toString();
// Sign signature
const sign = config.privateKey.createSign('sha512');
sign.update(sigMsgString);
const signature = sign.sign();
m.add_string(atob(signatureToString)); // signature
this.parceler.send(m);
I read public/private key is so you can
create JWT token with private / public key
hand out your public key only to 3rd parties
3rd parties can now validate users JWT tokens via the public key
However, their example with private / public key requires the private key to validate which seems odd ->
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
try {
Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("auth0")
.build(); //Reusable verifier instance
DecodedJWT jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
//Invalid signature/claims
}
Is there no way to validate with just the public key?
On this line:
Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
pass the privateKey as null. Private keys are for signing.
Algorithm algorithm = Algorithm.RSA256(publicKey, null);
I'm trying to encrypt plain texts with public key.
My code keeps fail with InvalidKeyException.
This is my code:
private const val pubkey = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100f357429c22add0d547ee3e4e876f921a0114d1aaa2e6eeac6177a6a2e2565ce9593b78ea0ec1d8335a9f12356f08e99ea0c3455d849774d85f954ee68d63fc8d6526918210f28dc51aa333b0c4cdc6bf9b029d1c50b5aef5e626c9c8c9c16231c41eef530be91143627205bbbf99c2c261791d2df71e69fbc83cdc7e37c1b3df4ae71244a691c6d2a73eab7617c713e9c193484459f45adc6dd0cba1d54f1abef5b2c34dee43fc0c067ce1c140bc4f81b935c94b116cce404c5b438a0395906ff0133f5b1c6e3b2bb423c6c350376eb4939f44461164195acc51ef44a34d4100f6a837e3473e3ce2e16cedbe67ca48da301f64fc4240b878c9cc6b3d30c316b50203010001"
private val cipher: Cipher
init {
val bytesKey = Base64.getDecoder().decode(pubkey)
val keySpec = X509EncodedKeySpec(bytesKey)
val keyFactory = KeyFactory.getInstance("RSA")
val publicKey = keyFactory.generatePublic(keySpec) // where exception has been thrown
cipher = Cipher.getInstance("RSA")
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
}
fun encrypt(plainText: String): String {
val bytePlain = cipher.doFinal(plainText.toByteArray())
return Base64.getEncoder().encodeToString(bytePlain)
}
pubkey contains the hex encoded key, i.e. for the initialization of bytesKey a hex decoding is necessary and no Base64 decoding.
Here you can find an implementation for a hex decoding for Kotlin.
Note also that when instantiating the cipher, it is better to specify the padding besides the algorithm, e.g. RSA/ECB/PKCS1Padding, otherwise the provider dependent default padding is applied, which may be a different one than you expect.
I am trying to parse a public key in the RSA format from kotlin. I have the key in a string whose contents are like this:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAwAzOKC8d0o0dcv1KqILLehASGgOWyjlAc+adazix6ThhX7QeD3Qw
HzxPpbwsJrVPIEMEIN383awIqnCfIL+AbCQPL13XaUCCS74wC5a84X1r6hcI5XO1
9CPAn+jBKmTr4hPaHWKxuhfO3PcXxGfQdXyqNT96bCYnAYaeSECohFjqDbe+RFcL
1lIns2GtQPMh1/uDyhPA+8HSguREWn+Ac3I2c0wtrzZa6R4nruPgIi6XbWRqAskr
tzbO2Xy6O1DcERH9tg+es/pbrWHRHrwEmLXorj3iGqkJJBUmLeW6B5EjmIgiukdJ
dw7bLTNcwf2n0BLJy/bgnhcw4TMOzUadSQIDAQAB
-----END RSA PUBLIC KEY-----
I found a lot of code examples to do this that involve trimming out the BEGIN and END, using String.replace() but that seemed hacky to me. The BouncyCastle code seems to handle this already including the ability to create a parsers for the different types of "files" it encounters. I'm trying this:
try {
val parser = PEMParser(StringReader(publicKeyString))
val pemObject = parser.readPemObject()
val pemContent = pemObject.content
val key = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(pemContent)
serviceLogger.info("Key object: {}", key)
} catch (e: Exception) {
serviceLogger.error("Could not generate key from keyspec", e)
}
I get as far as a pemContent (an array of bytes) without a problem, but when I try to actually parse that into an RSAPublicKey I get this:
java.lang.IllegalArgumentException: failed to construct sequence from byte[]: DEF length 3 object truncated by 2
What I can't figure out is if I'm calling RSAPublicKey.getInstance() correctly - with the content of the entire PemObject - or is this exception telling me that there's something wrong with my key.
The examples I have been able to find on this are pretty old, and the APIs seem to have evolved to the point that I shouldn't have to be chopping up strings manually.
I doubt this really helps the matter, but I'm generating this file in go from an rsa keypair:
func PublicKeyToPemBytes(prvkey *rsa.PrivateKey) ([]byte, error) {
var pubkey *rsa.PublicKey
pubkey = &prvkey.PublicKey
pubkey_bytes := x509.MarshalPKCS1PublicKey(pubkey)
if pubkey_bytes == nil {
return nil, errors.New("Public key could not be serialized")
}
pubkey_pem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubkey_bytes,
},
)
return pubkey_pem, nil
}
The go rsa.PublicKey object contains an N and an E. It gives me a file like listed above, and the base64 decoding results in the exact same length, 270 bytes.
dave_thompson_085 was right. This code actually does work. He asked me if I altered the data, which made me look more closely at it and I realized I was doing a .toUpperCase() on the base64. The result was still perfectly valid base64 with some bits flipped on here and there. I shouldn't have been doing that .toUpperCase() at all, I just didn't see it until he said that. Bouncy does work.
I am trying to get the modulus value of a private key using bouncy castle library. I was able to get PrivateKeyInfo object how can i get the modulus value from this?
You could do as follow (this code is for public key but yours should be similar)
PublicKey key = getPublicKey();
KeyFactory keyFac = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pkSpec = keyFac.getKeySpec(key,
RSAPublicKeySpec.class);
byte[] modulusBytes = pkSpec.getModulus().toByteArray();
modulusBytes = stripLeadingZeros(modulusBytes);