as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

@amazon-devices/keplercrypto

@amazon-devices/keplercrypto

KeplerCrypto API提供的功能可让您使用行业标准算法执行典型的加密操作,例如读取、生成和管理加密密钥。

注意:​ 不支持在模拟器中运行此API。

开始使用

设置

  1. 将以下库依赖项添加到package.json文件的dependencies部分。

已复制到剪贴板。

    "@amazon-devices/keplercrypto": "	~2.0,

用法

在使用KeplerCrypto功能的源文件中,从Turbo模块导入所需的数据类型。

已复制到剪贴板。

  import {
    AsymmetricAlgorithm,
    AsymmetricKeyBuilder,
    CbcContextBuilder,
    CtrContextBuilder,
    Crypto,
    DigestAlgorithm,
    EccCurve,
    GcmContextBuilder,
    KeyPurpose,
    PrivateKey,
    PublicKey,
    SymmetricAlgorithm,
    SymmetricKey,
  } from '@amazon-devices/keplercrypto';

要想使用KeplerCrypto Turbo模块,首先必须创建Crypto类的实例。

已复制到剪贴板。

  /**
  * 创建Crypto对象。
  */
  const crypto = new Crypto();

下面的示例代码仅用于解释说明,为了便于理解,已做了简化处理。当发生错误时,KeplerCrypto API中的大多数方法都会抛出一个异常。

将您的调用封装在try-catch块中,以恰当地处理发生的任何错误。

已复制到剪贴板。

try {
  crypto.getRandom(length);
} catch (e) {
  if (e instanceof InvalidArgumentError) {...}
  else if (e instanceof SecurityError) {...}
}

查看文档,了解各个特定方法可能抛出的具体异常。

ECDSA签名和验证

以下示例代码包括ECDSA密钥对生成、消息签名和验证。

步骤1: 创建ECDSA密钥构建器

已复制到剪贴板。

// 创建新的ECDSA密钥构建器
const keyBuilder = crypto.makeEccKeyBuilder();
// 将密钥标记为可导出
keyBuilder.exportable = true;
// 设置密钥用途
keyBuilder.purposes = [KeyPurpose.SIGN, KeyPurpose.VERIFY];

步骤2: 生成密钥对

您可以生成ECDSA密钥对或构造私钥。

要生成ECDSA密钥对,请调用buildGenerated()

已复制到剪贴板。

// 生成ECDSA密钥对
const privateKey = await keyBuilder.buildGenerated();
// 获取公钥
const publicKey = privateKey.getPublicKey();

要根据现有DER字符串构造私钥,请调用buildPrivateFromDer()

已复制到剪贴板。

// 根据现有DER字符串构建私钥
const privateKey = await keyBuilder.buildPrivateFromDer(privateKeyDer);
const publicKey = privateKey.getPublicKey();

</viv>

步骤3: 创建签名上下文构建器

已复制到剪贴板。

const builder = crypto.makeSignatureContextBuilder();
builder.signingAlgorithm = crypto.getAsymmetricAlgorithmByName(AsymmetricAlgorithm.ECDSA);

步骤4: 对消息进行签名并获取签名

已复制到剪贴板。

// 使用私钥构建签名上下文
const signer = builder.buildSigningContext(privateKey);
const message = '这是一条非常重要的消息';
const messageBuffer = new TextEncoder().encode(message).buffer;

// 对消息签名
const signedMessage = await signer.sign(messageBuffer);

步骤5: 使用签名验证消息

已复制到剪贴板。

// 使用公钥构建验证上下文
const verifier = builder.buildVerificationContext(publicKey);

// 验证消息
const result = await verifier.verify(messageBuffer, signedMessage);

RSA签名和验证

以下示例代码包括RSA密钥对生成、消息签名和验证。

步骤1: 创建RSA密钥构建器

已复制到剪贴板。

// 创建RSA密钥构建器
const keybuilder = crypto.makeRsaKeyBuilder();
// 将密钥标记为可导出
keyBuilder.exportable = true;
// 设置密钥用途
keyBuilder.purposes = [KeyPurpose.SIGN, KeyPurpose.VERIFY];

步骤2: 生成密钥对

您可以生成RSA密钥对或构造私钥。

要生成RSA密钥对,请调用buildGenerated()

已复制到剪贴板。

// 生成RSA密钥对
const privateKey = await keyBuilder.buildGenerated();
// 获取公钥
const publicKey = privateKey.getPublicKey();

要根据现有DER字符串构造私钥,请调用buildPrivateFromDer()

已复制到剪贴板。

// 根据现有DER字符串构建私钥
const privateKey = await keyBuilder.buildPrivateFromDer(privateKeyDer);
const publicKey = privateKey.getPublicKey();

步骤3: 创建签名上下文构建器并对消息进行签名

通过调用buildSigningContext() 创建签名上下文构建器,然后使用RSA-PKCS1 v1.5架构对消息进行签名以获取签名。

已复制到剪贴板。

// 使用私钥构建签名上下文
const builder = crypto.makeRsassaPkcs1ContextBuilder();
const digestAlgorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);
builder.digestAlgorithm = digestAlgorithm;
const rsaPkcs1Signer = builder.buildSigningContext(privateKey);
const message = '这是一条非常重要的消息';
const messageBuffer = new TextEncoder().encode(message).buffer;

