├── LICENSE ├── README.md ├── dev ├── CryptoConstant.js ├── CryptoMessage.js └── CryptoPro.js ├── package.json └── src ├── cryptoAPI.js └── nativeBridge.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Alexander 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CryptoProAPI 2 | Простое API для работы с КриптоПро ЭЦП Browser plug-in 3 | 4 | 5 | ### Вкратце 6 | 1. Подключение 7 | 2. Получение информации из ключа 8 | 3. Получение всех сертификатов установленных на компьютере 9 | 4. Вычисление хеш 10 | 5. Создание подписи 11 | 6. Верификация подписи 12 | 13 | 14 | ### Использование 15 | 16 | #### Подключение 17 | 18 | Чтобы эта штура зарботала, достаточно подключить [один файл](https://github.com/shanhaichik/CryptoProAPI/blob/master/src/cryptoAPI.js). 19 | 20 | ```html 21 | 22 | ``` 23 | 24 | #### Получение информации из ключа 25 | 26 | ##### Метод getByHash 27 | Получение сертификата по хешу ключа (fingerprint) 28 | 29 | ```javascript 30 | var key = CryptoPro.getByHash('000000000000000000000000').get(); 31 | 32 | // или 33 | 34 | var key = CryptoPro.getByHash('000000000000000000000000'); 35 | key.get(); 36 | ``` 37 | 38 | ##### Метод getExtendedKeyUsage 39 | Получение информации из ключа 40 | Получение OID сертификата (улучшенного ключа) 41 | 42 | ```javascript 43 | var key = CryptoPro.getByHash('000000000000000000000000'); 44 | 45 | key.getExtendedKeyUsage(); 46 | ``` 47 | 48 | ##### Метод hasKeyUsageOID 49 | Проверка наличия OID или группы OID в ключе 50 | 51 | ```javascript 52 | key.hasKeyUsageOID('1.3.6.1.5.5.7.3.2'); 53 | 54 | //или 55 | 56 | key.hasKeyUsageOID(["1.3.6.1.5.5.7.3.4", "1.3.6.1.5.5.7.3.2", "1.2.643.2.2.34.6"]); 57 | ``` 58 | 59 | ##### Метод isKeyValid 60 | Получение информации валидный ключ или нет 61 | 62 | ```javascript 63 | key.isKeyValid(); 64 | ``` 65 | 66 | ##### Метод getOwner 67 | Парсит SubjectName ключа по тегам 68 | 69 | ```javascript 70 | key.getOwner(); 71 | ``` 72 | 73 | ##### Метод getIssuer 74 | Парсит IssuerName ключа по тегам 75 | 76 | ```javascript 77 | key.getIssuer(); 78 | ``` 79 | 80 | ##### Метод getAlgorithm 81 | Информауия об алгоритме 82 | 83 | ```javascript 84 | key.getAlgorithm(); 85 | ``` 86 | 87 | #### Получение всех сертификатов установленных на компьютере. 88 | 89 | ##### Метод getList 90 | ```javascript 91 | CryptoPro.getList(); 92 | ``` 93 | 94 | 95 | #### Создание ЭП 96 | 97 | ##### Метод SignPkcs7 98 | Создание ЭП в формате Pkcs7 99 | 100 | Параметры: 101 | * Хеш / Fingerprint {String} 102 | * Данные для подписи {String} 103 | * Прикрепленная / отсоединенная {Boolean, default:false} 104 | 105 | ```javascript 106 | CryptoPro.SignPkcs7(hash, signData, signType); 107 | ``` 108 | 109 | ##### Метод SignXML 110 | Создание ЭП в формате XML 111 | 112 | Параметры: 113 | * Хеш / Fingerprint {String} 114 | * Данные для подписи {String} 115 | 116 | ```javascript 117 | CryptoPro.SignXML(hash, signData); 118 | ``` 119 | 120 | 121 | ##### Метод SignHash 122 | Создание ЭП по хэш значению 123 | 124 | Параметры: 125 | * Хеш / Fingerprint {String} 126 | * Вычисленный хеш данных {String} 127 | * Отсоединенная {Boolean, default:false} 128 | 129 | ```javascript 130 | CryptoPro.SignHash(hash, hashValue, signType); 131 | ``` 132 | 133 | 134 | #### Вычисление хеш 135 | 136 | ##### Метод getHash 137 | Вычисление хеш значеняи данных по Гост. 138 | 139 | Параметры: 140 | * Строка для вычисления хеш {String} 141 | * Вычисления хеш бинарных данных {Boolean, default:false} 142 | 143 | ```javascript 144 | CryptoPro.getHash(str, binary); 145 | ``` 146 | 147 | 148 | #### Верификация ЭП 149 | 150 | ##### Метод getHash 151 | Верификация подписи в формате Pkcs7 152 | 153 | Параметры: 154 | * Строка с подписью {String} 155 | * Тип подписи открепленная/присоединенная {Boolean, default:false} 156 | 157 | ```javascript 158 | CryptoPro.getHash(signature, signType); 159 | ``` 160 | 161 | ##### Метод VerifyXML 162 | Верификация подписи в формате XML 163 | 164 | Параметры: 165 | * Строка с подписью {String} 166 | 167 | ```javascript 168 | CryptoPro.VerifyXML(signature); 169 | ``` 170 | 171 | ##### Метод VerifyHash 172 | Верификация подписипо хэш значению 173 | 174 | Параметры: 175 | * Хеш / Fingerprint {String} 176 | * Вычисленный хеш данных {String} 177 | * Строка с подписью {String} 178 | * Отсоединенная {Boolean, default:false} 179 | 180 | ```javascript 181 | CryptoPro.VerifyHash(hash, hashValue, signature, signType); 182 | ``` 183 | 184 | #### Любые замечания, баги и предложения приветствуются и дают в карму +1. -------------------------------------------------------------------------------- /dev/CryptoConstant.js: -------------------------------------------------------------------------------- 1 | var CryptoConstant = {}; 2 | 3 | // CAPICOM_STORE_LOCATION enumeration 4 | CryptoConstant.StoreLocation = { 5 | CAPICOM_MEMORY_STORE: 0, 6 | CAPICOM_LOCAL_MACHINE_STORE: 1, 7 | CAPICOM_CURRENT_USER_STORE: 2, 8 | CAPICOM_ACTIVE_DIRECTORY_USER_STORE: 3, 9 | CAPICOM_SMART_CARD_USER_STORE: 4 10 | }; 11 | 12 | // CAPICOM_STORE_OPEN_MODE enumeration 13 | CryptoConstant.StoreOpenMode = { 14 | CAPICOM_STORE_OPEN_READ_ONLY: 0, 15 | CAPICOM_STORE_OPEN_READ_WRITE: 1, 16 | CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED: 2, 17 | CAPICOM_STORE_OPEN_EXISTING_ONLY: 128, 18 | CAPICOM_STORE_OPEN_INCLUDE_ARCHIVED: 256 19 | }; 20 | 21 | // CAPICOM_CERTIFICATE_FIND_TYPE enumeration 22 | CryptoConstant.CertFindType = { 23 | CAPICOM_CERTIFICATE_FIND_SHA1_HASH: 0, 24 | CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME: 1, 25 | CAPICOM_CERTIFICATE_FIND_ISSUER_NAME: 2, 26 | CAPICOM_CERTIFICATE_FIND_ROOT_NAME: 3, 27 | CAPICOM_CERTIFICATE_FIND_TEMPLATE_NAME: 4, 28 | CAPICOM_CERTIFICATE_FIND_EXTENSION: 5, 29 | CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY: 6, 30 | CAPICOM_CERTIFICATE_FIND_APPLICATION_POLICY: 7, 31 | CAPICOM_CERTIFICATE_FIND_CERTIFICATE_POLICY: 8, 32 | CAPICOM_CERTIFICATE_FIND_TIME_VALID: 9, 33 | CAPICOM_CERTIFICATE_FIND_TIME_NOT_YET_VALID: 10, 34 | CAPICOM_CERTIFICATE_FIND_TIME_EXPIRED: 11, 35 | CAPICOM_CERTIFICATE_FIND_KEY_USAGE: 12 36 | }; 37 | 38 | CryptoConstant.Time = { 39 | AUTHENTICATED_ATTRIBUTE_SIGNING_TIME: 0 40 | }; 41 | 42 | CryptoConstant.Check = { 43 | CHECK_NONE: 0, 44 | CHECK_TRUSTED_ROOT: 1, 45 | CHECK_TIME_VALIDITY: 2, 46 | CHECK_SIGNATURE_VALIDITY: 4, 47 | CHECK_ONLINE_REVOCATION_STATUS: 8, 48 | CHECK_OFFLINE_REVOCATION_STATUS: 16, 49 | TRUST_IS_NOT_TIME_VALID: 1, 50 | TRUST_IS_NOT_TIME_NESTED: 2, 51 | TRUST_IS_REVOKED: 4, 52 | TRUST_IS_NOT_SIGNATURE_VALID: 8, 53 | TRUST_IS_NOT_VALID_FOR_USAGE: 16, 54 | TRUST_IS_UNTRUSTED_ROOT: 32, 55 | TRUST_REVOCATION_STATUS_UNKNOWN: 64, 56 | TRUST_IS_CYCLIC: 128, 57 | TRUST_IS_PARTIAL_CHAIN: 65536, 58 | TRUST_CTL_IS_NOT_TIME_VALID: 131072, 59 | TRUST_CTL_IS_NOT_SIGNATURE_VALID: 262144, 60 | TRUST_CTL_IS_NOT_VALID_FOR_USAGE: 524288, 61 | }; 62 | 63 | // CAPICOM_PROPID enumeration 64 | CryptoConstant.PropId = { 65 | CAPICOM_PROPID_UNKNOWN: 0, 66 | CAPICOM_PROPID_KEY_PROV_HANDLE: 1, 67 | CAPICOM_PROPID_KEY_PROV_INFO: 2, 68 | CAPICOM_PROPID_SHA1_HASH: 3, 69 | CAPICOM_PROPID_HASH_PROP: 3, 70 | CAPICOM_PROPID_MD5_HASH: 4, 71 | CAPICOM_PROPID_KEY_CONTEXT: 5, 72 | CAPICOM_PROPID_KEY_SPEC: 6, 73 | CAPICOM_PROPID_IE30_RESERVED: 7, 74 | CAPICOM_PROPID_PUBKEY_HASH_RESERVED: 8, 75 | CAPICOM_PROPID_ENHKEY_USAGE: 9, 76 | CAPICOM_PROPID_CTL_USAGE: 9, 77 | CAPICOM_PROPID_NEXT_UPDATE_LOCATION: 10, 78 | CAPICOM_PROPID_FRIENDLY_NAME: 11, 79 | CAPICOM_PROPID_PVK_FILE: 12, 80 | CAPICOM_PROPID_DESCRIPTION: 13, 81 | CAPICOM_PROPID_ACCESS_STATE: 14, 82 | CAPICOM_PROPID_SIGNATURE_HASH: 15, 83 | CAPICOM_PROPID_SMART_CARD_DATA: 16, 84 | CAPICOM_PROPID_EFS: 17, 85 | CAPICOM_PROPID_FORTEZZA_DATA: 18, 86 | CAPICOM_PROPID_ARCHIVED: 19, 87 | CAPICOM_PROPID_KEY_IDENTIFIER: 20, 88 | CAPICOM_PROPID_AUTO_ENROLL: 21, 89 | CAPICOM_PROPID_PUBKEY_ALG_PARA: 22, 90 | CAPICOM_PROPID_CROSS_CERT_DIST_POINTS: 23, 91 | CAPICOM_PROPID_ISSUER_PUBLIC_KEY_MD5_HASH: 24, 92 | CAPICOM_PROPID_SUBJECT_PUBLIC_KEY_MD5_HASH: 25, 93 | CAPICOM_PROPID_ENROLLMENT: 26, 94 | CAPICOM_PROPID_DATE_STAMP: 27, 95 | CAPICOM_PROPID_ISSUER_SERIAL_NUMBER_MD5_HASH: 28, 96 | CAPICOM_PROPID_SUBJECT_NAME_MD5_HASH: 29, 97 | CAPICOM_PROPID_EXTENDED_ERROR_INFO: 30, 98 | CAPICOM_PROPID_RENEWAL: 64, 99 | CAPICOM_PROPID_ARCHIVED_KEY_HASH: 65, 100 | CAPICOM_PROPID_FIRST_RESERVED: 66, 101 | CAPICOM_PROPID_LAST_RESERVED: 0x00007FFF, 102 | CAPICOM_PROPID_FIRST_USER: 0x00008000, 103 | CAPICOM_PROPID_LAST_USER: 0x0000FFFF 104 | }; 105 | 106 | // CADESCOM_XML_SIGNATURE_TYPE enumeration 107 | CryptoConstant.SignatureType = { 108 | CADESCOM_XML_SIGNATURE_TYPE_ENVELOPED: 0, 109 | CADESCOM_XML_SIGNATURE_TYPE_ENVELOPING: 1, 110 | CADESCOM_XML_SIGNATURE_TYPE_TEMPLATE: 2 111 | }; 112 | 113 | // CADESCOM_HASH_ALGORITHM enumeration 114 | CryptoConstant.HashAlgorithm = { 115 | CADESCOM_HASH_ALGORITHM_CP_GOST_3411: 100, 116 | CADESCOM_HASH_ALGORITHM_MD2: 1, 117 | CADESCOM_HASH_ALGORITHM_MD4: 2, 118 | CADESCOM_HASH_ALGORITHM_MD5: 3, 119 | CADESCOM_HASH_ALGORITHM_SHA_256: 4, 120 | CADESCOM_HASH_ALGORITHM_SHA_384: 5, 121 | CADESCOM_HASH_ALGORITHM_SHA_512: 6, 122 | CADESCOM_HASH_ALGORITHM_SHA1: 0 123 | }; 124 | 125 | CryptoConstant.CadesType = { 126 | CADESCOM_CADES_DEFAULT: 0, 127 | CADESCOM_CADES_BES: 1, 128 | CADESCOM_CADES_X_LONG_TYPE_1: 0x5d 129 | }; 130 | 131 | CryptoConstant.ContentEncoding = { 132 | CADESCOM_BASE64_TO_BINARY: 0x01, 133 | CADESCOM_STRING_TO_UCS2LE: 0x00 134 | }; 135 | 136 | CryptoConstant.StoreNames = { 137 | CAPICOM_MY_STORE: "My" 138 | }; 139 | 140 | CryptoConstant.Chain = { 141 | CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT: 0, 142 | CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN: 1, 143 | CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY: 2 144 | }; 145 | 146 | CryptoConstant.GostXmlDSigUrls = { 147 | XmlDsigGost3410Url: "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102001-gostr3411", 148 | XmlDsigGost3411Url: "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr3411", 149 | XmlDsigGost3410UrlObsolete: "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411", 150 | XmlDsigGost3411UrlObsolete: "http://www.w3.org/2001/04/xmldsig-more#gostr3411" 151 | }; 152 | 153 | 154 | 155 | 156 | if (typeof define === 'function' && typeof define.amd !== 'undefined') { 157 | define('CryptoConstant', CryptoConstant); 158 | } 159 | 160 | if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 161 | module.exports = CryptoConstant; 162 | } 163 | else { 164 | window.CryptoConstant = CryptoConstant; 165 | } -------------------------------------------------------------------------------- /dev/CryptoMessage.js: -------------------------------------------------------------------------------- 1 | var CryptoMessage = { 2 | 3 | noCertificate: 'В хранилище нет ни одного сертификата', 4 | 5 | noHashCertificate: 'Не удалось найти сертификат в хранилище по Hash', 6 | 7 | noCertificatesStore: 'В хранилище не найдено ни одного сертификата', 8 | 9 | cantCreateSignature: 'Не получилось создать, подпись в формате Pkcs7 из за ошибки:', 10 | 11 | cantCreateSignatureXML: 'Не получилось создать, подпись в формате XML из за ошибки:', 12 | 13 | cantCreateSignatureHash: 'Не получилось создать, подпись Hash значения из за ошибки:', 14 | 15 | noPlugin: 'Не установлен браузер плагин или Крипто Про CSP', 16 | 17 | verifyPkcs7: 'Верификация подписи формата Pkcs7 не прошла из-из ошибки', 18 | 19 | verifyXML: 'Верификация подписи формата XML не прошла из-из ошибки', 20 | 21 | verifyHash: 'Верификация подписи Hash не прошла из-из ошибки:', 22 | 23 | noNativeBridge: 'Не найдена функция call_ru_cryptopro_npcades_10_native_bridge. Для корректной работы подключите файл nativeBridge.js' 24 | }; 25 | 26 | 27 | if (typeof define === 'function' && typeof define.amd !== 'undefined') { 28 | define('CryptoMessage', CryptoMessage); 29 | } 30 | 31 | if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 32 | module.exports = CryptoMessage; 33 | } 34 | else { 35 | window.CryptoMessage = CryptoMessage; 36 | } -------------------------------------------------------------------------------- /dev/CryptoPro.js: -------------------------------------------------------------------------------- 1 | var CryptoConstant = require('./CryptoConstant'); 2 | var CryptoMessage = require('./CryptoMessage'); 3 | 4 | window.CryptoPro = (function(crypto, constant, message) { 5 | 'use strict'; 6 | 7 | if(Object.keys(crypto).length) { 8 | return crypto; 9 | } 10 | //Установлен и включен браузер плагин 11 | var _enablePlugin = false, _private; 12 | 13 | _private = { 14 | isIE:(navigator.userAgent.match(/msie/i) || navigator.userAgent.match(/Trident\/./i)), 15 | isApple: (navigator.userAgent.match(/ipod/i) || navigator.userAgent.match(/ipad/i) || navigator.userAgent.match(/iphone/i)), 16 | 17 | /* 18 | * Добавление object в DOM для работы с Crypto API 19 | * 20 | * @method init 21 | */ 22 | init: function() { 23 | var o = document.createElement('object'); 24 | o.id = 'cadesplugin'; 25 | o.type = 'application/x-cades'; 26 | o.className = 'hiddenObject'; 27 | document.body.appendChild(o); 28 | 29 | if(!this.checkPlugin()) { 30 | throw new Error(message.noPlugin); 31 | } 32 | }, 33 | 34 | /* 35 | * Проверка установлен и включен Браузер плагин с Крипто Про CSP 36 | * 37 | * @method checkPlugin 38 | * @returns {Boolean|String} Возвращает объект с информацией о Крипто Про CSP или false 39 | */ 40 | checkPlugin: function() { 41 | try { 42 | var csp = this.createObject('CAdESCOM.About'); 43 | return csp; 44 | } 45 | catch(e) {} 46 | 47 | return false; 48 | }, 49 | 50 | /* 51 | * Создание объекта 52 | * 53 | * @method createObject 54 | * @param {String} name Имя создаваемого объекта 55 | * @returns {Boolean|String} Возвращает информацию о Крипто Про CSP или false 56 | */ 57 | createObject:function(name){ 58 | if(this.isApple) { 59 | if(call_ru_cryptopro_npcades_10_native_bridge 60 | && typeof call_ru_cryptopro_npcades_10_native_bridge === 'function') { 61 | return call_ru_cryptopro_npcades_10_native_bridge("CreateObject", [name]); 62 | } 63 | else { 64 | throw new Error(message.noNativeBridge); 65 | } 66 | } 67 | 68 | if(!this.isIE){ 69 | var o = document.getElementById('cadesplugin'); 70 | return o.CreateObject(name); 71 | } 72 | return new ActiveXObject(name); 73 | }, 74 | 75 | /* 76 | * Преобразует дату для IE 77 | * 78 | * @method convertDate 79 | * @param {Date} data 80 | * @returns {Date} Возвращает дату 81 | */ 82 | convertDate:function(date){ 83 | if(!this.isIE){ 84 | return date; 85 | } 86 | return date.getVarDate(); 87 | }, 88 | 89 | /* 90 | * Переворот строки 91 | * 92 | * @method reverse 93 | * @param {String} srt 94 | * @returns {String} Возвращает перевернутую строку 95 | */ 96 | reverse: function (str) { 97 | var newStr = '', i; 98 | for (i = str.length - 1; i >= 0; i--) { 99 | newStr += str.charAt(i); 100 | } 101 | return newStr; 102 | }, 103 | 104 | /* 105 | * Перевод строки в base64 106 | * 107 | * @method base64Encode 108 | * @param {String} srt Исходная строка 109 | * @returns {String} Возвращает base64 110 | */ 111 | base64Encode: function (str) { 112 | str = JSON.stringify(str); //?? 113 | str = unescape(encodeURIComponent(str)); 114 | 115 | var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 116 | var out = "", 117 | i = 0, 118 | len = str.length, 119 | c1, c2, c3; 120 | while (i < len) { 121 | c1 = str.charCodeAt(i++) & 0xff; 122 | if (i == len) { 123 | out += CHARS.charAt(c1 >> 2); 124 | out += CHARS.charAt((c1 & 0x3) << 4); 125 | out += "=="; 126 | break; 127 | } 128 | c2 = str.charCodeAt(i++); 129 | if (i == len) { 130 | out += CHARS.charAt(c1 >> 2); 131 | out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); 132 | out += CHARS.charAt((c2 & 0xF) << 2); 133 | out += "="; 134 | break; 135 | } 136 | c3 = str.charCodeAt(i++); 137 | out += CHARS.charAt(c1 >> 2); 138 | out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); 139 | out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); 140 | out += CHARS.charAt(c3 & 0x3F); 141 | } 142 | return out; 143 | }, 144 | 145 | /* 146 | * Проверка на массив 147 | * 148 | * @method isArray 149 | * @param {Array} x Массив 150 | * @returns {Boolean} 151 | */ 152 | isArray: function (x) { 153 | return Object.prototype.toString.call(x) === '[object Array]'; 154 | } 155 | 156 | }; 157 | 158 | /* 159 | * Получение сертификата из хранища по хэшу 160 | * 161 | * @method getByHash 162 | * @param {String} hash Fingerprint сертификата для поиска в хранилище 163 | * @returns {Object} Возвращает найденый сертификат 164 | */ 165 | crypto.getByHash = function(hash) { 166 | 167 | if (!(this instanceof crypto.getByHash)) { 168 | return new crypto.getByHash(hash); 169 | } 170 | 171 | var store, certificates; 172 | 173 | if(!_enablePlugin) { 174 | _private.init(); 175 | } 176 | 177 | store = _private.createObject('CAPICOM.store'); 178 | 179 | try { 180 | store.Open(constant.StoreLocation.CAPICOM_CURRENT_USER_STORE, 181 | constant.StoreNames.CAPICOM_MY_STORE, 182 | constant.StoreOpenMode.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED); 183 | 184 | certificates = store.Certificates; 185 | if(certificates.Count === 0) { 186 | throw new Error(message.noCertificate); 187 | } 188 | else { 189 | certificates = certificates.Find(constant.CertFindType.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, hash); 190 | if(certificates.Count > 0) 191 | this.cetificate = certificates.Item(1); 192 | else 193 | throw new Error(message.noHashCertificate); 194 | } 195 | 196 | } 197 | catch (e){ 198 | if (e.number !== -2138568446) // отказ от выбора сертификата 199 | throw new Error("Ошибка при получении сертификата: " + e); 200 | this.cetificate = null; 201 | } 202 | finally { 203 | store.Close(); 204 | store = certificates = null; 205 | } 206 | }; 207 | 208 | 209 | crypto.getByHash.prototype = { 210 | /* 211 | * Получение объекта сертификата 212 | * 213 | * @method get 214 | * @returns {Object} Возвращает найденый сертификат 215 | */ 216 | get: function() { 217 | return this.cetificate; 218 | }, 219 | 220 | /* 221 | * Получение OID сертификата 222 | * 223 | * @method getExtendedKeyUsage 224 | * @returns {Array} Возвращает массив OID (улучшенного ключа) 225 | */ 226 | getExtendedKeyUsage: function () { 227 | var key = this.cetificate, count = key.ExtendedKeyUsage().EKUs.Count, OIDS = []; 228 | 229 | if (count > 0) { 230 | while (count > 0) { 231 | OIDS.push(key.ExtendedKeyUsage().EKUs.Item(count).OID); 232 | count--; 233 | } 234 | } 235 | 236 | return OIDS; 237 | }, 238 | 239 | /* 240 | * Проверка наличия OID или группы OID в ключе 241 | * 242 | * @method hasKeyUsageOID 243 | * @param {String|Array} OID код OID или массив 244 | * @returns {Boolean|Object} Возвращает наличие OID в ключе или объект если их несколько 245 | */ 246 | hasKeyUsageOID: function (OID) { 247 | if(_private.isArray(OID)) { 248 | var keys = this.getExtendedKeyUsage(); 249 | var result = {}, count = OID.length-1; 250 | 251 | while(count > -1) { 252 | result[OID[count]] = !!~keys.indexOf(OID[count]); 253 | count--; 254 | } 255 | 256 | return result; 257 | } 258 | else{ 259 | return !!~this.getExtendedKeyUsage().indexOf(OID); 260 | } 261 | }, 262 | 263 | /* 264 | * Проверка валидный ключ или нет 265 | * 266 | * @method isKeyValid 267 | * @returns {Boolean} 268 | */ 269 | isKeyValid: function() { 270 | return !!this.cetificate.IsValid().Result; 271 | }, 272 | 273 | /* 274 | * Парсит SubjectName ключа по тегам 275 | * 276 | * @method getOwner 277 | * @returns {String} Возвращает структурированную информацию о владельце ключа 278 | */ 279 | getOwner: function() { 280 | var subject = this.cetificate.SubjectName.split(', '), 281 | tags = { 282 | 'CN=' : 'Владелец', 283 | 'S=' : 'Регион/Город', 284 | 'STREET=' : 'Адрес', 285 | 'O=' : 'Компания', 286 | 'OU=' : 'Тип должности', 287 | 'T=' : 'Должность', 288 | 'ОГРН=' : 'ОГРН', 289 | 'СНИЛС=' : 'СНИЛС', 290 | 'ИНН=' : 'ИНН', 291 | 'E=' : 'Email', 292 | 'L=' : 'Город' 293 | }; 294 | 295 | subject = subject.map(function(el){ 296 | var tag = el.substring(0, el.indexOf('=')+1); 297 | if(tags[tag]) return el.replace(tag, tags[tag]+': '); 298 | }).filter(function(el){ 299 | return !!el; 300 | }); 301 | 302 | return subject.join('\n'); 303 | }, 304 | 305 | /* 306 | * Парсит IssuerName ключа по тегам 307 | * 308 | * @method getOwner 309 | * @returns {String} Возвращает структурированную информацию о издателе ключа 310 | */ 311 | getIssuer: function() { 312 | var subject = this.cetificate.SubjectName.split(', '), 313 | tags = { 314 | 'CN=' : 'Удостоверяющий центр', 315 | 'S=' : 'Регион/Город', 316 | 'STREET=' : 'Адрес', 317 | 'O=' : 'Компания', 318 | 'OU=' : 'Тип', 319 | 'T=' : 'Должность', 320 | 'ОГРН=' : 'ОГРН', 321 | 'СНИЛС=' : 'СНИЛС', 322 | 'ИНН=' : 'ИНН', 323 | 'E=' : 'Email', 324 | 'L=' : 'Город' 325 | }; 326 | 327 | subject = subject.map(function(el){ 328 | var tag = el.substring(0, el.indexOf('=')+1); 329 | if(tags[tag]) return el.replace(tag, tags[tag]+': '); 330 | }).filter(function(el){ 331 | return !!el; 332 | }); 333 | 334 | return subject.join('\n'); 335 | }, 336 | 337 | /* 338 | * Вытаскивает информацию об алгоритме 339 | * 340 | * @method getAlgorithm 341 | * @returns {Object} Возвращает объект с информацией об алгоритме 342 | */ 343 | getAlgorithm: function() { 344 | return { 345 | Algorithm: this.cetificate.PublicKey().Algorithm.FriendlyName, 346 | OID: this.cetificate.PublicKey().Algorithm.Value 347 | } 348 | } 349 | }; 350 | 351 | /* 352 | * Получение списка всех сртификатов хранилища 353 | * 354 | * @method getList 355 | * @returns {Array} Возвращает массив с информацией об установленных ключах 356 | */ 357 | crypto.getList = function() { 358 | var store, certificates; 359 | 360 | if(!_enablePlugin) { 361 | _private.init(); 362 | } 363 | 364 | store = _private.createObject('CAPICOM.store'); 365 | 366 | try { 367 | store.Open(constant.StoreLocation.CAPICOM_CURRENT_USER_STORE, 368 | constant.StoreNames.CAPICOM_MY_STORE, 369 | constant.StoreOpenMode.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED); 370 | 371 | certificates = store.Certificates; 372 | if(certificates.Count === 0) { 373 | throw new Error(message.noCertificate) 374 | } 375 | else { 376 | var certificate, list = [], i; 377 | // Не рассматриваются сертификаты, в которых отсутствует закрытый ключ или не действительны на данный момент 378 | certificates = certificates.Find(constant.CertFindType.CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY, constant.PropId.CAPICOM_PROPID_KEY_PROV_INFO) 379 | .Find(constant.CertFindType.CAPICOM_CERTIFICATE_FIND_TIME_VALID); 380 | 381 | i = certificates.Count; 382 | if(i > 0) { 383 | while(i > 0) { 384 | certificate = certificates.Item(i); 385 | 386 | list.push( 387 | { 388 | thumbprint: certificate.Thumbprint, 389 | inform: certificate.GetInfo(0), 390 | validTo: certificate.ValidToDate, 391 | validFrom: certificate.ValidFromDate 392 | } 393 | ); 394 | i-- 395 | } 396 | } 397 | else { 398 | throw new Error(message.noCertificatesStore); 399 | 400 | } 401 | } 402 | } 403 | catch (e){ 404 | if (e.number !== -2138568446) // отказ от выбора сертификата 405 | throw new Error("Ошибка при получении сертификата: "+ e.message); 406 | return; 407 | } 408 | finally { 409 | store.Close(); 410 | store = certificates = null; 411 | } 412 | 413 | return list; 414 | }; 415 | 416 | /* 417 | * Создание ЭП в формате Pkcs7 418 | * 419 | * @method SignPkcs7 420 | * @param {String} hash fingerprint сертификата для подписи 421 | * @param {String} signData Данные для подписи 422 | * @param {Boolean} signType Тип подписи открепленная/присоединенная 423 | * @returns {String} Возвращает строку в формате base64 424 | */ 425 | crypto.SignPkcs7 = function(hash, signData, signType) { 426 | var signer, signedData, signedTime, time = new Date(), type = !!signType; 427 | 428 | signer = _private.createObject('CAdESCOM.CPSigner'); 429 | signedData = _private.createObject('CAdESCOM.CadesSignedData'); 430 | signedTime = _private.createObject('CADESCOM.CPAttribute'); 431 | 432 | // Готовим метку времени создания подписи 433 | signedTime.Name = constant.Time.AUTHENTICATED_ATTRIBUTE_SIGNING_TIME; 434 | signedTime.Value = _private.convertDate(time); 435 | 436 | // Вытаскиваем нужный сертификат для создания подписи 437 | signer.Certificate = this.getByHash(hash).get(); 438 | // Добавляем метку времени в подпись 439 | signer.AuthenticatedAttributes2.Add(signedTime); 440 | // Выставляем глубину проверки цепочки сертификатов 441 | signer.Options = constant.Chain.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN; 442 | // Задаем тип преобразования данных 443 | signedData.ContentEncoding = constant.ContentEncoding.CADESCOM_BASE64_TO_BINARY; 444 | // Добавляем данные для подписи 445 | signedData.Content = (signType) ? signData :_private.base64Encode(signData); 446 | 447 | try { 448 | var signature = signedData.SignCades(signer, constant.CadesType.CADESCOM_CADES_BES, type); 449 | } 450 | catch (e) { 451 | throw new Error(message.cantCreateSignature+" " + e); 452 | } 453 | finally { 454 | signer = signedData = signedTime = null; 455 | } 456 | 457 | return signature; 458 | }; 459 | 460 | /* 461 | * Создание ЭП в формате XML 462 | * 463 | * @method SignXML 464 | * @param {String} hash fingerprint сертификата для подписи 465 | * @param {String} signData Данные для подписи 466 | * @returns {String} Возвращает строку в виде XML с подписью 467 | */ 468 | crypto.SignXML = function(hash, signData) { 469 | var signer, signerXML; 470 | 471 | signer = _private.createObject('CAdESCOM.CPSigner'); 472 | signerXML = _private.createObject('CAdESCOM.SignedXML'); 473 | 474 | // Вытаскиваем нужный сертификат для создания подписи 475 | signer.Certificate = this.getByHash(hash).get(); 476 | // Добавляем данные для подписи 477 | signerXML.Content = signData; 478 | // Устанавливаем тип подписи 479 | signerXML.SignatureType = constant.SignatureType.CADESCOM_XML_SIGNATURE_TYPE_ENVELOPED; 480 | // Устанавливаем алгоритм подписи 481 | signerXML.SignatureMethod = constant.GostXmlDSigUrls.XmlDsigGost3410Url; 482 | // Устанавливаем алгоритм хэширования 483 | signerXML.DigestMethod = constant.GostXmlDSigUrls.XmlDsigGost3411Url; 484 | 485 | try { 486 | var signature = signerXML.Sign(signer) 487 | } 488 | catch(e) { 489 | throw new Error(message.cantCreateSignatureXML+" " + e); 490 | } 491 | finally { 492 | signer = signerXML = null; 493 | } 494 | 495 | return signature; 496 | }; 497 | 498 | /* 499 | * Вычсление Hash значения данных или бинарных данных 500 | * 501 | * @method getHash 502 | * @param {String} str строка для вычисления hash значения 503 | * @param {Boolean} binary вычисления хеш бинарных данных 504 | * @returns {String} Возвращает hash строку 505 | */ 506 | crypto.getHash = function (str, binary) { 507 | var hashData, hash; 508 | hashData = _private.createObject('CAdESCOM.HashedData'); 509 | 510 | // Алгоритм хэширования нужно указать до того, как будут переданы данные 511 | hashData.Algorithm = constant.HashAlgorithm.CADESCOM_HASH_ALGORITHM_CP_GOST_3411; 512 | if(binary !== undefined && binary === true) { 513 | // Указываем кодировку данных 514 | // Кодировка должна быть указана до того, как будут переданы сами данные 515 | hashData.DataEncoding = constant.ContentEncoding.CADESCOM_BASE64_TO_BINARY; 516 | 517 | str = _private.base64Encode(str); 518 | } 519 | 520 | hashData.Hash(str); 521 | 522 | // Хэш-значение будет вычислено от данных в кодировке UCS2-LE 523 | // Для алгоритма SHA-1 хэш-значение будет совпадать с вычисленным при помощи CAPICOM 524 | hash = hashData.Value; 525 | 526 | hashData = null; 527 | return hash; 528 | }; 529 | 530 | /* 531 | * Создание ЭП по хэш значению 532 | * 533 | * @method SignHash 534 | * @param {String} hash fingerprint сертификата для подписи 535 | * @param {String} hashValue хэш подписываемых данных 536 | * @param {Boolean} signType отсоединенная / присоединенная 537 | * @returns {String} Возвращает подпись 538 | */ 539 | crypto.SignHash = function(hash, hashValue, signType) { 540 | var hashData, rawSignature, signature; 541 | 542 | if(signType === true) { 543 | var signer = _private.createObject('CAdESCOM.CPSigner'); 544 | rawSignature = _private.createObject('CAdESCOM.CadesSignedData'); 545 | signer.Certificate = this.getByHash(hash).get(); 546 | } 547 | else{ 548 | rawSignature = _private.createObject('CAdESCOM.RawSignature'); 549 | var certificate = this.getByHash(hash).get(); 550 | } 551 | 552 | hashData = _private.createObject('CAdESCOM.HashedData'); 553 | 554 | // Инициализируем объект заранее вычисленным хэш-значением 555 | // Алгоритм хэширования нужно указать до того, как будет передано хэш-значение 556 | hashData.Algorithm = constant.HashAlgorithm.CADESCOM_HASH_ALGORITHM_CP_GOST_3411; 557 | hashData.SetHashValue(hashValue); 558 | 559 | try { 560 | if(signType === true) 561 | signature = rawSignature.SignHash(hashData, signer, constant.ContentEncoding.CADESCOM_BASE64_TO_BINARY); 562 | else 563 | signature = rawSignature.SignHash(hashData, certificate); 564 | } 565 | catch(e) { 566 | throw new Error(message.cantCreateSignatureHash+' '+e); 567 | } 568 | 569 | hashData = rawSignature = null; 570 | 571 | return signature; 572 | }; 573 | 574 | /* 575 | * Верификация подписипо хэш значению 576 | * 577 | * @method VerifyHash 578 | * @param {String} hash fingerprint сертификата для подписи 579 | * @param {String} hashValue хэш подписываемых данных 580 | * @param {String} signature подпись 581 | * @param {Boolean} signType отсоединенная / присоединенная 582 | * @returns {Boolean} 583 | */ 584 | crypto.VerifyHash = function (hash, hashValue, signature, signType) { 585 | var hashData, rawSignature, certificate; 586 | 587 | hashData = _private.createObject('CAdESCOM.HashedData'); 588 | certificate = this.getByHash(hash).get(); 589 | 590 | if(signType === true) 591 | rawSignature = _private.createObject('CAdESCOM.CadesSignedData'); 592 | else 593 | rawSignature = _private.createObject('CAdESCOM.RawSignature'); 594 | 595 | hashData.Algorithm = constant.HashAlgorithm.CADESCOM_HASH_ALGORITHM_CP_GOST_3411; 596 | hashData.SetHashValue(hashValue); 597 | 598 | try { 599 | if(signType === true) 600 | rawSignature.VerifyHash(hashData, signature, constant.ContentEncoding.CADESCOM_BASE64_TO_BINARY); 601 | else 602 | rawSignature.VerifyHash(hashData, certificate, signature); 603 | } 604 | catch (e) { 605 | throw new Error(message.verifyHash+' '+e); 606 | } 607 | finally { 608 | hashData = certificate = rawSignature = null 609 | } 610 | 611 | return true; 612 | }; 613 | 614 | /* 615 | * Верификация подписи в формате Pkcs7 616 | * 617 | * @method VerifyPkcs7 618 | * @param {String} signature строка с подписью 619 | * @param {Boolean} signType Тип подписи открепленная/присоединенная 620 | * @returns {Boolean|String} Валидна или строку с ошибкой 621 | */ 622 | crypto.VerifyPkcs7 = function (signature, signType){ 623 | var signedData, type = !!signType; 624 | 625 | signedData = _private.createObject('CAdESCOM.CadesSignedData'); 626 | 627 | try { 628 | signedData.VerifyCades(signature, constant.CadesType.CADESCOM_CADES_BES, type); 629 | } 630 | catch(e) { 631 | throw new Error(message.verifyPkcs7+" " + e); 632 | } finally { 633 | signedData = null; 634 | } 635 | 636 | return true; 637 | }; 638 | 639 | /* 640 | * Верификация подписи в формате XML 641 | * 642 | * @method VerifyXML 643 | * @param {String} signature строка с подписью 644 | * @returns {Boolean|String} Валидна или строку с ошибкой 645 | */ 646 | crypto.VerifyXML = function(signature){ 647 | var signerXML = _private.createObject('CAdESCOM.SignedXML'); 648 | 649 | try { 650 | signerXML.Verify(signature) 651 | } 652 | catch(e) { 653 | throw new Error(message.verifyXML+" " + e); 654 | } 655 | finally { 656 | signerXML = null; 657 | } 658 | 659 | return true; 660 | }; 661 | 662 | return crypto; 663 | 664 | }(window['CryptoPro'] || {}, CryptoConstant, CryptoMessage)); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CryptoProAPI", 3 | "version": "0.0.1", 4 | "description": "Простое API для работы с КриптоПро ЭЦП Browser plug-in", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/shanhaichik/CryptoProAPI.git" 8 | }, 9 | "author": { 10 | "name": "Alexander Dukhovnyak", 11 | "email": "shanhaichik@gmail.com" 12 | }, 13 | "license": "MIT", 14 | "main": "src/cryptoAPI.js", 15 | "scripts": { 16 | "watch": "watchify ./dev/CryptoPro.js -o dev/bundle.js -v -d", 17 | "browserify": "browserify ./dev/CryptoPro.js | uglifyjs -m > src/cryptoAPI.js", 18 | "build": "npm run browserify ", 19 | "start": "npm run watch" 20 | }, 21 | "devDependencies": { 22 | "browserify": "~6.0.3", 23 | "uglify-js": "~2.4.15", 24 | "watchify": "~2.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cryptoAPI.js: -------------------------------------------------------------------------------- 1 | (function e(t,_,C){function r(i,E){if(!_[i]){if(!t[i]){var A=typeof require=="function"&&require;if(!E&&A)return A(i,!0);if(n)return n(i,!0);var O=new Error("Cannot find module '"+i+"'");throw O.code="MODULE_NOT_FOUND",O}var I=_[i]={exports:{}};t[i][0].call(I.exports,function(e){var _=t[i][1][e];return r(_?_:e)},I,I.exports,e,t,_,C)}return _[i].exports}var n=typeof require=="function"&&require;for(var i=0;i=0;_--){t+=e.charAt(_)}return t},base64Encode:function(e){e=JSON.stringify(e);e=unescape(encodeURIComponent(e));var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var _="",C=0,r=e.length,n,i,E;while(C>2);_+=t.charAt((n&3)<<4);_+="==";break}i=e.charCodeAt(C++);if(C==r){_+=t.charAt(n>>2);_+=t.charAt((n&3)<<4|(i&240)>>4);_+=t.charAt((i&15)<<2);_+="=";break}E=e.charCodeAt(C++);_+=t.charAt(n>>2);_+=t.charAt((n&3)<<4|(i&240)>>4);_+=t.charAt((i&15)<<2|(E&192)>>6);_+=t.charAt(E&63)}return _},isArray:function(e){return Object.prototype.toString.call(e)==="[object Array]"}};e.getByHash=function(n){if(!(this instanceof e.getByHash)){return new e.getByHash(n)}var i,E;if(!C){r.init()}i=r.createObject("CAPICOM.store");try{i.Open(t.StoreLocation.CAPICOM_CURRENT_USER_STORE,t.StoreNames.CAPICOM_MY_STORE,t.StoreOpenMode.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED);E=i.Certificates;if(E.Count===0){throw new Error(_.noCertificate)}else{E=E.Find(t.CertFindType.CAPICOM_CERTIFICATE_FIND_SHA1_HASH,n);if(E.Count>0)this.cetificate=E.Item(1);else throw new Error(_.noHashCertificate)}}catch(A){if(A.number!==-2138568446)throw new Error("Ошибка при получении сертификата: "+A);this.cetificate=null}finally{i.Close();i=E=null}};e.getByHash.prototype={get:function(){return this.cetificate},getExtendedKeyUsage:function(){var e=this.cetificate,t=e.ExtendedKeyUsage().EKUs.Count,_=[];if(t>0){while(t>0){_.push(e.ExtendedKeyUsage().EKUs.Item(t).OID);t--}}return _},hasKeyUsageOID:function(e){if(r.isArray(e)){var t=this.getExtendedKeyUsage();var _={},C=e.length-1;while(C>-1){_[e[C]]=!!~t.indexOf(e[C]);C--}return _}else{return!!~this.getExtendedKeyUsage().indexOf(e)}},isKeyValid:function(){return!!this.cetificate.IsValid().Result},getOwner:function(){var e=this.cetificate.SubjectName.split(", "),t={"CN=":"Владелец","S=":"Регион/Город","STREET=":"Адрес","O=":"Компания","OU=":"Тип должности","T=":"Должность","ОГРН=":"ОГРН","СНИЛС=":"СНИЛС","ИНН=":"ИНН","E=":"Email","L=":"Город"};e=e.map(function(e){var _=e.substring(0,e.indexOf("=")+1);if(t[_])return e.replace(_,t[_]+": ")}).filter(function(e){return!!e});return e.join("\n")},getIssuer:function(){var e=this.cetificate.SubjectName.split(", "),t={"CN=":"Удостоверяющий центр","S=":"Регион/Город","STREET=":"Адрес","O=":"Компания","OU=":"Тип","T=":"Должность","ОГРН=":"ОГРН","СНИЛС=":"СНИЛС","ИНН=":"ИНН","E=":"Email","L=":"Город"};e=e.map(function(e){var _=e.substring(0,e.indexOf("=")+1);if(t[_])return e.replace(_,t[_]+": ")}).filter(function(e){return!!e});return e.join("\n")},getAlgorithm:function(){return{Algorithm:this.cetificate.PublicKey().Algorithm.FriendlyName,OID:this.cetificate.PublicKey().Algorithm.Value}}};e.getList=function(){var e,n;if(!C){r.init()}e=r.createObject("CAPICOM.store");try{e.Open(t.StoreLocation.CAPICOM_CURRENT_USER_STORE,t.StoreNames.CAPICOM_MY_STORE,t.StoreOpenMode.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED);n=e.Certificates;if(n.Count===0){throw new Error(_.noCertificate)}else{var i,E=[],A;n=n.Find(t.CertFindType.CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY,t.PropId.CAPICOM_PROPID_KEY_PROV_INFO).Find(t.CertFindType.CAPICOM_CERTIFICATE_FIND_TIME_VALID);A=n.Count;if(A>0){while(A>0){i=n.Item(A);E.push({thumbprint:i.Thumbprint,inform:i.GetInfo(0),validTo:i.ValidToDate,validFrom:i.ValidFromDate});A--}}else{throw new Error(_.noCertificatesStore)}}}catch(O){if(O.number!==-2138568446)throw new Error("Ошибка при получении сертификата: "+O.message);return}finally{e.Close();e=n=null}return E};e.SignPkcs7=function(e,C,n){var i,E,A,O=new Date,I=!!n;i=r.createObject("CAdESCOM.CPSigner");E=r.createObject("CAdESCOM.CadesSignedData");A=r.createObject("CADESCOM.CPAttribute");A.Name=t.Time.AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;A.Value=r.convertDate(O);i.Certificate=this.getByHash(e).get();i.AuthenticatedAttributes2.Add(A);i.Options=t.Chain.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN;E.ContentEncoding=t.ContentEncoding.CADESCOM_BASE64_TO_BINARY;E.Content=n?C:r.base64Encode(C);try{var a=E.SignCades(i,t.CadesType.CADESCOM_CADES_BES,I)}catch(o){throw new Error(_.cantCreateSignature+" "+o)}finally{i=E=A=null}return a};e.SignXML=function(e,C){var n,i;n=r.createObject("CAdESCOM.CPSigner");i=r.createObject("CAdESCOM.SignedXML");n.Certificate=this.getByHash(e).get();i.Content=C;i.SignatureType=t.SignatureType.CADESCOM_XML_SIGNATURE_TYPE_ENVELOPED;i.SignatureMethod=t.GostXmlDSigUrls.XmlDsigGost3410Url;i.DigestMethod=t.GostXmlDSigUrls.XmlDsigGost3411Url;try{var E=i.Sign(n)}catch(A){throw new Error(_.cantCreateSignatureXML+" "+A)}finally{n=i=null}return E};e.getHash=function(e,_){var C,n;C=r.createObject("CAdESCOM.HashedData");C.Algorithm=t.HashAlgorithm.CADESCOM_HASH_ALGORITHM_CP_GOST_3411;if(_!==undefined&&_===true){C.DataEncoding=t.ContentEncoding.CADESCOM_BASE64_TO_BINARY;e=r.base64Encode(e)}C.Hash(e);n=C.Value;C=null;return n};e.SignHash=function(e,C,n){var i,E,A;if(n===true){var O=r.createObject("CAdESCOM.CPSigner");E=r.createObject("CAdESCOM.CadesSignedData");O.Certificate=this.getByHash(e).get()}else{E=r.createObject("CAdESCOM.RawSignature");var I=this.getByHash(e).get()}i=r.createObject("CAdESCOM.HashedData");i.Algorithm=t.HashAlgorithm.CADESCOM_HASH_ALGORITHM_CP_GOST_3411;i.SetHashValue(C);try{if(n===true)A=E.SignHash(i,O,t.ContentEncoding.CADESCOM_BASE64_TO_BINARY);else A=E.SignHash(i,I)}catch(a){throw new Error(_.cantCreateSignatureHash+" "+a)}i=E=null;return A};e.VerifyHash=function(e,C,n,i){var E,A,O;E=r.createObject("CAdESCOM.HashedData");O=this.getByHash(e).get();if(i===true)A=r.createObject("CAdESCOM.CadesSignedData");else A=r.createObject("CAdESCOM.RawSignature");E.Algorithm=t.HashAlgorithm.CADESCOM_HASH_ALGORITHM_CP_GOST_3411;E.SetHashValue(C);try{if(i===true)A.VerifyHash(E,n,t.ContentEncoding.CADESCOM_BASE64_TO_BINARY);else A.VerifyHash(E,O,n)}catch(I){throw new Error(_.verifyHash+" "+I)}finally{E=O=A=null}return true};e.VerifyPkcs7=function(e,C){var n,i=!!C;n=r.createObject("CAdESCOM.CadesSignedData");try{n.VerifyCades(e,t.CadesType.CADESCOM_CADES_BES,i)}catch(E){throw new Error(_.verifyPkcs7+" "+E)}finally{n=null}return true};e.VerifyXML=function(e){var t=r.createObject("CAdESCOM.SignedXML");try{t.Verify(e)}catch(C){throw new Error(_.verifyXML+" "+C)}finally{t=null}return true};return e}(window["CryptoPro"]||{},C,r)},{"./CryptoConstant":1,"./CryptoMessage":2}]},{},[3]); -------------------------------------------------------------------------------- /src/nativeBridge.js: -------------------------------------------------------------------------------- 1 | var ru_cryptopro_npcades_10_native_bridge = { 2 | callbacksCount : 1, 3 | callbacks : {}, 4 | 5 | // Automatically called by native layer when a result is available 6 | resultForCallback : function resultForCallback(callbackId, resultArray) { 7 | "use strict"; 8 | 9 | var callback = ru_cryptopro_npcades_10_native_bridge.callbacks[callbackId]; 10 | if (!callback) { 11 | return; 12 | } else { 13 | callback.apply(null, resultArray); 14 | } 15 | }, 16 | 17 | // Use this in javascript to request native objective-c code 18 | // functionName : string (I think the name is explicit :p) 19 | // args : array of arguments 20 | // callback : function with n-arguments that is going to be called when the native code returned 21 | call : function call(functionName, args, callback) { 22 | "use strict"; 23 | 24 | var hasCallback = callback && typeof callback === "function", 25 | callbackId = hasCallback ? ru_cryptopro_npcades_10_native_bridge.callbacksCount += 1 : 0, 26 | iframe = document.createElement("IFRAME"), 27 | arrObjs = ["_CPNP_handle"]; 28 | 29 | if (hasCallback) { 30 | ru_cryptopro_npcades_10_native_bridge.callbacks[callbackId] = callback; 31 | } 32 | 33 | try { 34 | iframe.setAttribute("src", "cpnp-js-call:" + functionName + ":" + callbackId + ":" + encodeURIComponent(JSON.stringify(args, arrObjs))); 35 | } catch (e) { 36 | throw e; 37 | } 38 | 39 | document.documentElement.appendChild(iframe); 40 | iframe.parentNode.removeChild(iframe); 41 | iframe = null; 42 | } 43 | }; 44 | 45 | function call_ru_cryptopro_npcades_10_native_bridge(functionName, array) { 46 | "use strict"; 47 | 48 | var tmpobj, 49 | ex; 50 | 51 | try { 52 | ru_cryptopro_npcades_10_native_bridge.call(functionName, array, function (e, response) { 53 | var str = 'tmpobj=' + response; 54 | ex = e; 55 | eval(str); 56 | if (typeof (tmpobj) === "string") { 57 | tmpobj = tmpobj.replace(/\\\n/gm, "\n"); 58 | tmpobj = tmpobj.replace(/\\\r/gm, "\r"); 59 | } 60 | }); 61 | if (ex) { 62 | throw ex; 63 | } else { 64 | return tmpobj; 65 | } 66 | } catch (e) { 67 | throw e; 68 | } 69 | } --------------------------------------------------------------------------------