23个稳定版本 (8个主要版本)

9.5.0 2024年7月9日
9.3.0 2023年9月28日
9.0.1 2023年7月13日
8.0.0 2023年6月30日
1.0.0 2022年7月27日

#50 in 密码学

Download history 822/week @ 2024-04-27 484/week @ 2024-05-04 355/week @ 2024-05-11 327/week @ 2024-05-18 403/week @ 2024-05-25 497/week @ 2024-06-01 537/week @ 2024-06-08 790/week @ 2024-06-15 687/week @ 2024-06-22 1515/week @ 2024-06-29 645/week @ 2024-07-06 1224/week @ 2024-07-13 1391/week @ 2024-07-20 300/week @ 2024-07-27 551/week @ 2024-08-03 331/week @ 2024-08-10

2,678 每月下载量
12 个crate中使用 (10个直接使用)

自定义许可证

295KB
5.5K SLoC

CryptoCore

Build status Build status latest version

该crate实现了在许多其他Cosmian产品中使用的加密原语(现代加密和签名方案),如Cloudproof库和KMS。

它主要是RustCrypto库的薄层,尽可能暴露更简单、更一致的Traits,例如lib

  • 隐藏了所有令人困惑的 GenericArray 类型,并仅使用 [u8; N] 数组,
  • 提供了曲线私钥的单个表示形式,
  • 确保在使用后始终从内存中擦除秘密,
  • 添加了使用示例,
  • 添加了与 libsodium 兼容性的测试,
  • 等等。

该crate可能在将来消失,因为RustCrypto库在发展。

使用

要使用Cosmian CryptoCore,请使用Cargo添加依赖项

cargo add cosmian_crypto_core

示例用法

本文件提供了最常见的用例示例。所有示例均可在示例目录中找到。

构建

要安装和构建Cosmian CryptoCore,请克隆仓库

git clone https://github.com/Cosmian/crypto_core.git

使用Cargo构建它

cargo build --release

进一步提高性能

使用以下标志(SIMD指令)运行夜间后端将提高Ristretto后端约33%的性能,AES GCM约25%,ED25519后端约15%

  RUSTFLAGS='--cfg curve25519_dalek_backend="simd" -C target_cpu=native'

运行测试和基准

使用以下命令运行测试

cargo test --release

使用以下命令运行基准测试

cargo bench

对称密钥加密

此crate提供了标准化的认证加密方案:AES-GCM - 128位和256位密钥 - Chacha20 Poly1305,以及XChacha Poly1305。所有这些原语都可用三种模式:向量组合、向量分离和流式传输。

在组合和分离模式中,AES 256 GCM、Chacha20-Poly1305和XChachaPoly1305与IETF等效的libsodium兼容。有关libsodium实现的详细信息,请参阅此文档

AES版本在可用时使用AES-NI指令,这在大多数现代处理器上都是如此。所有这些原语都很快,在2.6GHz Intel Core i7上,平均2.5µs内对字节数组进行加密和认证。

组合模式下字节数组的对称密钥加密

