generated from TBD54566975/tbd-project-template
-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
) * Refactor Ed25519 to generateKey instead of generateKeyPair * Refactor Secp256k1 to generateKey instead of generateKeyPair and simplify sign/verify * Refactor X25519 to generateKey instead of generateKeyPair * Refactor PBKDF2 to use JWKs * Remove CryptoKeyToJwkMixin * Improve test coverage for PBKDF2 * Refactor Ed25519, Secp256k1, and X25519 to use JWKs * Refactor EcdhAlgorithm to use JWK * Refactor EcdsaAlgorithm to use JWK * Refactor EdDsaAlgorithm to use JWK * Refactor AesCtrAlgorithm to use JWK * Refactor AesCtrAlgorithm to JWK * Refactor AesGcm to use JWK * Bump @noble ciphers, curves, and hashes dependencies --------- Signed-off-by: Frank Hinek <[email protected]>
- Loading branch information
1 parent
c417ba0
commit 590a5fc
Showing
70 changed files
with
8,001 additions
and
5,255 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,64 @@ | ||
import { universalTypeOf } from '@web5/common'; | ||
|
||
import type { Web5Crypto } from '../../types/web5-crypto.js'; | ||
import type { JwkOperation, PrivateKeyJwk } from '../../jose.js'; | ||
|
||
import { Jose } from '../../jose.js'; | ||
import { InvalidAccessError } from '../errors.js'; | ||
import { checkRequiredProperty } from '../../utils.js'; | ||
import { CryptoAlgorithm } from '../crypto-algorithm.js'; | ||
import { InvalidAccessError, OperationError } from '../errors.js'; | ||
|
||
export abstract class BaseAesAlgorithm extends CryptoAlgorithm { | ||
|
||
public checkGenerateKey(options: { | ||
public checkGenerateKeyOptions(options: { | ||
algorithm: Web5Crypto.AesGenerateKeyOptions, | ||
keyUsages: Web5Crypto.KeyUsage[] | ||
keyOperations: JwkOperation[] | ||
}): void { | ||
const { algorithm, keyUsages } = options; | ||
const { algorithm, keyOperations } = options; | ||
|
||
// Algorithm specified in the operation must match the algorithm implementation processing the operation. | ||
this.checkAlgorithmName({ algorithmName: algorithm.name }); | ||
// The algorithm object must contain a length property. | ||
checkRequiredProperty({ property: 'length', inObject: algorithm }); | ||
// The length specified must be a number. | ||
if (universalTypeOf(algorithm.length) !== 'Number') { | ||
throw new TypeError(`Algorithm 'length' is not of type: Number.`); | ||
|
||
// If specified, key operations must be permitted by the algorithm implementation processing the operation. | ||
if (keyOperations) { | ||
this.checkKeyOperations({ keyOperations, allowedKeyOperations: this.keyOperations }); | ||
} | ||
// The length specified must be one of the allowed bit lengths for AES. | ||
if (![128, 192, 256].includes(algorithm.length)) { | ||
throw new OperationError(`Algorithm 'length' must be 128, 192, or 256.`); | ||
} | ||
|
||
public checkSecretKey(options: { | ||
key: PrivateKeyJwk | ||
}): void { | ||
const { key } = options; | ||
|
||
// The options object must contain a key property. | ||
checkRequiredProperty({ property: 'key', inObject: options }); | ||
|
||
// The key object must be a JSON Web key (JWK). | ||
this.checkJwk({ key }); | ||
|
||
// The key object must be an octet sequence (oct) private key in JWK format. | ||
if (!Jose.isOctPrivateKeyJwk(key)) { | ||
throw new InvalidAccessError('Requested operation is only valid for oct private keys.'); | ||
} | ||
|
||
// If specified, the key's algorithm must match the algorithm implementation processing the operation. | ||
if (key.alg) { | ||
this.checkKeyAlgorithm({ keyAlgorithmName: key.alg }); | ||
} | ||
// The key usages specified must be permitted by the algorithm implementation processing the operation. | ||
this.checkKeyUsages({ keyUsages, allowedKeyUsages: this.keyUsages }); | ||
} | ||
|
||
public abstract generateKey(options: { | ||
algorithm: Web5Crypto.AesGenerateKeyOptions, | ||
extractable: boolean, | ||
keyUsages: Web5Crypto.KeyUsage[] | ||
}): Promise<Web5Crypto.CryptoKey>; | ||
keyOperations: JwkOperation[] | ||
}): Promise<PrivateKeyJwk>; | ||
|
||
public override async deriveBits(): Promise<Uint8Array> { | ||
throw new InvalidAccessError(`Requested operation 'deriveBits' is not valid for ${this.name} keys.`); | ||
throw new InvalidAccessError(`Requested operation 'deriveBits' is not valid for AES algorithm.`); | ||
} | ||
|
||
public override async sign(): Promise<Uint8Array> { | ||
throw new InvalidAccessError(`Requested operation 'sign' is not valid for ${this.name} keys.`); | ||
throw new InvalidAccessError(`Requested operation 'sign' is not valid for AES algorithm.`); | ||
} | ||
|
||
public override async verify(): Promise<boolean> { | ||
throw new InvalidAccessError(`Requested operation 'verify' is not valid for ${this.name} keys.`); | ||
throw new InvalidAccessError(`Requested operation 'verify' is not valid for AES algorithm.`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,96 @@ | ||
import { universalTypeOf } from '@web5/common'; | ||
|
||
import type { Web5Crypto } from '../../types/web5-crypto.js'; | ||
import type { JwkOperation, PrivateKeyJwk } from '../../jose.js'; | ||
|
||
import { BaseAesAlgorithm } from './base.js'; | ||
import { OperationError } from '../errors.js'; | ||
import { checkRequiredProperty } from '../../utils.js'; | ||
|
||
export abstract class BaseAesCtrAlgorithm extends BaseAesAlgorithm { | ||
|
||
public readonly name = 'AES-CTR'; | ||
|
||
public readonly keyUsages: Web5Crypto.KeyUsage[] = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey']; | ||
public readonly keyOperations: JwkOperation[] = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey']; | ||
|
||
public checkAlgorithmOptions(options: { | ||
algorithm: Web5Crypto.AesCtrOptions, | ||
key: Web5Crypto.CryptoKey | ||
algorithm: Web5Crypto.AesCtrOptions | ||
}): void { | ||
const { algorithm, key } = options; | ||
const { algorithm } = options; | ||
|
||
// Algorithm specified in the operation must match the algorithm implementation processing the operation. | ||
this.checkAlgorithmName({ algorithmName: algorithm.name }); | ||
|
||
// The algorithm object must contain a counter property. | ||
checkRequiredProperty({ property: 'counter', inObject: algorithm }); | ||
|
||
// The counter must a Uint8Array. | ||
if (!(universalTypeOf(algorithm.counter) === 'Uint8Array')) { | ||
throw new TypeError(`Algorithm 'counter' is not of type: Uint8Array.`); | ||
} | ||
|
||
// The initial value of the counter block must be 16 bytes long (the AES block size). | ||
if (algorithm.counter.byteLength !== 16) { | ||
throw new OperationError(`Algorithm 'counter' must have length: 16 bytes.`); | ||
} | ||
|
||
// The algorithm object must contain a length property. | ||
checkRequiredProperty({ property: 'length', inObject: algorithm }); | ||
|
||
// The length specified must be a number. | ||
if (universalTypeOf(algorithm.length) !== 'Number') { | ||
throw new TypeError(`Algorithm 'length' is not of type: Number.`); | ||
} | ||
|
||
// The length specified must be between 1 and 128. | ||
if ((algorithm.length < 1 || algorithm.length > 128)) { | ||
throw new OperationError(`Algorithm 'length' should be in the range: 1 to 128.`); | ||
} | ||
// The options object must contain a key property. | ||
checkRequiredProperty({ property: 'key', inObject: options }); | ||
// The key object must be a CryptoKey. | ||
this.checkCryptoKey({ key }); | ||
// The key algorithm must match the algorithm implementation processing the operation. | ||
this.checkKeyAlgorithm({ keyAlgorithmName: key.algorithm.name }); | ||
// The CryptoKey object must be a secret key. | ||
this.checkKeyType({ keyType: key.type, allowedKeyType: 'secret' }); | ||
} | ||
|
||
public checkDecryptOptions(options: { | ||
algorithm: Web5Crypto.AesCtrOptions, | ||
key: PrivateKeyJwk, | ||
data: Uint8Array | ||
}): void { | ||
const { algorithm, key, data } = options; | ||
|
||
// Validate the algorithm input parameters. | ||
this.checkAlgorithmOptions({ algorithm }); | ||
|
||
// Validate the secret key. | ||
this.checkSecretKey({ key }); | ||
|
||
// If specified, the secret key must be allowed to be used for 'decrypt' operations. | ||
if (key.key_ops) { | ||
this.checkKeyOperations({ keyOperations: ['decrypt'], allowedKeyOperations: key.key_ops }); | ||
} | ||
|
||
// The data must be a Uint8Array. | ||
if (universalTypeOf(data) !== 'Uint8Array') { | ||
throw new TypeError('The data must be of type Uint8Array.'); | ||
} | ||
} | ||
|
||
public checkEncryptOptions(options: { | ||
algorithm: Web5Crypto.AesCtrOptions, | ||
key: PrivateKeyJwk, | ||
data: Uint8Array | ||
}): void { | ||
const { algorithm, key, data } = options; | ||
|
||
// Validate the algorithm and key input parameters. | ||
this.checkAlgorithmOptions({ algorithm }); | ||
|
||
// Validate the secret key. | ||
this.checkSecretKey({ key }); | ||
|
||
// If specified, the secret key must be allowed to be used for 'encrypt' operations. | ||
if (key.key_ops) { | ||
this.checkKeyOperations({ keyOperations: ['encrypt'], allowedKeyOperations: key.key_ops }); | ||
} | ||
|
||
// The data must be a Uint8Array. | ||
if (universalTypeOf(data) !== 'Uint8Array') { | ||
throw new TypeError('The data must be of type Uint8Array.'); | ||
} | ||
} | ||
} |
Oops, something went wrong.