// 对消息签名
const signedMessage = await rsaPkcs1Signer.sign(messageBuffer);

步骤4: 验证消息

通过调用使用RSA-PKCS1 v1.5标准的rsaPkcs1Verifier.verify() 来使用签名进行消息验证。

已复制到剪贴板。

// 使用公钥构建验证上下文
const rsaPkcs1Verifier = builder.buildVerificationContext(publicKey);

// 验证消息
const result = await rsaPkcs1Verifier.verify(messageBuffer, signedMessage);

步骤5: 对消息签名并获得签名

要使用RSA-PSS标准对消息进行签名,请调用rsaPssSigner.sign(),它会返回已签名消息的签名。

已复制到剪贴板。

// 为了保证填充机制正确并提升安全性,盐值的长度通常应与摘要长度保持一致。
// 使用不同的盐值长度可能也能工作,但不建议这样做。
builder.saltLength = digestAlgorithm.size / 8;
// 使用私钥构建签名上下文
const rsaPssSigner = builder.buildSigningContext(privateKey);
const message = '这是一条非常重要的消息';
const messageBuffer = new TextEncoder().encode(message).buffer;

// 对消息签名
const signedMessage = await rsaPssSigner.sign(messageBuffer);

要验证消息,请调用rsaPssVerifier.verify() 并传递消息的签名。

已复制到剪贴板。

// 使用公钥构建验证上下文
const rsaPssVerifier = builder.buildVerificationContext(publicKey);

// 验证消息
const result = await rsaPssVerifier.verify(messageBuffer, signedMessage);

HMAC签名和验证

以下示例说明如何生成密钥、导出密钥、对数据签名并进行验证。

已复制到剪贴板。

// 生成密钥
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
keyBuilder.bits = 256;
const key = await keyBuilder.buildGenerated();

// 导出安全密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 获取摘要算法
const digestAlgorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);

// 使用安全密钥和摘要算法创建HMAC上下文构建器
const builder = crypto.makeHmacContextBuilder();
builder.key = key;
builder.digestAlgorithm = digestAlgorithm;

// 对数据签名
const signContext = builder.build();
const tag = await signContext.sign(plaintext);

// 验证数据
const verifyContext = builder.build();
const tag = signContext.sign(plaintext);
const result1 = await verifyContext.verify(plaintext, tag);

// 尝试使用导出的密钥进行验证
const exportedBuilder = crypto.makeHmacContextBuilder();
exportedBuilder.key = exportedKey;
exportedBuilder.digestAlgorithm(digestAlgorithm);
const exportedVerifyContext = exportedBuilder.build();
const result2 = await exportedVerifyContext.verify(plaintext, tag);

使用AES CBC分组密码对消息进行加密

以下示例说明如何生成AES-256密钥、导出密钥、创建AES-256 CBC密码上下文构建器,以及如何使用它对明文进行签名。

已复制到剪贴板。

// 生成AES-256密钥
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.bits = 256;
keyBuilder.exportable = true;
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
keyBuilder.purposes = purposes;
const key = await keyBuilder.buildGenerated();

// 导出AES密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = purposes;
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 创建AES-256 CBC密码上下文构建器
const builder = crypto.makeCbcCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));

// 设置正确的IV
const iv = new Uint8Array(builder.ivSize).buffer;
builder.iv = iv;
// 设置密钥
builder.key = key;

// 加密明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const encryptionContext = builder.buildEncryptionContext();
const ciphertext = await encryptionContext.encrypt(plaintextBuffer);

// 将密文解密
const decryptionContext = builder.buildDecryptionContext();
const decrypted = await decryptionContext.decrypt(ciphertext);

// 尝试使用导出的密钥然后用它将密文解密
const exportedBuilder = crypto.makeCbcCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));
exportedBuilder.iv = iv;
exportedBuilder.key = exportedKey;
const exportedDecryptionContext = exportedBuilder.buildDecryptionContext();
const exportedDecrypted = await exportedDecryptionContext.decrypt(ciphertext);

使用AES CTR分组密码对消息进行加密

以下示例说明如何生成AES-CTR密钥、导出密钥、创建AES-256 CTR密码上下文构建器,以及如何使用它对明文进行签名。

已复制到剪贴板。

// 生成AES-256密钥
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = purposes;
keyBuilder.bits = 256;
const key = await keyBuilder.buildGenerated();

// 导出AES密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = purposes;
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 创建AES CTR密码上下文构建器
const builder = crypto.makeCtrCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));
// 设置正确的计数和随机数
builder.count = 12;
builder.nonce = 12;
// 设置密钥
builder.key = key;

// 加密明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const encryptionContext = builder.buildEncryptionContext();
const ciphertext = await encryptionContext.encrypt(plaintextBuffer);

// 将密文解密
const decryptionContext = builder.buildDecryptionContext();
const decrypted = await decryptionContext.decrypt(ciphertext);
const result1 = plaintext === new TextDecoder('utf-8').decode(decrypted);

// 将导出的密钥与CTR密码上下文构建器一起使用
builder.key = exportedKey;

// 尝试使用导出的密钥解密
const exportedDecryptionContext = builder.buildDecryptionContext();
const exportedDecrypted = await exportedDecryptionContext.decrypt(ciphertext);
const result2 = plaintext === new TextDecoder('utf-8').decode(exportedDecrypted);