在组合模式中,原语将明文作为一个字节数组向量加密,并为包含加密数据和MAC的密文分配一个新向量。

  use cosmian_crypto_core::XChaCha20Poly1305;
  use cosmian_crypto_core::{
      reexport::rand_core::SeedableRng, CsRng, Dem, FixedSizeCBytes, Instantiable, Nonce,
      RandomFixedSizeCBytes, SymmetricKey,
  };

  // Choose one of these DEMs depending on your use case
  // type SC = Aes128Gcm;
  // type SC = Aes256Gcm;
  // type SC = ChaCha20Poly1305;
  type SC = XChaCha20Poly1305;

  // A cryptographically secure random generator
  let mut rng = CsRng::from_entropy();

  // the message to encrypt
  let message = b"my secret message";
  // the secret key used to encrypt the message
  // which is shared between the sender and the recipient
  let secret_key = SymmetricKey::new(&mut rng);

  // the additional data shared between the sender and the recipient to authenticate the message
  let additional_data = Some(b"additional data".as_slice());

  // the sender generate a Nonce and encrypts the message
  let nonce = Nonce::new(&mut rng);
  let dem = SC::new(&secret_key);
  let ciphertext = dem.encrypt(&nonce, message, additional_data).unwrap();

  // to transmit the message, the sender can concatenate the nonce and the ciphertext
  // and send the concatenated result to the recipient
  let ciphertext = [nonce.as_bytes(), ciphertext.as_slice()].concat();

  // the ciphertext size is the message size plus the nonce size plus the authentication tag size
  assert_eq!(
      ciphertext.len(),
      message.len() + SC::NONCE_LENGTH + SC::MAC_LENGTH
  );

  // the recipient extracts the nonce and decrypts the message
  let nonce = Nonce::try_from_slice(&ciphertext[..SC::NONCE_LENGTH]).unwrap();
  let dem = SC::new(&secret_key);
  let plaintext = dem
      .decrypt(&nonce, &ciphertext[SC::NONCE_LENGTH..], additional_data)
      .unwrap();

  // assert the decrypted message is identical to the original plaintext
  assert_eq!(plaintext, message, "Decryption failed");

分离模式下字节数组的对称密钥加密

在组合模式中,原语将明文作为一个可变字节数组向量就地加密;它返回加密调用上的MAC标签。

use cosmian_crypto_core::DemInPlace;
use cosmian_crypto_core::{
    reexport::rand_core::SeedableRng, CsRng, FixedSizeCBytes, Instantiable, Nonce,
    RandomFixedSizeCBytes, SymmetricKey, XChaCha20Poly1305,
};

// Choose one of these DEMs depending on your use case
// type SC = Aes128Gcm;
// type SC = Aes256Gcm;
// type SC = ChaCha20Poly1305;
type SC = XChaCha20Poly1305;

// A cryptographically secure random generator
let mut rng = CsRng::from_entropy();

// the message to encrypt
let message = b"my secret message";
// the secret key used to encrypt the message
// which is shared between the sender and the recipient
let secret_key = SymmetricKey::new(&mut rng);

// the additional data shared between the sender and the recipient to authenticate the message
let additional_data = Some(b"additional data".as_slice());

// the sender generate a Nonce and encrypts the message in place
// the encryption method returns the tag/MAC
let mut bytes = message.to_vec();
let nonce = Nonce::new(&mut rng);
let dem = SC::new(&secret_key);
let tag = dem
    .encrypt_in_place_detached(&nonce, &mut bytes, additional_data)
    .unwrap();

// to transmit the message, the sender can concatenate the nonce, the encrypted data and the MAC
// then send the concatenated result to the recipient
let ciphertext = [nonce.as_bytes(), bytes.as_slice(), tag.as_slice()].concat();

// the ciphertext size is the message size plus the nonce size plus the authentication tag size
assert_eq!(
    ciphertext.len(),
    message.len() + SC::NONCE_LENGTH + SC::MAC_LENGTH
);

// the recipient extracts the nonce, message and the tag/MAC then decrypt the message in place
let nonce = Nonce::try_from_slice(&ciphertext[..SC::NONCE_LENGTH]).unwrap();
let mut bytes = ciphertext[SC::NONCE_LENGTH..ciphertext.len() - SC::MAC_LENGTH].to_vec();
let tag = ciphertext[ciphertext.len() - SC::MAC_LENGTH..].to_vec();

let dem = SC::new(&secret_key);
dem.decrypt_in_place_detached(&nonce, &mut bytes, &tag, additional_data)
    .unwrap();

// assert the decrypted message is identical to the original plaintext
assert_eq!(bytes.as_slice(), message, "Decryption failed");

字节数流的对称密钥加密

库公开了在RustCrypto AEAD crate中提供的2个流式DEMS,这些DEMS基于论文在线认证加密及其密文重用误用抵抗中描述的认证加密构造。

