我刚开始摆弄密码学,我试图用以太坊钱包公钥加密文档,然后用同一个钱包的私钥解密它。
我有这些功能来实现:
import { stringToWordArray, wordArrayToArrayBuffer, wordArrayToUint8Array } from "./utls";
import { ethers, utils, providers } from 'ethers';
import * as CryptoJS from 'crypto-js';
// Generate a random symmetric key
export const generateSymmetricKey = async (): Promise<{ key: string; iv: string }> => {
const key = CryptoJS.lib.WordArray.random(256 / 8).toString(CryptoJS.enc.Hex);
const iv = CryptoJS.lib.WordArray.random(128 / 8).toString(CryptoJS.enc.Hex);
return { key, iv };
};
// Encrypt a document using a symmetric key
export const encryptDocument = async (publicKey: string, document: Blob, iv: CryptoJS.lib.WordArray): Promise<string> => {
// Convert document to WordArray
const fileReader = new FileReader();
fileReader.readAsArrayBuffer(document);
const arrayBuffer = await new Promise<ArrayBuffer>((resolve) => {
fileReader.onload = (event) => {
if (event.target) {
resolve(event.target.result as ArrayBuffer);
}
};
});
const uint8Array = new Uint8Array(arrayBuffer);
const array = Array.from(uint8Array, (byte) => byte);
const wordArray = CryptoJS.lib.WordArray.create(array);
// Generate random AES key
const aesKey = CryptoJS.lib.WordArray.random(256 / 8);
// Encrypt document with AES key
const encryptedDoc = CryptoJS.AES.encrypt(wordArray, aesKey, { mode: CryptoJS.mode.CBC, iv: iv });
// Encrypt AES key with recipient's public key
const encryptedAesKey = CryptoJS.enc.Base64.stringify(CryptoJS.AES.encrypt(
aesKey.toString(),
publicKey,
{
mode: CryptoJS.mode.CBC,
iv: iv
},
).ciphertext);
// Return concatenated encrypted AES key and encrypted document
return `${encryptedAesKey}\n${encryptedDoc}`;
}
// Function to decrypt document
export const decryptDocument = async (encryptedDocument: string, decryptedSymmetricKey: CryptoJS.lib.WordArray, iv: CryptoJS.lib.WordArray): Promise<ArrayBuffer> => {
// Convert the encrypted document to a WordArray
const encryptedWordArray = CryptoJS.enc.Hex.parse(encryptedDocument);
// Decrypt the document using the decrypted symmetric key and IV
const decryptedDocumentWordArray = CryptoJS.AES.decrypt(
CryptoJS.lib.CipherParams.create({ ciphertext: encryptedWordArray }),
decryptedSymmetricKey,
{ iv: iv }
);
// Convert the decrypted document to an ArrayBuffer
const decryptedData = new Uint8Array(decryptedDocumentWordArray.words);
return decryptedData.buffer;
}
// Encrypt a symmetric key using the Ethereum wallet public key
export const encryptSymmetricKey = async (publicKey: string, symmetricKey: CryptoJS.lib.WordArray, iv: CryptoJS.lib.WordArray): Promise<string> => {
const aesKey = CryptoJS.enc.Base64.stringify(symmetricKey);
const aesIv = CryptoJS.enc.Base64.stringify(iv);
const provider = new ethers.providers.AlchemyProvider('mainnet', 'SF*************9A');
const wallet = ethers.Wallet.createRandom().connect(provider);
const encrypted = await wallet.encrypt(JSON.stringify({ key: aesKey, iv: aesIv }), { publicKey });
return encrypted;
}
// Decrypt a symmetric key using the Ethereum wallet private key
export const decryptSymmetricKey = async (privateKey: string, encryptedSymmetricKey: string, iv: string): Promise<{ key: CryptoJS.lib.WordArray; iv: CryptoJS.lib.WordArray }> => {
// Decrypt encrypted symmetric key with private key
// const encryptedJson = JSON.parse(encryptedSymmetricKey);
const wallet = await ethers.Wallet.fromEncryptedJson(encryptedSymmetricKey, privateKey);
console.log('Wallet: ', wallet)
// Decrypt AES key from encrypted data
const decryptedAesKey = CryptoJS.enc.Utf8.parse(wallet.privateKey.slice(2));
const ivWordArray = CryptoJS.enc.Hex.parse(iv);
return {
key: decryptedAesKey,
iv: ivWordArray,
};
}
然后我在以下测试函数中测试它们:
async function test(file: Blob) {
const wallet = ethers.Wallet.createRandom();
const { key, iv } = await generateSymmetricKey();
const encryptedDocument = await encryptDocument(wallet.publicKey, file, stringToWordArray(iv));
const encryptedSymmetricKey = await encryptSymmetricKey(wallet.publicKey, stringToWordArray(key), stringToWordArray(iv));
console.log('encryptedDocument: ', encryptedDocument)
console.log('encryptedSymmetricKey: ', encryptedSymmetricKey)
// Decrypt the symmetric key using the ethereum wallet private key
const decryptedSymmetricKey = await decryptSymmetricKey(wallet.privateKey, encryptedSymmetricKey, iv);
// Decrypt the document using the decrypted symmetric key
const decryptedDocument = await decryptDocument(encryptedDocument, decryptedSymmetricKey.key, decryptedSymmetricKey.iv);
console.log('decryptedSymmetricKey: ', decryptedSymmetricKey)
console.log('decryptedDocument: ', decryptedDocument)
}
我能够成功加密文档和对称密钥。因此,当记录它们时,我得到类似这样的 encryptedDocument 的东西,它是非常长的字符串。
encryptedDocument: atsbkigb2TrbyAe3kJ0uyBgAAku/Pllua83TJao018fmCmbZ6WCA/qVdO7dEf7SUdvpxPA/wq6aJkP1K61831sKLZORI3TrA0szGi3RjnC4=
aTsKhdzRufdtFmtirmdm5S4a8ppf+OSix6Rnr7QNzBzpZ9cqvpl/UuR0pphtCeW1xR8Bq6nPb26WxvrWlUaa2F855S1K0J0wzpeyYHnYBEGairjgU7vkemP2gVB9iOm76J2Hhd7t2aSJg7Ds4vBKwdlmbPP+vVmyl4YFSbi1vz20+4T7N/P7sC5VIKva5Y8738qtvt2l1vpg...
对于加密的对称密钥:
{"address":"7bd44*****************6eee81","id":"3e9dbab7-cda1-44d3-9b75-0d653b775264","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"cc5c23****************626d0"},"ciphertext":"873******************9d97bc3c40","kdf":"scrypt","kdfparams":{"salt":"5114b**********************11a93b64","n":131072,"dklen":32,"p":1,"r":8},"mac":"ded3de**********ed2e18033a"},"x-ethers":{"client":"ethers.js","gethFilename":"UTC--2023-02-23T08-09-41.0Z--7bd44a2656bc6fa08ab07e12034a2c94936eee81","mnemonicCounter":"88d13d*********19fd9540","mnemonicCiphertext":"74643be**********03ae0e6e","path":"m/44'/60'/0'/0/0","locale":"en","version":"0.1"}}
当我尝试解密对称密钥时出现问题。所以在
decryptSymmetricKey
函数中,错误发生在这一行:
const wallet = await ethers.Wallet.fromEncryptedJson(encryptedSymmetricKey, privateKey);
Error: invalid password
看来以太坊钱包的privateKey是不正确的
我不确定我在哪里犯了错误,因为我确定我正在从同一个以太坊钱包传递用于加密的公钥和用于解密的私钥。