使用AES GCM分组密码对消息进行加密

以下示例说明如何生成AES-256 GCM密钥、导出密钥、创建AES-256 GCM密码上下文构建器,以及如何使用它对明文进行签名。

已复制到剪贴板。

// 生成AES-256密钥
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = purposes;
keyBuilder.bits = 256;
const key = await keyBuilder.buildGenerated();

// 导出AES密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = purposes;
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 创建AES-256 GCM密码上下文构建器
const builder = crypto.makeGcmCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));

// 使用4字节标识符初始化IV以使用随机化的
// 随机数序列。或者,使用大小为builder.getIvSize() 的向量对其进行初始化
// 以使用任意随机数。
const iv = new Uint8Array([0xab, 0xcd, 0xef, 0x01]);

builder.iv = iv;
builder.key = key;

// 加密明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const encryptionContext = builder.buildEncryptionContext();
const ciphertext = await encryptionContext.encrypt(plaintextBuffer);

// 将密文解密
const decryptionContext = builder.buildDecryptionContext();
const decrypted = await decryptionContext.decrypt(ciphertext);

// 将导出的密钥与GCM密码上下文构建器一起使用
builder.key = exportedKey;
// 尝试使用导出的密钥解密
const exportedDecryptionContext = builder.buildDecryptionContext();
const exportedDecrypted = await exportedDecryptionContext.decrypt(ciphertext);

使用RSA-OAEP加密消息

以下示例说明如何生成RSA-OAEP密钥、导出密钥、创建上下文构建器,以及如何使用它对明文进行签名。

已复制到剪贴板。

// 获取摘要算法和非对称算法,并定义密钥用途
const sha = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA384);
const alg = crypto.getAsymmetricAlgorithmByName(AsymmetricAlgorithm.RSA_OAEP);
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];

// 创建一个RsaOaepKeyBuilder
const keyBuilder = crypto.makeRsaOaepKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = purposes;
keyBuilder.bits = 384;

// 从密钥构建器生成私钥
const privateKey = await keyBuilder.buildGenerated();

// 导出密钥供以后的测试案例使用
const rawPrivateKey = await privateKey.exportDer();

// 获取对应的公钥
const publicKey = privateKey.getPublicKey();

// 导出公钥以备后用
const rawPublicKey = await publickey.exportDer();

// 根据消息构建明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;

// 使用alg和sha构建RSA-OAEP密码上下文
const rsaOaepCipherContext = crypto.makeRsaOaepCipherContextBuilder(alg, sha);

// 使用公钥基于RSA-OAEP密码上下文构建加密上下文
const rsaOaepEncryptionContext = rsaOaepCipherContext.buildEncryptionContext(publickey);

// 使用加密上下文加密
const ciphertext = await rsaOaepEncryptionContext.encrypt(plaintextBuffer);

// 基于密码上下文构建解密上下文
const rsaOaepDecryptionContext = rsaOaepCipherContext.buildDecryptionContext(privatekey);

// 使用解密上下文进行解密
const decrypted = await rsaOaepDecryptionContext.decrypt(ciphertext);

// 确保解密后的消息与明文相同
const result1 = plaintext === new TextDecoder('utf-8').decode(decrypted);

// 使用导出的密钥来构建私钥和公钥
const exportedPrivkey = await keyBuilder.buildPrivateFromDer(rawPrivateKey);
const exportedRsaOaepDecryptionContext = rsaOaepCipherContext.buildDecryptionContext(exportedPrivkey);

// 使用导入的密钥解密密文并确保解密后的消息与明文一致
const exportedDecrypted = await exportedRsaOaepDecryptionContext.decrypt(ciphertext);
const result2 = plaintext === new TextDecoder('utf-8').decode(exportedDecrypted);

// 使用导入的公钥进行加密,使用原始私钥进行解密
// 并确保解密后的消息与明文一致
const exportedPublicKey = await keyBuilder.buildPublicFromDer(rawPublicKey);
const exportedRsaOaepEncryptionContext = rsaOaepCipherContext.buildEncryptionContext(exportedPublicKey);
const exportedCiphertext = await exportedRsaOaepEncryptionContext.encrypt(plaintextBuffer);
const exportedDecryptedAgain = await rsaOaepDecryptionContext.decrypt(exportedCiphertext);
const result3 = plaintext === new TextDecoder('utf-8').decode(exportedDecryptedAgain);

创建消息摘要

以下代码示例调用getDigestAlgorithmByName() 来获取摘要,创建摘要上下文,对示例字符串进行编码,并获取该字符串的摘要。

已复制到剪贴板。

const builder = crypto.makeDigestContextBuilder();
builder.digestAlgorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);
const digestContext = builder.build();

const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const hash = await digestContext.digest(plaintextBuffer);

使用HKDF(HMAC密钥派生函数)派生密钥

const salt = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const info = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // 来自密钥的额外信息

// 创建密钥(如果您已经有了一个用于DERIVE的密钥,则为可选项)
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.bits = 256; // 任意长度
keyBuilder.exportable = false;
keyBuilder.purposes = [KeyPurpose.DERIVE]; // 重要须知:密钥必须能够派生
const secret = await keyBuilder.buildGenerated();
const algorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);