use cosmian_crypto_core::XChaCha20Poly1305;
use cosmian_crypto_core::{
    reexport::{aead::Payload, rand_core::SeedableRng},
    CsRng, DemStream, Instantiable, Nonce, RandomFixedSizeCBytes, SymmetricKey,
};

// Choose one of these streaming DEMs depending on your use case
// type SC = Aes128Gcm;
// type SC = Aes256Gcm;
// type SC = ChaCha20Poly1305;
type SC = XChaCha20Poly1305;

let message = b"Hello, World!";

// The message will be encrypted in 2 chunks, one of size 8 and one of size 5
// In real life, the block size should be much larger and typically a multiple of 4096
const BLOCK_SIZE: usize = 8;

// use some additional data to authenticate the message
let aad = b"the aad";

// generate a random key and nonce
let mut rng = CsRng::from_entropy();
let secret_key = SymmetricKey::new(&mut rng);
let nonce = Nonce::new(&mut rng);

// Instantiate a streaming encryptor
// Two streaming encryptor are available: EncryptorBE32 and EncryptorLE31
// Check the documentation of the DemStream trait for more details
let mut encryptor = SC::new(&secret_key).into_stream_encryptor_be32(&nonce);

// Encrypt the first chunk
// Encryption of all chunks except the last should use `encrypt_next`
let mut ciphertext = encryptor
    .encrypt_next(Payload {
        msg: &message[..BLOCK_SIZE],
        aad,
    })
    .unwrap();

// Encrypt the second and last chunk using `encrypt_last`
ciphertext.extend_from_slice(
    &encryptor
        .encrypt_last(Payload {
            msg: &message[BLOCK_SIZE..],
            aad,
        })
        .unwrap(),
);

// decryption

// Instantiate a streaming decryptor
let mut decryptor = SC::new(&secret_key).into_stream_decryptor_be32(&nonce);

// Decrypt the first chunk which is BLOCK_SIZE + MAC_LENGTH bytes long
// Decryption of all chunks except the last should use `decrypt_next`
let mut plaintext = decryptor
    .decrypt_next(Payload {
        msg: &ciphertext[..BLOCK_SIZE + SC::MAC_LENGTH],
        aad,
    })
    .unwrap();

// decrypt the second and last chunk
plaintext.extend_from_slice(
    &decryptor
        .decrypt_last(Payload {
            msg: &ciphertext[BLOCK_SIZE + SC::MAC_LENGTH..],
            aad,
        })
        .unwrap(),
);

assert_eq!(
    message.as_slice(),
    plaintext.as_slice(),
    "Decryption failed"
);

ECIES - 椭圆曲线集成加密方案

库公开了8个ECIES方案

Curve 25519

这些使用Dalek实现的25519曲线。

  • EciesSalsaSealBox:使用X25519 KEM和Salsa20 Poly1305 DEM。此方案与libsodium密封盒兼容,但不在DEM认证中提供对附加数据的支持。
  • EciesX25519XChaCha20:使用X25519 KEM和XChaCha20 Poly1305 DEM;它使用HChaCha进行临时对称密钥派生,并使用Blake2b进行nonce生成。如有疑问,此方案为推荐方案。
  • EciesR25519Aes128:其KEM基于25519曲线的Ristretto群,并使用AES 128 GCM作为DEM。临时对称密钥的派生和nonce的生成均使用Shake128执行。
  • EciesX25519Aes128:使用X25519 KEM并使用AES 128 GCM作为DEM。临时对称密钥的派生和nonce的生成均使用Shake128执行。

NIST曲线

ECIES支持NIST的P384、P256、P224和P192曲线,使用其RustCrypto实现。实现使用相应的曲线KEM和AES 128 GCM DEM。临时对称密钥的派生和nonce的生成均使用Shake128执行。

  • EciesP384Aes128
  • EciesP256Aes128
  • EciesP224Aes128
  • EciesP192Aes128

性能

