silk.crypto.legacy_pem.
Encrypt and decrypt PEM keys with the legacy OpenSSL scheme of the Proc-Type and DEK-Info
headers (RFC 1421 framing).
When to use#
Use LegacyPem for a -----BEGIN RSA PRIVATE KEY----- or -----BEGIN EC PRIVATE KEY-----
block with Proc-Type: 4,ENCRYPTED, such as the output of export with type: 'pkcs1' or
'sec1' and a cipher in Node.js. For PKCS #8 keys, use silk.crypto.pkcs8, which is stronger.
Details#
The key is EVP_BytesToKey with MD5, one iteration, and the first 8 bytes of the IV as the
salt. The cipher is AES, Camellia, or ARIA with a 128, 192, or 256-bit key, or Triple DES, all
in CBC mode with PKCS #7 padding (LegacyPemCipher). Read the DEK-Info header with
Pem.header of silk.encoding.pem and pass it to LegacyPem.decrypt; LegacyPem.writeHeaders
writes the two headers for Pem.encode. Nothing allocates.
Errors#
The functions return a LegacyPemError. On an error the output does not change.
Gotchas#
The scheme derives the key with one MD5 call, so a weak password falls fast to guessing. A wrong
password usually fails with WrongPassword, but about one in 256 passes the padding check;
check that the result parses as a key.
Examples#
Encrypt and decrypt a key#
import silk.crypto.legacy_pem { LegacyPem, LegacyPemCipher, LegacyPemError }
import silk.core.result { Result }
import silk.collections.slice { Slice }
pub fn main() -> i32 {
let iv: [u8; 16] = [1; 16]
let mut headers: [u8; 96] = [0; 96]
let headerLength = LegacyPem.writeHeaders(LegacyPemCipher.Aes256Cbc, &iv, &mut headers)
// The DEK-Info value starts after "Proc-Type: 4,ENCRYPTED\nDEK-Info: ".
let dekInfo = Slice.view<u8>(&headers, 33, headerLength - 34)
let mut sealed: [u8; 32] = [0; 32]
let length = match LegacyPem.encrypt(LegacyPemCipher.Aes256Cbc, b"secret", &iv, b"key bytes", &mut sealed) {
Result<usize, LegacyPemError>.Success { value } => value
Result<usize, LegacyPemError>.Failure { error: _ } => {
return 1
}
}
let mut opened: [u8; 32] = [0; 32]
let back = match LegacyPem.decrypt(dekInfo, b"secret", Slice.view<u8>(&sealed, 0, length), &mut opened) {
Result<usize, LegacyPemError>.Success { value } => value
Result<usize, LegacyPemError>.Failure { error: _ } => {
return 1
}
}
if back != 9 || opened[0] != 107 {
return 1
}
return 0
}Import as LegacyPem with import silk.crypto.legacy_pem { LegacyPem }.
Public declarations: 3.
LegacyPemError#
pub union LegacyPemErrorThe reason that a LegacyPem function rejected a call. The output does not change.
InvalidDekInfo#
InvalidDekInfoThe DEK-Info value is not a supported cipher name, a comma, and the IV in hex.
WrongPassword#
WrongPasswordThe decrypted data does not end in valid padding: the password is wrong, or the data was changed.
InvalidInputLength#
InvalidInputLengthThe ciphertext is empty or not a whole number of blocks.
InvalidIvLength#
InvalidIvLengthThe IV given to LegacyPem.encrypt is not one cipher block.
OutputTooSmall#
OutputTooSmallThe output buffer is shorter than the bytes the call writes.
Implementation Debug for LegacyPemError#
impl Debug for LegacyPemErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as WrongPassword.
LegacyPemCipher#
pub enum LegacyPemCipherThe CBC ciphers of the legacy scheme, with their DEK-Info names.
Aes128Cbc#
Aes128CbcAES-128-CBC.
Aes192Cbc#
Aes192CbcAES-192-CBC.
Aes256Cbc#
Aes256CbcAES-256-CBC.
TripleDesCbc#
TripleDesCbcDES-EDE3-CBC, Triple DES with a 24-byte key.
Camellia128Cbc#
Camellia128CbcCAMELLIA-128-CBC.
Camellia192Cbc#
Camellia192CbcCAMELLIA-192-CBC.
Camellia256Cbc#
Camellia256CbcCAMELLIA-256-CBC.
Aria128Cbc#
Aria128CbcARIA-128-CBC.
Aria192Cbc#
Aria192CbcARIA-192-CBC.
Aria256Cbc#
Aria256CbcARIA-256-CBC.
Implementation LegacyPemCipher#
impl LegacyPemCipherMethod name#
pub fn name(self: &Self) -> &'static [u8]Returns the name that DEK-Info uses, such as AES-256-CBC.
Method keyLength#
pub fn keyLength(self: &Self) -> usizeReturns the key length in bytes.
Method blockLength#
pub fn blockLength(self: &Self) -> usizeReturns the block length in bytes, which is also the IV length: 8 for Triple DES, 16 for the others.
LegacyPem#
pub struct LegacyPemFunctions of the legacy PEM encryption scheme.
Implementation LegacyPem#
impl LegacyPemAssociated function decrypt#
pub fn decrypt(dekInfo: &[u8], password: &[u8], ciphertext: &[u8], output: &mut [u8]) -> Result<usize, LegacyPemError>Decrypts ciphertext, the decoded body of a block whose DEK-Info header is dekInfo, with
password into output, and returns the number of bytes written.
The cipher name in dekInfo compares without regard to case, as in OpenSSL. The result is at
most ciphertext.length bytes.
Errors#
InvalidDekInfoifdekInfois not a name ofLegacyPemCipher, a comma, and one block of IV in hex.InvalidInputLengthifciphertextis empty or not a whole number of blocks.WrongPasswordif the padding is wrong after decryption.OutputTooSmallifoutputis shorter thanciphertext.
Associated function encryptedLength#
pub fn encryptedLength(cipher: LegacyPemCipher, length: usize) -> usizeReturns the number of bytes that LegacyPem.encrypt writes for length bytes with
cipher: the length padded to the next whole block.
Associated function encrypt#
pub fn encrypt(cipher: LegacyPemCipher, password: &[u8], iv: &[u8], plaintext: &[u8], output: &mut [u8]) -> Result<usize, LegacyPemError>Encrypts plaintext, the DER of a key, with cipher, password, and iv into output,
and returns the number of bytes written, LegacyPem.encryptedLength.
iv is one random cipher block; its first 8 bytes are also the salt of the key.
Errors#
InvalidIvLengthifivis not one block ofcipher.OutputTooSmallifoutputis shorter thanLegacyPem.encryptedLength.
Associated function headersLength#
pub fn headersLength(cipher: LegacyPemCipher) -> usizeReturns the number of bytes that LegacyPem.writeHeaders writes for cipher.
Associated function writeHeaders#
pub fn writeHeaders(cipher: LegacyPemCipher, iv: &[u8], output: &mut [u8]) -> usizeWrites the Proc-Type and DEK-Info header lines for cipher and iv to output, each
ending with LF, ready for the headers of Pem.encode, and returns the number of bytes
written, LegacyPem.headersLength.
The IV is written in uppercase hex, as OpenSSL does. It traps if iv is not one block of
cipher or output is shorter than LegacyPem.headersLength.
Category: Cryptography.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.