fn nss_public_key_from_der_spki(spki: &[u8]) -> Result<PublicKey> { // TODO: replace this with an nss-gk-api function // https://github.com/mozilla/nss-gk-api/issues/7 letmut spki_item = SECItemBorrowed::wrap(spki); let spki_item_ptr: *mut SECItem = spki_item.as_mut(); let nss_spki = unsafe {
SubjectPublicKeyInfo::from_ptr(SECKEY_DecodeDERSubjectPublicKeyInfo(spki_item_ptr))?
}; let public_key = unsafe { PublicKey::from_ptr(SECKEY_ExtractPublicKey(*nss_spki))? };
Ok(public_key)
}
/// ECDH using NSS types. Computes the x coordinate of scalar multiplication of `peer_public` by /// `client_private`. fn ecdh_nss_raw(client_private: PrivateKey, peer_public: PublicKey) -> Result<Vec<u8>> { let ecdh_x_coord = unsafe {
PK11_PubDeriveWithKDF(
*client_private,
*peer_public,
PR_FALSE,
std::ptr::null_mut(),
std::ptr::null_mut(),
CKM_ECDH1_DERIVE,
CKM_SHA512_HMAC, // unused
CKA_DERIVE, // unused 0,
CKD_NULL,
std::ptr::null_mut(),
std::ptr::null_mut(),
)
.into_result()?
}; let ecdh_x_coord_bytes = ecdh_x_coord.as_bytes()?;
Ok(ecdh_x_coord_bytes.to_vec())
}
fn generate_p256_nss() -> Result<(PrivateKey, PublicKey)> { // Hard-coding the P256 OID here is easier than extracting a group name from peer_public and // comparing it with P256. We'll fail in `PK11_GenerateKeyPairWithOpFlags` if peer_public is on // the wrong curve. let oid_bytes = der::object_id(der::OID_SECP256R1_BYTES)?; letmut oid = SECItemBorrowed::wrap(&oid_bytes); let oid_ptr: *mut SECItem = oid.as_mut();
let slot = Slot::internal()?;
letmut client_public_ptr = ptr::null_mut();
// We have to be careful with error handling between the `PK11_GenerateKeyPairWithOpFlags` and // `PublicKey::from_ptr` calls here, so I've wrapped them in the same unsafe block as a // warning. TODO(jms) Replace this once there is a safer alternative. // https://github.com/mozilla/nss-gk-api/issues/1 unsafe { let client_private = // Type of `param` argument depends on mechanism. For EC keygen it is // `SECKEYECParams *` which is a typedef for `SECItem *`.
PK11_GenerateKeyPairWithOpFlags(
*slot,
CKM_EC_KEY_PAIR_GEN,
oid_ptr.cast(),
&mut client_public_ptr,
PK11_ATTR_EXTRACTABLE | PK11_ATTR_INSENSITIVE | PK11_ATTR_SESSION,
CKF_DERIVE,
CKF_DERIVE,
ptr::null_mut(),
)
.into_result()?;
let client_public = PublicKey::from_ptr(client_public_ptr)?;
Ok((client_private, client_public))
}
}
/// This returns a PKCS#8 ECPrivateKey and an uncompressed SEC1 public key. pubfn gen_p256() -> Result<(Vec<u8>, Vec<u8>)> {
nss_gk_api::init();
let (client_private, client_public) = generate_p256_nss()?;
let pkcs8_priv = unsafe { let pkcs8_priv_item: ScopedSECItem =
PK11_ExportDERPrivateKeyInfo(*client_private, ptr::null_mut()).into_result()?;
pkcs8_priv_item.into_vec()
};
let (r, s) = signature_buf.split_at(32);
der::sequence(&[&der::integer(r)?, &der::integer(s)?])
}
/// Ephemeral ECDH over P256. Takes a DER SubjectPublicKeyInfo that encodes a public key. Generates /// an ephemeral P256 key pair. Returns /// 1) the x coordinate of the shared point, and /// 2) the uncompressed SEC 1 encoding of the ephemeral public key. pubfn ecdhe_p256_raw(peer_spki: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
nss_gk_api::init();
let peer_public = nss_public_key_from_der_spki(peer_spki)?;
let (client_private, client_public) = generate_p256_nss()?;
let shared_point = ecdh_nss_raw(client_private, peer_public)?;
Ok((shared_point, client_public.key_data()?))
}
/// AES-256-CBC encryption for data that is a multiple of the AES block size (16 bytes) in length. /// Uses the zero IV if `iv` is None. pubfn encrypt_aes_256_cbc_no_pad(key: &[u8], iv: Option<&[u8]>, data: &[u8]) -> Result<Vec<u8>> {
nss_gk_api::init();
if key.len() != 32 { return Err(CryptoError::LibraryFailure);
}
let iv = iv.unwrap_or(&[0u8; AES_BLOCK_SIZE]);
if iv.len() != AES_BLOCK_SIZE { return Err(CryptoError::LibraryFailure);
}
let in_len = match c_uint::try_from(data.len()) {
Ok(in_len) => in_len,
_ => return Err(CryptoError::LibraryFailure),
};
if data.len() % AES_BLOCK_SIZE != 0 { return Err(CryptoError::LibraryFailure);
}
letmut params = SECItemBorrowed::wrap(iv); let params_ptr: *mut SECItem = params.as_mut(); letmut out_len: c_uint = 0; letmut out = vec![0; data.len()]; unsafe {
PK11_Encrypt(
*sym_key,
CKM_AES_CBC,
params_ptr,
out.as_mut_ptr(),
&mut out_len,
in_len,
data.as_ptr(),
in_len,
)
.into_result()?
} // CKM_AES_CBC should have output length equal to input length.
debug_assert_eq!(out_len, in_len);
Ok(out)
}
/// AES-256-CBC decryption for data that is a multiple of the AES block size (16 bytes) in length. /// Uses the zero IV if `iv` is None. pubfn decrypt_aes_256_cbc_no_pad(key: &[u8], iv: Option<&[u8]>, data: &[u8]) -> Result<Vec<u8>> {
nss_gk_api::init();
if key.len() != 32 { return Err(CryptoError::LibraryFailure);
}
let iv = iv.unwrap_or(&[0u8; AES_BLOCK_SIZE]);
if iv.len() != AES_BLOCK_SIZE { return Err(CryptoError::LibraryFailure);
}
let in_len = match c_uint::try_from(data.len()) {
Ok(in_len) => in_len,
_ => return Err(CryptoError::LibraryFailure),
};
if data.len() % AES_BLOCK_SIZE != 0 { return Err(CryptoError::LibraryFailure);
}
let peer_public = nss_public_key_from_der_spki(peer_spki)?;
// NSS has no mechanism to import a raw elliptic curve coordinate as a private key. // We need to encode it in an RFC 5208 PrivateKeyInfo: // // PrivateKeyInfo ::= SEQUENCE { // version Version, // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, // privateKey PrivateKey, // attributes [0] IMPLICIT Attributes OPTIONAL } // // Version ::= INTEGER // PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier // PrivateKey ::= OCTET STRING // Attributes ::= SET OF Attribute // // The privateKey field will contain an RFC 5915 ECPrivateKey: // ECPrivateKey ::= SEQUENCE { // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), // privateKey OCTET STRING, // parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, // publicKey [1] BIT STRING OPTIONAL // }
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.