在25519曲线上实现的性能最佳,2.6GHz Intel Core i7上的加密和解密均低于100µs。NIST P256曲线的实现加密和解密速度约为500µs,而P384的实现速度约为2ms。

使用cargo bench运行基准测试,以检查您硬件的性能。

安全性

25519曲线和P256曲线的实现提供128位的经典安全性(无后量子安全性)。

字节数组的ECIES加密

以下示例展示了如何使用ECIES X25519(密钥封装机制)结合XChaCha20 Poly1305(数据加密机制)对字节数组进行加密。同时,它还演示了在DEM认证中使用附加数据的方法。

加密使用公钥进行,解密使用私钥进行。

use cosmian_crypto_core::{
    reexport::rand_core::SeedableRng, CsRng, Ecies, EciesX25519XChaCha20,
    X25519PrivateKey, X25519PublicKey,
};

// A cryptographic random number generator
let mut rng = CsRng::from_entropy();

// Generate a key pair
let private_key = X25519PrivateKey::new(&mut rng);
let public_key = X25519PublicKey::from(&private_key);

// The plain text to encrypt
let plaintext = b"Hello, World!";

// Some optional authenticated data for theDEM scheme
let authenticated_data = b"Optional authenticated data";

// Encrypt the message with the public key using ECIES X25519 XChaCha20
let ciphertext =
    EciesX25519XChaCha20::encrypt(&mut rng, &public_key, plaintext, Some(authenticated_data))
        .unwrap();

// Decrypt the message using the private key
let plaintext_ =
    EciesX25519XChaCha20::decrypt(&private_key, &ciphertext, Some(authenticated_data)).unwrap();

// Check if the decrypted message is the same as the original message
assert_eq!(plaintext, &plaintext_[..]);

字节数流的ECIES加密

以下示例展示了如何使用ECIES X25519(密钥封装机制)结合XChaCha20 Poly1305(数据加密机制)对字节数据流进行加密。

use aead::Payload;
use cosmian_crypto_core::{
    reexport::rand_core::SeedableRng, CsRng, EciesStream, EciesX25519XChaCha20,
    FixedSizeCBytes, RandomFixedSizeCBytes, X25519PrivateKey, X25519PublicKey,
    XChaCha20Poly1305,
};

// generate a random key and nonce
let mut rng = CsRng::from_entropy();

// generate a key pair
let private_key = X25519PrivateKey::new(&mut rng);
let public_key = X25519PublicKey::from(&private_key);

// The plain text to encrypt
let message = b"Hello, World!";

// Some optional authenticated data for theDEM scheme
let authenticated_data = b"Optional authenticated data";

// there will be 2 chunks for the message, one of size 8 and one of size 5
const BLOCK_SIZE: usize = 8;

let (ephemeral_public_key, mut encryptor) =
    EciesX25519XChaCha20::get_dem_encryptor_be32(&mut rng, &public_key).unwrap();

// prepend the ciphertext with the ephemeral public key
let mut ciphertext = ephemeral_public_key.to_bytes().to_vec();

// encrypt the first chunk
ciphertext.extend(
    encryptor
        .encrypt_next(Payload {
            msg: &message[..BLOCK_SIZE],
            aad: authenticated_data,
        })
        .unwrap(),
);

// encrypt the second and last chunk
ciphertext.extend_from_slice(
    &encryptor
        .encrypt_last(Payload {
            msg: &message[BLOCK_SIZE..],
            aad: authenticated_data,
        })
        .unwrap(),
);

// decryption

//recover the ephemeral public key from the ciphertext
let ephemeral_public_key =
    X25519PublicKey::try_from_slice(&ciphertext[..X25519PublicKey::LENGTH]).unwrap();

// Instantiate a decryptor
let mut decryptor =
    EciesX25519XChaCha20::get_dem_decryptor_be32(&private_key, &ephemeral_public_key).unwrap();

