otp-crypto
Version:
Pseudo one-time pad crypto library for plaintext data exchange.
59 lines (53 loc) • 2.61 kB
JavaScript
export default class OtpCrypto {
static encryptedDataConverter = {
strToBytes: string => new Uint8Array(string.split('').map(char => char.codePointAt(0))),
bytesToStr: bytes => {
let string = ''
bytes.forEach(byte => { string += String.fromCodePoint(byte) })
return string
},
base64ToBytes (base64) { return this.strToBytes(atob(base64)) },
bytesToBase64 (bytes) { return btoa(this.bytesToStr(bytes)) },
}
static decryptedDataConverter = {
strToBytes: string => new TextEncoder().encode(string),
bytesToStr: bytes => new TextDecoder().decode(bytes),
base64ToBytes (base64) { return this.strToBytes(atob(base64)) },
bytesToBase64 (bytes) { return btoa(this.bytesToStr(bytes)) },
}
static xorByteArrays = function (messageBytes, keyBytes) {
const bytesLeft = keyBytes.length - messageBytes.length
const isKeyLongEnough = bytesLeft >= 0
const minLength = Math.min(messageBytes.length, keyBytes.length)
const resultBytes = new Uint8Array(minLength)
for (let idx = 0; idx < minLength; idx++) {
resultBytes[idx] = messageBytes[idx] ^ keyBytes[idx]
}
return { resultBytes, bytesLeft, isKeyLongEnough }
}
static encrypt (plaintext, keyBytes) {
const bytesUnencrypted = this.decryptedDataConverter.strToBytes(plaintext)
const bytesEncrypted = this.xorByteArrays(bytesUnencrypted, keyBytes)
const stringEncrypted = this.encryptedDataConverter.bytesToStr(bytesEncrypted.resultBytes)
const base64Encrypted = btoa(stringEncrypted)
const bytesUsed = bytesEncrypted.resultBytes.length
const remainingKey = keyBytes.slice(bytesUsed)
const bytesLeft = bytesEncrypted.bytesLeft
const isKeyLongEnough = bytesEncrypted.isKeyLongEnough
return { base64Encrypted, remainingKey, bytesUsed, bytesLeft, isKeyLongEnough }
}
static decrypt (base64Encrypted, keyBytes) {
const stringEncrypted = atob(base64Encrypted)
const bytesEncrypted = this.encryptedDataConverter.strToBytes(stringEncrypted)
const bytesDecrypted = this.xorByteArrays(bytesEncrypted, keyBytes)
const plaintextDecrypted = this.decryptedDataConverter.bytesToStr(bytesDecrypted.resultBytes)
const bytesUsed = bytesDecrypted.resultBytes.length
const remainingKey = keyBytes.slice(bytesUsed)
const bytesLeft = bytesDecrypted.bytesLeft
const isKeyLongEnough = bytesDecrypted.isKeyLongEnough
return { plaintextDecrypted, remainingKey, bytesUsed, bytesLeft, isKeyLongEnough }
}
static generateRandomBytes (numberOfBytes) {
return crypto.getRandomValues(new Uint8Array(numberOfBytes))
}
}