summaryrefslogtreecommitdiff
path: root/ext/crypto/ed25519.rs
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2022-09-27 17:43:42 +0530
committerGitHub <noreply@github.com>2022-09-27 17:43:42 +0530
commitf02f2425d5e5947a3cc5a95775c8cae5a6e82881 (patch)
tree06fa5a08cd27d5bb07b9736d072c3f1fb9e556dc /ext/crypto/ed25519.rs
parentf3dd13730c592b76778fa047a098214bc1934216 (diff)
feat(ext/crypto): add x25519 and Ed25519 CFRG curves (#14119)
Diffstat (limited to 'ext/crypto/ed25519.rs')
-rw-r--r--ext/crypto/ed25519.rs128
1 files changed, 128 insertions, 0 deletions
diff --git a/ext/crypto/ed25519.rs b/ext/crypto/ed25519.rs
new file mode 100644
index 000000000..a8060cae1
--- /dev/null
+++ b/ext/crypto/ed25519.rs
@@ -0,0 +1,128 @@
+use deno_core::error::AnyError;
+use deno_core::op;
+use deno_core::ZeroCopyBuf;
+use elliptic_curve::pkcs8::PrivateKeyInfo;
+use rand::rngs::OsRng;
+use rand::RngCore;
+use ring::signature::Ed25519KeyPair;
+use ring::signature::KeyPair;
+use spki::der::Decode;
+use spki::der::Encode;
+
+#[op(fast)]
+pub fn op_generate_ed25519_keypair(pkey: &mut [u8], pubkey: &mut [u8]) -> bool {
+ let mut rng = OsRng;
+ rng.fill_bytes(pkey);
+
+ let pair = match Ed25519KeyPair::from_seed_unchecked(pkey) {
+ Ok(p) => p,
+ Err(_) => return false,
+ };
+ pubkey.copy_from_slice(pair.public_key().as_ref());
+ true
+}
+
+#[op(fast)]
+pub fn op_sign_ed25519(key: &[u8], data: &[u8], signature: &mut [u8]) -> bool {
+ let pair = match Ed25519KeyPair::from_seed_unchecked(key) {
+ Ok(p) => p,
+ Err(_) => return false,
+ };
+ signature.copy_from_slice(pair.sign(data).as_ref());
+ true
+}
+
+#[op(fast)]
+pub fn op_verify_ed25519(pubkey: &[u8], data: &[u8], signature: &[u8]) -> bool {
+ ring::signature::UnparsedPublicKey::new(&ring::signature::ED25519, pubkey)
+ .verify(data, signature)
+ .is_ok()
+}
+
+// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
+pub const ED25519_OID: const_oid::ObjectIdentifier =
+ const_oid::ObjectIdentifier::new_unwrap("1.3.101.112");
+
+#[op(fast)]
+pub fn op_import_spki_ed25519(key_data: &[u8], out: &mut [u8]) -> bool {
+ // 2-3.
+ let pk_info = match spki::SubjectPublicKeyInfo::from_der(key_data) {
+ Ok(pk_info) => pk_info,
+ Err(_) => return false,
+ };
+ // 4.
+ let alg = pk_info.algorithm.oid;
+ if alg != ED25519_OID {
+ return false;
+ }
+ // 5.
+ if pk_info.algorithm.parameters.is_some() {
+ return false;
+ }
+ out.copy_from_slice(pk_info.subject_public_key);
+ true
+}
+
+#[op(fast)]
+pub fn op_import_pkcs8_ed25519(key_data: &[u8], out: &mut [u8]) -> bool {
+ // 2-3.
+ let pk_info = match PrivateKeyInfo::from_der(key_data) {
+ Ok(pk_info) => pk_info,
+ Err(_) => return false,
+ };
+ // 4.
+ let alg = pk_info.algorithm.oid;
+ if alg != ED25519_OID {
+ return false;
+ }
+ // 5.
+ if pk_info.algorithm.parameters.is_some() {
+ return false;
+ }
+ // 6.
+ // CurvePrivateKey ::= OCTET STRING
+ if pk_info.private_key.len() != 32 {
+ return false;
+ }
+ out.copy_from_slice(pk_info.private_key);
+ true
+}
+
+#[op]
+pub fn op_export_spki_ed25519(pubkey: &[u8]) -> Result<ZeroCopyBuf, AnyError> {
+ let key_info = spki::SubjectPublicKeyInfo {
+ algorithm: spki::AlgorithmIdentifier {
+ // id-Ed25519
+ oid: ED25519_OID,
+ parameters: None,
+ },
+ subject_public_key: pubkey,
+ };
+ Ok(key_info.to_vec()?.into())
+}
+
+#[op]
+pub fn op_export_pkcs8_ed25519(pkey: &[u8]) -> Result<ZeroCopyBuf, AnyError> {
+ let pk_info = rsa::pkcs8::PrivateKeyInfo {
+ public_key: None,
+ algorithm: rsa::pkcs8::AlgorithmIdentifier {
+ // id-Ed25519
+ oid: ED25519_OID,
+ parameters: None,
+ },
+ private_key: pkey, // OCTET STRING
+ };
+
+ Ok(pk_info.to_vec()?.into())
+}
+
+// 'x' from Section 2 of RFC 8037
+// https://www.rfc-editor.org/rfc/rfc8037#section-2
+#[op]
+pub fn op_jwk_x_ed25519(pkey: &[u8]) -> Result<String, AnyError> {
+ let pair = Ed25519KeyPair::from_seed_unchecked(pkey)?;
+ Ok(base64::encode_config(
+ pair.public_key().as_ref(),
+ base64::URL_SAFE_NO_PAD,
+ ))
+}