VirgilSecurity / virgil-crypto-javascript

Virgil JavaScript Crypto Library is a high-level cryptographic library that allows you to perform all necessary operations for secure storing and transferring data and everything required to become HIPAA and GDPR compliant.
https://developer.virgilsecurity.com/docs/how-to#cryptography
BSD 3-Clause "New" or "Revised" License
35 stars 4 forks source link

How to import ed25519 keys? #39

Closed max-mapper closed 5 years ago

max-mapper commented 5 years ago

I am trying to import PEM encoded ed25519 keys (these are derived from test vectors, not used in anything real)

-----BEGIN PRIVATE KEY-----
MFECAQEEIOpPW/6GlNi7dLe1lARjL9WWi3dO1UXoEN6cMqT7QZL0oAUGAytlcKEj
AyEAW6O5rG6Q6D7/zSWsTlihNlqeNaPTrl6we55NkLz3UG0=
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MDQwDgYHKoZIzj0CAQYDK2VwAyIAAFujuaxukOg+/80lrE5YoTZanjWj065esHue
TZC891Bt
-----END PUBLIC KEY-----

But when I do importPrivateKey I get:

Error: Module: virgil/crypto. Error code: 7. Invalid format of the Public Key.
Module: virgil/crypto/mbedtls. Error code: -14848. PK - Elliptic curve is unsupported (only NIST curves are supported)

Is there some other way to create VirgilPrivateKey and VirgilPublicKey objects?

SergeySeroshtan commented 5 years ago

Hi @maxogden. Thanks for your time diving to our crypto products. There are some issues with the private key.

-----BEGIN PRIVATE KEY-----
MFECAQEEIOpPW/6GlNi7dLe1lARjL9WWi3dO1UXoEN6cMqT7QZL0oAUGAytlcKEj
AyEAW6O5rG6Q6D7/zSWsTlihNlqeNaPTrl6we55NkLz3UG0=
-----END PRIVATE KEY-----
  1. Used PEM title BEGIN PRIVATE KEY specifies that private key is encoded as PKCS#8 ASN.1 type PrivateKeyInfo:
    PrivateKeyInfo ::= SEQUENCE {
    version                   Version,
    privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
    privateKey                PrivateKey,
    attributes                [0]  IMPLICIT Attributes OPTIONAL }
  2. But actually it is encoded as SEC 1 ASN.1 type ECPrivateKey:
    ECPrivateKey ::= SEQUENCE {
     version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
     privateKey     OCTET STRING,
     parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
     publicKey  [1] BIT STRING OPTIONAL }

    And as defined in the RFC 5915 PEM header and footer should be :

    -----BEGIN EC PRIVATE KEY-----
    -----END EC PRIVATE KEY-----
  3. Nevertheless, Header and Footer replacement can not completely fix the issue, as curves ed25519 and curve25519 are not included to the SEC 1 standard and RFC 5915 and can not be represented as a NamedCurve defined in the RFC 5912.

Solution:

  1. Use ASN.1 type PrivateKeyInfo or it's newer version OneAsymmetricKey defined in the RFC 5958 and referenced in the RFC 8410 for keys for Ed25519, Ed448, X25519, and X448.

  2. Generate new ed25519 private keys via this library:

    
    import { VirgilCrypto } from 'virgil-crypto';

const virgilCrypto = new VirgilCrypto(); const keyPair = virgilCrypto.generateKeys();


 or by [Virgil CLI](https://developer.virgilsecurity.com/docs/sdk-and-tools/virgil-cli/generate-keypair).

Note, for inspecting ASN.1 DER and PEM encoded types, useful [online tool](https://lapo.it/asn1js/) can be used.
max-mapper commented 5 years ago

Ah that makes sense, my mistake. Thank you :)

max-mapper commented 5 years ago

Got it working

-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIOpPW/6GlNi7dLe1lARjL9WWi3dO1UXoEN6cMqT7QZL0
-----END PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAW6O5rG6Q6D7/zSWsTlihNlqeNaPTrl6we55NkLz3UG0=
-----END PUBLIC KEY-----

Ended up using pkcs8-pem for the private key and spki-pem for the public key.

import { composePrivateKey, composePublicKey } from 'crypto-key-composer'

function privateToPem(privateKey) {
  var decomposed = {
    format: 'pkcs8-pem',
    keyAlgorithm: { id: 'ed25519' },
    keyData: {
      seed: privateKey,
    },
  }
  return composePrivateKey(decomposed)
}

function publicToPem(publicKey) {
  var decomposed = {
    format: 'spki-pem',
    keyAlgorithm: { id: 'ed25519' },
    keyData: {
      bytes: publicKey,
    },
  }
  return composePublicKey(decomposed)
}