// decrypt the first chunk which is BLOCK_SIZE + MAC_LENGTH bytes long
let mut plaintext = decryptor
    .decrypt_next(Payload {
        msg: &ciphertext[X25519PublicKey::LENGTH
            ..X25519PublicKey::LENGTH + BLOCK_SIZE + XChaCha20Poly1305::MAC_LENGTH],
        aad: authenticated_data,
    })
    .unwrap();

// decrypt the second and last chunk
plaintext.extend_from_slice(
    &decryptor
        .decrypt_last(Payload {
            msg: &ciphertext
                [X25519PublicKey::LENGTH + BLOCK_SIZE + XChaCha20Poly1305::MAC_LENGTH..],
            aad: authenticated_data,
        })
        .unwrap(),
);

assert_eq!(
    message.as_slice(),
    plaintext.as_slice(),
    "Decryption failed"
);

密钥封装

支持使用以下方式实现密钥封装和解封装:

  • 基于RFC 5649的对称密钥封装方案。
  • 使用上述ECIES方案之一生成椭圆曲线密钥对
  • 使用RSA密钥对

RFC 5649

RFC 5649密钥封装方案通过在key_wrapping_rfc_5649.rs中公开的key_wrapKey_unwrap方法实现。这些方法与PKCS#11 CKM_AES_KEY_WRAP_KWP机制兼容(该机制用于混合RSA-AES密钥封装方案,见下文)

示例

let kek =
    b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
let key_to_wrap =
    b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
let wrapped_key = [
    199, 131, 191, 63, 110, 233, 156, 72, 218, 187, 196, 16, 226, 132, 197, 44, 191, 117,
    133, 120, 152, 157, 225, 138, 50, 148, 201, 164, 209, 151, 200, 162, 98, 112, 72, 139,
    28, 233, 128, 22,
];

assert_eq!(
    key_wrap(key_to_wrap, kek).expect("Failed to wrap"),
    wrapped_key
);
assert_eq!(
    key_unwrap(&wrapped_key, kek).expect("Failed to unwrap"),
    key_to_wrap
);

ECIES密钥封装

有关ECIES方案详情,请参阅上文的Ecies

RSA密钥封装

为大小为2048位、3072位和4096位的RSA密钥实现了各种PKCS#11兼容的密钥封装方案。

以下是算法列表及其对应的CKM机制。建议优先使用Aes256Sha256算法。

  • Pkcs1v1_5,遵循PKCS#11 CKM_RSA_PKCS的PKCS #1 v1.5 RSA。可能的明文最大长度为m = k - 11,其中k是RSA模的长度。

  • OaepSha256,遵循PKCS#11 CKM_RSA_PKCS_OAEP的PKCS #1 RSA带有OAEP块格式。使用的哈希函数是SHA256。可能的明文最大长度为m = k - 2*h_len - 2,其中k是RSA模的长度,h_len是可选标签的哈希长度。

  • OaepSha1,遵循PKCS#11 CKM_RSA_PKCS_OAEP的PKCS #1 RSA带有OAEP块格式。使用的哈希函数是SHA1。因此,此算法不推荐使用,仅保留在此以保持与旧系统的兼容性。可能的明文最大长度为m = k - 2*h_len - 2,其中k是RSA模的长度,h_len是可选标签的哈希长度。此算法与Google Cloud KMS兼容

    • RSA_OAEP_3072_SHA256,使用3072位RSA密钥
    • RSA_OAEP_4096_SHA256,使用4096位RSA密钥
  • OaepSha3,遵循PKCS#11 CKM_RSA_PKCS_OAEP的PKCS #1 RSA带有OAEP块格式。使用的哈希函数是SHA3。并且仅保留在此以保持与旧系统的兼容性。可能的明文最大长度为m = k - 2*h_len - 2,其中k是RSA模的长度,h_len是可选标签的哈希长度。

  • Aes256Sha256,使用256位AES密钥进行密钥封装,遵循PKCS#11 CKM_RSA_AES_KEY_WRAP。使用的哈希函数是SHA256。AES封装遵循RFC 5649,与PKCS#11 CKM_AES_KEY_WRAP_KWP兼容,没有对明文大小的限制(除了AES的限制);EC私钥的推荐明文格式是PKCS#8。此算法与Google Cloud KMS兼容

    • RSA_OAEP_3072_SHA256_AES_256,使用3072位RSA密钥
    • RSA_OAEP_4096_SHA256_AES_256,使用4096位RSA密钥
  • Aes256Sha1,使用256位AES密钥进行密钥封装,遵循PKCS#11 CKM_RSA_AES_KEY_WRAP。使用的哈希函数是SHA1。因此,此算法不推荐使用,仅保留在此以保持与旧系统的兼容性。AES封装遵循RFC 5649,与PKCS#11 CKM_AES_KEY_WRAP_KWP兼容,没有对明文大小的限制;EC私钥的推荐明文格式是PKCS#8。此算法与Google Cloud KMS兼容

    • RSA_OAEP_3072_SHA1_AES_256,使用3072位RSA密钥
    • RSA_OAEP_4096_SHA1_AES_256,使用4096位RSA密钥
  • Aes256Sha3,使用256位AES密钥进行密钥封装,遵循PKCS#11 CKM_RSA_AES_KEY_WRAP。使用的哈希函数是SHA3-256(定义在FIPS 202中)。AES封装遵循RFC 5649,与PKCS#11 CKM_AES_KEY_WRAP_KWP兼容,因为没有对明文大小的限制;EC私钥的推荐明文格式为PKCS#8。

