mirror of
https://github.com/matrix-org/matrix-hookshot.git
synced 2025-03-10 21:19:13 +00:00
Fix PKCS1 handling (#929)
* Support pkcs1 format keys. * Test pkcs1 support. * changelog * rust formatting
This commit is contained in:
parent
4839340c86
commit
ff200114a6
1
changelog.d/929.bugfix
Normal file
1
changelog.d/929.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Track which key was used to encrypt secrets in storage, and encrypt/decrypt secrets in Rust.
|
@ -3,6 +3,7 @@ use std::string::FromUtf8Error;
|
|||||||
use base64ct::{Base64, Encoding};
|
use base64ct::{Base64, Encoding};
|
||||||
use napi::bindgen_prelude::Buffer;
|
use napi::bindgen_prelude::Buffer;
|
||||||
use napi::Error;
|
use napi::Error;
|
||||||
|
use rsa::pkcs1::DecodeRsaPrivateKey;
|
||||||
use rsa::pkcs8::DecodePrivateKey;
|
use rsa::pkcs8::DecodePrivateKey;
|
||||||
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
|
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
|
||||||
|
|
||||||
@ -17,7 +18,9 @@ struct TokenEncryption {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
enum TokenEncryptionError {
|
enum TokenEncryptionError {
|
||||||
FromUtf8(FromUtf8Error),
|
FromUtf8(FromUtf8Error),
|
||||||
PrivateKey(rsa::pkcs8::Error),
|
UnknownFormat,
|
||||||
|
PrivateKey8(rsa::pkcs8::Error),
|
||||||
|
PrivateKey1(rsa::pkcs1::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -31,8 +34,16 @@ enum DecryptError {
|
|||||||
impl TokenEncryption {
|
impl TokenEncryption {
|
||||||
pub fn new(private_key_data: Vec<u8>) -> Result<Self, TokenEncryptionError> {
|
pub fn new(private_key_data: Vec<u8>) -> Result<Self, TokenEncryptionError> {
|
||||||
let data = String::from_utf8(private_key_data).map_err(TokenEncryptionError::FromUtf8)?;
|
let data = String::from_utf8(private_key_data).map_err(TokenEncryptionError::FromUtf8)?;
|
||||||
let private_key = RsaPrivateKey::from_pkcs8_pem(data.as_str())
|
let private_key: RsaPrivateKey;
|
||||||
.map_err(TokenEncryptionError::PrivateKey)?;
|
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();
|
let public_key = private_key.to_public_key();
|
||||||
Ok(TokenEncryption {
|
Ok(TokenEncryption {
|
||||||
private_key,
|
private_key,
|
||||||
|
@ -4,6 +4,7 @@ import { expect } from "chai";
|
|||||||
|
|
||||||
describe("TokenEncryption", () => {
|
describe("TokenEncryption", () => {
|
||||||
let keyPromise: Promise<Buffer>;
|
let keyPromise: Promise<Buffer>;
|
||||||
|
let keyPromisePKCS1: Promise<Buffer>;
|
||||||
async function createTokenEncryption() {
|
async function createTokenEncryption() {
|
||||||
return new TokenEncryption(await keyPromise);
|
return new TokenEncryption(await keyPromise);
|
||||||
}
|
}
|
||||||
@ -24,6 +25,21 @@ describe("TokenEncryption", () => {
|
|||||||
} satisfies RSAKeyPairOptions<"pem", "pem">, (err, _, privateKey) => {
|
} satisfies RSAKeyPairOptions<"pem", "pem">, (err, _, privateKey) => {
|
||||||
if (err) { reject(err) } else { resolve(Buffer.from(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() => {
|
it('should be able to encrypt a string into a single part', async() => {
|
||||||
const tokenEncryption = await createTokenEncryption();
|
const tokenEncryption = await createTokenEncryption();
|
||||||
@ -45,4 +61,9 @@ describe("TokenEncryption", () => {
|
|||||||
const result = tokenEncryption.decrypt(value);
|
const result = tokenEncryption.decrypt(value);
|
||||||
expect(result).to.equal(plaintext);
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user