mirror of
https://github.com/cupcakearmy/occulto.git
synced 2024-12-22 09:46:28 +00:00
rely on native api
This commit is contained in:
parent
a015d4f46a
commit
4f17d72ea7
164
src/AES.ts
164
src/AES.ts
@ -1,164 +0,0 @@
|
||||
import forge from 'node-forge'
|
||||
|
||||
export enum Ciphers {
|
||||
AES_256_GCM,
|
||||
AES_192_GCM,
|
||||
AES_128_GCM,
|
||||
AES_256_CTR,
|
||||
AES_192_CTR,
|
||||
AES_128_CTR,
|
||||
AES_256_CBC,
|
||||
AES_192_CBC,
|
||||
AES_128_CBC,
|
||||
}
|
||||
|
||||
type CipherConfig = {
|
||||
alg: forge.cipher.Algorithm,
|
||||
saltSize: number
|
||||
keySize: number
|
||||
tagSize: number
|
||||
it: number
|
||||
}
|
||||
|
||||
type EncryptedItem = {
|
||||
alg: forge.cipher.Algorithm,
|
||||
data: string,
|
||||
keySize: number,
|
||||
iv: string,
|
||||
it: number
|
||||
salt: string,
|
||||
tag: string,
|
||||
tagSize: number,
|
||||
}
|
||||
|
||||
export default class AES {
|
||||
|
||||
static Ciphers = Ciphers
|
||||
|
||||
static encrypt(data: string, key: string, type: Ciphers = Ciphers.AES_256_GCM): string {
|
||||
const { alg, it, keySize, saltSize, tagSize } = AES.getCipherConfig(type)
|
||||
const salt = forge.random.getBytesSync(saltSize)
|
||||
const iv = forge.random.getBytesSync(keySize)
|
||||
|
||||
const cipher = forge.cipher.createCipher(
|
||||
alg,
|
||||
forge.pkcs5.pbkdf2(key, salt, it, keySize),
|
||||
)
|
||||
|
||||
cipher.start({
|
||||
iv,
|
||||
tagLength: tagSize,
|
||||
})
|
||||
cipher.update(forge.util.createBuffer(data))
|
||||
cipher.finish()
|
||||
|
||||
const encrypted: EncryptedItem = {
|
||||
alg,
|
||||
data: forge.util.hexToBytes(cipher.output.toHex()),
|
||||
keySize,
|
||||
iv,
|
||||
it,
|
||||
salt,
|
||||
tag: forge.util.hexToBytes(cipher.mode.tag.toHex()),
|
||||
tagSize,
|
||||
}
|
||||
|
||||
return Buffer.from(JSON.stringify(encrypted)).toString('base64')
|
||||
}
|
||||
|
||||
static decrypt(e: string, key: string): string {
|
||||
const { alg, data, keySize, iv, it, salt, tag, tagSize }: EncryptedItem = JSON.parse(Buffer.from(e, 'base64').toString())
|
||||
|
||||
const cipher = forge.cipher.createCipher(
|
||||
alg,
|
||||
forge.pkcs5.pbkdf2(key, salt, it, keySize),
|
||||
)
|
||||
|
||||
cipher.start({
|
||||
iv,
|
||||
tag: new forge.util.ByteStringBuffer(tag),
|
||||
tagLength: tagSize,
|
||||
})
|
||||
cipher.update(new forge.util.ByteStringBuffer(data))
|
||||
cipher.finish()
|
||||
|
||||
return cipher.output.toString()
|
||||
}
|
||||
|
||||
private static getCipherConfig = (type: Ciphers): CipherConfig => {
|
||||
switch (type) {
|
||||
case Ciphers.AES_128_GCM:
|
||||
return {
|
||||
alg: 'AES-GCM',
|
||||
saltSize: 128,
|
||||
keySize: 16,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_192_GCM:
|
||||
return {
|
||||
alg: 'AES-GCM',
|
||||
saltSize: 128,
|
||||
keySize: 24,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_256_GCM:
|
||||
return {
|
||||
alg: 'AES-GCM',
|
||||
saltSize: 128,
|
||||
keySize: 32,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_128_CBC:
|
||||
return {
|
||||
alg: 'AES-CBC',
|
||||
saltSize: 128,
|
||||
keySize: 16,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_192_CBC:
|
||||
return {
|
||||
alg: 'AES-CBC',
|
||||
saltSize: 128,
|
||||
keySize: 24,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_256_CBC:
|
||||
return {
|
||||
alg: 'AES-CBC',
|
||||
saltSize: 128,
|
||||
keySize: 32,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_128_CTR:
|
||||
return {
|
||||
alg: 'AES-CTR',
|
||||
saltSize: 128,
|
||||
keySize: 16,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_192_CTR:
|
||||
return {
|
||||
alg: 'AES-CTR',
|
||||
saltSize: 128,
|
||||
keySize: 24,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
case Ciphers.AES_256_CTR:
|
||||
return {
|
||||
alg: 'AES-CTR',
|
||||
saltSize: 128,
|
||||
keySize: 32,
|
||||
tagSize: 128,
|
||||
it: 2 ** 12,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
src/RSA.ts
39
src/RSA.ts
@ -1,39 +0,0 @@
|
||||
import forge from 'node-forge'
|
||||
import { Base64 } from './Util'
|
||||
|
||||
type PrivateKey = string
|
||||
type PublicKey = string
|
||||
|
||||
export type KeyPair = {
|
||||
pub: PublicKey
|
||||
prv: PrivateKey
|
||||
}
|
||||
|
||||
|
||||
export default class RSA {
|
||||
|
||||
static gen = (size: number = 2 ** 12): Promise<KeyPair> => new Promise<KeyPair>((resolve, reject) => {
|
||||
forge.pki.rsa.generateKeyPair({ bits: size }, function (err, keypair) {
|
||||
if (err) reject()
|
||||
else resolve({
|
||||
pub: forge.pki.publicKeyToPem(keypair.publicKey),
|
||||
prv: forge.pki.privateKeyToPem(keypair.privateKey),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
static encrypt(data: string, key: PublicKey): string {
|
||||
const obj = forge.pki.publicKeyFromPem(key)
|
||||
if (obj instanceof ArrayBuffer) throw new Error()
|
||||
|
||||
return Base64.encode(obj.encrypt(data))
|
||||
}
|
||||
|
||||
static decrypt(data: string, key: PrivateKey): string {
|
||||
const obj = forge.pki.privateKeyFromPem(key)
|
||||
if (obj instanceof ArrayBuffer) throw new Error()
|
||||
|
||||
return obj.decrypt(Base64.decode(data))
|
||||
}
|
||||
|
||||
}
|
157
src/Symmetric.ts
Normal file
157
src/Symmetric.ts
Normal file
@ -0,0 +1,157 @@
|
||||
import {
|
||||
Cipher,
|
||||
CipherCCM,
|
||||
CipherGCM,
|
||||
createCipheriv,
|
||||
createDecipheriv,
|
||||
Decipher,
|
||||
DecipherCCM,
|
||||
DecipherGCM,
|
||||
randomBytes,
|
||||
scryptSync,
|
||||
} from 'crypto'
|
||||
import { TransformOptions } from 'stream'
|
||||
|
||||
import { Base64 } from './Util'
|
||||
|
||||
export enum Ciphers {
|
||||
ChaCha20,
|
||||
ChaCha20_Poly1305,
|
||||
AES_256_GCM,
|
||||
AES_192_GCM,
|
||||
AES_128_GCM,
|
||||
AES_256_CTR,
|
||||
AES_192_CTR,
|
||||
AES_128_CTR,
|
||||
}
|
||||
|
||||
type CipherConfig = {
|
||||
alg: string,
|
||||
keySize: number,
|
||||
ivSize: number
|
||||
mac?: number
|
||||
}
|
||||
|
||||
type EncryptedItem = {
|
||||
alg: string,
|
||||
data: string,
|
||||
iv: string,
|
||||
salt: string
|
||||
keySize: number,
|
||||
tag?: string,
|
||||
tagSize?: number
|
||||
}
|
||||
|
||||
export default class Symmetric {
|
||||
|
||||
static Ciphers = Ciphers
|
||||
static Encoding: BufferEncoding = 'base64'
|
||||
|
||||
static encrypt(data: string, pass: string, type: Ciphers = Ciphers.AES_256_CTR): string {
|
||||
const { alg, ivSize, mac, keySize } = Symmetric.getCipherConfig(type)
|
||||
|
||||
const iv = randomBytes(ivSize)
|
||||
const salt = randomBytes(keySize)
|
||||
const key = scryptSync(pass, salt, keySize)
|
||||
|
||||
// @ts-ignore
|
||||
const options: TransformOptions = mac ? { authTagLength: mac } : undefined
|
||||
const cipher: CipherGCM | CipherCCM | Cipher = createCipheriv(alg, key, iv, options)
|
||||
let content: Buffer = Buffer.concat([
|
||||
cipher.update(data),
|
||||
cipher.final(),
|
||||
])
|
||||
|
||||
let tag: string | undefined = undefined
|
||||
// @ts-ignore
|
||||
if (mac) tag = cipher.getAuthTag().toString(Symmetric.Encoding)
|
||||
|
||||
const encrypted: EncryptedItem = {
|
||||
alg,
|
||||
data: content.toString(Symmetric.Encoding),
|
||||
tag,
|
||||
iv: iv.toString(Symmetric.Encoding),
|
||||
salt: salt.toString(Symmetric.Encoding),
|
||||
keySize,
|
||||
tagSize: mac,
|
||||
}
|
||||
|
||||
return Base64.encode(JSON.stringify(encrypted))
|
||||
}
|
||||
|
||||
static decrypt(e: string, pass: string): string {
|
||||
const { alg, data, iv, tag, salt, keySize, tagSize }: EncryptedItem = JSON.parse(Base64.decode(e))
|
||||
const key = scryptSync(pass, Buffer.from(salt, Symmetric.Encoding), keySize)
|
||||
|
||||
// @ts-ignore
|
||||
const options: TransformOptions = tag ? { authTagLength: tagSize } : undefined
|
||||
const decipher: DecipherGCM | DecipherCCM | Decipher = createDecipheriv(alg, key, Buffer.from(iv, Symmetric.Encoding), options)
|
||||
|
||||
// @ts-ignore
|
||||
if (tag) decipher.setAuthTag(Buffer.from(tag, Symmetric.Encoding))
|
||||
|
||||
const decrypted: Buffer = Buffer.concat([
|
||||
decipher.update(Buffer.from(data, Symmetric.Encoding)),
|
||||
decipher.final(),
|
||||
])
|
||||
|
||||
return decrypted.toString()
|
||||
}
|
||||
|
||||
private static getCipherConfig = (type: Ciphers): CipherConfig => {
|
||||
switch (type) {
|
||||
case Ciphers.AES_128_GCM:
|
||||
return {
|
||||
alg: 'aes-128-gcm',
|
||||
ivSize: 16,
|
||||
keySize: 16,
|
||||
mac: 16,
|
||||
}
|
||||
case Ciphers.AES_192_GCM:
|
||||
return {
|
||||
alg: 'aes-192-gcm',
|
||||
ivSize: 16,
|
||||
keySize: 24,
|
||||
mac: 16,
|
||||
}
|
||||
case Ciphers.AES_256_GCM:
|
||||
return {
|
||||
alg: 'aes-256-gcm',
|
||||
ivSize: 16,
|
||||
keySize: 32,
|
||||
mac: 16,
|
||||
}
|
||||
case Ciphers.AES_128_CTR:
|
||||
return {
|
||||
alg: 'aes-128-ctr',
|
||||
ivSize: 16,
|
||||
keySize: 16,
|
||||
}
|
||||
case Ciphers.AES_192_CTR:
|
||||
return {
|
||||
alg: 'aes-192-ctr',
|
||||
ivSize: 16,
|
||||
keySize: 24,
|
||||
}
|
||||
case Ciphers.AES_256_CTR:
|
||||
return {
|
||||
alg: 'aes-256-ctr',
|
||||
ivSize: 16,
|
||||
keySize: 32,
|
||||
}
|
||||
case Ciphers.ChaCha20:
|
||||
return {
|
||||
alg: 'chacha20',
|
||||
ivSize: 16,
|
||||
keySize: 32,
|
||||
}
|
||||
case Ciphers.ChaCha20_Poly1305:
|
||||
return {
|
||||
alg: 'chacha20-poly1305',
|
||||
ivSize: 16,
|
||||
keySize: 32,
|
||||
mac: 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
src/index.ts
12
src/index.ts
@ -1,12 +1,12 @@
|
||||
import AES from './AES'
|
||||
import RSA from './RSA'
|
||||
import Symmetric from './Symmetric'
|
||||
|
||||
export default {
|
||||
const exp = {
|
||||
RSA,
|
||||
AES,
|
||||
Symmetric,
|
||||
}
|
||||
|
||||
export {
|
||||
AES,
|
||||
RSA,
|
||||
module.exports = {
|
||||
...exp,
|
||||
default: exp,
|
||||
}
|
Loading…
Reference in New Issue
Block a user