204 lines
4.8 KiB
JavaScript
204 lines
4.8 KiB
JavaScript
export default class FakeWebCrypto {
|
|
constructor() {}
|
|
|
|
deinit() {}
|
|
|
|
initialize() {
|
|
return
|
|
}
|
|
|
|
randomString(len) {
|
|
const charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
let randomString = ''
|
|
for (let i = 0; i < len; i++) {
|
|
const randomPoz = Math.floor(Math.random() * charSet.length)
|
|
randomString += charSet.substring(randomPoz, randomPoz + 1)
|
|
}
|
|
return randomString
|
|
}
|
|
|
|
generateUUIDSync = () => {
|
|
const globalScope = getGlobalScope()
|
|
const crypto = globalScope.crypto || globalScope.msCrypto
|
|
if (crypto) {
|
|
const buf = new Uint32Array(4)
|
|
crypto.getRandomValues(buf)
|
|
let idx = -1
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
idx++
|
|
const r = (buf[idx >> 3] >> ((idx % 8) * 4)) & 15
|
|
const v = c === 'x' ? r : (r & 0x3) | 0x8
|
|
return v.toString(16)
|
|
})
|
|
} else {
|
|
let d = new Date().getTime()
|
|
if (globalScope.performance && typeof globalScope.performance.now === 'function') {
|
|
d += performance.now() // use high-precision timer if available
|
|
}
|
|
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
const r = (d + Math.random() * 16) % 16 | 0
|
|
d = Math.floor(d / 16)
|
|
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)
|
|
})
|
|
return uuid
|
|
}
|
|
}
|
|
|
|
generateUUID = () => {
|
|
return this.generateUUIDSync()
|
|
}
|
|
|
|
timingSafeEqual(a, b) {
|
|
return a === b
|
|
}
|
|
|
|
base64Encode(text) {
|
|
return btoa(text)
|
|
}
|
|
|
|
base64URLEncode(text) {
|
|
return this.base64Encode(text).replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '')
|
|
}
|
|
|
|
base64Decode(base64String) {
|
|
return atob(base64String)
|
|
}
|
|
|
|
async pbkdf2(password, salt, iterations, length) {
|
|
return btoa(password + salt + iterations)
|
|
}
|
|
|
|
generateRandomKey(bits) {
|
|
const bitsPerHexChar = 4
|
|
const length = bits / bitsPerHexChar
|
|
return this.randomString(length)
|
|
}
|
|
|
|
async aes256CbcEncrypt(plaintext, iv, key) {
|
|
const data = {
|
|
plaintext,
|
|
iv,
|
|
key,
|
|
}
|
|
return btoa(JSON.stringify(data))
|
|
}
|
|
|
|
async aes256CbcDecrypt(ciphertext, iv, key) {
|
|
const data = JSON.parse(atob(ciphertext))
|
|
if (data.key !== key || data.iv !== iv) {
|
|
return undefined
|
|
}
|
|
return data.plaintext
|
|
}
|
|
|
|
async hmac256(message, key) {
|
|
return btoa(message + key)
|
|
}
|
|
|
|
async sha256(text) {
|
|
return new SNWebCrypto().sha256(text)
|
|
}
|
|
|
|
async hmac1(message, key) {
|
|
return btoa(message + key)
|
|
}
|
|
|
|
async unsafeSha1(text) {
|
|
return btoa(text)
|
|
}
|
|
|
|
argon2(password, salt, iterations, bytes, length) {
|
|
const bitsPerHexChar = 4
|
|
const bitsInByte = 8
|
|
const encoded = btoa(password)
|
|
const desiredLength = length * (bitsInByte / bitsPerHexChar)
|
|
const missingLength = desiredLength - encoded.length
|
|
const result = `${encoded}${encoded.repeat(Math.ceil(missingLength / encoded.length))}`.slice(0, desiredLength)
|
|
return result
|
|
}
|
|
|
|
xchacha20Encrypt(plaintext, nonce, key, assocData) {
|
|
const data = {
|
|
plaintext,
|
|
nonce,
|
|
key,
|
|
assocData,
|
|
}
|
|
return btoa(JSON.stringify(data))
|
|
}
|
|
|
|
xchacha20Decrypt(ciphertext, nonce, key, assocData) {
|
|
const data = JSON.parse(atob(ciphertext))
|
|
if (data.key !== key || data.nonce !== nonce || data.assocData !== assocData) {
|
|
return undefined
|
|
}
|
|
return data.plaintext
|
|
}
|
|
|
|
sodiumCryptoBoxEasyEncrypt(message, nonce, senderSecretKey, recipientPublicKey) {
|
|
const data = {
|
|
message,
|
|
nonce,
|
|
recipientPublicKey,
|
|
senderSecretKey,
|
|
}
|
|
return btoa(JSON.stringify(data))
|
|
}
|
|
|
|
sodiumCryptoBoxEasyDecrypt(ciphertext, nonce, senderPublicKey, recipientSecretKey) {
|
|
const data = JSON.parse(atob(ciphertext))
|
|
if (
|
|
data.senderPublicKey !== senderPublicKey ||
|
|
data.recipientSecretKey !== recipientSecretKey ||
|
|
data.nonce !== nonce ||
|
|
data.assocData !== assocData
|
|
) {
|
|
return undefined
|
|
}
|
|
return data.message
|
|
}
|
|
|
|
sodiumCryptoSign(message, secretKey) {
|
|
const data = {
|
|
message,
|
|
secretKey,
|
|
}
|
|
return btoa(JSON.stringify(data))
|
|
}
|
|
|
|
sodiumCryptoKdfDeriveFromKey(key, subkeyNumber, subkeyLength, context) {
|
|
return btoa(key + subkeyNumber + subkeyLength + context)
|
|
}
|
|
|
|
sodiumCryptoGenericHash(message, key) {
|
|
return btoa(message + key)
|
|
}
|
|
|
|
sodiumCryptoSignVerify(message, signature, publicKey) {
|
|
return true
|
|
}
|
|
|
|
sodiumCryptoBoxSeedKeypair(seed) {
|
|
return {
|
|
privateKey: seed,
|
|
publicKey: seed,
|
|
}
|
|
}
|
|
|
|
|
|
sodiumCryptoSignSeedKeypair(seed) {
|
|
return {
|
|
privateKey: seed,
|
|
publicKey: seed,
|
|
}
|
|
}
|
|
|
|
generateOtpSecret() {
|
|
return 'WQVV2GFBRQWU3UQZWQFZC37PSNRXKTA6'
|
|
}
|
|
|
|
totpToken(secret, timestamp, tokenLength, step) {
|
|
return '123456'
|
|
}
|
|
}
|