// 创建上下文构建器
const ctxBuilder = crypto.makeHkdfContextBuilder();
ctxBuilder.info = info;
ctxBuilder.salt = salt;
ctxBuilder.hashAlgorithm = algorithm;
// 创建派生上下文
const ctx = ctxBuilder.buildKeyDerivationContext(secret);

// 派生对称密钥
// 重要须知:派生的密钥必须与所用算法的长度相匹配
const generatedKeyLen = algorithm.size / 8;
const symmKey = ctx.deriveKey(generatedKeyLen);

// 改为派生一个原始密钥
const rawKey = ctx.deriveBits(generatedKeyLen);

使用PBKDF2(基于密码的密钥派生函数2)派生密钥

已复制到剪贴板。

const iterations = 10000; // 迭代次数,值越大越安全,但性能下降幅度也越大。
                          // 10000是一个合理的值,不会导致性能下降太多
const salt = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const generatedKeyLen = 512;

// 创建上下文构建器
const ctxBuilder = crypto.makePbkdf2ContextBuilder();

// 创建密钥(如果您已经有了一个用于DERIVE的密钥,则为可选项)
const keyBuilder = crypto.makeSymmetricKeyBuilder()
keyBuilder.bits = 256;  // 任意长度
keyBuilder.exportable = false;
keyBuilder.purposes = [KeyPurpose.DERIVE];  // 重要须知:密钥必须能够派生
const secret = await keyBuilder.buildGenerated();

const algorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);

// 创建派生上下文
ctxBuilder.iterations = iterations;
ctxBuilder.salt = salt;
ctxBuilder.hashAlgorithm = algorithm;
const ctx = buildKeyDerivationContext(secret);

// 派生对称密钥
const symmKey = await ctx.deriveKey(generatedKeyLen);

// 改为派生一个原始密钥
const rawKey = await ctx.deriveBits(generatedKeyLen);

网页加密API shim层

KeplerCrypto库提供了一个shim层,用于实现网页加密API(仅提供英文版)。有关API方法和参数,请参阅现有的网页加密API MDN文档

网页加密用法示例

以下示例介绍如何导入和使用网页加密API shim层。

导入API

已复制到剪贴板。

import {WebCrypto} from '@amazon-devices/keplercrypto';

初始化WebCrypto对象

已复制到剪贴板。

const wc = new WebCrypto();

可选: 在globalThis上公开crypto实例

已复制到剪贴板。

// 如果globalThis不存在,则定义它
if (typeof globalThis === 'undefined') {
  (window as any).globalThis = window;
}
globalThis.crypto = wc.crypto as any;

调用网页加密API

下一个代码示例生成ECDH CryptoKeyPair

已复制到剪贴板。

const nonExtractableKeyPair = (await wc.crypto.subtle.generateKey(
  {
    name: 'ECDH',
    namedCurve: 'P-256',
  },
  false, // 不可提取
  ['deriveBits'],
)) as CryptoKeyPair;

支持的网页加密算法

该库仍在开发中,网页加密实现仅提供整个W3C网页加密规范的一个子集。未来版本将支持更多操作。

注意:网页加密shim层实现中不支持deriveKey。
有关密钥派生功能,请使用标准KeplerCrypto API,如上文“使用HKDF派生密钥”和“使用PBKDF2派生密钥”的示例所示。

网页加密支持的密钥格式

使用网页加密API导入和导出密钥时,支持以下格式:

密钥类型 支持的导入格式 支持的导出格式
AES raw、jwk raw、jwk
HMAC raw、jwk raw、jwk
ECDH pkcs8、spki、jwk pkcs8、spki、jwk

格式描述:

  • raw: 未格式化的二进制数据,用于对称密钥(AES或HMAC)或椭圆曲线公钥。
  • pkcs8: RSA或椭圆曲线私钥的PKCS #8格式。
  • spki: RSA或椭圆曲线公钥的SubjectPublicKeyInfo格式。
  • jwk: JSON网页密钥格式(所有密钥类型均支持)

导入密钥的示例:

已复制到剪贴板。

// 导入原始格式的AES密钥
const rawKey = new Uint8Array([...]);  // 您的密钥字节
const importedKey = await wc.crypto.subtle.importKey(
  "raw",                // 格式
  rawKey,               // 密钥数据
  { name: "AES-GCM" },  // 算法
  false,                // 可提取
  ["encrypt", "decrypt"] // 密钥用法
);

网页加密API支持矩阵

算法操作:

  • ✓ = 支持
  • ✗ = 不支持
算法 encrypt() decrypt() sign() verify() digest() deriveKey() importKey() exportKey() deriveBits() generateKey()
RSASSA-PKCS1v1
RSA-PSS
RSA-OAEP
ECDH
ECDSA
AES-CTR
AES-CBC
AES-GCM
HMAC
SHA-1
SHA-256
SHA-384
SHA-512
HKDF
PBKDF2

KeplerCrypto概述

KeplerCrypto API提供的功能可让您使用行业标准算法执行典型的加密操作,例如读取、生成和管理加密密钥。

开始使用

KeplerCrypto API已包含在Kepler SDK中。

安装和设置KeplerCrypto

