Skip to content

Export raw Ed25519 key? #3000

Description

@justablob

I'm trying to export an Ed25519 private key without any PEM/DER encoding around it but i'm kind of struggling:

key.export({ type: "pkcs8", format: "der" })

gives me a 48-byte Buffer (which makes sense, it's ASN1, not the raw key), but that makes me wonder if there's any way to get the raw 32-byte private key. I could probably use some ASN1 library to get it from the DER Buffer but that's a little convoluted. It's possible that I'm completely missing something here.

Activity

  1. markg85 commented on Oct 4, 2020

    @markg85

    I'm having the exact same issue and trouble figuring it out.
    If i do:

    const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519")
    console.log(privateKey.export({ format: 'pem', type: 'pkcs8' }))
    

    I get:

    -----BEGIN PRIVATE KEY-----
    MC4CAQAwBQYDK2VwBCIEICNhgbLqX0mBVyhVpkuxSFXZduLShA0mCrm7AT3TPete
    -----END PRIVATE KEY-----
    

    But if i try to just print the key with something like:

    console.log(Buffer.from(privateKey.toString("base64")).toString("hex"))
    

    Then i get a 32 byte long string where i was expecting a 64 byte long one.

    5b6f626a656374204f626a6563745d
    

    I'm assuming "we" are doing something wrong. But it's super difficult to figure out what. As there doesn't seem to be much information about it. I know for sure that i'm doing something wrong as that 5b6f626a656374204f626a6563745d stays the same over every run. Which is impossible given that i generate a new key every time. I assume it's the object name.

    The alternative that i do know is string replacing the pem header from the export which does give just the key... But i have a hard time considering that the "right approach".

    Help, please :)

  2. gireeshpunathil commented on Nov 6, 2020

    @gireeshpunathil
    Member

    @nodejs/crypto

  3. mildsunrise commented on Nov 6, 2020

    @mildsunrise

    @markg85 Your problem is different than the one @justablob posted. If you want to get the base64 without the BEGIN / END lines, you can export as DER and encode with base64:

    console.log( privateKey.export({ format: 'der', type: 'pkcs8' }).toString('base64') )
  4. mildsunrise commented on Nov 6, 2020

    @mildsunrise

    @justablob We don't implement algorithm-specific APIs, so you can't access the individual parameters of a key, only serialize it. (This particular algorithm only has one parameter on the private key)

    Your best bet to access key parameters is probably to parse the DER, here's a quick & dirty example:

    function findDer(data, index, tagByte) {
        while (true) {
            if (data.length < 2)
                throw Error('unexpected EOF')
            const [ tag, length ] = data
            data = data.subarray(2)
            if ((tag & 31) === 31 || length >> 7)
                throw Error('not implemented')
            if (data.length < length)
                throw Error('unexpected EOF')
            if (index-- === 0) {
                if (tag !== tagByte) throw Error(`unexpected tag ${tag}`)
                return data.subarray(0, length)
            }
            data = data.subarray(length)
        }
    }
    
    let data = privateKey.export({ format: 'der', type: 'pkcs8' })
    data = findDer(data, 0, (1 << 5) | 16) // SEQUENCE (PrivateKeyInfo)
    data = findDer(data, 2, 4) // OCTET STRING (PrivateKey)
    data = findDer(data, 0, 4) // OCTET STRING (CurvePrivateKey)
  5. markg85 commented on Nov 8, 2020

    @markg85

    @markg85 Your problem is different than the one @justablob posted. If you want to get the base64 without the BEGIN / END lines, you can export as DER and encode with base64:

    console.log( privateKey.export({ format: 'der', type: 'pkcs8' }).toString('base64') )

    Awesome! That was the hint i needed to get it working. Thank you!

  6. PoojaDurgad commented on Dec 17, 2020

    @PoojaDurgad

    closing as answered. feel free to reopen the issue if its still outstanding

  7. FireballDark commented on Oct 12, 2021

    @FireballDark

    Unfortunately, PKCS8 DER/PEM format is something completely strange and incompatible in Ed25519 world. You can't use this type of keys in libsodium or lots of other libraries that expect the raw data.
    There should be Raw export through WebCrypto and just Crypto APIs

  8. zdenham commented on Nov 9, 2022

    @zdenham

    I'm not super familiar with ASN1 edge cases, but this is working for me:

    const { publicKey, privateKey } = generateKeyPairSync('ed25519');
    const der = privateKey.export({ format: 'der', type: 'pkcs8' }).toString('hex');
    const rawHex = der.substring(32); // can serialize this / use it with libsodium etc...
  9. panva commented on Mar 13, 2026

    @panva
    Member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions