Добавлен модуль sjcl для шифрования AES, т.к. WebCrypto API не работает с http, а только с https
This commit is contained in:
@@ -1,70 +1,25 @@
|
||||
import {Buffer} from 'safe-buffer';
|
||||
import sjclWrapper from './sjclWrapper';
|
||||
|
||||
//не менять
|
||||
const iv = Buffer.from('B6E2XejNh2dS');
|
||||
let aesKeys = {};
|
||||
const iv = 'B6E2XejNh2dS';
|
||||
const salt = 'Liberama project is awesome';
|
||||
|
||||
export async function aesKeyFromPassword(password) {
|
||||
return await window.crypto.subtle.importKey(
|
||||
"raw", //only "raw" is allowed
|
||||
Buffer.from(password), //your password
|
||||
{
|
||||
name: "PBKDF2",
|
||||
},
|
||||
false, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
["deriveKey"] //can be any combination of "deriveKey" and "deriveBits"
|
||||
).then((key) => {
|
||||
return window.crypto.subtle.deriveKey(
|
||||
{
|
||||
"name": "PBKDF2",
|
||||
salt: Buffer.from('Liberama project is awesome'),//не менять
|
||||
iterations: 1000,
|
||||
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
},
|
||||
key, //your key from generateKey or importKey
|
||||
{ //the key type you want to create based on the derived bits
|
||||
name: "AES-GCM", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC")
|
||||
//the generateKey parameters for that type of algorithm
|
||||
length: 256, //can be 128, 192, or 256
|
||||
},
|
||||
false, //whether the derived key is extractable (i.e. can be used in exportKey)
|
||||
["encrypt", "decrypt"] //limited to the options in that algorithm's importKey
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export async function aesEncrypt(data, password) {
|
||||
if (!aesKeys[password])
|
||||
aesKeys[password] = await aesKeyFromPassword(password);
|
||||
|
||||
const key = aesKeys[password];
|
||||
|
||||
return await window.crypto.subtle.encrypt(
|
||||
{
|
||||
name: "AES-GCM",
|
||||
iv
|
||||
},
|
||||
key, //from generateKey or importKey above
|
||||
data //ArrayBuffer of data you want to encrypt
|
||||
export function aesEncrypt(data, password) {
|
||||
return sjclWrapper.codec.bytes.fromBits(
|
||||
sjclWrapper.encryptArray(
|
||||
password, sjclWrapper.codec.bytes.toBits(data), {iv, salt}
|
||||
).ct
|
||||
);
|
||||
}
|
||||
|
||||
export async function aesDecrypt(data, password) {
|
||||
if (!aesKeys[password])
|
||||
aesKeys[password] = await aesKeyFromPassword(password);
|
||||
|
||||
const key = aesKeys[password];
|
||||
|
||||
return await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-GCM",
|
||||
iv
|
||||
},
|
||||
key, //from generateKey or importKey above
|
||||
data //ArrayBuffer of the data
|
||||
export function aesDecrypt(data, password) {
|
||||
return sjclWrapper.codec.bytes.fromBits(
|
||||
sjclWrapper.decryptArray(
|
||||
password, {ct: sjclWrapper.codec.bytes.toBits(data)}, {iv, salt}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export async function sha256(data) {
|
||||
return await crypto.subtle.digest("SHA-256", Buffer.from(data));
|
||||
export function sha256(str) {
|
||||
return sjclWrapper.codec.bytes.fromBits(sjclWrapper.hash.sha256.hash(str));
|
||||
}
|
||||
|
||||
145
client/share/sjclWrapper.js
Normal file
145
client/share/sjclWrapper.js
Normal file
@@ -0,0 +1,145 @@
|
||||
import sjcl from 'sjcl';
|
||||
|
||||
//везде недоработки...
|
||||
|
||||
sjcl.codec.bytes = {
|
||||
fromBits: function(arr) {
|
||||
var out = [], bl = sjcl.bitArray.bitLength(arr), i, tmp;
|
||||
for (i=0; i<bl/8; i++) {
|
||||
if ((i&3) === 0) {
|
||||
tmp = arr[i/4];
|
||||
}
|
||||
out.push(tmp >>> 24);
|
||||
tmp <<= 8;
|
||||
}
|
||||
return out;
|
||||
},
|
||||
toBits: function(bytes) {
|
||||
var out = [], i, tmp=0;
|
||||
for (i=0; i<bytes.length; i++) {
|
||||
tmp = tmp << 8 | bytes[i];
|
||||
if ((i&3) === 3) {
|
||||
out.push(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
if (i&3) {
|
||||
out.push(sjcl.bitArray.partial(8*(i&3), tmp));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.json._add = function(target, src, requireSame) {
|
||||
if (target === undefined) { target = {}; }
|
||||
if (src === undefined) { return target; }
|
||||
var i;
|
||||
for (i in src) {
|
||||
if (src.hasOwnProperty(i)) {
|
||||
if (requireSame && target[i] !== undefined && target[i] !== src[i]) {
|
||||
throw new sjcl.exception.invalid("required parameter overridden");
|
||||
}
|
||||
target[i] = src[i];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
sjcl.encryptArray = function(password, plaintext, params, rp) {
|
||||
params = params || {};
|
||||
rp = rp || {};
|
||||
|
||||
var j = sjcl.json, p = j._add({ iv: sjcl.random.randomWords(4,0) },
|
||||
j.defaults), tmp, prp, adata;
|
||||
j._add(p, params);
|
||||
adata = p.adata;
|
||||
if (typeof p.salt === "string") {
|
||||
p.salt = sjcl.codec.base64.toBits(p.salt);
|
||||
}
|
||||
if (typeof p.iv === "string") {
|
||||
p.iv = sjcl.codec.base64.toBits(p.iv);
|
||||
}
|
||||
|
||||
if (!sjcl.mode[p.mode] ||
|
||||
!sjcl.cipher[p.cipher] ||
|
||||
(typeof password === "string" && p.iter <= 100) ||
|
||||
(p.ts !== 64 && p.ts !== 96 && p.ts !== 128) ||
|
||||
(p.ks !== 128 && p.ks !== 192 && p.ks !== 256) ||
|
||||
(p.iv.length < 2 || p.iv.length > 4)) {
|
||||
throw new sjcl.exception.invalid("json encrypt: invalid parameters");
|
||||
}
|
||||
|
||||
if (typeof password === "string") {
|
||||
tmp = sjcl.misc.cachedPbkdf2(password, p);
|
||||
password = tmp.key.slice(0,p.ks/32);
|
||||
p.salt = tmp.salt;
|
||||
} else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.publicKey) {
|
||||
tmp = password.kem();
|
||||
p.kemtag = tmp.tag;
|
||||
password = tmp.key.slice(0,p.ks/32);
|
||||
}
|
||||
if (typeof plaintext === "string") {
|
||||
plaintext = sjcl.codec.utf8String.toBits(plaintext);
|
||||
}
|
||||
if (typeof adata === "string") {
|
||||
p.adata = adata = sjcl.codec.utf8String.toBits(adata);
|
||||
}
|
||||
prp = new sjcl.cipher[p.cipher](password);
|
||||
|
||||
j._add(rp, p);
|
||||
rp.key = password;
|
||||
|
||||
/* do the encryption */
|
||||
if (p.mode === "ccm" && sjcl.arrayBuffer && sjcl.arrayBuffer.ccm && plaintext instanceof ArrayBuffer) {
|
||||
p.ct = sjcl.arrayBuffer.ccm.encrypt(prp, plaintext, p.iv, adata, p.ts);
|
||||
} else {
|
||||
p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, adata, p.ts);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
sjcl.decryptArray = function(password, ciphertext, params) {
|
||||
params = params || {};
|
||||
|
||||
var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),ciphertext), params, true), ct, tmp, prp, adata=p.adata;
|
||||
if (typeof p.salt === "string") {
|
||||
p.salt = sjcl.codec.base64.toBits(p.salt);
|
||||
}
|
||||
if (typeof p.iv === "string") {
|
||||
p.iv = sjcl.codec.base64.toBits(p.iv);
|
||||
}
|
||||
|
||||
if (!sjcl.mode[p.mode] ||
|
||||
!sjcl.cipher[p.cipher] ||
|
||||
(typeof password === "string" && p.iter <= 100) ||
|
||||
(p.ts !== 64 && p.ts !== 96 && p.ts !== 128) ||
|
||||
(p.ks !== 128 && p.ks !== 192 && p.ks !== 256) ||
|
||||
(!p.iv) ||
|
||||
(p.iv.length < 2 || p.iv.length > 4)) {
|
||||
throw new sjcl.exception.invalid("json decrypt: invalid parameters");
|
||||
}
|
||||
|
||||
if (typeof password === "string") {
|
||||
tmp = sjcl.misc.cachedPbkdf2(password, p);
|
||||
password = tmp.key.slice(0,p.ks/32);
|
||||
p.salt = tmp.salt;
|
||||
} else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.secretKey) {
|
||||
password = password.unkem(sjcl.codec.base64.toBits(p.kemtag)).slice(0,p.ks/32);
|
||||
}
|
||||
if (typeof adata === "string") {
|
||||
adata = sjcl.codec.utf8String.toBits(adata);
|
||||
}
|
||||
prp = new sjcl.cipher[p.cipher](password);
|
||||
|
||||
/* do the decryption */
|
||||
if (p.mode === "ccm" && sjcl.arrayBuffer && sjcl.arrayBuffer.ccm && p.ct instanceof ArrayBuffer) {
|
||||
ct = sjcl.arrayBuffer.ccm.decrypt(prp, p.ct, p.iv, p.tag, adata, p.ts);
|
||||
} else {
|
||||
ct = sjcl.mode[p.mode].decrypt(prp, p.ct, p.iv, adata, p.ts);
|
||||
}
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
export default sjcl;
|
||||
Reference in New Issue
Block a user