silk.crypto.des_wrap.

Wrap keys with the Triple DES key wrap of RFC 3217 (CMS id-alg-CMS3DESwrap).

When to use#

Use TripleDesKeyWrap where a format or protocol names Triple DES key wrap, such as old CMS messages or Node's des3-wrap cipher. For new designs, use silk.crypto.aes_wrap.

Details#

The key-encryption key is 24 bytes (K1, K2, K3). TripleDesKeyWrap.wrap appends the first 8 bytes of the SHA-1 of the input as an integrity value, encrypts that with Triple DES in CBC mode under a caller's 8-byte IV, puts the IV in front, reverses the bytes, and encrypts again in CBC mode under the fixed IV 4ADDA22C79E82105. The input is a nonzero multiple of 8 bytes, and the output is 16 bytes longer. As in OpenSSL, any such length is taken, and the key bytes' parity is not changed. TripleDesKeyWrap.unwrap reverses the steps and checks the integrity value. Nothing allocates.

Errors#

The functions return a TripleDesKeyWrapError. The checks on lengths come before the first write. On IntegrityCheckFailed, unwrapping sets the bytes it wrote back to zero.

Gotchas#

The IV must be random for each wrap: RFC 3217 takes it from a random source, and OpenSSL draws one itself. Take 8 bytes from silk.system.random.

Examples#

Wrap and unwrap a key#

silk
import silk.crypto.des_wrap { TripleDesKeyWrap, TripleDesKeyWrapError }
import silk.core.result { Result }

pub fn main() -> i32 {
  let kek: [u8; 24] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
  let iv: [u8; 8] = [9; 8]
  let secret: [u8; 24] = [7; 24]
  let mut wrapped: [u8; 40] = [0; 40]
  if let Result.Failure { error: _ } = TripleDesKeyWrap.wrap(&kek, &iv, &secret, &mut wrapped) { return 1 }
  let mut unwrapped: [u8; 24] = [0; 24]
  return match TripleDesKeyWrap.unwrap(&kek, &wrapped, &mut unwrapped) {
    Result<usize, TripleDesKeyWrapError>.Success { value } => if value == 24 && unwrapped[0] == 7 { 0 } else { 1 }
    Result<usize, TripleDesKeyWrapError>.Failure { error: _ } => 1
  }
}

Import as TripleDesKeyWrap with import silk.crypto.des_wrap { TripleDesKeyWrap }.

Public declarations: 2.

TripleDesKeyWrapError#

silk
pub enum TripleDesKeyWrapError

The reason that a key wrap call was rejected. The checks run in the order of the variants.

InvalidKeyLength#

silk
InvalidKeyLength

The key-encryption key is not 24 bytes.

InvalidIvLength#

silk
InvalidIvLength

The IV is not 8 bytes.

InvalidInputLength#

silk
InvalidInputLength

The input length is not one that the algorithm takes.

OutputTooSmall#

silk
OutputTooSmall

The output is shorter than the bytes the call writes.

IntegrityCheckFailed#

silk
IntegrityCheckFailed

The unwrapped integrity value does not match: the key is wrong or the input was changed.

Implementation Debug for TripleDesKeyWrapError#

silk
impl Debug for TripleDesKeyWrapError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as InvalidKeyLength.

TripleDesKeyWrap#

silk
pub struct TripleDesKeyWrap

Functions that wrap and unwrap keys with Triple DES (RFC 3217).

Details#

The key-encryption key is 24 bytes. Wrapping adds 16 bytes. Nothing allocates.

Implementation TripleDesKeyWrap#

silk
impl TripleDesKeyWrap

Associated function wrapIv#

silk
pub fn wrapIv() -> [u8; 8]

Returns the fixed IV of the second encryption, 4ADDA22C79E82105.

Associated function wrap#

silk
pub fn wrap(key: &[u8], iv: &[u8], input: &[u8], output: &mut [u8]) -> Result<usize, TripleDesKeyWrapError>

Wraps input (a nonzero multiple of 8 bytes) under key with the random 8-byte iv into the first input.length + 16 bytes of output, and returns that length.

Errors#

  • InvalidKeyLength if key is not 24 bytes.

  • InvalidIvLength if iv is not 8 bytes.

  • InvalidInputLength if input is empty or not a multiple of 8.

  • OutputTooSmall if output is shorter than input.length + 16.

Associated function unwrap#

silk
pub fn unwrap(key: &[u8], input: &[u8], output: &mut [u8]) -> Result<usize, TripleDesKeyWrapError>

Unwraps input (a multiple of 8 bytes, at least 24) under key, checks its integrity value, writes the key to the first input.length - 16 bytes of output, and returns that length.

Errors#

  • InvalidKeyLength if key is not 24 bytes.

  • InvalidInputLength if input is shorter than 24 bytes or not a multiple of 8.

  • OutputTooSmall if output is shorter than input.length - 16.

  • IntegrityCheckFailed if the integrity value does not match. The written bytes are zero.

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.

View the source of this page