使用CKM_RSA_AES_KEY_WRAP与SHA-256和AES 256的示例

use cosmian_crypto_core::{
    reexport::rand_core::{RngCore, SeedableRng},
    CsRng, RsaKeyLength, RsaKeyWrappingAlgorithm, RsaPrivateKey,
};
use zeroize::Zeroizing;

let mut rng = CsRng::from_entropy();
println!("... Generating a 3072 bit RSA key ...");
let rsa_private_key = RsaPrivateKey::new(&mut rng, RsaKeyLength::Modulus3072).unwrap();

let mut key_to_wrap = [0_u8; 32];
rng.fill_bytes(&mut key_to_wrap);

let mut key_to_wrap = [0_u8; 189];
rng.fill_bytes(&mut key_to_wrap);
let key_to_wrap = Zeroizing::from(key_to_wrap.to_vec());

let rsa_public_key = rsa_private_key.public_key();

print!("Key wrapping with PKCS#11 CKM_RSA_AES_KEY_WRAP SHA-256 AES 256 ...");
let wrapped_key = rsa_public_key
    .wrap_key(
        &mut rng,
        RsaKeyWrappingAlgorithm::Aes256Sha256,
        &key_to_wrap,
    )
    .unwrap();

print!("unwrapping ...: ");
let unwrapped_key = rsa_private_key
    .unwrap_key(RsaKeyWrappingAlgorithm::Aes256Sha256, &wrapped_key)
    .unwrap();

assert_eq!(unwrapped_key, key_to_wrap);
println!("OK");

签名

当前该库公开了EdDSA(Ed25519)签名方案。很快将公开更多签名方案。

静态实现

使用静态签名实现,在2.6 GHz Intel Core i7上签名和验证大约需要50µs。

use cosmian_crypto_core::{
    reexport::{
        rand_core::SeedableRng,
        signature::{Signer, Verifier},
    },
    CsRng, Ed25519PrivateKey, Ed25519PublicKey, RandomFixedSizeCBytes,
};

// instantiate a random number generator
let mut rng = CsRng::from_entropy();

// the message to sign
let message = b"Hello, world!";

// sign the message with the private key
let private_key = Ed25519PrivateKey::new(&mut rng);
let signature = private_key.try_sign(message).unwrap();

// verify the signature with the public key
let public_key = Ed25519PublicKey::from(&private_key);
public_key.verify(message, &signature).unwrap();

缓存实现

使用缓存签名实现,签名大约需要25µs,验证在2.6 GHz Intel Core i7上仍然大约需要50µs。

