silk.encoding.pem.
Read and write PEM, the Base64 text armor for keys and certificates (RFC 7468).
When to use#
Use Pem to find the -----BEGIN PRIVATE KEY----- style blocks in text and get their DER
bytes, or to wrap DER bytes in such a block, for example for createPrivateKey and export in
Node.js. The DER itself is read by the key modules, such as silk.crypto.rsa.
Details#
Pem.find returns the next block at or after an offset as a PemSection of offsets into the
input, so nothing is copied. Text before, between, and after blocks is skipped. Inside a block
the Base64 may wrap at any width and may hold spaces, tabs, and CR or LF line ends, as OpenSSL
allows. RFC 1421 headers such as Proc-Type and DEK-Info, which a legacy encrypted key has,
end at the first empty line and can be read with Pem.header. Pem.encode writes such
headers when given, then Base64 lines of 64 characters, with LF line ends. Nothing allocates.
Errors#
The functions return a PemError. On an error the output does not change.
Gotchas#
The Base64 of a block must be canonical: padding only at the end, and zero unused bits. A label
is not checked against a list; compare Pem.label with the one you expect.
Examples#
Round trip a block#
import silk.encoding.pem { Pem, PemError, PemSection }
import silk.core.result { Result }
pub fn main() -> i32 {
let mut text: [u8; 64] = [0; 64]
let length = match Pem.encode(b"TEST", b"", b"hello", &mut text) {
Result<usize, PemError>.Success { value } => value
Result<usize, PemError>.Failure { error: _ } => {
return 1
}
}
if length != Pem.encodedLength(4, 0, 5) {
return 1
}
let section = match Pem.find(&text, 0) {
Result<PemSection, PemError>.Success { value } => move value
Result<PemSection, PemError>.Failure { error: _ } => {
return 1
}
}
let label = Pem.label(&text, §ion)
if label.length != 4 || label[0] != 84 {
return 1
}
let mut bytes: [u8; 8] = [0; 8]
let decoded = match Pem.decode(&text, §ion, &mut bytes) {
Result<usize, PemError>.Success { value } => value
Result<usize, PemError>.Failure { error: _ } => {
return 1
}
}
if decoded != 5 || bytes[0] != 104 || bytes[4] != 111 {
return 1
}
return 0
}Import as Pem with import silk.encoding.pem { Pem }.
Public declarations: 3.
PemError#
pub union PemErrorThe reason that a Pem function rejected a call. The output does not change.
NotFound#
NotFoundNo -----BEGIN line starts at or after the offset.
Malformed#
MalformedA block starts but is not well formed: the BEGIN or END line is broken, the labels differ, the END line is missing, or the Base64 is not canonical.
OutputTooSmall#
OutputTooSmallThe output buffer is shorter than the bytes the call writes.
InvalidLabel#
InvalidLabelThe label is empty, or holds a byte other than printable ASCII without -.
Implementation Debug for PemError#
impl Debug for PemErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as NotFound.
PemSection#
pub struct PemSectionOne PEM block, as offsets into the text that Pem.find read.
Details#
The label is labelStart to labelEnd, the RFC 1421 headers are headersStart to headersEnd
(empty when there are none), and the Base64 body is bodyStart to bodyEnd. The block ends at
end, after the END line, where the next search can start.
Field start#
pub start: usizeThe offset of the -----BEGIN line.
Field labelStart#
pub labelStart: usizeThe offset of the first byte of the label.
Field labelEnd#
pub labelEnd: usizeThe offset after the label.
Field headersStart#
pub headersStart: usizeThe offset of the first header line.
Field headersEnd#
pub headersEnd: usizeThe offset after the headers and the empty line that ends them.
Field bodyStart#
pub bodyStart: usizeThe offset of the Base64 body.
Field bodyEnd#
pub bodyEnd: usizeThe offset of the -----END line.
Field end#
pub end: usizeThe offset after the END line and its line end.
Pem#
pub struct PemFunctions that find, decode, and encode PEM blocks.
Implementation Pem#
impl PemAssociated function find#
pub fn find(input: &[u8], offset: usize) -> Result<PemSection, PemError>Returns the next PEM block that starts at or after offset of input.
Errors#
NotFoundif no-----BEGINline starts at or afteroffset.Malformedif the first such block is broken, or its END line is missing or has another label.
Associated function label#
pub fn label<'a>(input: &'a [u8], section: &PemSection) -> &'a [u8]Returns the label of section, such as PRIVATE KEY.
Associated function header#
pub fn header<'a>(input: &'a [u8], section: &PemSection, name: &[u8]) -> Option<&'a [u8]>Returns the value of the RFC 1421 header name of section, such as DEK-Info, without the
spaces around it, or None if the block has no such header.
The name compares exactly. A header that continues on the next line is not joined.
Associated function decode#
pub fn decode(input: &[u8], section: &PemSection, output: &mut [u8]) -> Result<usize, PemError>Decodes the Base64 body of section into output and returns the number of bytes written.
Errors#
Malformedif the body is not canonical Base64 once spaces, tabs, CR, and LF are removed.OutputTooSmallifoutputis shorter than the decoded bytes.
Associated function encodedLength#
pub fn encodedLength(labelLength: usize, headersLength: usize, length: usize) -> usizeReturns the number of bytes that Pem.encode writes for a label of labelLength bytes,
headersLength bytes of headers, and length bytes of data.
Associated function encode#
pub fn encode(label: &[u8], headers: &[u8], bytes: &[u8], output: &mut [u8]) -> Result<usize, PemError>Writes bytes as a PEM block with label label to output and returns the number of bytes
written, Pem.encodedLength.
headers is empty, or RFC 1421 header lines that each end with LF, such as
Proc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,...\n; the empty line after them is added.
The Base64 lines have 64 characters and LF line ends.
Errors#
InvalidLabeliflabelis empty, or holds a byte outside printable ASCII or a-.Malformedifheadersis not empty and does not end with LF, or holds an empty line.OutputTooSmallifoutputis shorter thanPem.encodedLength.
Category: Encoding.
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.