diff --git a/src/crypto.ts b/src/crypto.ts index 109b285..d28e586 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -30,7 +30,17 @@ export async function generateRsaKeyPair(): Promise { // keys are extractable. // remove this - return { publicKey: {} as any, privateKey: {} as any }; + const { publicKey, privateKey } = await webcrypto.subtle.generateKey( + { + name: "RSA-OAEP", + modulusLength: 2048, + publicExponent: new Uint8Array([1, 0, 1]), + hash: { name: "SHA-256" }, + }, + true, + ["encrypt", "decrypt"] + ); + return { publicKey, privateKey }; } // Export a crypto public key to a base64 string format @@ -38,63 +48,108 @@ export async function exportPubKey(key: webcrypto.CryptoKey): Promise { // TODO implement this function to return a base64 string version of a public key // remove this - return ""; + const exportedKey = await webcrypto.subtle.exportKey("spki", key); + return arrayBufferToBase64(exportedKey); } // Export a crypto private key to a base64 string format export async function exportPrvKey( - key: webcrypto.CryptoKey | null + key: webcrypto.CryptoKey | null ): Promise { // TODO implement this function to return a base64 string version of a private key // remove this - return ""; + if (key === null) { + return null; + } + const exportedKey = await webcrypto.subtle.exportKey("pkcs8", key); + return arrayBufferToBase64(exportedKey); } + + // Import a base64 string public key to its native format export async function importPubKey( - strKey: string + strKey: string ): Promise { // TODO implement this function to go back from the result of the exportPubKey function to it's native crypto key object // remove this - return {} as any; + const keyBuffer = base64ToArrayBuffer(strKey); + return await webcrypto.subtle.importKey( + "spki", + keyBuffer, + { + name: "RSA-OAEP", + hash: "SHA-256", + }, + true, + ["encrypt"] + ); } // Import a base64 string private key to its native format export async function importPrvKey( - strKey: string + strKey: string ): Promise { // TODO implement this function to go back from the result of the exportPrvKey function to it's native crypto key object // remove this - return {} as any; + const keyBuffer = base64ToArrayBuffer(strKey); + return await webcrypto.subtle.importKey( + "pkcs8", + keyBuffer, + { + name: "RSA-OAEP", + hash: "SHA-256", + }, + true, + ["decrypt"] + ); } // Encrypt a message using an RSA public key export async function rsaEncrypt( - b64Data: string, - strPublicKey: string + b64Data: string, + strPublicKey: string ): Promise { // TODO implement this function to encrypt a base64 encoded message with a public key // tip: use the provided base64ToArrayBuffer function // remove this - return ""; + const data = base64ToArrayBuffer(b64Data); + const publicKey = await importPubKey(strPublicKey); + const encryptedData = await webcrypto.subtle.encrypt( + { + name: "RSA-OAEP", + }, + publicKey, + data + ); + return arrayBufferToBase64(encryptedData); } // Decrypts a message using an RSA private key export async function rsaDecrypt( - data: string, - privateKey: webcrypto.CryptoKey + data: string, + privateKey: webcrypto.CryptoKey ): Promise { // TODO implement this function to decrypt a base64 encoded message with a private key // tip: use the provided base64ToArrayBuffer function // remove this - return ""; + const encryptedData = base64ToArrayBuffer(data); + const decryptedData = await webcrypto.subtle.decrypt( + { + name: "RSA-OAEP", + }, + privateKey, + encryptedData + ); + return arrayBufferToBase64(decryptedData); } + // ###################### // ### Symmetric keys ### // ###################### @@ -106,45 +161,96 @@ export async function createRandomSymmetricKey(): Promise { // keys are extractable. // remove this - return {} as any; + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + return key; } + // Export a crypto symmetric key to a base64 string format export async function exportSymKey(key: webcrypto.CryptoKey): Promise { // TODO implement this function to return a base64 string version of a symmetric key // remove this - return ""; + const exportedKey = await webcrypto.subtle.exportKey("raw", key); + return arrayBufferToBase64(exportedKey); } // Import a base64 string format to its crypto native format export async function importSymKey( - strKey: string + strKey: string ): Promise { // TODO implement this function to go back from the result of the exportSymKey function to it's native crypto key object // remove this - return {} as any; + const keyBuffer = base64ToArrayBuffer(strKey); + const key = await webcrypto.subtle.importKey( + "raw", + keyBuffer, + { + name: "AES-CBC", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + return key; } // Encrypt a message using a symmetric key export async function symEncrypt( - key: webcrypto.CryptoKey, - data: string + key: webcrypto.CryptoKey, + data: string ): Promise { // TODO implement this function to encrypt a base64 encoded message with a public key // tip: encode the data to a uin8array with TextEncoder - return ""; + const dataUint8Array = new TextEncoder().encode(data); + const iv = crypto.getRandomValues(new Uint8Array(16)); + const encryptedData = await webcrypto.subtle.encrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + dataUint8Array + ); + const concatenatedData = new Uint8Array([...iv, ...new Uint8Array(encryptedData)]); + const base64EncryptedData = arrayBufferToBase64(concatenatedData.buffer); + return base64EncryptedData; } + + // Decrypt a message using a symmetric key export async function symDecrypt( - strKey: string, - encryptedData: string + strKey: string, + encryptedData: string ): Promise { // TODO implement this function to decrypt a base64 encoded message with a private key // tip: use the provided base64ToArrayBuffer function and use TextDecode to go back to a string format - return ""; + const key = await importSymKey(strKey); + const encryptedDataBuffer = base64ToArrayBuffer(encryptedData); + const iv = encryptedDataBuffer.slice(0, 16); + const decryptedDataBuffer = await webcrypto.subtle.decrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + encryptedDataBuffer.slice(16) + ); + + // Convert the decrypted data to a UTF-8 string + const decryptedDataString = new TextDecoder().decode(decryptedDataBuffer); + + return decryptedDataString; }