Fix PKCS1 handling (#929)

* Support pkcs1 format keys.

* Test pkcs1 support.

* changelog

* rust formatting
This commit is contained in:
Will Hunt 2024-04-16 22:05:36 +01:00 committed by GitHub
parent 4839340c86
commit ff200114a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 3 deletions

1
changelog.d/929.bugfix Normal file
View File

@ -0,0 +1 @@
Track which key was used to encrypt secrets in storage, and encrypt/decrypt secrets in Rust.

View File

@ -3,6 +3,7 @@ use std::string::FromUtf8Error;
use base64ct::{Base64, Encoding};
use napi::bindgen_prelude::Buffer;
use napi::Error;
use rsa::pkcs1::DecodeRsaPrivateKey;
use rsa::pkcs8::DecodePrivateKey;
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
@ -17,7 +18,9 @@ struct TokenEncryption {
#[allow(dead_code)]
enum TokenEncryptionError {
FromUtf8(FromUtf8Error),
PrivateKey(rsa::pkcs8::Error),
UnknownFormat,
PrivateKey8(rsa::pkcs8::Error),
PrivateKey1(rsa::pkcs1::Error),
}
#[derive(Debug)]
@ -31,8 +34,16 @@ enum DecryptError {
impl TokenEncryption {
pub fn new(private_key_data: Vec<u8>) -> Result<Self, TokenEncryptionError> {
let data = String::from_utf8(private_key_data).map_err(TokenEncryptionError::FromUtf8)?;
let private_key = RsaPrivateKey::from_pkcs8_pem(data.as_str())
.map_err(TokenEncryptionError::PrivateKey)?;
let private_key: RsaPrivateKey;
if data.starts_with("-----BEGIN PRIVATE KEY-----") {
private_key = RsaPrivateKey::from_pkcs8_pem(data.as_str())
.map_err(TokenEncryptionError::PrivateKey8)?;
} else if data.starts_with("-----BEGIN RSA PRIVATE KEY-----") {
private_key = RsaPrivateKey::from_pkcs1_pem(data.as_str())
.map_err(TokenEncryptionError::PrivateKey1)?;
} else {
return Err(TokenEncryptionError::UnknownFormat);
}
let public_key = private_key.to_public_key();
Ok(TokenEncryption {
private_key,

View File

@ -4,6 +4,7 @@ import { expect } from "chai";
describe("TokenEncryption", () => {
let keyPromise: Promise<Buffer>;
let keyPromisePKCS1: Promise<Buffer>;
async function createTokenEncryption() {
return new TokenEncryption(await keyPromise);
}
@ -24,6 +25,21 @@ describe("TokenEncryption", () => {
} satisfies RSAKeyPairOptions<"pem", "pem">, (err, _, privateKey) => {
if (err) { reject(err) } else { resolve(Buffer.from(privateKey)) }
}));
keyPromisePKCS1 = new Promise<Buffer>((resolve, reject) => generateKeyPair("rsa", {
// Deliberately shorter length to speed up test
modulusLength: 2048,
privateKeyEncoding: {
type: "pkcs1",
format: "pem",
},
publicKeyEncoding: {
format: "pem",
type: "pkcs1",
}
} satisfies RSAKeyPairOptions<"pem", "pem">, (err, _, privateKey) => {
if (err) { reject(err) } else { resolve(Buffer.from(privateKey)) }
}));
}, );
it('should be able to encrypt a string into a single part', async() => {
const tokenEncryption = await createTokenEncryption();
@ -45,4 +61,9 @@ describe("TokenEncryption", () => {
const result = tokenEncryption.decrypt(value);
expect(result).to.equal(plaintext);
});
it('should support pkcs1 format keys', async() => {
const tokenEncryption = new TokenEncryption(await keyPromisePKCS1);
const result = tokenEncryption.encrypt('hello world');
expect(result).to.have.lengthOf(1);
});
});