зеркало из
1
0
Форкнуть 0
braintree-encryption/lib/braintree.js

228 строки
5.7 KiB
JavaScript

(function () {
for (var key in sjcl.beware) {
if (sjcl.beware.hasOwnProperty(key)) {
sjcl.beware[key]();
}
}
})();
var Braintree = {
sjcl: sjcl,
version: "1.3.10"
};
Braintree.generateAesKey = function () {
return {
key: sjcl.random.randomWords(8, 0),
encrypt: function (plainText) {
return this.encryptWithIv(plainText, sjcl.random.randomWords(4, 0));
},
encryptWithIv: function (plaintext, iv) {
var aes = new sjcl.cipher.aes(this.key),
plaintextBits = sjcl.codec.utf8String.toBits(plaintext),
ciphertextBits = sjcl.mode.cbc.encrypt(aes, plaintextBits, iv),
ciphertextAndIvBits = sjcl.bitArray.concat(iv, ciphertextBits);
return sjcl.codec.base64.fromBits(ciphertextAndIvBits);
}
};
};
Braintree.create = function (publicKey) {
return new Braintree.EncryptionClient(publicKey);
};
Braintree.EncryptionClient = function (publicKey) {
var self = this,
hiddenFields = [];
self.publicKey = publicKey;
self.version = Braintree.version;
var createElement = function (tagName, attrs) {
var element, attr, value;
element = document.createElement(tagName);
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
value = attrs[attr];
element.setAttribute(attr, value);
}
}
return element;
};
var extractForm = function (object) {
if (window.jQuery && object instanceof jQuery) {
return object[0];
} else if (object.nodeType && object.nodeType === 1) {
return object;
} else {
return document.getElementById(object);
}
};
var extractIntegers = function (asn1) {
var parts = [],
start, end, data,
i;
if (asn1.typeName() === "INTEGER") {
start = asn1.posContent();
end = asn1.posEnd();
data = asn1.stream.hexDump(start, end).replace(/[ \n]/g, "");
parts.push(data);
}
if (asn1.sub !== null) {
for (i = 0; i < asn1.sub.length; i++) {
parts = parts.concat(extractIntegers(asn1.sub[i]));
}
}
return parts;
};
var findInputs = function (element) {
var found = [],
children = element.children,
child, i;
for (i = 0; i < children.length; i++) {
child = children[i];
if (child.nodeType === 1 && child.attributes["data-encrypted-name"]) {
found.push(child);
} else if (child.children && child.children.length > 0) {
found = found.concat(findInputs(child));
}
}
return found;
};
var generateRsaKey = function () {
var asn1, exponent, parts, modulus, rawKey, rsa;
try {
rawKey = b64toBA(publicKey);
asn1 = ASN1.decode(rawKey);
} catch (e) {
throw "Invalid encryption key. Please use the key labeled 'Client-Side Encryption Key'";
}
parts = extractIntegers(asn1);
if (parts.length !== 2) {
throw "Invalid encryption key. Please use the key labeled 'Client-Side Encryption Key'";
}
modulus = parts[0];
exponent = parts[1];
rsa = new RSAKey();
rsa.setPublic(modulus, exponent);
return rsa;
};
var generateHmacKey = function () {
return {
key: sjcl.random.randomWords(8, 0),
sign: function (message) {
var hmac = new sjcl.misc.hmac(this.key, sjcl.hash.sha256),
signature = hmac.encrypt(message);
return sjcl.codec.base64.fromBits(signature);
}
};
};
self.encrypt = function (plaintext) {
var rsa = generateRsaKey(),
aes = Braintree.generateAesKey(),
hmac = generateHmacKey(),
ciphertext = aes.encrypt(plaintext),
signature = hmac.sign(sjcl.codec.base64.toBits(ciphertext)),
combinedKey = sjcl.bitArray.concat(aes.key, hmac.key),
encodedKey = sjcl.codec.base64.fromBits(combinedKey),
hexEncryptedKey = rsa.encrypt(encodedKey),
prefix = "$bt4|javascript_" + self.version.replace(/\./g, "_") + "$",
encryptedKey = null;
if(hexEncryptedKey) {
encryptedKey = hex2b64(hexEncryptedKey);
}
return prefix + encryptedKey + "$" + ciphertext + "$" + signature;
};
self.encryptForm = function (form) {
var element, encryptedValue,
fieldName, hiddenField,
i, inputs;
form = extractForm(form);
inputs = findInputs(form);
while (hiddenFields.length > 0) {
try {
form.removeChild(hiddenFields[0]);
} catch (err) {}
hiddenFields.splice(0, 1);
}
for (i = 0; i < inputs.length; i++) {
element = inputs[i];
fieldName = element.getAttribute("data-encrypted-name");
encryptedValue = self.encrypt(element.value);
element.removeAttribute("name");
hiddenField = createElement("input", {
value: encryptedValue,
type: "hidden",
name: fieldName
});
hiddenFields.push(hiddenField);
form.appendChild(hiddenField);
}
};
self.onSubmitEncryptForm = function (form, callback) {
var wrappedCallback;
form = extractForm(form);
wrappedCallback = function (e) {
self.encryptForm(form);
return (!!callback) ? callback(e) : e;
};
if (window.jQuery) {
window.jQuery(form).submit(wrappedCallback);
} else if (form.addEventListener) {
form.addEventListener("submit", wrappedCallback, false);
} else if (form.attachEvent) {
form.attachEvent("onsubmit", wrappedCallback);
}
};
// backwards compatibility
self.formEncrypter = {
encryptForm: self.encryptForm,
extractForm: extractForm,
onSubmitEncryptForm: self.onSubmitEncryptForm
};
sjcl.random.startCollectors();
};
window.Braintree = Braintree;
if (typeof define === "function") {
define("braintree", function () {
return Braintree;
});
}