summaryrefslogtreecommitdiff
path: root/school/node_modules/node-forge/js/pkcs7.js
diff options
context:
space:
mode:
Diffstat (limited to 'school/node_modules/node-forge/js/pkcs7.js')
-rw-r--r--school/node_modules/node-forge/js/pkcs7.js842
1 files changed, 842 insertions, 0 deletions
diff --git a/school/node_modules/node-forge/js/pkcs7.js b/school/node_modules/node-forge/js/pkcs7.js
new file mode 100644
index 0000000..ffa7413
--- /dev/null
+++ b/school/node_modules/node-forge/js/pkcs7.js
@@ -0,0 +1,842 @@
+/**
+ * Javascript implementation of PKCS#7 v1.5. Currently only certain parts of
+ * PKCS#7 are implemented, especially the enveloped-data content type.
+ *
+ * @author Stefan Siegl
+ *
+ * Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
+ *
+ * Currently this implementation only supports ContentType of either
+ * EnvelopedData or EncryptedData on root level. The top level elements may
+ * contain only a ContentInfo of ContentType Data, i.e. plain data. Further
+ * nesting is not (yet) supported.
+ *
+ * The Forge validators for PKCS #7's ASN.1 structures are available from
+ * a seperate file pkcs7asn1.js, since those are referenced from other
+ * PKCS standards like PKCS #12.
+ */
+(function() {
+/* ########## Begin module implementation ########## */
+function initModule(forge) {
+
+// shortcut for ASN.1 API
+var asn1 = forge.asn1;
+
+// shortcut for PKCS#7 API
+var p7 = forge.pkcs7 = forge.pkcs7 || {};
+
+/**
+ * Converts a PKCS#7 message from PEM format.
+ *
+ * @param pem the PEM-formatted PKCS#7 message.
+ *
+ * @return the PKCS#7 message.
+ */
+p7.messageFromPem = function(pem) {
+ var msg = forge.pem.decode(pem)[0];
+
+ if(msg.type !== 'PKCS7') {
+ var error = new Error('Could not convert PKCS#7 message from PEM; PEM ' +
+ 'header type is not "PKCS#7".');
+ error.headerType = msg.type;
+ throw error;
+ }
+ if(msg.procType && msg.procType.type === 'ENCRYPTED') {
+ throw new Error('Could not convert PKCS#7 message from PEM; PEM is encrypted.');
+ }
+
+ // convert DER to ASN.1 object
+ var obj = asn1.fromDer(msg.body);
+
+ return p7.messageFromAsn1(obj);
+};
+
+/**
+ * Converts a PKCS#7 message to PEM format.
+ *
+ * @param msg The PKCS#7 message object
+ * @param maxline The maximum characters per line, defaults to 64.
+ *
+ * @return The PEM-formatted PKCS#7 message.
+ */
+p7.messageToPem = function(msg, maxline) {
+ // convert to ASN.1, then DER, then PEM-encode
+ var pemObj = {
+ type: 'PKCS7',
+ body: asn1.toDer(msg.toAsn1()).getBytes()
+ };
+ return forge.pem.encode(pemObj, {maxline: maxline});
+};
+
+/**
+ * Converts a PKCS#7 message from an ASN.1 object.
+ *
+ * @param obj the ASN.1 representation of a ContentInfo.
+ *
+ * @return the PKCS#7 message.
+ */
+p7.messageFromAsn1 = function(obj) {
+ // validate root level ContentInfo and capture data
+ var capture = {};
+ var errors = [];
+ if(!asn1.validate(obj, p7.asn1.contentInfoValidator, capture, errors))
+ {
+ var error = new Error('Cannot read PKCS#7 message. ' +
+ 'ASN.1 object is not an PKCS#7 ContentInfo.');
+ error.errors = errors;
+ throw error;
+ }
+
+ var contentType = asn1.derToOid(capture.contentType);
+ var msg;
+
+ switch(contentType) {
+ case forge.pki.oids.envelopedData:
+ msg = p7.createEnvelopedData();
+ break;
+
+ case forge.pki.oids.encryptedData:
+ msg = p7.createEncryptedData();
+ break;
+
+ case forge.pki.oids.signedData:
+ msg = p7.createSignedData();
+ break;
+
+ default:
+ throw new Error('Cannot read PKCS#7 message. ContentType with OID ' +
+ contentType + ' is not (yet) supported.');
+ }
+
+ msg.fromAsn1(capture.content.value[0]);
+ return msg;
+};
+
+/**
+ * Converts a single RecipientInfo from an ASN.1 object.
+ *
+ * @param obj The ASN.1 representation of a RecipientInfo.
+ *
+ * @return The recipientInfo object.
+ */
+var _recipientInfoFromAsn1 = function(obj) {
+ // Validate EnvelopedData content block and capture data.
+ var capture = {};
+ var errors = [];
+ if(!asn1.validate(obj, p7.asn1.recipientInfoValidator, capture, errors))
+ {
+ var error = new Error('Cannot read PKCS#7 message. ' +
+ 'ASN.1 object is not an PKCS#7 EnvelopedData.');
+ error.errors = errors;
+ throw error;
+ }
+
+ return {
+ version: capture.version.charCodeAt(0),
+ issuer: forge.pki.RDNAttributesAsArray(capture.issuer),
+ serialNumber: forge.util.createBuffer(capture.serial).toHex(),
+ encryptedContent: {
+ algorithm: asn1.derToOid(capture.encAlgorithm),
+ parameter: capture.encParameter.value,
+ content: capture.encKey
+ }
+ };
+};
+
+/**
+ * Converts a single recipientInfo object to an ASN.1 object.
+ *
+ * @param obj The recipientInfo object.
+ *
+ * @return The ASN.1 representation of a RecipientInfo.
+ */
+var _recipientInfoToAsn1 = function(obj) {
+ return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // Version
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
+ asn1.integerToDer(obj.version).getBytes()),
+ // IssuerAndSerialNumber
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // Name
+ forge.pki.distinguishedNameToAsn1({attributes: obj.issuer}),
+ // Serial
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
+ forge.util.hexToBytes(obj.serialNumber))
+ ]),
+ // KeyEncryptionAlgorithmIdentifier
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // Algorithm
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
+ asn1.oidToDer(obj.encryptedContent.algorithm).getBytes()),
+ // Parameter, force NULL, only RSA supported for now.
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
+ ]),
+ // EncryptedKey
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
+ obj.encryptedContent.content)
+ ]);
+};
+
+/**
+ * Map a set of RecipientInfo ASN.1 objects to recipientInfo objects.
+ *
+ * @param objArr Array of ASN.1 representations RecipientInfo (i.e. SET OF).
+ *
+ * @return array of recipientInfo objects.
+ */
+var _recipientInfosFromAsn1 = function(objArr) {
+ var ret = [];
+ for(var i = 0; i < objArr.length; i ++) {
+ ret.push(_recipientInfoFromAsn1(objArr[i]));
+ }
+ return ret;
+};
+
+/**
+ * Map an array of recipientInfo objects to ASN.1 objects.
+ *
+ * @param recipientsArr Array of recipientInfo objects.
+ *
+ * @return Array of ASN.1 representations RecipientInfo.
+ */
+var _recipientInfosToAsn1 = function(recipientsArr) {
+ var ret = [];
+ for(var i = 0; i < recipientsArr.length; i ++) {
+ ret.push(_recipientInfoToAsn1(recipientsArr[i]));
+ }
+ return ret;
+};
+
+/**
+ * Map messages encrypted content to ASN.1 objects.
+ *
+ * @param ec The encryptedContent object of the message.
+ *
+ * @return ASN.1 representation of the encryptedContent object (SEQUENCE).
+ */
+var _encryptedContentToAsn1 = function(ec) {
+ return [
+ // ContentType, always Data for the moment
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
+ asn1.oidToDer(forge.pki.oids.data).getBytes()),
+ // ContentEncryptionAlgorithmIdentifier
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // Algorithm
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
+ asn1.oidToDer(ec.algorithm).getBytes()),
+ // Parameters (IV)
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
+ ec.parameter.getBytes())
+ ]),
+ // [0] EncryptedContent
+ asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
+ ec.content.getBytes())
+ ])
+ ];
+};
+
+/**
+ * Reads the "common part" of an PKCS#7 content block (in ASN.1 format)
+ *
+ * This function reads the "common part" of the PKCS#7 content blocks
+ * EncryptedData and EnvelopedData, i.e. version number and symmetrically
+ * encrypted content block.
+ *
+ * The result of the ASN.1 validate and capture process is returned
+ * to allow the caller to extract further data, e.g. the list of recipients
+ * in case of a EnvelopedData object.
+ *
+ * @param msg the PKCS#7 object to read the data to.
+ * @param obj the ASN.1 representation of the content block.
+ * @param validator the ASN.1 structure validator object to use.
+ *
+ * @return the value map captured by validator object.
+ */
+var _fromAsn1 = function(msg, obj, validator) {
+ var capture = {};
+ var errors = [];
+ if(!asn1.validate(obj, validator, capture, errors)) {
+ var error = new Error('Cannot read PKCS#7 message. ' +
+ 'ASN.1 object is not a supported PKCS#7 message.');
+ error.errors = error;
+ throw error;
+ }
+
+ // Check contentType, so far we only support (raw) Data.
+ var contentType = asn1.derToOid(capture.contentType);
+ if(contentType !== forge.pki.oids.data) {
+ throw new Error('Unsupported PKCS#7 message. ' +
+ 'Only wrapped ContentType Data supported.');
+ }
+
+ if(capture.encryptedContent) {
+ var content = '';
+ if(forge.util.isArray(capture.encryptedContent)) {
+ for(var i = 0; i < capture.encryptedContent.length; ++i) {
+ if(capture.encryptedContent[i].type !== asn1.Type.OCTETSTRING) {
+ throw new Error('Malformed PKCS#7 message, expecting encrypted ' +
+ 'content constructed of only OCTET STRING objects.');
+ }
+ content += capture.encryptedContent[i].value;
+ }
+ } else {
+ content = capture.encryptedContent;
+ }
+ msg.encryptedContent = {
+ algorithm: asn1.derToOid(capture.encAlgorithm),
+ parameter: forge.util.createBuffer(capture.encParameter.value),
+ content: forge.util.createBuffer(content)
+ };
+ }
+
+ if(capture.content) {
+ var content = '';
+ if(forge.util.isArray(capture.content)) {
+ for(var i = 0; i < capture.content.length; ++i) {
+ if(capture.content[i].type !== asn1.Type.OCTETSTRING) {
+ throw new Error('Malformed PKCS#7 message, expecting ' +
+ 'content constructed of only OCTET STRING objects.');
+ }
+ content += capture.content[i].value;
+ }
+ } else {
+ content = capture.content;
+ }
+ msg.content = forge.util.createBuffer(content);
+ }
+
+ msg.version = capture.version.charCodeAt(0);
+ msg.rawCapture = capture;
+
+ return capture;
+};
+
+/**
+ * Decrypt the symmetrically encrypted content block of the PKCS#7 message.
+ *
+ * Decryption is skipped in case the PKCS#7 message object already has a
+ * (decrypted) content attribute. The algorithm, key and cipher parameters
+ * (probably the iv) are taken from the encryptedContent attribute of the
+ * message object.
+ *
+ * @param The PKCS#7 message object.
+ */
+var _decryptContent = function (msg) {
+ if(msg.encryptedContent.key === undefined) {
+ throw new Error('Symmetric key not available.');
+ }
+
+ if(msg.content === undefined) {
+ var ciph;
+
+ switch(msg.encryptedContent.algorithm) {
+ case forge.pki.oids['aes128-CBC']:
+ case forge.pki.oids['aes192-CBC']:
+ case forge.pki.oids['aes256-CBC']:
+ ciph = forge.aes.createDecryptionCipher(msg.encryptedContent.key);
+ break;
+
+ case forge.pki.oids['desCBC']:
+ case forge.pki.oids['des-EDE3-CBC']:
+ ciph = forge.des.createDecryptionCipher(msg.encryptedContent.key);
+ break;
+
+ default:
+ throw new Error('Unsupported symmetric cipher, OID ' +
+ msg.encryptedContent.algorithm);
+ }
+ ciph.start(msg.encryptedContent.parameter);
+ ciph.update(msg.encryptedContent.content);
+
+ if(!ciph.finish()) {
+ throw new Error('Symmetric decryption failed.');
+ }
+
+ msg.content = ciph.output;
+ }
+};
+
+p7.createSignedData = function() {
+ var msg = null;
+ msg = {
+ type: forge.pki.oids.signedData,
+ version: 1,
+ certificates: [],
+ crls: [],
+ // populated during sign()
+ digestAlgorithmIdentifiers: [],
+ contentInfo: null,
+ signerInfos: [],
+
+ fromAsn1: function(obj) {
+ // validate SignedData content block and capture data.
+ _fromAsn1(msg, obj, p7.asn1.signedDataValidator);
+ msg.certificates = [];
+ msg.crls = [];
+ msg.digestAlgorithmIdentifiers = [];
+ msg.contentInfo = null;
+ msg.signerInfos = [];
+
+ var certs = msg.rawCapture.certificates.value;
+ for(var i = 0; i < certs.length; ++i) {
+ msg.certificates.push(forge.pki.certificateFromAsn1(certs[i]));
+ }
+
+ // TODO: parse crls
+ },
+
+ toAsn1: function() {
+ // TODO: add support for more data types here
+ if('content' in msg) {
+ throw new Error('Signing PKCS#7 content not yet implemented.');
+ }
+
+ // degenerate case with no content
+ if(!msg.contentInfo) {
+ msg.sign();
+ }
+
+ var certs = [];
+ for(var i = 0; i < msg.certificates.length; ++i) {
+ certs.push(forge.pki.certificateToAsn1(msg.certificates[0]));
+ }
+
+ var crls = [];
+ // TODO: implement CRLs
+
+ // ContentInfo
+ return asn1.create(
+ asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // ContentType
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
+ asn1.oidToDer(msg.type).getBytes()),
+ // [0] SignedData
+ asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // Version
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
+ asn1.integerToDer(msg.version).getBytes()),
+ // DigestAlgorithmIdentifiers
+ asn1.create(
+ asn1.Class.UNIVERSAL, asn1.Type.SET, true,
+ msg.digestAlgorithmIdentifiers),
+ // ContentInfo
+ msg.contentInfo,
+ // [0] IMPLICIT ExtendedCertificatesAndCertificates
+ asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, certs),
+ // [1] IMPLICIT CertificateRevocationLists
+ asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, crls),
+ // SignerInfos
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true,
+ msg.signerInfos)
+ ])
+ ])
+ ]);
+ },
+
+ /**
+ * Signs the content.
+ *
+ * @param signer the signer (or array of signers) to sign as, for each:
+ * key the private key to sign with.
+ * [md] the message digest to use, defaults to sha-1.
+ */
+ sign: function(signer) {
+ if('content' in msg) {
+ throw new Error('PKCS#7 signing not yet implemented.');
+ }
+
+ if(typeof msg.content !== 'object') {
+ // use Data ContentInfo
+ msg.contentInfo = asn1.create(
+ asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // ContentType
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
+ asn1.oidToDer(forge.pki.oids.data).getBytes())
+ ]);
+
+ // add actual content, if present
+ if('content' in msg) {
+ msg.contentInfo.value.push(
+ // [0] EXPLICIT content
+ asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
+ msg.content)
+ ]));
+ }
+ }
+
+ // TODO: generate digest algorithm identifiers
+
+ // TODO: generate signerInfos
+ },
+
+ verify: function() {
+ throw new Error('PKCS#7 signature verification not yet implemented.');
+ },
+
+ /**
+ * Add a certificate.
+ *
+ * @param cert the certificate to add.
+ */
+ addCertificate: function(cert) {
+ // convert from PEM
+ if(typeof cert === 'string') {
+ cert = forge.pki.certificateFromPem(cert);
+ }
+ msg.certificates.push(cert);
+ },
+
+ /**
+ * Add a certificate revokation list.
+ *
+ * @param crl the certificate revokation list to add.
+ */
+ addCertificateRevokationList: function(crl) {
+ throw new Error('PKCS#7 CRL support not yet implemented.');
+ }
+ };
+ return msg;
+};
+
+/**
+ * Creates an empty PKCS#7 message of type EncryptedData.
+ *
+ * @return the message.
+ */
+p7.createEncryptedData = function() {
+ var msg = null;
+ msg = {
+ type: forge.pki.oids.encryptedData,
+ version: 0,
+ encryptedContent: {
+ algorithm: forge.pki.oids['aes256-CBC']
+ },
+
+ /**
+ * Reads an EncryptedData content block (in ASN.1 format)
+ *
+ * @param obj The ASN.1 representation of the EncryptedData content block
+ */
+ fromAsn1: function(obj) {
+ // Validate EncryptedData content block and capture data.
+ _fromAsn1(msg, obj, p7.asn1.encryptedDataValidator);
+ },
+
+ /**
+ * Decrypt encrypted content
+ *
+ * @param key The (symmetric) key as a byte buffer
+ */
+ decrypt: function(key) {
+ if(key !== undefined) {
+ msg.encryptedContent.key = key;
+ }
+ _decryptContent(msg);
+ }
+ };
+ return msg;
+};
+
+/**
+ * Creates an empty PKCS#7 message of type EnvelopedData.
+ *
+ * @return the message.
+ */
+p7.createEnvelopedData = function() {
+ var msg = null;
+ msg = {
+ type: forge.pki.oids.envelopedData,
+ version: 0,
+ recipients: [],
+ encryptedContent: {
+ algorithm: forge.pki.oids['aes256-CBC']
+ },
+
+ /**
+ * Reads an EnvelopedData content block (in ASN.1 format)
+ *
+ * @param obj the ASN.1 representation of the EnvelopedData content block.
+ */
+ fromAsn1: function(obj) {
+ // validate EnvelopedData content block and capture data
+ var capture = _fromAsn1(msg, obj, p7.asn1.envelopedDataValidator);
+ msg.recipients = _recipientInfosFromAsn1(capture.recipientInfos.value);
+ },
+
+ toAsn1: function() {
+ // ContentInfo
+ return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // ContentType
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
+ asn1.oidToDer(msg.type).getBytes()),
+ // [0] EnvelopedData
+ asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
+ // Version
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
+ asn1.integerToDer(msg.version).getBytes()),
+ // RecipientInfos
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true,
+ _recipientInfosToAsn1(msg.recipients)),
+ // EncryptedContentInfo
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true,
+ _encryptedContentToAsn1(msg.encryptedContent))
+ ])
+ ])
+ ]);
+ },
+
+ /**
+ * Find recipient by X.509 certificate's issuer.
+ *
+ * @param cert the certificate with the issuer to look for.
+ *
+ * @return the recipient object.
+ */
+ findRecipient: function(cert) {
+ var sAttr = cert.issuer.attributes;
+
+ for(var i = 0; i < msg.recipients.length; ++i) {
+ var r = msg.recipients[i];
+ var rAttr = r.issuer;
+
+ if(r.serialNumber !== cert.serialNumber) {
+ continue;
+ }
+
+ if(rAttr.length !== sAttr.length) {
+ continue;
+ }
+
+ var match = true;
+ for(var j = 0; j < sAttr.length; ++j) {
+ if(rAttr[j].type !== sAttr[j].type ||
+ rAttr[j].value !== sAttr[j].value) {
+ match = false;
+ break;
+ }
+ }
+
+ if(match) {
+ return r;
+ }
+ }
+
+ return null;
+ },
+
+ /**
+ * Decrypt enveloped content
+ *
+ * @param recipient The recipient object related to the private key
+ * @param privKey The (RSA) private key object
+ */
+ decrypt: function(recipient, privKey) {
+ if(msg.encryptedContent.key === undefined && recipient !== undefined &&
+ privKey !== undefined) {
+ switch(recipient.encryptedContent.algorithm) {
+ case forge.pki.oids.rsaEncryption:
+ case forge.pki.oids.desCBC:
+ var key = privKey.decrypt(recipient.encryptedContent.content);
+ msg.encryptedContent.key = forge.util.createBuffer(key);
+ break;
+
+ default:
+ throw new Error('Unsupported asymmetric cipher, ' +
+ 'OID ' + recipient.encryptedContent.algorithm);
+ }
+ }
+
+ _decryptContent(msg);
+ },
+
+ /**
+ * Add (another) entity to list of recipients.
+ *
+ * @param cert The certificate of the entity to add.
+ */
+ addRecipient: function(cert) {
+ msg.recipients.push({
+ version: 0,
+ issuer: cert.issuer.attributes,
+ serialNumber: cert.serialNumber,
+ encryptedContent: {
+ // We simply assume rsaEncryption here, since forge.pki only
+ // supports RSA so far. If the PKI module supports other
+ // ciphers one day, we need to modify this one as well.
+ algorithm: forge.pki.oids.rsaEncryption,
+ key: cert.publicKey
+ }
+ });
+ },
+
+ /**
+ * Encrypt enveloped content.
+ *
+ * This function supports two optional arguments, cipher and key, which
+ * can be used to influence symmetric encryption. Unless cipher is
+ * provided, the cipher specified in encryptedContent.algorithm is used
+ * (defaults to AES-256-CBC). If no key is provided, encryptedContent.key
+ * is (re-)used. If that one's not set, a random key will be generated
+ * automatically.
+ *
+ * @param [key] The key to be used for symmetric encryption.
+ * @param [cipher] The OID of the symmetric cipher to use.
+ */
+ encrypt: function(key, cipher) {
+ // Part 1: Symmetric encryption
+ if(msg.encryptedContent.content === undefined) {
+ cipher = cipher || msg.encryptedContent.algorithm;
+ key = key || msg.encryptedContent.key;
+
+ var keyLen, ivLen, ciphFn;
+ switch(cipher) {
+ case forge.pki.oids['aes128-CBC']:
+ keyLen = 16;
+ ivLen = 16;
+ ciphFn = forge.aes.createEncryptionCipher;
+ break;
+
+ case forge.pki.oids['aes192-CBC']:
+ keyLen = 24;
+ ivLen = 16;
+ ciphFn = forge.aes.createEncryptionCipher;
+ break;
+
+ case forge.pki.oids['aes256-CBC']:
+ keyLen = 32;
+ ivLen = 16;
+ ciphFn = forge.aes.createEncryptionCipher;
+ break;
+
+ case forge.pki.oids['des-EDE3-CBC']:
+ keyLen = 24;
+ ivLen = 8;
+ ciphFn = forge.des.createEncryptionCipher;
+ break;
+
+ default:
+ throw new Error('Unsupported symmetric cipher, OID ' + cipher);
+ }
+
+ if(key === undefined) {
+ key = forge.util.createBuffer(forge.random.getBytes(keyLen));
+ } else if(key.length() != keyLen) {
+ throw new Error('Symmetric key has wrong length; ' +
+ 'got ' + key.length() + ' bytes, expected ' + keyLen + '.');
+ }
+
+ // Keep a copy of the key & IV in the object, so the caller can
+ // use it for whatever reason.
+ msg.encryptedContent.algorithm = cipher;
+ msg.encryptedContent.key = key;
+ msg.encryptedContent.parameter = forge.util.createBuffer(
+ forge.random.getBytes(ivLen));
+
+ var ciph = ciphFn(key);
+ ciph.start(msg.encryptedContent.parameter.copy());
+ ciph.update(msg.content);
+
+ // The finish function does PKCS#7 padding by default, therefore
+ // no action required by us.
+ if(!ciph.finish()) {
+ throw new Error('Symmetric encryption failed.');
+ }
+
+ msg.encryptedContent.content = ciph.output;
+ }
+
+ // Part 2: asymmetric encryption for each recipient
+ for(var i = 0; i < msg.recipients.length; i ++) {
+ var recipient = msg.recipients[i];
+
+ // Nothing to do, encryption already done.
+ if(recipient.encryptedContent.content !== undefined) {
+ continue;
+ }
+
+ switch(recipient.encryptedContent.algorithm) {
+ case forge.pki.oids.rsaEncryption:
+ recipient.encryptedContent.content =
+ recipient.encryptedContent.key.encrypt(
+ msg.encryptedContent.key.data);
+ break;
+
+ default:
+ throw new Error('Unsupported asymmetric cipher, OID ' +
+ recipient.encryptedContent.algorithm);
+ }
+ }
+ }
+ };
+ return msg;
+};
+
+} // end module implementation
+
+/* ########## Begin module wrapper ########## */
+var name = 'pkcs7';
+if(typeof define !== 'function') {
+ // NodeJS -> AMD
+ if(typeof module === 'object' && module.exports) {
+ var nodeJS = true;
+ define = function(ids, factory) {
+ factory(require, module);
+ };
+ } else {
+ // <script>
+ if(typeof forge === 'undefined') {
+ forge = {};
+ }
+ return initModule(forge);
+ }
+}
+// AMD
+var deps;
+var defineFunc = function(require, module) {
+ module.exports = function(forge) {
+ var mods = deps.map(function(dep) {
+ return require(dep);
+ }).concat(initModule);
+ // handle circular dependencies
+ forge = forge || {};
+ forge.defined = forge.defined || {};
+ if(forge.defined[name]) {
+ return forge[name];
+ }
+ forge.defined[name] = true;
+ for(var i = 0; i < mods.length; ++i) {
+ mods[i](forge);
+ }
+ return forge[name];
+ };
+};
+var tmpDefine = define;
+define = function(ids, factory) {
+ deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
+ if(nodeJS) {
+ delete define;
+ return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
+ }
+ define = tmpDefine;
+ return define.apply(null, Array.prototype.slice.call(arguments, 0));
+};
+define([
+ 'require',
+ 'module',
+ './aes',
+ './asn1',
+ './des',
+ './oids',
+ './pem',
+ './pkcs7asn1',
+ './random',
+ './util',
+ './x509'
+], function() {
+ defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
+});
+})();