要将API添加到您的项目,请在应用的根目录中打开package.json文件并添加以下依赖项。

  "dependencies": {
    "@amazon-devices/keplercrypto": "*",
    ...
  },

在您的应用中使用KeplerCrypto API

在使用KeplerCrypto功能的源文件中,从Turbo模块导入所需的数据类型。

  import {
    AsymmetricAlgorithm,
    AsymmetricKeyBuilder,
    CbcContextBuilder,
    CtrContextBuilder,
    Crypto,
    DigestAlgorithm,
    EccCurve,
    GcmContextBuilder,
    KeyPurpose,
    PrivateKey,
    PublicKey,
    SymmetricAlgorithm,
    SymmetricKey,
  } from '@amazon-devices/keplercrypto';

接下来,获取一个Crypto实例。

  /**
  * 创建Crypto对象。
  */
  const crypto = new Crypto();

要想使用KeplerCrypto Turbo模块,首先必须创建Crypto类的实例。

KeplerCrypto常见用例

下面的示例代码仅用于解释说明,为了便于理解,已做了简化处理。当发生错误时,KeplerCrypto API中的大多数方法都会抛出一个异常。

将您的调用封装在try-catch块中,以恰当地处理发生的任何错误。例如:

try {
  crypto.getRandom(length);
} catch (e) {
  if (e instanceof InvalidArgumentError) {...}
  else if (e instanceof SecurityError) {...}
}

查看您调用的任何方法的文档,了解它抛出的特定异常。

注意:​ 不支持在模拟器中运行此Turbo模块。

ECDSA签名和验证

以下示例代码包括ECDSA密钥对生成、消息签名和验证。

步骤1: 创建ECDSA密钥构建器

// 创建新的ECDSA密钥构建器
const keyBuilder = crypto.makeEccKeyBuilder();
// 将密钥标记为可导出
keyBuilder.exportable = true;
// 设置密钥用途
keyBuilder.purposes = [KeyPurpose.SIGN, KeyPurpose.VERIFY];

步骤2: 生成密钥对

您可以生成ECDSA密钥对或构造私钥。

要生成ECDSA密钥对,请调用buildGenerated()

// 生成ECDSA密钥对
const privateKey = await keyBuilder.buildGenerated();
// 获取公钥
const publicKey = privateKey.getPublicKey();

要根据现有DER字符串构造私钥,请调用buildPrivateFromDer()

// 根据现有DER字符串构建私钥
const privateKey = await keyBuilder.buildPrivateFromDer(privateKeyDer);
const publicKey = privateKey.getPublicKey();

步骤3: 创建签名上下文构建器

const builder = crypto.makeSignatureContextBuilder();
builder.signingAlgorithm = crypto.getAsymmetricAlgorithmByName(AsymmetricAlgorithm.ECDSA);

步骤4: 对消息进行签名并获取签名

// 使用私钥构建签名上下文
const signer = builder.buildSigningContext(privateKey);
const message = '这是一条非常重要的消息';
const messageBuffer = new TextEncoder().encode(message).buffer;

// 对消息签名
const signedMessage = await signer.sign(messageBuffer);

步骤5: 使用签名验证消息

// 使用公钥构建验证上下文
const verifier = builder.buildVerificationContext(publicKey);

// 验证消息
const result = await verifier.verify(messageBuffer, signedMessage);

RSA签名和验证

以下示例代码包括RSA密钥对生成、消息签名和验证。

步骤1: 创建RSA密钥构建器

// 创建RSA密钥构建器
const keybuilder = crypto.makeRsaKeyBuilder();
// 将密钥标记为可导出
keyBuilder.exportable = true;
// 设置密钥用途
keyBuilder.purposes = [KeyPurpose.SIGN, KeyPurpose.VERIFY];

步骤2: 生成密钥对

您可以生成RSA密钥对或构造私钥。

要生成RSA密钥对,请调用buildGenerated()

// 生成RSA密钥对
const privateKey = await keyBuilder.buildGenerated();
// 获取公钥
const publicKey = privateKey.getPublicKey();

要根据现有DER字符串构造私钥,请调用buildPrivateFromDer()

// 根据现有DER字符串构建私钥
const privateKey = await keyBuilder.buildPrivateFromDer(privateKeyDer);
const publicKey = privateKey.getPublicKey();

步骤3: 创建签名上下文构建器并对消息进行签名

通过调用buildSigningContext() 创建签名上下文构建器,然后使用RSA-PKCS1 v1.5架构对消息进行签名以获取签名。

// 使用私钥构建签名上下文
const builder = crypto.makeRsassaPkcs1ContextBuilder();
const digestAlgorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);
builder.digestAlgorithm = digestAlgorithm;
const rsaPkcs1Signer = builder.buildSigningContext(privateKey);
const message = '这是一条非常重要的消息';
const messageBuffer = new TextEncoder().encode(message).buffer;

// 对消息签名
const signedMessage = await rsaPkcs1Signer.sign(messageBuffer);

步骤4: 验证消息

通过调用使用RSA-PKCS1 v1.5标准的rsaPkcs1Verifier.verify() 来使用签名进行消息验证。

// 使用公钥构建验证上下文
const rsaPkcs1Verifier = builder.buildVerificationContext(publicKey);

// 验证消息
const result = await rsaPkcs1Verifier.verify(messageBuffer, signedMessage);

