Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ed25519-keygen

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ed25519-keygen - npm Package Compare versions

Comparing version 0.4.10 to 0.4.11

4

hdkey.js

@@ -0,1 +1,2 @@

/*! micro-ed25519-hdkey - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { ed25519 } from '@noble/curves/ed25519';

@@ -81,2 +82,3 @@ import { hmac } from '@noble/hashes/hmac';

const parts = path.replace(/^[mM]'?\//, '').split('/');
// tslint:disable-next-line
let child = this;

@@ -90,2 +92,3 @@ for (const c of parts) {

throw new Error('Invalid index');
// hardened key
if (forceHardened || m[2] === "'")

@@ -100,2 +103,3 @@ idx += HARDENED_OFFSET;

throw new Error(`Non-hardened child derivation not possible for Ed25519 (index=${index})`);
// Hardened child: 0x00 || ser256(kpar) || ser32(index)
const data = concatBytes(ZERO, this.privateKey, toU32(index));

@@ -102,0 +106,0 @@ const I = hmac(sha512, this.chainCode, data);

1

index.d.ts

@@ -1,2 +0,1 @@

export {};
//# sourceMappingURL=index.d.ts.map

@@ -0,2 +1,2 @@

"use strict";
throw new Error('The module has no entry-point: consult README for usage');
export {};

@@ -5,5 +5,9 @@ import { ed25519 } from '@noble/curves/ed25519';

const base36 = utils.chain(utils.radix(36), utils.alphabet('0123456789abcdefghijklmnopqrstuvwxyz'), utils.padding(0), utils.join(''));
// Formats IPNS public key in bytes array format to 'ipns://k...' string format
export function formatPublicKey(pubBytes) {
return `ipns://k${base36.encode(pubBytes)}`;
}
// Takes an IPNS pubkey (address) string as input and returns bytes array of the key
// Supports various formats ('ipns://k', 'ipns://b', 'ipns://f')
// Handles decoding and validation of the key before returning pubkey bytes
export function parseAddress(address) {

@@ -15,5 +19,7 @@ address = address.toLowerCase();

if (address.startsWith('k')) {
// Decode base-36 pubkey (after removing 'k' prefix) and encode it as a hex string
hexKey = hex.encode(base36.decode(address.slice(1)));
}
else if (address.startsWith('b')) {
// Decode base-32 pubkey (after removing 'b' prefix) and encode it as a hex string
hexKey = hex.encode(base32.decode(address.slice(1).toUpperCase()));

@@ -25,14 +31,21 @@ }

else
throw new Error('Unsupported Base-X Format');
throw new Error('Unsupported Base-X Format'); // Throw error if pubkey format is not supported
// Check if hexKey has expected prefix '0172002408011220' and length of 80
if (hexKey.startsWith('0172002408011220') && hexKey.length === 80) {
return hex.decode(hexKey);
}
// Throw error if IPNS key prefix is invalid
throw new Error('Invalid IPNS Key Prefix: ' + hexKey);
}
// Generates an ed25519 pubkey from a seed and converts it to several IPNS pubkey formats
export async function getKeys(seed) {
//? privKey "seed" should be checked for <ed25519.curve.n?
if (seed.length != 32)
throw new TypeError('Seed must be 32 bytes in length');
// Generate ed25519 public key from seed
const pubKey = await ed25519.getPublicKey(seed);
// Create public key bytes by concatenating prefix bytes and pubKey
const pubKeyBytes = concatBytes(new Uint8Array([0x01, 0x72, 0x00, 0x24, 0x08, 0x01, 0x12, 0x20]), pubKey);
const hexKey = hex.encode(pubKeyBytes).toLowerCase();
// Return different representations of the keys
return {

@@ -39,0 +52,0 @@ publicKey: `0x${hexKey}`,

{
"name": "ed25519-keygen",
"version": "0.4.10",
"version": "0.4.11",
"description": "Generate ed25519 keys for SSH, PGP (GPG), TOR, IPNS and SLIP-0010 hdkey",

@@ -39,11 +39,11 @@ "type": "module",

"dependencies": {
"@noble/curves": "~1.2.0",
"@noble/hashes": "~1.3.2",
"@scure/base": "~1.1.2",
"micro-packed": "^0.3.2"
"@noble/curves": "~1.3.0",
"@noble/hashes": "~1.3.3",
"@scure/base": "~1.1.5",
"micro-packed": "~0.5.2"
},
"devDependencies": {
"micro-should": "0.4.0",
"prettier": "2.8.4",
"typescript": "5.0.2"
"prettier": "3.1.1",
"typescript": "5.3.2"
},

@@ -50,0 +50,0 @@ "exports": {

@@ -7,102 +7,56 @@ import * as P from 'micro-packed';

export declare const PacketLen: P.BytesCoderStream<number> & P.BytesCoder<number>;
export declare const PubKeyPacket: P.CoderType<{
export declare const PubKeyPacket: P.CoderType<P.StructInput<{
version: undefined;
created: number;
algo: {
TAG: "ECDH";
data: {
curve: string;
pub: bigint;
params: {
hash: string;
encryption: string;
} & {};
} & {};
} | {
TAG: "EdDSA";
data: {
curve: string;
pub: bigint;
} & {};
};
} & {}>;
declare const SecretKeyPacket: P.CoderType<{
type: {
TAG: "encrypted";
data: {
secret: Uint8Array;
enc: string;
S2K: {
TAG: "simple";
data: {
hash: string;
} & {};
} | {
TAG: "salted";
data: {
hash: string;
salt: Uint8Array;
} & {};
} | {
TAG: "iterated";
data: {
hash: string;
salt: Uint8Array;
count: number;
} & {};
};
iv: Uint8Array;
} & {};
} | {
TAG: "plain";
data: {
secret: Uint8Array;
} & {};
} | {
TAG: "encrypted2";
data: {
secret: Uint8Array;
enc: string;
S2K: {
TAG: "simple";
data: {
hash: string;
} & {};
} | {
TAG: "salted";
data: {
hash: string;
salt: Uint8Array;
} & {};
} | {
TAG: "iterated";
data: {
hash: string;
salt: Uint8Array;
count: number;
} & {};
};
iv: Uint8Array;
} & {};
};
pub: {
created: number;
algo: {
TAG: "ECDH";
data: {
curve: string;
pub: bigint;
params: {
hash: string;
encryption: string;
} & {};
} & {};
} | {
algo: P.Values<{
EdDSA: {
TAG: "EdDSA";
data: {
curve: string;
pub: bigint;
} & {};
data: P.StructInput<{
curve: any;
pub: any;
}>;
};
} & {};
} & {}>;
ECDH: {
TAG: "ECDH";
data: P.StructInput<{
curve: any;
pub: any;
params: any;
}>;
};
}>;
}>>;
declare const SecretKeyPacket: P.CoderType<P.StructInput<{
pub: P.StructInput<{
version: any;
created: any;
algo: any;
}>;
type: P.Values<{
plain: {
TAG: "plain";
data: P.StructInput<{
secret: any;
}>;
};
encrypted: {
TAG: "encrypted";
data: P.StructInput<{
enc: any;
S2K: any;
iv: any;
secret: any;
}>;
};
encrypted2: {
TAG: "encrypted2";
data: P.StructInput<{
enc: any;
S2K: any;
iv: any;
secret: any;
}>;
};
}>;
}>>;
type SecretKeyType = P.UnwrapCoder<typeof SecretKeyPacket>;

@@ -109,0 +63,0 @@ export declare const Stream: P.CoderType<any[]>;

@@ -12,2 +12,9 @@ import { ed25519, x25519 } from '@noble/curves/ed25519';

import * as P from 'micro-packed';
// RFCS:
// - main: https://datatracker.ietf.org/doc/html/rfc4880
// - ecdh: https://datatracker.ietf.org/doc/html/rfc6637
// - ed25519: https://www.ietf.org/archive/id/draft-koch-eddsa-for-openpgp-04.txt
// - bis: https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-rfc4880bis-10#section-5.2.3.1
// Safari supports AES_CFB via webCrypto, but chromium/firefox do not.
// Test page: https://diafygi.github.io/webcrypto-examples/
const BLOCK_LEN = 16;

@@ -49,2 +56,4 @@ const IV = new Uint8Array(BLOCK_LEN);

}
// PGP Types
// Multiprecision Integers [RFC4880](https://datatracker.ietf.org/doc/html/rfc4880)
export const mpi = P.wrap({

@@ -60,2 +69,7 @@ encodeStream: (w, value) => {

});
// GnuGP violates spec by using non-zero stripped MPI's for secret keys (opaque MPI/SOS).
// We need to do the same to create equal keys.
// More info:
// - https://www.mhonarc.org/archive/html/ietf-openpgp/2019-10/msg00041.html
// - https://marc.info/?l=gnupg-devel&m=161518990118244&w=2
export const opaquempi = P.wrap({

@@ -68,4 +82,7 @@ encodeStream: (w, value) => {

});
const OID_MSB = 2 ** 7;
const OID_NO_MSB = 2 ** 7 - 1;
// ASN.1 OID (object identifier) without tag & length
// First two elements: [i0 * 40 + i1].
// Others: split in groups of 7 bit chunks, add 0x80 every byte except last(stop flag), like utf8.
const OID_MSB = 2 ** 7; // mask for 8 bit
const OID_NO_MSB = 2 ** 7 - 1; // mask for all bits except 8
export const oid = P.wrap({

@@ -132,3 +149,5 @@ encodeStream: (w, value) => {

});
const PGP_PACKET_VERSION = P.magic(P.hex(1), '04');
// PGP Structures
const PGP_PACKET_VERSION = P.magic(P.hex(1), '04'); // only version 4 is supported
// Other (RSA/ElGamal/etc) is unsupported
const pubKeyEnum = P.map(P.U8, {

@@ -185,2 +204,3 @@ ECDH: 18,

});
// bis4880
const AEADEnum = P.map(P.U8, {

@@ -191,2 +211,3 @@ None: 0,

});
// https://datatracker.ietf.org/doc/html/rfc4880#section-3.7.1
const S2KEnum = P.map(P.U8, { simple: 0, salted: 1, iterated: 3 });

@@ -198,2 +219,3 @@ const S2K = P.tag(S2KEnum, {

});
// https://datatracker.ietf.org/doc/html/rfc6637#section-9
const ECDSAPub = P.struct({ curve: ECEnum, pub: mpi });

@@ -223,5 +245,7 @@ const ECDHPub = P.struct({

S2K,
// IV as blocksize of algo. For AES it is 16 bytes, others is not supported
iv: P.bytes(16),
secret: P.bytes(null),
});
// NOTE: SecretKey is specific packet type as per spec. For user facing API we using 'privateKey'
const SecretKeyPacket = P.struct({

@@ -231,6 +255,9 @@ pub: PubKeyPacket,

plain: [0x00, PlainSecretKey],
// Skipping 'Any other value is a symmetric-key encryption algorithm identifier.'
encrypted: [254, EncryptedSecretKey],
// Same as above, but secret is with checksum
encrypted2: [255, EncryptedSecretKey],
}),
});
// https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.1
const SigTypeEnum = P.map(P.U8, {

@@ -253,2 +280,3 @@ binary: 0x00,

});
// https://datatracker.ietf.org/doc/html/rfc4880.html#section-5.2.3.1
const signatureSubpacket = P.map(P.U8, {

@@ -279,2 +307,3 @@ signatureCreationTime: 2,

embeddedSignature: 32,
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-rfc4880bis-10#section-5.2.3.1
issuerFingerprint: 33,

@@ -320,7 +349,10 @@ preferredAEADAlgorithms: 34,

hashPrefix: P.bytes(2),
// 2: ec + dsa, 1 for rsa
sig: P.array(null, mpi),
});
const UserPacket = P.string(null);
// PGP Functions
const EXPBIAS6 = (count) => (16 + (count & 15)) << ((count >> 4) + 6);
function deriveKey(hash, len, password, salt, count) {
// Important: there is difference between zero and empty count
count = count === undefined ? 0 : EXPBIAS6(count);

@@ -335,2 +367,3 @@ const data = salt ? concatBytes(salt, password) : password;

const h = hashC.create();
// prefix
if (r > 0)

@@ -352,2 +385,3 @@ h.update(new Uint8Array(r));

};
// https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.4
const hashTail = new Uint8Array([0x04, 0xff]);

@@ -381,2 +415,3 @@ const hashPubKey = P.struct({

const getKeyId = (fp) => fp.slice(-16);
// https://datatracker.ietf.org/doc/html/rfc4880#section-6.1
function crc24(data) {

@@ -402,5 +437,9 @@ let crc = 0xb704ce;

};
// https://datatracker.ietf.org/doc/html/rfc4880#section-4.2
// Old packet: [1, version: 0, tag(4), lenType(2)] -- 8 bits
// New packet: [1, version: 1, tag(6)] + len(bytes) -> not supported, GPG generates version 0 for now
const PacketHead = P.struct({
magic: P.magic(P.bits(1), 1),
version: P.magic(P.bits(1), 0),
// https://datatracker.ietf.org/doc/html/rfc4880#section-4.3
tag: P.map(P.bits(4), {

@@ -442,2 +481,3 @@ public_key_encrypted_session_key: 1,

export const Stream = P.array(null, Packet);
// Key generation
const EDSIGN = P.array(null, P.U256BE);

@@ -452,2 +492,3 @@ async function signData(head, unhashed, data, privateKey) {

const [data, checksum] = [secret.slice(0, -2), P.U16BE.decode(secret.slice(-2))];
// Wow, third checksum algorithm in single spec!
let ourChecksum = 0;

@@ -477,2 +518,3 @@ for (let i = 0; i < data.length; i++)

throw new Error(`PGP.secretKey unsupported publicKey algorithm: ${key.pub.algo.TAG}`);
// Decoded as generic MPI, not as OpaqueMPI
if (key.type.TAG === 'encrypted2')

@@ -515,2 +557,3 @@ return decodeSecretChecksum(decryptedKey);

async function getCerts(edPriv, cvPriv, user, created = 0) {
// key settings same as in PGP to avoid fingerprinting since they are part of public key
const preferredEncryptionAlgorithms = ['aes256', 'aes192', 'aes128', 'tripledes'];

@@ -572,2 +615,7 @@ const preferredHashAlgorithms = ['sha512', 'sha384', 'sha256', 'sha224', 'sha1'];

}
/*
NOTE: gpg: warning: lower 3 bits of the secret key are not cleared
happens even for keys generated with GnuPG 2.3.6, because check looks at item as Opaque MPI, when it is just MPI:
https://dev.gnupg.org/rGdbfb7f809b89cfe05bdacafdb91a2d485b9fe2e0
*/
export async function getKeys(privKey, user, password, created = 0) {

@@ -577,2 +625,3 @@ const { keyId } = await getPublicPackets(privKey, privKey, created);

const publicKey = await formatPublic(privKey, cvPrivate, user, created);
// The slow part
const privateKey = await formatPrivate(privKey, cvPrivate, user, password, created);

@@ -579,0 +628,0 @@ return { keyId, privateKey, publicKey };

@@ -5,31 +5,30 @@ import * as P from 'micro-packed';

export declare const SSHKeyType: P.CoderType<undefined>;
export declare const PublicKey: P.CoderType<{
export declare const PublicKey: P.CoderType<P.StructInput<{
keyType: undefined;
pubKey: Uint8Array;
} & {}>;
export declare const AuthData: P.CoderType<{
}>>;
export declare const AuthData: P.CoderType<P.StructInput<{
nonce: Uint8Array;
auth: string;
userAuthRequest: number;
user: string;
pubKey: {
pubKey: Uint8Array;
} & {};
userAuthRequest: number;
conn: string;
auth: string;
haveSig: number;
} & {}>;
keyType: undefined;
pubKey: P.StructInput<{
keyType: any;
pubKey: any;
}>;
}>>;
export type AuthDataType = P.UnwrapCoder<typeof AuthData>;
export declare const PrivateExport: P.Coder<{
keys: ({
pubKey: {
pubKey: Uint8Array;
} & {};
privKey: {
pubKey: Uint8Array;
check1: Uint8Array;
check2: Uint8Array;
privKey: Uint8Array;
comment: string;
} & {};
} & {})[];
} & {}, string>;
export declare const PrivateExport: P.Coder<P.StructInput<{
magic: undefined;
ciphername: undefined;
kdfname: undefined;
kdfopts: undefined;
keys: P.StructInput<{
pubKey: any;
privKey: any;
}>[];
}>, string>;
export declare function formatPublicKey(bytes: Uint8Array, comment?: string): string;

@@ -36,0 +35,0 @@ export declare function getFingerprint(bytes: Uint8Array): string;

@@ -18,9 +18,10 @@ import { ed25519 } from '@noble/curves/ed25519';

}), (i) => i + 1);
// https://tools.ietf.org/html/draft-miller-ssh-agent-02#section-4.5
export const AuthData = P.struct({
nonce: SSHBuf,
userAuthRequest: P.U8,
userAuthRequest: P.U8, // == 50
user: SSHString,
conn: SSHString,
auth: SSHString,
haveSig: P.U8,
haveSig: P.U8, // == 1
keyType: SSHKeyType,

@@ -31,2 +32,3 @@ pubKey: P.prefix(P.U32BE, PublicKey),

magic: P.magicBytes('openssh-key-v1\0'),
// Only decrypted ed25519 keys supported for now
ciphername: P.magic(SSHString, 'none'),

@@ -46,4 +48,7 @@ kdfname: P.magic(SSHString, 'none'),

const blob = PublicKey.encode({ pubKey: bytes });
// ssh-keygen -l -f ~/.ssh/id_ed25519
// 256 SHA256:+WK/Sl4XJjoxDlAWYuhq4Fl2hka9j3GOUjYczQkqnCI user@comp.local (ED25519)
return `SHA256:${base64.encode(sha256(blob)).replace(/=$/, '')}`;
}
// For determenistic generation in tests
export async function getKeys(privateKey, comment, checkBytes = randomBytes(4)) {

@@ -60,2 +65,3 @@ const pubKey = await ed25519.getPublicKey(privateKey);

privKey: {
// Check bytes, should be same
check1: checkBytes,

@@ -72,2 +78,3 @@ check2: checkBytes,

}
// For SSH Agents
export function authSign(privateKey, data) {

@@ -74,0 +81,0 @@ return ed25519.sign(AuthData.encode(data), privateKey);

@@ -7,3 +7,5 @@ import { ed25519 } from '@noble/curves/ed25519';

export function formatPublicKey(pubBytes) {
// checksum = H(".onion checksum" || pubkey || version)
const checksum = sha3_256(concatBytes(utf8.decode('.onion checksum'), pubBytes, ADDRESS_VERSION));
// onion_address = base32(pubkey || checksum || version);
const addr = concatBytes(pubBytes, checksum.slice(0, 2), ADDRESS_VERSION);

@@ -16,2 +18,3 @@ return `${base32.encode(addr).toLowerCase()}.onion`;

const addr = base32.decode(address.replace(/\.onion$/, '').toUpperCase());
// skip last 3 bytes
const skip = addr.slice(0, addr.length - 3);

@@ -18,0 +21,0 @@ const key = formatPublicKey(skip);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc