feat: v1.6.0, support kyber1024
This commit is contained in:
@@ -25,8 +25,9 @@ use crate::compress::GzStreamDecoder;
|
||||
use crate::config::TinyEncryptConfig;
|
||||
use crate::consts::{
|
||||
DATE_TIME_FORMAT,
|
||||
ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519,
|
||||
ENC_CHACHA20_POLY1305_P256, ENC_CHACHA20_POLY1305_P384, ENC_CHACHA20_POLY1305_X25519,
|
||||
ENC_AES256_GCM_KYBER1204, ENC_AES256_GCM_P256, ENC_AES256_GCM_P384,
|
||||
ENC_AES256_GCM_X25519, ENC_CHACHA20_POLY1305_KYBER1204, ENC_CHACHA20_POLY1305_P256,
|
||||
ENC_CHACHA20_POLY1305_P384, ENC_CHACHA20_POLY1305_X25519,
|
||||
SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
|
||||
};
|
||||
use crate::crypto_cryptor::{Cryptor, KeyNonce};
|
||||
@@ -451,6 +452,8 @@ pub fn try_decrypt_key(config: &Option<TinyEncryptConfig>,
|
||||
#[cfg(feature = "secure-enclave")]
|
||||
TinyEncryptEnvelopType::KeyP256 => try_decrypt_se_key_ecdh(config, envelop),
|
||||
TinyEncryptEnvelopType::PivRsa => try_decrypt_piv_key_rsa(config, envelop, pin, slot),
|
||||
#[cfg(feature = "macos")]
|
||||
TinyEncryptEnvelopType::StaticKyber1024 => try_decrypt_key_ecdh_static_kyber1204(config, envelop),
|
||||
unknown_type => simple_error!("Unknown or unsupported type: {}", unknown_type.get_name()),
|
||||
}
|
||||
}
|
||||
@@ -619,7 +622,42 @@ fn try_decrypt_key_ecdh_static_x25519(config: &Option<TinyEncryptConfig>, envelo
|
||||
};
|
||||
|
||||
let shared_secret = opt_result!(
|
||||
util_keychainstatic::decrypt_data(&keychain_key, &e_pub_key_bytes), "Decrypt static x25519 failed: {}");
|
||||
util_keychainstatic::decrypt_x25519_data(&keychain_key, &e_pub_key_bytes), "Decrypt static x25519 failed: {}");
|
||||
|
||||
let key = util::simple_kdf(shared_secret.as_slice());
|
||||
let key_nonce = KeyNonce { k: &key, n: &wrap_key.nonce };
|
||||
let decrypted_key = crypto_simple::decrypt(
|
||||
cryptor, &key_nonce, &wrap_key.encrypted_data)?;
|
||||
util::zeroize(key);
|
||||
util::zeroize(shared_secret);
|
||||
Ok(decrypted_key)
|
||||
}
|
||||
|
||||
#[cfg(feature = "macos")]
|
||||
fn try_decrypt_key_ecdh_static_kyber1204(config: &Option<TinyEncryptConfig>, envelop: &TinyEncryptEnvelop) -> XResult<Vec<u8>> {
|
||||
let wrap_key = WrapKey::parse(&envelop.encrypted_key)?;
|
||||
let cryptor = match wrap_key.header.enc.as_str() {
|
||||
ENC_AES256_GCM_KYBER1204 => Cryptor::Aes256Gcm,
|
||||
ENC_CHACHA20_POLY1305_KYBER1204 => Cryptor::ChaCha20Poly1305,
|
||||
_ => return simple_error!("Unsupported header enc: {}", &wrap_key.header.enc),
|
||||
};
|
||||
let e_pub_key_bytes = wrap_key.header.get_e_pub_key_bytes()?;
|
||||
let config = opt_value_result!(config, "Tiny encrypt config is not found");
|
||||
let config_envelop = opt_value_result!(
|
||||
config.find_by_kid(&envelop.kid), "Cannot find config for: {}", &envelop.kid);
|
||||
let config_envelop_args = opt_value_result!(&config_envelop.args, "No arguments found for: {}", &envelop.kid);
|
||||
if config_envelop_args.len() != 1 && config_envelop_args.len() != 3 {
|
||||
return simple_error!("Not enough arguments for: {}", &envelop.kid);
|
||||
}
|
||||
|
||||
let keychain_key = if config_envelop_args.len() == 1 {
|
||||
KeychainKey::parse(&config_envelop_args[0])?
|
||||
} else {
|
||||
KeychainKey::from(&config_envelop_args[0], &config_envelop_args[1], &config_envelop_args[2])
|
||||
};
|
||||
|
||||
let shared_secret = opt_result!(
|
||||
util_keychainstatic::decrypt_kyber1204_data(&keychain_key, &e_pub_key_bytes), "Decrypt static kyber1204 failed: {}");
|
||||
|
||||
let key = util::simple_kdf(shared_secret.as_slice());
|
||||
let key_nonce = KeyNonce { k: &key, n: &wrap_key.nonce };
|
||||
|
||||
@@ -13,18 +13,14 @@ use rust_util::util_time::UnixEpochTime;
|
||||
use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_env};
|
||||
use crate::compress::GzStreamEncoder;
|
||||
use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop};
|
||||
use crate::consts::{
|
||||
ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519,
|
||||
ENC_CHACHA20_POLY1305_P256, ENC_CHACHA20_POLY1305_P384, ENC_CHACHA20_POLY1305_X25519,
|
||||
SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
|
||||
};
|
||||
use crate::consts::{ENC_AES256_GCM_KYBER1204, ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519, ENC_CHACHA20_POLY1305_KYBER1204, ENC_CHACHA20_POLY1305_P256, ENC_CHACHA20_POLY1305_P384, ENC_CHACHA20_POLY1305_X25519, SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT};
|
||||
use crate::crypto_cryptor::{Cryptor, KeyNonce};
|
||||
use crate::crypto_rsa;
|
||||
use crate::spec::{
|
||||
EncEncryptedMeta, EncMetadata,
|
||||
TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta,
|
||||
};
|
||||
use crate::util_ecdh::{ecdh_p256, ecdh_p384, ecdh_x25519};
|
||||
use crate::util_ecdh::{ecdh_kyber1024, ecdh_p256, ecdh_p384, ecdh_x25519};
|
||||
use crate::util_progress::Progress;
|
||||
use crate::wrap_key::{WrapKey, WrapKeyHeader};
|
||||
|
||||
@@ -279,6 +275,9 @@ fn encrypt_envelops(cryptor: Cryptor, key: &[u8], envelops: &[&TinyEncryptConfig
|
||||
TinyEncryptEnvelopType::PivP384 => {
|
||||
encrypted_envelops.push(encrypt_envelop_ecdh_p384(cryptor, key, envelop)?);
|
||||
}
|
||||
TinyEncryptEnvelopType::StaticKyber1024 => {
|
||||
encrypted_envelops.push(encrypt_envelop_ecdh_kyber1204(cryptor, key, envelop)?);
|
||||
}
|
||||
_ => return simple_error!("Not supported type: {:?}", envelop.r#type),
|
||||
}
|
||||
}
|
||||
@@ -315,6 +314,16 @@ fn encrypt_envelop_ecdh_x25519(cryptor: Cryptor, key: &[u8], envelop: &TinyEncry
|
||||
encrypt_envelop_shared_secret(cryptor, key, &shared_secret, &ephemeral_spki, enc_type, envelop)
|
||||
}
|
||||
|
||||
fn encrypt_envelop_ecdh_kyber1204(cryptor: Cryptor, key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
|
||||
let public_key_point_hex = &envelop.public_part;
|
||||
let (shared_secret, ephemeral_spki) = ecdh_kyber1024::compute_kyber1024_shared_secret(public_key_point_hex)?;
|
||||
let enc_type = match cryptor {
|
||||
Cryptor::Aes256Gcm => ENC_AES256_GCM_KYBER1204,
|
||||
Cryptor::ChaCha20Poly1305 => ENC_CHACHA20_POLY1305_KYBER1204,
|
||||
};
|
||||
encrypt_envelop_shared_secret(cryptor, key, &shared_secret, &ephemeral_spki, enc_type, envelop)
|
||||
}
|
||||
|
||||
fn encrypt_envelop_shared_secret(cryptor: Cryptor,
|
||||
key: &[u8],
|
||||
shared_secret: &[u8],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use clap::Args;
|
||||
use pqcrypto_traits::kem::PublicKey;
|
||||
use rust_util::{debugging, information, opt_result, simple_error, success, warning, XResult};
|
||||
|
||||
use crate::config::TinyEncryptConfigEnvelop;
|
||||
@@ -6,25 +7,33 @@ use crate::spec::TinyEncryptEnvelopType;
|
||||
#[cfg(feature = "secure-enclave")]
|
||||
use crate::util_keychainkey;
|
||||
use crate::util_keychainstatic;
|
||||
use crate::util_keychainstatic::{KeychainKey, X25519StaticSecret};
|
||||
use crate::util_keychainstatic::{KeychainKey, KeychainStaticSecret, KeychainStaticSecretAlgorithm};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct CmdInitKeychain {
|
||||
/// Secure Enclave
|
||||
#[arg(long, short = 'S')]
|
||||
pub secure_enclave: bool,
|
||||
|
||||
/// Expose secure enclave private key data
|
||||
#[arg(long, short = 'E')]
|
||||
pub expose_secure_enclave_private_key: bool,
|
||||
|
||||
// /// Keychain name, or default
|
||||
// #[arg(long, short = 'c')]
|
||||
// pub keychain_name: Option<String>,
|
||||
|
||||
/// Service name, or default: tiny-encrypt
|
||||
#[arg(long, short = 's')]
|
||||
pub server_name: Option<String>,
|
||||
|
||||
/// Key name
|
||||
#[arg(long, short = 'n')]
|
||||
pub key_name: String,
|
||||
|
||||
/// Algorithm (x25519, or kyber1024, default x25519)
|
||||
#[arg(long, short = 'a')]
|
||||
pub algorithm: Option<String>,
|
||||
}
|
||||
|
||||
const DEFAULT_SERVICE_NAME: &str = "tiny-encrypt";
|
||||
@@ -79,31 +88,77 @@ pub fn keychain_key_static(cmd_init_keychain: CmdInitKeychain) -> XResult<()> {
|
||||
let key_name = &cmd_init_keychain.key_name;
|
||||
let keychain_key = KeychainKey::from_default_keychain(service_name, key_name);
|
||||
|
||||
let public_key = match keychain_key.get_password()? {
|
||||
Some(static_x25519) => {
|
||||
warning!("Key already exists: {}.{}", service_name, key_name);
|
||||
let x25519_static_secret = X25519StaticSecret::parse_bytes(static_x25519.as_ref())?;
|
||||
x25519_static_secret.to_public_key()?
|
||||
}
|
||||
None => {
|
||||
let (keychain_key_bytes, public_key) = util_keychainstatic::generate_static_x25519_secret();
|
||||
debugging!("Keychain key : {}", keychain_key_bytes);
|
||||
opt_result!(
|
||||
keychain_key.set_password(keychain_key_bytes.as_bytes()),
|
||||
"Write static x25519 failed: {}"
|
||||
);
|
||||
public_key
|
||||
let mut envelop_type = match &cmd_init_keychain.algorithm {
|
||||
None => TinyEncryptEnvelopType::StaticX25519,
|
||||
Some(algorithm) => {
|
||||
let a_lower = algorithm.to_lowercase();
|
||||
if &a_lower == "kyber" || &a_lower == "kyber1024" {
|
||||
TinyEncryptEnvelopType::StaticKyber1024
|
||||
} else if &a_lower == "25519" || &a_lower == "x25519" || &a_lower == "cv25519" || &a_lower == "curve25519" {
|
||||
TinyEncryptEnvelopType::StaticX25519
|
||||
} else {
|
||||
return simple_error!("Unknown algorithm: {}", algorithm);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let public_key_hex = match keychain_key.get_password()? {
|
||||
Some(static_key) => {
|
||||
warning!("Key already exists: {}.{}", service_name, key_name);
|
||||
let keychain_static_secret = KeychainStaticSecret::parse_bytes(static_key.as_ref())?;
|
||||
match keychain_static_secret.algo {
|
||||
KeychainStaticSecretAlgorithm::X25519 => {
|
||||
envelop_type = TinyEncryptEnvelopType::StaticX25519;
|
||||
}
|
||||
KeychainStaticSecretAlgorithm::Kyber1024 => {
|
||||
envelop_type = TinyEncryptEnvelopType::StaticKyber1024;
|
||||
}
|
||||
}
|
||||
match keychain_static_secret.algo {
|
||||
KeychainStaticSecretAlgorithm::X25519 => {
|
||||
let public_key = keychain_static_secret.to_x25519_public_key()?;
|
||||
hex::encode(public_key.as_bytes())
|
||||
}
|
||||
KeychainStaticSecretAlgorithm::Kyber1024 => {
|
||||
let (_, public_key) = keychain_static_secret.to_kyber1204_static_secret()?;
|
||||
hex::encode(public_key.as_bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let (keychain_key_bytes, public_key_hex) = match envelop_type {
|
||||
TinyEncryptEnvelopType::StaticX25519 => {
|
||||
let (keychain_key_bytes, public_key) = util_keychainstatic::generate_static_x25519_secret();
|
||||
(keychain_key_bytes, hex::encode(public_key.as_bytes()))
|
||||
}
|
||||
TinyEncryptEnvelopType::StaticKyber1024 => {
|
||||
let (keychain_key_bytes, public_key) = util_keychainstatic::generate_static_kyber1024_secret();
|
||||
(keychain_key_bytes, hex::encode(public_key.as_bytes()))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
debugging!("Keychain key : {}", keychain_key_bytes);
|
||||
opt_result!(
|
||||
keychain_key.set_password(keychain_key_bytes.as_bytes()),
|
||||
"Write static key failed: {}"
|
||||
);
|
||||
public_key_hex
|
||||
}
|
||||
};
|
||||
|
||||
let public_key_hex = hex::encode(public_key.as_bytes());
|
||||
success!("Keychain name: {}", &key_name);
|
||||
success!("Public key : {}", &public_key_hex);
|
||||
|
||||
let kid_part2 = if public_key_hex.len() <= 64 {
|
||||
public_key_hex.clone()
|
||||
} else {
|
||||
public_key_hex.chars().take(64).collect()
|
||||
};
|
||||
|
||||
let config_envelop = TinyEncryptConfigEnvelop {
|
||||
r#type: TinyEncryptEnvelopType::StaticX25519,
|
||||
r#type: envelop_type,
|
||||
sid: Some(key_name.clone()),
|
||||
kid: format!("keychain:{}", &public_key_hex),
|
||||
kid: format!("keychain:{}", &kid_part2),
|
||||
desc: Some("Keychain static".to_string()),
|
||||
args: Some(vec![keychain_key.to_str()]),
|
||||
public_part: public_key_hex,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::{env, fs};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rust_util::{debugging, opt_result, simple_error, warning, XResult};
|
||||
@@ -100,7 +101,7 @@ impl TinyEncryptConfig {
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn resolve_path_namespace(&self, path: &PathBuf, append_te: bool) -> PathBuf {
|
||||
pub fn resolve_path_namespace(&self, path: &Path, append_te: bool) -> PathBuf {
|
||||
if let Some(path_str) = path.to_str() {
|
||||
if path_str.starts_with(':') {
|
||||
let namespace = path_str.chars().skip(1)
|
||||
@@ -117,7 +118,7 @@ impl TinyEncryptConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
path.clone()
|
||||
path.to_path_buf()
|
||||
}
|
||||
|
||||
pub fn find_namespace(&self, prefix: &str) -> Option<&String> {
|
||||
@@ -208,9 +209,9 @@ impl TinyEncryptConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_path_namespace(config: &Option<TinyEncryptConfig>, path: &PathBuf, append_te: bool) -> PathBuf {
|
||||
pub fn resolve_path_namespace(config: &Option<TinyEncryptConfig>, path: &Path, append_te: bool) -> PathBuf {
|
||||
match config {
|
||||
None => path.clone(),
|
||||
None => path.to_path_buf(),
|
||||
Some(config) => config.resolve_path_namespace(path, append_te),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
pub const ENC_AES256_GCM_P256: &str = "aes256-gcm-p256";
|
||||
pub const ENC_AES256_GCM_P384: &str = "aes256-gcm-p384";
|
||||
pub const ENC_AES256_GCM_X25519: &str = "aes256-gcm-x25519";
|
||||
pub const ENC_AES256_GCM_KYBER1204: &str = "aes256-gcm-kyber1204";
|
||||
pub const ENC_CHACHA20_POLY1305_P256: &str = "chacha20-poly1305-p256";
|
||||
pub const ENC_CHACHA20_POLY1305_P384: &str = "chacha20-poly1305-p384";
|
||||
pub const ENC_CHACHA20_POLY1305_X25519: &str = "chacha20-poly1305-x25519";
|
||||
pub const ENC_CHACHA20_POLY1305_KYBER1204: &str = "chacha20-poly1305-kyber1204";
|
||||
|
||||
// Extend and config file
|
||||
pub const TINY_ENC_FILE_EXT: &str = ".tinyenc";
|
||||
|
||||
@@ -76,6 +76,9 @@ pub enum TinyEncryptEnvelopType {
|
||||
// Keychain Static X25519 (less secure)
|
||||
#[serde(rename = "static-x25519")]
|
||||
StaticX25519,
|
||||
// Keychain Static Kyber1024 (less secure)
|
||||
#[serde(rename = "static-kyber1024")]
|
||||
StaticKyber1024,
|
||||
// Secure Enclave ECDH P256
|
||||
#[serde(rename = "key-p256")]
|
||||
KeyP256,
|
||||
@@ -106,6 +109,7 @@ impl TinyEncryptEnvelopType {
|
||||
TinyEncryptEnvelopType::PgpRsa => "pgp-rsa",
|
||||
TinyEncryptEnvelopType::PgpX25519 => "pgp-x25519",
|
||||
TinyEncryptEnvelopType::StaticX25519 => "static-x25519",
|
||||
TinyEncryptEnvelopType::StaticKyber1024 => "static-kyber1024",
|
||||
TinyEncryptEnvelopType::KeyP256 => "key-p256",
|
||||
TinyEncryptEnvelopType::Age => "age",
|
||||
TinyEncryptEnvelopType::PivP256 => "piv-p256",
|
||||
@@ -120,6 +124,7 @@ impl TinyEncryptEnvelopType {
|
||||
TinyEncryptEnvelopType::PgpRsa => false,
|
||||
TinyEncryptEnvelopType::PgpX25519 => false,
|
||||
TinyEncryptEnvelopType::StaticX25519 => true,
|
||||
TinyEncryptEnvelopType::StaticKyber1024 => true,
|
||||
TinyEncryptEnvelopType::KeyP256 => true,
|
||||
TinyEncryptEnvelopType::Age => false,
|
||||
TinyEncryptEnvelopType::PivP256 => false,
|
||||
|
||||
@@ -61,3 +61,18 @@ pub mod ecdh_x25519 {
|
||||
Ok((shared_secret.as_bytes().to_vec(), ephemeral_public.as_bytes().to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ecdh_kyber1024 {
|
||||
use pqcrypto_kyber::kyber1024;
|
||||
use pqcrypto_kyber::kyber1024::PublicKey as Kyber1024PublicKey;
|
||||
use pqcrypto_traits::kem::{Ciphertext, PublicKey, SharedSecret};
|
||||
use rust_util::{opt_result, XResult};
|
||||
|
||||
pub fn compute_kyber1024_shared_secret(public_key_point_hex: &str) -> XResult<(Vec<u8>, Vec<u8>)> {
|
||||
let public_key_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse Kyber1024 public key hex failed: {}");
|
||||
let public_key = opt_result!(Kyber1024PublicKey::from_bytes(&public_key_bytes), "Parse Kyber1024 public key failed: {}");
|
||||
let (shared_secret, ciphertext) = kyber1024::encapsulate(&public_key);
|
||||
|
||||
Ok((shared_secret.as_bytes().to_vec(), ciphertext.as_bytes().to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
use pqcrypto_kyber::kyber1024;
|
||||
use pqcrypto_kyber::kyber1024::Ciphertext as Kyber1024Ciphertext;
|
||||
use pqcrypto_kyber::kyber1024::PublicKey as Kyber1024PublicKey;
|
||||
use pqcrypto_kyber::kyber1024::SecretKey as Kyber1024SecretKey;
|
||||
use rust_util::{debugging, opt_result, opt_value_result, simple_error, XResult};
|
||||
use security_framework::os::macos::keychain::SecKeychain;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
const X2559_PLAIN_PREFIX: &str = "x25519-plain:";
|
||||
const KYBER1024_PLAIN_PREFIX: &str = "kyber1024-plain:";
|
||||
const KEYCHAIN_KEY_PREFIX: &str = "keychain:";
|
||||
|
||||
pub struct KeychainKey {
|
||||
@@ -12,48 +17,112 @@ pub struct KeychainKey {
|
||||
pub key_name: String,
|
||||
}
|
||||
|
||||
|
||||
pub struct X25519StaticSecret {
|
||||
pub secret: Vec<u8>,
|
||||
pub enum KeychainStaticSecretAlgorithm {
|
||||
X25519,
|
||||
Kyber1024,
|
||||
}
|
||||
|
||||
impl Zeroize for X25519StaticSecret {
|
||||
impl KeychainStaticSecretAlgorithm {
|
||||
pub fn prefix(&self) -> &'static str {
|
||||
match self {
|
||||
Self::X25519 => X2559_PLAIN_PREFIX,
|
||||
Self::Kyber1024 => KYBER1024_PLAIN_PREFIX,
|
||||
}
|
||||
}
|
||||
pub fn from_prefix(str: &str) -> Option<Self> {
|
||||
if str.starts_with(X2559_PLAIN_PREFIX) {
|
||||
Some(Self::X25519)
|
||||
} else if str.starts_with(KYBER1024_PLAIN_PREFIX) {
|
||||
Some(Self::Kyber1024)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KeychainStaticSecret {
|
||||
pub algo: KeychainStaticSecretAlgorithm,
|
||||
pub secret: Vec<u8>,
|
||||
pub public: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Zeroize for KeychainStaticSecret {
|
||||
fn zeroize(&mut self) {
|
||||
self.secret.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl X25519StaticSecret {
|
||||
impl KeychainStaticSecret {
|
||||
pub fn parse_bytes(bs: &[u8]) -> XResult<Self> {
|
||||
let key_str = opt_result!(String::from_utf8(bs.to_vec()), "Parse static x25519 failed: {}");
|
||||
let key_str = opt_result!(String::from_utf8(bs.to_vec()), "Parse static secret failed: {}");
|
||||
Self::parse(&key_str)
|
||||
}
|
||||
|
||||
pub fn parse(key: &str) -> XResult<Self> {
|
||||
if !key.starts_with(X2559_PLAIN_PREFIX) {
|
||||
return simple_error!("Not X25519 plain key");
|
||||
}
|
||||
let extract_key_hex = &key[X2559_PLAIN_PREFIX.len()..];
|
||||
let extract_key = opt_result!(hex::decode(extract_key_hex), "Decode X25519 plain key failed: {}");
|
||||
let algo = opt_value_result!(
|
||||
KeychainStaticSecretAlgorithm::from_prefix(key), "Unknown static secret: {}", key);
|
||||
let extract_key_hex = &key[algo.prefix().len()..];
|
||||
let extract_key = opt_result!(hex::decode(extract_key_hex), "Decode static secret plain key failed: {}");
|
||||
let (secret, public) = match algo {
|
||||
KeychainStaticSecretAlgorithm::X25519 => {
|
||||
(extract_key, None)
|
||||
}
|
||||
KeychainStaticSecretAlgorithm::Kyber1024 => {
|
||||
// pub const PQCLEAN_KYBER1024_CLEAN_CRYPTO_SECRETKEYBYTES: usize = 3168;
|
||||
// pub const PQCLEAN_KYBER1024_CLEAN_CRYPTO_PUBLICKEYBYTES: usize = 1568;
|
||||
let secret_key_bytes_len = 3168;
|
||||
let public_key_bytes_len = 1568;
|
||||
if extract_key.len() != secret_key_bytes_len + public_key_bytes_len {
|
||||
return simple_error!("Bad kyber1024 secret and public keys.");
|
||||
}
|
||||
(extract_key[0..secret_key_bytes_len].to_vec(), Some(extract_key[secret_key_bytes_len..].to_vec()))
|
||||
}
|
||||
};
|
||||
Ok(Self {
|
||||
secret: extract_key,
|
||||
algo,
|
||||
secret,
|
||||
public,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_str(&self) -> String {
|
||||
let mut v = String::new();
|
||||
v.push_str(X2559_PLAIN_PREFIX);
|
||||
v.push_str(self.algo.prefix());
|
||||
v.push_str(&hex::encode(&self.secret));
|
||||
if let Some(public) = &self.public {
|
||||
v.push_str(&hex::encode(public));
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Self {
|
||||
pub fn from_x25519_bytes(secret: &[u8]) -> Self {
|
||||
Self::from_bytes(KeychainStaticSecretAlgorithm::X25519, secret, None)
|
||||
}
|
||||
|
||||
pub fn from_kyber1024_bytes(secret: &[u8], public: &[u8]) -> Self {
|
||||
Self::from_bytes(KeychainStaticSecretAlgorithm::Kyber1024, secret, Some(public))
|
||||
}
|
||||
|
||||
pub fn from_bytes(algo: KeychainStaticSecretAlgorithm, secret: &[u8], public: Option<&[u8]>) -> Self {
|
||||
Self {
|
||||
secret: bytes.to_vec(),
|
||||
algo,
|
||||
secret: secret.to_vec(),
|
||||
public: public.map(|p| p.to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_static_secret(&self) -> XResult<StaticSecret> {
|
||||
pub fn to_kyber1204_static_secret(&self) -> XResult<(Kyber1024SecretKey, Kyber1024PublicKey)> {
|
||||
use pqcrypto_traits::kem::{PublicKey, SecretKey};
|
||||
let secret_key = opt_result!(Kyber1024SecretKey::from_bytes(&self.secret),
|
||||
"Parse kyber1204 private key failed: {}");
|
||||
let public_key = opt_result!(match &self.public {
|
||||
None => return simple_error!("Kyber1204 public key not found."),
|
||||
Some(public) => Kyber1024PublicKey::from_bytes(public),
|
||||
}, "Parse kyber1204 public key failed: {}");
|
||||
Ok((secret_key, public_key))
|
||||
}
|
||||
|
||||
pub fn to_x25519_static_secret(&self) -> XResult<StaticSecret> {
|
||||
let secret_slice = self.secret.as_slice();
|
||||
let mut inner_secret: [u8; 32] = opt_result!(secret_slice.try_into(), "X25519 secret key error: {}");
|
||||
let static_secret = StaticSecret::from(inner_secret);
|
||||
@@ -61,8 +130,8 @@ impl X25519StaticSecret {
|
||||
Ok(static_secret)
|
||||
}
|
||||
|
||||
pub fn to_public_key(&self) -> XResult<PublicKey> {
|
||||
let static_secret = self.to_static_secret()?;
|
||||
pub fn to_x25519_public_key(&self) -> XResult<PublicKey> {
|
||||
let static_secret = self.to_x25519_static_secret()?;
|
||||
let public_key: PublicKey = (&static_secret).into();
|
||||
Ok(public_key)
|
||||
}
|
||||
@@ -141,11 +210,11 @@ impl KeychainKey {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt_data(keychain_key: &KeychainKey, ephemeral_public_key_bytes: &[u8]) -> XResult<Vec<u8>> {
|
||||
pub fn decrypt_x25519_data(keychain_key: &KeychainKey, ephemeral_public_key_bytes: &[u8]) -> XResult<Vec<u8>> {
|
||||
let static_x25519 = opt_value_result!(keychain_key.get_password()?, "Static X25519 not found: {}", &keychain_key.to_str());
|
||||
|
||||
let x25519_static_secret = X25519StaticSecret::parse_bytes(&static_x25519)?;
|
||||
let static_secret = x25519_static_secret.to_static_secret()?;
|
||||
let x25519_static_secret = KeychainStaticSecret::parse_bytes(&static_x25519)?;
|
||||
let static_secret = x25519_static_secret.to_x25519_static_secret()?;
|
||||
let inner_ephemeral_public_key: [u8; 32] = opt_result!(
|
||||
ephemeral_public_key_bytes.try_into(), "X25519 public key error: {}");
|
||||
let ephemeral_public_key = PublicKey::from(inner_ephemeral_public_key);
|
||||
@@ -154,10 +223,33 @@ pub fn decrypt_data(keychain_key: &KeychainKey, ephemeral_public_key_bytes: &[u8
|
||||
Ok(shared_secret.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
pub fn decrypt_kyber1204_data(keychain_key: &KeychainKey, ephemeral_public_key_bytes: &[u8]) -> XResult<Vec<u8>> {
|
||||
use pqcrypto_traits::kem::{Ciphertext, SharedSecret};
|
||||
let static_kyber1204 = opt_value_result!(keychain_key.get_password()?, "Static Kyber1204 not found: {}", &keychain_key.to_str());
|
||||
|
||||
let kyber1204_static_secret = KeychainStaticSecret::parse_bytes(&static_kyber1204)?;
|
||||
let (static_secret, _) = kyber1204_static_secret.to_kyber1204_static_secret()?;
|
||||
let ciphertext = opt_result!(
|
||||
Kyber1024Ciphertext::from_bytes(ephemeral_public_key_bytes), "Parse kyber1204 ciphertext failed: {}");
|
||||
let shared_secret = kyber1024::decapsulate(&ciphertext, &static_secret);
|
||||
|
||||
Ok(shared_secret.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
pub fn generate_static_x25519_secret() -> (String, PublicKey) {
|
||||
let static_secret = StaticSecret::random();
|
||||
let public_key: PublicKey = (&static_secret).into();
|
||||
let static_secret_bytes = static_secret.as_bytes();
|
||||
let x25519_static_secret = X25519StaticSecret::from_bytes(static_secret_bytes);
|
||||
let x25519_static_secret = KeychainStaticSecret::from_x25519_bytes(static_secret_bytes);
|
||||
(x25519_static_secret.to_str(), public_key)
|
||||
}
|
||||
|
||||
pub fn generate_static_kyber1024_secret() -> (String, Kyber1024PublicKey) {
|
||||
use pqcrypto_traits::kem::{PublicKey, SecretKey};
|
||||
let (public_key, private_key) = kyber1024::keypair();
|
||||
let static_secret_bytes = private_key.as_bytes();
|
||||
let static_public_bytes = public_key.as_bytes();
|
||||
let kyber1024_static_secret =
|
||||
KeychainStaticSecret::from_kyber1024_bytes(static_secret_bytes, static_public_bytes);
|
||||
(kyber1024_static_secret.to_str(), public_key)
|
||||
}
|
||||
Reference in New Issue
Block a user