步骤5: 对消息签名并获得签名

要使用RSA-PSS标准对消息进行签名,请调用rsaPssSigner.sign(),它会返回已签名消息的签名。

// 为了保证填充机制正确并提升安全性,盐值的长度通常应与摘要长度保持一致。
// 使用不同的盐值长度可能也能工作,但不建议这样做。
builder.saltLength = digestAlgorithm.size / 8;
// 使用私钥构建签名上下文
const rsaPssSigner = builder.buildSigningContext(privateKey);
const message = '这是一条非常重要的消息';
const messageBuffer = new TextEncoder().encode(message).buffer;

// 对消息签名
const signedMessage = await rsaPssSigner.sign(messageBuffer);

要验证消息,请调用rsaPssVerifier.verify() 并传递消息的签名。

// 使用公钥构建验证上下文
const rsaPssVerifier = builder.buildVerificationContext(publicKey);

// 验证消息
const result = await rsaPssVerifier.verify(messageBuffer, signedMessage);

HMAC签名和验证

以下示例说明如何生成密钥、导出密钥、对数据签名并进行验证。

// 生成密钥
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
keyBuilder.bits = 256;
const key = await keyBuilder.buildGenerated();

// 导出密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 获取摘要算法
const digestAlgorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);

// 使用密钥和摘要算法创建HMAC上下文构建器
const builder = crypto.makeHmacContextBuilder();
builder.key = key;
builder.digestAlgorithm = digestAlgorithm;

// 对数据签名
const signContext = builder.build();
const tag = await signContext.sign(plaintext);

// 验证数据
const verifyContext = builder.build();
const tag = signContext.sign(plaintext);
const result1 = await verifyContext.verify(plaintext, tag);

// 尝试使用导出的密钥进行验证
const exportedBuilder = crypto.makeHmacContextBuilder();
exportedBuilder.key = exportedKey;
exportedBuilder.digestAlgorithm(digestAlgorithm);
const exportedVerifyContext = exportedBuilder.build();
const result2 = await exportedVerifyContext.verify(plaintext, tag);

使用AES CBC分组密码对消息进行加密

以下示例说明如何生成AES-256密钥、导出密钥、创建AES-256 CBC密码上下文构建器,以及如何使用它对明文进行加密。

// 生成AES-256密钥
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.bits = 256;
keyBuilder.exportable = true;
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
keyBuilder.purposes = purposes;
const key = await keyBuilder.buildGenerated();

// 导出AES密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = purposes;
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 创建AES-256 CBC密码上下文构建器
const builder = crypto.makeCbcCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));

// 设置正确的IV
const iv = new Uint8Array(builder.ivSize).buffer;
builder.iv = iv;
// 设置密钥
builder.key = key;

// 加密明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const encryptionContext = builder.buildEncryptionContext();
const ciphertext = await encryptionContext.encrypt(plaintextBuffer);

// 将密文解密
const decryptionContext = builder.buildDecryptionContext();
const decrypted = await decryptionContext.decrypt(ciphertext);
const result1 = plaintext === new TextDecoder('utf-8').decode(decrypted);

// 尝试使用导出的密钥然后用它将密文解密
const exportedBuilder = crypto.makeCbcCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));
exportedBuilder.iv = iv;
exportedBuilder.key = exportedKey;
const exportedDecryptionContext = exportedBuilder.buildDecryptionContext();
const exportedDecrypted = await exportedDecryptionContext.decrypt(ciphertext);

使用AES CTR分组密码对消息进行加密

以下示例说明如何生成AES-CTR密钥、导出密钥、创建AES-256 CTR密码上下文构建器,以及如何使用它对明文进行加密。

// 生成AES-256密钥
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = purposes;
keyBuilder.bits = 256;
const key = await keyBuilder.buildGenerated();

// 导出AES密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = purposes;
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 创建AES CTR密码上下文构建器
const builder = crypto.makeCtrCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));
// 设置正确的计数和随机数
builder.count = 12;
builder.nonce = 12;
// 设置密钥
builder.key = key;

// 加密明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const encryptionContext = builder.buildEncryptionContext();
const ciphertext = await encryptionContext.encrypt(plaintextBuffer);

// 将密文解密
const decryptionContext = builder.buildDecryptionContext();
const decrypted = await decryptionContext.decrypt(ciphertext);
const result1 = plaintext === new TextDecoder('utf-8').decode(decrypted);

// 将导出的密钥与CTR密码上下文构建器一起使用
builder.key = exportedKey;

// 尝试使用导出的密钥解密
const exportedDecryptionContext = builder.buildDecryptionContext();
const exportedDecrypted = await exportedDecryptionContext.decrypt(ciphertext);
const result2 = plaintext === new TextDecoder('utf-8').decode(exportedDecrypted);

使用AES GCM分组密码对消息进行加密

以下示例说明如何生成AES-256 GCM密钥、导出密钥、创建AES-256 GCM密码上下文构建器,以及如何使用它对明文进行加密。

// 生成AES-256密钥
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = purposes;
keyBuilder.bits = 256;
const key = await keyBuilder.buildGenerated();

