@web5/agent
Version:
211 lines (191 loc) • 8.23 kB
text/typescript
import type {
Jwk,
Cipher,
KeyConverter,
KeyGenerator,
DecryptParams,
EncryptParams,
GenerateKeyParams,
} from '@web5/crypto';
import { AesGcm, AES_GCM_TAG_LENGTHS, CryptoAlgorithm } from '@web5/crypto';
import type { BytesToPrivateKeyParams, PrivateKeyToBytesParams } from '../types/params-direct.js';
/**
* The `AesGcmGenerateKeyParams` interface defines the algorithm-specific parameters that should be
* passed into the `generateKey()` method when using the AES-GCM algorithm.
*/
export interface AesGcmGenerateKeyParams extends GenerateKeyParams {
/** Specifies the algorithm variant for key generation in AES-GCM mode.
* The value determines the length of the key to be generated and must be one of the following:
* - `"A128GCM"`: Generates a 128-bit key.
* - `"A192GCM"`: Generates a 192-bit key.
* - `"A256GCM"`: Generates a 256-bit key.
*/
algorithm: 'A128GCM' | 'A192GCM' | 'A256GCM';
}
/**
* The `AesGcmParams` interface defines the algorithm-specific parameters that should be passed
* into the `encrypt()` and `decrypt()` methods when using the AES-GCM algorithm.
*/
export interface AesGcmParams {
/**
* The `additionalData` property is used for authentication alongside encrypted data but isn't
* encrypted itself. It must match in both encryption and decryption; a mismatch will cause
* decryption to fail. This feature allows for the authentication of data without encrypting it.
*
* The `additionalData` property is optional and omitting it does not compromise encryption
* security.
*/
additionalData?: Uint8Array;
/**
* The initialization vector (IV) must be unique for every encryption operation carried out with a
* given key. The IV need not be secret, but it must be unpredictable: that is, the IV must not be
* reused with the same key. The IV must be 12 bytes (96 bits) in length in accordance with the
* AES-GCM specification recommendedation to promote interoperability and efficiency.
*
* Note: It is OK to transmit the IV in the clear with the encrypted message.
*/
iv: Uint8Array;
/**
* This property determines the size in bits of the authentication tag generated in the encryption
* operation and used for authentication in the corresponding decryption. In accordance with the
* AES-GCM specification, the tag length must be 96, 104, 112, 120 or 128.
*
* The `tagLength` property is optional and defaults to 128 bits if omitted.
*/
tagLength?: typeof AES_GCM_TAG_LENGTHS[number];
}
/**
* The `AesGcmAlgorithm` class provides a concrete implementation for cryptographic operations using
* the AES algorithm in Galois/Counter Mode (GCM). This class implements both
* {@link Cipher | `Cipher`} and { @link KeyGenerator | `KeyGenerator`} interfaces, providing
* key generation, encryption, and decryption features.
*
* This class is typically accessed through implementations that extend the
* {@link CryptoApi | `CryptoApi`} interface.
*/
export class AesGcmAlgorithm extends CryptoAlgorithm
implements Cipher<AesGcmParams, AesGcmParams>,
KeyConverter,
KeyGenerator<AesGcmGenerateKeyParams, Jwk> {
public async bytesToPrivateKey({ privateKeyBytes }: BytesToPrivateKeyParams): Promise<Jwk> {
// Convert the byte array to a JWK.
const privateKey = await AesGcm.bytesToPrivateKey({ privateKeyBytes });
// Set the `alg` property based on the key length.
privateKey.alg = { 16: 'A128GCM', 24: 'A192GCM', 32: 'A256GCM' }[privateKeyBytes.length];
return privateKey;
}
/**
* Decrypts the provided data using AES-GCM.
*
* @remarks
* This method performs AES-GCM decryption on the given encrypted data using the specified key.
* It requires an initialization vector (IV), the encrypted data along with the decryption key,
* and optionally, additional authenticated data (AAD). The method returns the decrypted data as a
* Uint8Array. The optional `tagLength` parameter specifies the size in bits of the authentication
* tag used when encrypting the data. If not specified, the default tag length of 128 bits is
* used.
*
* @example
* ```ts
* const aesGcm = new AesGcmAlgorithm();
* const encryptedData = new Uint8Array([...]); // Encrypted data
* const iv = new Uint8Array([...]); // Initialization vector used during encryption
* const additionalData = new Uint8Array([...]); // Optional additional authenticated data
* const key = { ... }; // A Jwk object representing the AES key
* const decryptedData = await aesGcm.decrypt({
* data: encryptedData,
* iv,
* additionalData,
* key,
* tagLength: 128 // Optional tag length in bits
* });
* ```
*
* @param params - The parameters for the decryption operation.
*
* @returns A Promise that resolves to the decrypted data as a Uint8Array.
*/
public async decrypt(params:
DecryptParams & AesGcmParams
): Promise<Uint8Array> {
const plaintext = AesGcm.decrypt(params);
return plaintext;
}
/**
* Encrypts the provided data using AES-GCM.
*
* @remarks
* This method performs AES-GCM encryption on the given data using the specified key.
* It requires an initialization vector (IV), the encrypted data along with the decryption key,
* and optionally, additional authenticated data (AAD). The method returns the encrypted data as a
* Uint8Array. The optional `tagLength` parameter specifies the size in bits of the authentication
* tag generated in the encryption operation and used for authentication in the corresponding
* decryption. If not specified, the default tag length of 128 bits is used.
*
* @example
* ```ts
* const aesGcm = new AesGcmAlgorithm();
* const data = new TextEncoder().encode('Messsage');
* const iv = new Uint8Array([...]); // Initialization vector
* const additionalData = new Uint8Array([...]); // Optional additional authenticated data
* const key = { ... }; // A Jwk object representing an AES key
* const encryptedData = await aesGcm.encrypt({
* data,
* iv,
* additionalData,
* key,
* tagLength: 128 // Optional tag length in bits
* });
* ```
*
* @param params - The parameters for the encryption operation.
*
* @returns A Promise that resolves to the encrypted data as a Uint8Array.
*/
public async encrypt(params:
EncryptParams & AesGcmParams
): Promise<Uint8Array> {
const ciphertext = AesGcm.encrypt(params);
return ciphertext;
}
/**
* Generates a symmetric key for AES in Galois/Counter Mode (GCM) in JSON Web Key (JWK) format.
*
* @remarks
* This method generates a symmetric AES key for use in GCM mode, based on the specified
* `algorithm` parameter which determines the key length. It uses cryptographically secure random
* number generation to ensure the uniqueness and security of the key. The key is returned in JWK
* format.
*
* The generated key includes the following components:
* - `kty`: Key Type, set to 'oct' for Octet Sequence.
* - `k`: The symmetric key component, base64url-encoded.
* - `kid`: Key ID, generated based on the JWK thumbprint.
*
* @example
* ```ts
* const aesGcm = new AesGcmAlgorithm();
* const privateKey = await aesGcm.generateKey({ algorithm: 'A256GCM' });
* ```
*
* @param params - The parameters for the key generation.
*
* @returns A Promise that resolves to the generated symmetric key in JWK format.
*/
public async generateKey({ algorithm }:
AesGcmGenerateKeyParams
): Promise<Jwk> {
// Map algorithm name to key length.
const length = { A128GCM: 128, A192GCM: 192, A256GCM: 256 }[algorithm] as 128 | 192 | 256;
// Generate a random private key.
const privateKey = await AesGcm.generateKey({ length });
// Set the `alg` property based on the specified algorithm.
privateKey.alg = algorithm;
return privateKey;
}
public async privateKeyToBytes({ privateKey }: PrivateKeyToBytesParams): Promise<Uint8Array> {
// Convert the JWK to a byte array.
const privateKeyBytes = await AesGcm.privateKeyToBytes({ privateKey });
return privateKeyBytes;
}
}