This repository has been archived by the owner on Jul 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: use WebCrypto API instead of node crypto
Use WebCrypto API to ensure availability and operability in browser environments Closes #4
- Loading branch information
1 parent
5b19af9
commit f6573be
Showing
6 changed files
with
242 additions
and
55 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
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
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,18 +1,66 @@ | ||
import * as crypto from 'crypto'; | ||
import { Crypto } from '@peculiar/webcrypto'; | ||
import { pack, encode, str2ab } from './util'; | ||
|
||
export function encryptData( | ||
const crypto = new Crypto(); | ||
|
||
async function importRsaKey(pemBase64Encoded: string): Promise<CryptoKey> { | ||
const pem = window.atob(pemBase64Encoded); | ||
// fetch the part of the PEM string between header and footer | ||
const pemHeader = '-----BEGIN PUBLIC KEY-----'; | ||
const pemFooter = '-----END PUBLIC KEY-----'; | ||
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length); | ||
// base64 decode the string to get the binary data | ||
const binaryDerString = window.atob(pemContents); | ||
// convert from a binary string to an ArrayBuffer | ||
const binaryDer = str2ab(binaryDerString); | ||
|
||
return crypto.subtle.importKey( | ||
'spki', | ||
binaryDer, | ||
{ | ||
name: 'RSA-OAEP', | ||
hash: 'SHA-256', | ||
}, | ||
true, | ||
['encrypt'], | ||
); | ||
} | ||
|
||
export async function encryptData( | ||
keyOfHealthDepartment: string, | ||
data, | ||
): { dataToTransport: string; keyToTransport: string; nonce: string } { | ||
const nonce = crypto.randomBytes(16); | ||
const key = crypto.randomBytes(32); | ||
const cipher = crypto.createCipheriv('AES-256-CBC', key, nonce); | ||
): Promise<{ dataToTransport: string; keyToTransport: string; nonce: string }> { | ||
const nonce = crypto.getRandomValues(new Uint8Array(16)); | ||
const key = await crypto.subtle.generateKey( | ||
{ | ||
name: 'AES-GCM', | ||
length: 256, | ||
}, | ||
true, | ||
['encrypt'], | ||
); | ||
const publicKey = await importRsaKey(keyOfHealthDepartment); | ||
|
||
const dataString = JSON.stringify(data); | ||
const encryptedData = Buffer.concat([cipher.update(dataString, 'utf8'), cipher.final()]); | ||
const encryptedKey = crypto.publicEncrypt({ key: Buffer.from(keyOfHealthDepartment, 'base64') }, key); | ||
const encryptedData = await crypto.subtle.encrypt( | ||
{ | ||
name: 'AES-GCM', | ||
iv: nonce, | ||
}, | ||
key, | ||
encode(dataString), | ||
); | ||
|
||
const encryptedKey = await crypto.subtle.encrypt( | ||
{ | ||
name: 'RSA-OAEP', | ||
}, | ||
publicKey, | ||
await crypto.subtle.exportKey('raw', key), | ||
); | ||
return { | ||
dataToTransport: encryptedData.toString('base64'), | ||
keyToTransport: encryptedKey.toString('base64'), | ||
nonce: nonce.toString('base64'), | ||
dataToTransport: pack(encryptedData), | ||
keyToTransport: pack(encryptedKey), | ||
nonce: pack(nonce), | ||
}; | ||
} |
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,14 +1,47 @@ | ||
import * as crypto from 'crypto'; | ||
import * as md5 from 'md5'; | ||
|
||
export function getNameCheckHash(firstName: string, lastName: string): string { | ||
const str = `${firstName.trim()}${lastName.trim()}`.toLowerCase().replace(/\W/g, ''); | ||
return crypto.createHash('md5').update(str).digest('base64'); | ||
return md5(str); | ||
} | ||
export function getBirthDateCheckHash(birthDate?: string): string | undefined { | ||
if (!birthDate) { | ||
return undefined; | ||
} | ||
const date = new Date(birthDate); | ||
const str = `${date.getFullYear()}${(date.getMonth() + 1).toString().padStart(2, '0')}${date.getDate().toString().padStart(2, '0')}` | ||
return crypto.createHash('md5').update(str).digest('base64'); | ||
const str = `${date.getFullYear()}${(date.getMonth() + 1) | ||
.toString() | ||
.padStart(2, '0')}${date.getDate().toString().padStart(2, '0')}`; | ||
return md5(str); | ||
} | ||
|
||
export function encode(data: string): Uint8Array { | ||
const encoder = new TextEncoder(); | ||
return encoder.encode(data); | ||
} | ||
|
||
export function decode(data: Uint8Array): string { | ||
const decoder = new TextDecoder('utf8'); | ||
return decoder.decode(data); | ||
} | ||
|
||
export function str2ab(str: string): ArrayBuffer { | ||
const buf = new ArrayBuffer(str.length); | ||
const bufView = new Uint8Array(buf); | ||
for (let i = 0, strLen = str.length; i < strLen; i++) { | ||
bufView[i] = str.charCodeAt(i); | ||
} | ||
return buf; | ||
} | ||
|
||
export function ab2str(buf: ArrayBuffer): string { | ||
return String.fromCharCode.apply(null, new Uint8Array(buf)); | ||
} | ||
|
||
export function pack(buffer: ArrayBuffer): string { | ||
return window.btoa(ab2str(buffer)); | ||
} | ||
|
||
export function unpack(packed: string): ArrayBuffer { | ||
return str2ab(window.atob(packed)); | ||
} |
Oops, something went wrong.