// 导出AES密钥
const rawKey = key.exportRaw();
const exportedKeyBuilder = crypto.makeSymmetricKeyBuilder();
exportedKeyBuilder.exportable = true;
exportedKeyBuilder.purposes = purposes;
const exportedKey = await exportedKeyBuilder.buildFromRaw(rawKey);

// 创建AES-256 GCM密码上下文构建器
const builder = crypto.makeGcmCipherContextBuilder(crypto.getSymmetricAlgorithmByName(SymmetricAlgorithm.AES256));

// 使用4字节标识符初始化IV以使用随机化的
// 随机数序列。或者,使用大小为builder.getIvSize() 的向量对其进行初始化
// 以使用任意随机数。
const iv = new Uint8Array([0xab, 0xcd, 0xef, 0x01]);

builder.iv = iv;
builder.key = key;

// 加密明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const encryptionContext = builder.buildEncryptionContext();
const ciphertext = await encryptionContext.encrypt(plaintextBuffer);

// 将密文解密
const decryptionContext = builder.buildDecryptionContext();
const decrypted = await decryptionContext.decrypt(ciphertext);

// 将导出的密钥与GCM密码上下文构建器一起使用
builder.key = exportedKey;
// 尝试使用导出的密钥解密
const exportedDecryptionContext = builder.buildDecryptionContext();
const exportedDecrypted = await exportedDecryptionContext.decrypt(ciphertext);

使用RSA-OAEP加密消息

以下示例说明如何生成RSA-OAEP密钥、导出密钥、创建上下文构建器,以及如何使用它对明文进行加密。

// 获取摘要算法和非对称算法,并定义密钥用途
const sha = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA384);
const alg = crypto.getAsymmetricAlgorithmByName(AsymmetricAlgorithm.RSA_OAEP);
const purposes = [KeyPurpose.ENCRYPT, KeyPurpose.DECRYPT];

// 创建一个RsaOaepKeyBuilder
const keyBuilder = crypto.makeRsaOaepKeyBuilder();
keyBuilder.exportable = true;
keyBuilder.purposes = purposes;
keyBuilder.bits = 384;

// 从密钥构建器生成私钥
const privateKey = await keyBuilder.buildGenerated();

// 导出密钥供以后的测试案例使用
const rawPrivateKey = await privateKey.exportDer();

// 获取对应的公钥
const publicKey = privateKey.getPublicKey();

// 导出公钥以备后用
const rawPublicKey = await publickey.exportDer();

// 根据消息构建明文
const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;

// 使用alg和sha构建RSA-OAEP密码上下文
const rsaOaepCipherContext = crypto.makeRsaOaepCipherContextBuilder(alg, sha);

// 使用公钥基于RSA-OAEP密码上下文构建加密上下文
const rsaOaepEncryptionContext = rsaOaepCipherContext.buildEncryptionContext(publickey);

// 使用加密上下文加密
const ciphertext = await rsaOaepEncryptionContext.encrypt(plaintextBuffer);

// 基于密码上下文构建解密上下文
const rsaOaepDecryptionContext = rsaOaepCipherContext.buildDecryptionContext(privatekey);

// 使用解密上下文进行解密
const decrypted = await rsaOaepDecryptionContext.decrypt(ciphertext);

// 确保解密后的消息与明文相同
const result1 = plaintext === new TextDecoder('utf-8').decode(decrypted);

// 使用导出的密钥来构建私钥和公钥
const exportedPrivkey = await keyBuilder.buildPrivateFromDer(rawPrivateKey);
const exportedRsaOaepDecryptionContext = rsaOaepCipherContext.buildDecryptionContext(exportedPrivkey);

// 使用导入的密钥解密密文并确保解密后的消息与明文一致
const exportedDecrypted = await exportedRsaOaepDecryptionContext.decrypt(ciphertext);
const result2 = plaintext === new TextDecoder('utf-8').decode(exportedDecrypted);

// 使用导入的公钥进行加密,使用原始私钥进行解密
// 并确保解密后的消息与明文一致
const exportedPublicKey = await keyBuilder.buildPublicFromDer(rawPublicKey);
const exportedRsaOaepEncryptionContext = rsaOaepCipherContext.buildEncryptionContext(exportedPublicKey);
const exportedCiphertext = await exportedRsaOaepEncryptionContext.encrypt(plaintextBuffer);
const exportedDecryptedAgain = await rsaOaepDecryptionContext.decrypt(exportedCiphertext);
const result3 = plaintext === new TextDecoder('utf-8').decode(exportedDecryptedAgain);

创建消息摘要

以下代码示例调用getDigestAlgorithmByName() 来获取摘要,创建摘要上下文,对示例字符串进行编码,并获取该字符串的摘要。

const builder = crypto.makeDigestContextBuilder();
builder.digestAlgorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);
const digestContext = builder.build();

const plaintext = '使用此字符串';
const plaintextBuffer = new TextEncoder().encode(plaintext).buffer;
const hash = await digestContext.digest(plaintextBuffer);

使用HKDF(HMAC密钥派生函数)派生密钥

const salt = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const info = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // 来自密钥的额外信息

// 创建密钥(如果您已经有了一个用于DERIVE的密钥,则为可选项)
const keyBuilder = crypto.makeSymmetricKeyBuilder();
keyBuilder.bits = 256; // 任意长度
keyBuilder.exportable = false;
keyBuilder.purposes = [KeyPurpose.DERIVE]; // 重要须知:密钥必须能够派生
const secret = await keyBuilder.buildGenerated();
const algorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);