use cosmian_crypto_core::{
    reexport::{
        rand_core::SeedableRng,
        signature::{Signer, Verifier},
    },
    Cached25519Signer, CsRng, Ed25519PrivateKey, Ed25519PublicKey, RandomFixedSizeCBytes,
};

// instantiate a random number generator
let mut rng = CsRng::from_entropy();

// instantiate the cached signer
let private_key = Ed25519PrivateKey::new(&mut rng);
let cached_signer = Cached25519Signer::try_from(&private_key).unwrap();

// verify the signatures
let public_key = Ed25519PublicKey::from(&private_key);

let message = b"Hello, world!";
let signature = cached_signer.try_sign(message).unwrap();
public_key.verify(message, &signature).unwrap();

let message = b"I'm sorry, Dave. I'm afraid I can't do that.";
let signature = cached_signer.try_sign(message).unwrap();
public_key.verify(message, &signature).unwrap();

使用密钥对

签名API还公开了与RustCrypto实现兼容的Keypair

use cosmian_crypto_core::{
    reexport::{
        rand_core::SeedableRng,
        signature::{Signer, Verifier},
    },
    CsRng, Ed25519Keypair, FixedSizeCBytes,
};
let mut rng = CsRng::from_entropy();
let message = b"Hello, world!";

// generate a keypair
let keypair = Ed25519Keypair::new(&mut rng);

// serialize the keypair
let serialized_keypair = keypair.to_bytes();

// deserialize the keypair
let keypair = Ed25519Keypair::try_from_bytes(serialized_keypair).unwrap();

//assert equality
assert_eq!(keypair.to_bytes(), serialized_keypair);

// sign the message using the keypair
let signature = keypair.try_sign(message).unwrap();

// verify the signature
keypair.verify(message, &signature).unwrap();

加密安全随机数生成器 (CS-RNG)

该库公开了一个加密安全的随机数生成器(CS-RNG),它使用来自rand_chacha的CHACHA算法12轮实现。它是128位安全的。

性能:每次实例化1.7µs。下一个伪随机数以纳秒为单位生成。

use cosmian_crypto_core::CsRng;
let mut rng = CsRng::from_entropy();

密钥派生函数 (KDF)

该库使用来自sha3crate的SHAKE算法的纯Rust实现。有两种实现可供选择

  • kdf128,在经典设置中128位安全,适用于至少256位(32字节)的输入大小。
  • kdf256,在经典设置中256位安全,适用于至少512位(64字节)的输入大小。

这两种算法在2.7GHz Intel Core i7上的运行时间少于500ns。

#[macro_use]
use cosmian_crypto_core::kdf256;

const KEY_LENGTH: usize = 32;

const ikm: &str = "asdf34@!dsa@grq5e$2ASGy5";

// derive a 32-bytes key
let key = kdf256!(KEY_LENGTH, ikm.as_bytes());

assert_eq!(KEY_LENGTH, key.len());

Blake2散列

该库公开了两个版本的Blake2,这是在RFC 7693中指定的

  • blake2s:针对8到32位平台进行优化,可以生成1到32字节(256位)大小的摘要
  • blake2b:针对64位平台进行优化,可以生成1到64字节(512位)大小的摘要

Blake2的运行时间少于200ns,这比大多数硬件上的Sha3和Shake快约3倍,但在用作生成可变长度哈希时可能会失败,特别是当输入长度太短时。

#[macro_use]
use cosmian_crypto_core::{blakebs, CryptoCoreError};

const LENGTH: usize = 12;

let msg1 = b"asdf34@!dsa@grq5e$2ASGy5";
let msg2 = b"oiu54%6uhg1@34";
let res = blake2b!(LENGTH, msg1, msg2).unwrap();

assert_eq!(LENGTH, res.len());

代码文档

可以使用Cargo生成文档

cargo docs

它也可在doc.rs上找到。

依赖关系

~4.5–8MB
~137K SLoC