New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.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.2.4 to 0.3.0

hdkey.d.ts

14

package.json
{
"name": "ed25519-keygen",
"version": "0.2.4",
"description": "Generate ed25519 keys deterministically for SSH, PGP (GPG) and TOR",
"version": "0.3.0",
"description": "Generate ed25519 keys for SSH, PGP (GPG), TOR and SLIP-0010 hdkey",
"type": "module",

@@ -13,2 +13,6 @@ "main": "index.js",

"index.d.ts.map",
"src/hdkey.ts",
"hdkey.js",
"hdkey.d.ts",
"hdkey.d.ts.map",
"src/pgp.ts",

@@ -38,3 +42,3 @@ "pgp.js",

"devDependencies": {
"micro-should": "0.2.0",
"micro-should": "0.4.0",
"prettier": "2.6.2",

@@ -48,2 +52,6 @@ "typescript": "4.7.3"

},
"./hdkey": {
"types": "./hdkey.d.ts",
"default": "./hdkey.js"
},
"./ssh": {

@@ -50,0 +58,0 @@ "types": "./ssh.d.ts",

@@ -7,4 +7,81 @@ import * as P from 'micro-packed';

export declare const PacketLen: P.BytesCoderStream<number> & P.BytesCoder<number>;
export declare const PubKeyPacket: P.CoderType<{
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<{
secret: Uint8Array;
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: {

@@ -30,24 +107,2 @@ created: number;

} & {};
s2k_type: number;
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;
} & {}>;

@@ -54,0 +109,0 @@ declare type SecretKeyType = P.UnwrapCoder<typeof SecretKeyPacket>;

@@ -225,3 +225,3 @@ import * as ed25519 from '@noble/ed25519';

});
const PubKeyPacket = P.struct({
export const PubKeyPacket = P.struct({
version: PGP_PACKET_VERSION,

@@ -234,10 +234,19 @@ created: P.U32BE,

});
const SecretKeyPacket = P.struct({
pub: PubKeyPacket,
s2k_type: P.U8,
const PlainSecretKey = P.struct({
secret: P.bytes(null),
});
const EncryptedSecretKey = P.struct({
enc: EncryptionEnum,
S2K: S2K,
S2K,
iv: P.bytes(16),
secret: P.bytes(null),
});
const SecretKeyPacket = P.struct({
pub: PubKeyPacket,
type: P.mappedTag(P.U8, {
plain: [0x00, PlainSecretKey],
encrypted: [254, EncryptedSecretKey],
encrypted2: [255, EncryptedSecretKey],
}),
});
const SigTypeEnum = P.map(P.U8, {

@@ -449,11 +458,22 @@ binary: 0x00,

}
function decodeSecretChecksum(secret) {
const [data, checksum] = [secret.slice(0, -2), P.U16BE.decode(secret.slice(-2))];
let ourChecksum = 0;
for (let i = 0; i < data.length; i++)
ourChecksum += data[i];
ourChecksum %= 65536;
if (ourChecksum !== checksum)
throw new Error('PGP.secretKey: wrong checksum for plain encoding');
return mpi.decode(data);
}
export async function decodeSecretKey(password, key) {
if (key.s2k_type !== 254)
throw new Error(`PGP.secretKey Unsupported s2k_type=${key.s2k_type}`);
const data = key.S2K.data;
const keyLen = EncryptionKeySize[key.enc];
if (key.type.TAG === 'plain')
return decodeSecretChecksum(key.type.data.secret);
const keyData = key.type.data;
const data = keyData.S2K.data;
const keyLen = EncryptionKeySize[keyData.enc];
if (keyLen === undefined)
throw new Error(`PGP.secretKey: unknown encryption mode=${key.enc}`);
throw new Error(`PGP.secretKey: unknown encryption mode=${keyData.enc}`);
const encKey = deriveKey(data.hash, keyLen, utf8.decode(password), data.salt, data.count);
const decrypted = await Encryption[key.enc].decrypt(key.secret, encKey, key.iv);
const decrypted = await Encryption[keyData.enc].decrypt(keyData.secret, encKey, keyData.iv);
const decryptedKey = decrypted.subarray(0, -20);

@@ -465,2 +485,4 @@ const checksum = Hash.sha1(decryptedKey);

throw new Error(`PGP.secretKey unsupported publicKey algorithm: ${key.pub.algo.TAG}`);
if (key.type.TAG === 'encrypted2')
return decodeSecretChecksum(decryptedKey);
return mpi.decode(decryptedKey);

@@ -477,3 +499,3 @@ }

const S2K = { TAG: 'iterated', data: { hash, salt, count } };
return { pub, s2k_type: 254, enc, S2K, iv, secret };
return { pub, type: { TAG: 'encrypted', data: { enc, S2K, iv, secret } } };
}

@@ -480,0 +502,0 @@ export const pubArmor = P.base64armor('PGP PUBLIC KEY BLOCK', 64, Stream, crc24);

# ed25519-keygen
Generate ed25519 keys deterministically for SSH, PGP (GPG) and TOR.
Generate ed25519 keys for SSH, PGP (GPG), TOR and SLIP-0010 hdkey.
Does not use CLI utils, everything is done programmatically in pure JS.
Generation is deterministic and done in pure javascript, without CLI tools. Uses audited [@noble/ed25519](https://github.com/paulmillr/noble-ed25519) under the hood.
Includes SLIP-0010 / BIP32 HDKey implementation, sponsored by the Kin Foundation for [Kinetic](https://github.com/kin-labs/kinetic).
## Usage

@@ -11,3 +13,3 @@

The package exports four modules:
The package exports five modules:

@@ -17,2 +19,3 @@ - [`ed25519-keygen/ssh`](#sshseed-username) for SSH key generation

- [`ed25519-keygen/tor`](#torseed) for TOR onion addresses
- [`ed25519-keygen/hdkey`](#hdkey) for [SLIP-0010](https://github.com/satoshilabs/slips/blob/master/slip-0010.md)/[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) HDKey
- [`ed25519-keygen/utils`](#randombyteslength) for cryptographically secure random number generator (CSPRNG)

@@ -148,2 +151,52 @@

## hdkey
SLIP-0010 hierarchical deterministic (HD) wallets for implementation. Based on audited code from [scure-bip32](https://github.com/paulmillr/scure-bip32). Check out [scure-bip39](https://github.com/paulmillr/scure-bip39) if you also need mnemonic phrases.
- SLIP-0010 publicKey is 33 bytes (see [this issue](https://github.com/satoshilabs/slips/issues/1251)), if you want 32-byte publicKey, use `.publicKeyRaw` getter
- SLIP-0010 vectors fingerprint is actually `parentFingerprint`
- SLIP-0010 doesn't allow deriving non-hardened keys for Ed25519, however some other libraries treat non-hardened keys (`m/0/1`) as hardened (`m/0'/1'`). If you want this behaviour, there is a flag `forceHardened` in `derive` method
```ts
import { HDKey } from 'ed25519-keygen/hdkey';
const hdkey1 = HDKey.fromMasterSeed(seed);
// props
[hdkey1.depth, hdkey1.index, hdkey1.chainCode];
console.log(hdkey2.privateKey, hdkey2.publicKey);
console.log(hdkey3.derive("m/0/2147483647'/1'"));
const sig = hdkey3.sign(hash);
hdkey3.verify(hash, sig);
```
Note: `chainCode` property is essentially a private part
of a secret "master" key, it should be guarded from unauthorized access.
The full API is:
```ts
class HDKey {
public static HARDENED_OFFSET: number;
public static fromMasterSeed(seed: Uint8Array | string): HDKey;
readonly depth: number = 0;
readonly index: number = 0;
readonly chainCode: Uint8Array | null = null;
readonly parentFingerprint: number = 0;
public readonly privateKey: Uint8Array;
get fingerprint(): number;
get fingerprintHex(): string;
get parentFingerprintHex(): string;
get pubKeyHash(): Uint8Array;
get publicKey(): Uint8Array;
get publicKeyRaw(): Uint8Array;
derive(path: string, forceHardened = false): HDKey;
deriveChild(index: number): HDKey;
sign(hash: Uint8Array): Uint8Array;
verify(hash: Uint8Array, signature: Uint8Array): boolean;
}
```
### `randomBytes(length)`

@@ -150,0 +203,0 @@

@@ -263,3 +263,3 @@ import * as ed25519 from '@noble/ed25519';

const PubKeyPacket = P.struct({
export const PubKeyPacket = P.struct({
version: PGP_PACKET_VERSION,

@@ -274,9 +274,9 @@ created: P.U32BE,

// NOTE: SecretKey is specific packet type as per spec. For user facing API we using 'privateKey'
const SecretKeyPacket = P.struct({
pub: PubKeyPacket,
s2k_type: P.U8,
// only for 254 & 255
const PlainSecretKey = P.struct({
secret: P.bytes(null),
});
const EncryptedSecretKey = P.struct({
enc: EncryptionEnum,
S2K: S2K,
S2K,
// IV as blocksize of algo. For AES it is 16 bytes, others is not supported

@@ -286,2 +286,13 @@ iv: P.bytes(16),

});
// NOTE: SecretKey is specific packet type as per spec. For user facing API we using 'privateKey'
const SecretKeyPacket = P.struct({
pub: PubKeyPacket,
type: P.mappedTag(P.U8, {
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],
}),
});
type SecretKeyType = P.UnwrapCoder<typeof SecretKeyPacket>;

@@ -536,7 +547,19 @@

function decodeSecretChecksum(secret: Bytes) {
const [data, checksum] = [secret.slice(0, -2), P.U16BE.decode(secret.slice(-2))];
// Wow, third checksum algorithm in single spec!
let ourChecksum = 0;
for (let i = 0; i < data.length; i++) ourChecksum += data[i];
ourChecksum %= 65536;
if (ourChecksum !== checksum) throw new Error('PGP.secretKey: wrong checksum for plain encoding');
return mpi.decode(data);
}
export async function decodeSecretKey(password: string, key: SecretKeyType) {
if (key.s2k_type !== 254) throw new Error(`PGP.secretKey Unsupported s2k_type=${key.s2k_type}`);
const data = key.S2K.data;
const keyLen = EncryptionKeySize[key.enc];
if (keyLen === undefined) throw new Error(`PGP.secretKey: unknown encryption mode=${key.enc}`);
if (key.type.TAG === 'plain') return decodeSecretChecksum(key.type.data.secret);
const keyData = key.type.data;
const data = keyData.S2K.data;
const keyLen = EncryptionKeySize[keyData.enc];
if (keyLen === undefined)
throw new Error(`PGP.secretKey: unknown encryption mode=${keyData.enc}`);
const encKey = deriveKey(

@@ -549,3 +572,3 @@ data.hash,

);
const decrypted = await Encryption[key.enc].decrypt(key.secret, encKey, key.iv);
const decrypted = await Encryption[keyData.enc].decrypt(keyData.secret, encKey, keyData.iv);
const decryptedKey = decrypted.subarray(0, -20);

@@ -558,2 +581,3 @@ const checksum = Hash.sha1(decryptedKey);

// Decoded as generic MPI, not as OpaqueMPI
if (key.type.TAG === 'encrypted2') return decodeSecretChecksum(decryptedKey);
return mpi.decode(decryptedKey);

@@ -579,3 +603,3 @@ }

const S2K = { TAG: 'iterated', data: { hash, salt, count } } as const;
return { pub, s2k_type: 254, enc, S2K, iv, secret };
return { pub, type: { TAG: 'encrypted', data: { enc, S2K, iv, secret } } };
}

@@ -582,0 +606,0 @@

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