// 创建上下文构建器
const ctxBuilder = crypto.makeHkdfContextBuilder();
ctxBuilder.info = info;
ctxBuilder.salt = salt;
ctxBuilder.hashAlgorithm = algorithm;
// 创建派生上下文
const ctx = ctxBuilder.buildKeyDerivationContext(secret);

// 派生对称密钥
// 重要须知:派生的密钥必须与所用算法的长度相匹配
const generatedKeyLen = algorithm.size / 8;
const symmKey = ctx.deriveKey(generatedKeyLen);

// 改为派生一个原始密钥
const rawKey = ctx.deriveBits(generatedKeyLen);

使用PBKDF2(基于密码的密钥派生函数2)派生密钥

const iterations = 10000; // 迭代次数。值越高越安全,但性能越低。
                          // 10000是一个合理的值,不会导致性能下降太多
const salt = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const generatedKeyLen = 512;

// 创建上下文构建器
const ctxBuilder = crypto.makePbkdf2ContextBuilder();

// 创建密钥(如果您已经有了一个用于DERIVE的密钥,则为可选项)
const keyBuilder = crypto.makeSymmetricKeyBuilder()
keyBuilder.bits = 256;  // 任意长度
keyBuilder.exportable = false;
keyBuilder.purposes = [KeyPurpose.DERIVE];  // 重要须知:密钥必须能够派生
const secret = await keyBuilder.buildGenerated();

const algorithm = crypto.getDigestAlgorithmByName(DigestAlgorithm.SHA256);

// 创建派生上下文
ctxBuilder.iterations = iterations;
ctxBuilder.salt = salt;
ctxBuilder.hashAlgorithm = algorithm;
const ctx = buildKeyDerivationContext(secret);

// 派生对称密钥
const symmKey = await ctx.deriveKey(generatedKeyLen);

// 改为派生一个原始密钥
const rawKey = await ctx.deriveBits(generatedKeyLen);

网页加密API shim层

KeplerCrypto库提供了一个shim层,用于实现网页加密API(仅提供英文版)。有关API方法和参数,请参阅现有的网页加密API MDN文档

网页加密用法示例

以下示例介绍如何导入和使用网页加密API shim层:

导入API

import {WebCrypto} from '@amazon-devices/keplercrypto';

初始化WebCrypto对象

const wc = new WebCrypto();

可选: 在globalThis上公开crypto实例

// 如果globalThis不存在,则定义它
if (typeof globalThis === 'undefined') {
  (window as any).globalThis = window;
}
globalThis.crypto = wc.crypto as any;

调用网页加密API

下一个代码示例生成ECDH CryptoKeyPair

const nonExtractableKeyPair = (await wc.crypto.subtle.generateKey(
  {
    name: 'ECDH',
    namedCurve: 'P-256',
  },
  false, // 不可提取
  ['deriveBits'],
)) as CryptoKeyPair;

支持的网页加密算法

该库仍在开发中,网页加密实现仅提供整个W3C网页加密规范的一个子集。未来版本将支持更多操作。

网页加密支持的密钥格式

使用网页加密API导入和导出密钥时,支持以下格式:

密钥类型 支持的导入格式 支持的导出格式
AES raw、jwk raw、jwk
HMAC raw、jwk raw、jwk
ECDH pkcs8、spki、jwk pkcs8、spki、jwk
ECDSA pkcs8、spki、jwk pkcs8、spki、jwk
HKDF raw raw
PBKDF2 raw raw
RSASSA-PKCS1-v1_5 pkcs8、spki、jwk pkcs8、spki、jwk
RSA-PSS pkcs8、spki、jwk pkcs8、spki、jwk
RSA-OAEP pkcs8、spki、jwk pkcs8、spki、jwk

格式描述:

  • raw: 未格式化的二进制数据,用于对称密钥或椭圆曲线公钥。
  • pkcs8: RSA或椭圆曲线私钥的PKCS #8格式。
  • spki: RSA或椭圆曲线公钥的SubjectPublicKeyInfo格式。
  • jwk: 对称密钥或RSA和椭圆曲线公钥/私钥的JSON网页密钥格式。

导入密钥的示例:

// 导入原始格式的AES密钥
const rawKey = new Uint8Array([...]);  // 您的密钥字节
const importedKey = await wc.crypto.subtle.importKey(
  "raw",                // 格式
  rawKey,               // 密钥数据
  { name: "AES-GCM" },  // 算法
  false,                // 可提取
  ["encrypt", "decrypt"] // 密钥用法
);

网页加密API支持矩阵

算法操作:

  • ✓ = 支持
  • ✗ = 不支持
  • — = 不适用
算法 encrypt() decrypt() sign() verify() digest() importKey() exportKey() generateKey() deriveBits() deriveKey() wrapKey() unwrapKey()
RSASSA-PKCS1v1
RSA-PSS
RSA-OAEP
ECDH
ECDSA
AES-CTR
AES-CBC
AES-GCM
AES-KW
HMAC
HKDF
PBKDF2
Ed25519
X25519
SHA-1
SHA-256
SHA-384
SHA-512

模块


Last updated: 2025年10月2日