diff --git a/.gitattributes b/.gitattributes index b5a039fa..bcf9e4d9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ resources/openpgp*.js binary +resources/keyring*.js binary diff --git a/.gitignore b/.gitignore index 90e9c209..7c65f83d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ resources/openpgpjs.pem build/ .DS_Store -node_modules -test/integration/lib \ No newline at end of file +node_modules/ +npm* +test/lib/ +resources/keyring_nodebug.js +resources/openpgp_nodebug.js diff --git a/Gruntfile.js b/Gruntfile.js index 1909a371..2358ec0e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,52 +1,158 @@ module.exports = function(grunt) { - 'use strict'; - // Project configuration. - grunt.initConfig({ - connect: { - dev: { - options: { - port: 8680, - base: '.', - keepalive: true - } - }, - test: { - options: { - port: 8681, - base: '.' - } - } + // Project configuration. + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + browserify: { + openpgp_nodebug: { + files: { + 'resources/openpgp_nodebug.js': [] }, - - mocha: { - all: { - options: { - urls: ['http://localhost:<%= connect.test.options.port %>/test/integration/index.html'], - run: false, - reporter: 'Spec' - } - } - }, - - copy: { - npm: { - expand: true, - flatten: true, - cwd: 'node_modules/', - src: ['requirejs/require.js', 'mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js'], - dest: 'test/integration/lib/' - } + options: { + alias: './src/:openpgp' } + }, + openpgp: { + files: { + 'resources/openpgp.js': [] + }, + options: { + debug: true, + alias: './src/:openpgp' + } + }, + keyring_nodebug: { + files: { + 'resources/keyring_nodebug.js': [] + }, + options: { + alias: './src/keyring/:keyring', + external: [ 'openpgp' ] + } + }, + keyring: { + files: { + 'resources/keyring.js': [] + }, + options: { + debug: true, + alias: './src/keyring/:keyring', + external: [ 'openpgp' ] + } + }, + unittests: { + files: { + 'test/lib/test-bundle.js': [] + }, + options: { + debug: true, + alias: './test/test-all.js:unittests', + external: [ 'openpgp', 'keyring' ] + } + }, + ci_tests: { + files: { + 'test/lib/ci-tests-bundle.js': [] + }, + options: { + debug: true, + alias: './test/ci-tests-all.js:ci-tests', + external: [ 'openpgp', 'keyring' ] + } + } + }, + replace : { + openpgpjs: { + src: ['resources/openpgp.js'], + dest: ['resources/openpgp.js'], + replacements: [{ + from: /OpenPGP.js VERSION/g, + to: 'OpenPGP.js v<%= pkg.version %>.<%= grunt.template.today("yyyymmdd") %>' + }] + }, + openpgpjs_nodebug: { + src: ['resources/openpgp_nodebug.js'], + dest: ['resources/openpgp_nodebug.js'], + replacements: [{ + from: /OpenPGP.js VERSION/g, + to: 'OpenPGP.js v<%= pkg.version %>.<%= grunt.template.today("yyyymmdd") %>' + }] + } + }, + uglify: { + openpgpjs: { + files: { + "resources/openpgp.min.js" : [ "resources/openpgp_nodebug.js" ], + "resources/keyring.min.js" : [ "resources/keyring_nodebug.js" ] + } + }, + options: { + banner: '/*! OpenPGPjs.org this is LGPL licensed code, see LICENSE/our website for more information.- v<%= pkg.version %> - ' + + '<%= grunt.template.today("yyyy-mm-dd") %> */' + } + }, + jsbeautifier : { + files : ["src/**/*.js"], + options : { + indent_size: 2, + preserve_newlines: true, + keep_array_indentation: false, + keep_function_indentation: false, + wrap_line_length: 120 + } + }, + jshint : { + all : ["src/**/*.js"] + }, + jsdoc : { + dist : { + src: ["README.md", "src"], + options: { + destination: "doc", + recurse: true, + template: "jsdoc.template" + } + } + }, + + copy: { + npm: { + expand: true, + flatten: true, + cwd: 'node_modules/', + src: ['mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js'], + dest: 'test/lib/' + } + } + }); + + // Load the plugin that provides the "uglify" task. + grunt.loadNpmTasks('grunt-browserify'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-text-replace'); + grunt.loadNpmTasks('grunt-jsbeautifier'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-jsdoc'); + + grunt.registerTask('default', 'Build OpenPGP.js', function() { + grunt.task.run(['browserify', 'replace', 'uglify']); + //TODO jshint is not run because of too many discovered issues, once these are addressed it should autorun + grunt.log.ok('Before Submitting a Pull Request please also run `grunt jshint`.'); + }); + grunt.registerTask('documentation', ['jsdoc']); + + // Load the plugin(s) + grunt.loadNpmTasks('grunt-contrib-copy'); + + // Alias the `mocha_phantomjs` task to run `mocha-phantomjs` + grunt.registerTask('mocha_phantomjs', 'mocha-phantomjs', function () { + var done = this.async(); + require('child_process').exec('node_modules/mocha-phantomjs/bin/mocha-phantomjs ./test/ci-tests.html', function (err, stdout) { + grunt.log.write(stdout); + done(err); }); + }); - // Load the plugin(s) - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-connect'); - grunt.loadNpmTasks('grunt-mocha'); - - // Test/Dev tasks - grunt.registerTask('dev', ['connect:dev']); - grunt.registerTask('test', ['copy', 'connect:test', 'mocha']); - -}; \ No newline at end of file + // Test/Dev tasks + grunt.registerTask('test', ['copy', 'mocha_phantomjs']); +}; diff --git a/Makefile b/Makefile index 8327ae58..fc8a6605 100644 --- a/Makefile +++ b/Makefile @@ -30,9 +30,17 @@ lint: @echo See http://code.google.com/closure/utilities/ @./scripts/lint.sh -minify: - @echo See http://code.google.com/closure/compiler/ - @./scripts/minimize.sh +bundle: + @browserify -d -r ./src/:openpgp > ./resources/openpgp.js + @browserify -r ./src/:openpgp > ./resources/openpgp_nodebug.js + @browserify -d -x openpgp -r ./src/keyring/:keyring > ./resources/keyring.js + @browserify -x openpgp -r ./src/keyring/:keyring > ./resources/keyring_nodebug.js + +bundle-test: + @browserify -d -x openpgp -x keyring -r ./test/test-all.js:unittests > ./test/lib/test-bundle.js + +bundle-ci-test: + @browserify -d -x openpgp -x keyring -r ./test/ci-tests-all.js:ci-tests > ./test/lib/ci-tests-bundle.js test: @echo to be implemented diff --git a/README.md b/README.md index e4984739..3bfc433b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -OpenPGP.js [![Build Status](https://travis-ci.org/openpgpjs/openpgpjs.png?branch=master,devel)](https://travis-ci.org/openpgpjs/openpgpjs) -========== +[![Build Status](https://secure.travis-ci.org/openpgpjs/openpgpjs.png?branch=master,devel)](http://travis-ci.org/openpgpjs/openpgpjs) +# What is OpenPGP.js? [OpenPGP.js](http://openpgpjs.org/) is a Javascript implementation of the OpenPGP protocol. This is defined in [RFC 4880](http://tools.ietf.org/html/rfc4880). # How do I use it? diff --git a/doc/JXG.Util.html b/doc/JXG.Util.html index 7c1ca492..c29632cf 100644 --- a/doc/JXG.Util.html +++ b/doc/JXG.Util.html @@ -85,7 +85,7 @@ The code is based on the source code for gunzip.c by Pasi Ojala
Source:
@@ -142,6 +142,8 @@ The code is based on the source code for gunzip.c by Pasi Ojala + +
@@ -164,7 +166,7 @@ The code is based on the source code for gunzip.c by Pasi Ojala
Source:
@@ -187,6 +189,71 @@ The code is based on the source code for gunzip.c by Pasi Ojala
+
+

<private, static> asciiCharCodeAt()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + +

<static> genUUID()

@@ -238,7 +305,7 @@ EXAMPLES:
Source:
@@ -307,7 +374,7 @@ EXAMPLES:
Source:
@@ -424,7 +491,7 @@ EXAMPLES:
Source:
@@ -487,15 +554,16 @@ EXAMPLES:
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) + Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST)
+ - + \ No newline at end of file diff --git a/doc/aes.html b/doc/aes.html new file mode 100644 index 00000000..90875076 --- /dev/null +++ b/doc/aes.html @@ -0,0 +1,126 @@ + + + + + JSDoc: Module: crypto/cipher/aes + + + + + + + + + + +
+ +

Module: crypto/cipher/aes

+ + + + + +
+ +
+

+ crypto/cipher/aes +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/aes.js.html b/doc/aes.js.html new file mode 100644 index 00000000..92e89619 --- /dev/null +++ b/doc/aes.js.html @@ -0,0 +1,561 @@ + + + + + JSDoc: Source: crypto/cipher/aes.js + + + + + + + + + + +
+ +

Source: crypto/cipher/aes.js

+ + + + + +
+
+
/* Rijndael (AES) Encryption
+ * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
+ * version 1.1, check www.haneWIN.de for the latest version
+
+ * This software is provided as-is, without express or implied warranty.  
+ * Permission to use, copy, modify, distribute or sell this software, with or
+ * without fee, for any purpose and by any individual or organization, is hereby
+ * granted, provided that the above copyright notice and this paragraph appear 
+ * in all copies. Distribution as a part of an application or binary must
+ * include the above copyright notice in the documentation and/or other
+ * materials provided with the application or distribution.
+ */
+
+/**
+ * @requires util
+ * @module crypto/cipher/aes
+ */
+
+var util = require('../../util');
+
+// The round constants used in subkey expansion
+var Rcon = [
+    0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
+    0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
+    0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+];
+
+// Precomputed lookup table for the SBox
+var S = [
+    99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
+    118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
+    114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
+    216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
+    235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
+    179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
+    190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
+    249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
+    188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
+    23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
+    144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
+    6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
+    141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
+    46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
+    181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
+    248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
+    140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
+    22
+];
+
+var T1 = [
+    0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
+    0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
+    0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
+    0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
+    0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+    0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
+    0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45,
+    0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
+    0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
+    0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+    0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9,
+    0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
+    0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d,
+    0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
+    0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+    0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
+    0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34,
+    0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
+    0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d,
+    0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+    0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
+    0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
+    0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972,
+    0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
+    0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+    0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
+    0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
+    0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
+    0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05,
+    0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+    0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142,
+    0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
+    0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
+    0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
+    0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+    0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
+    0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3,
+    0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
+    0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
+    0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+    0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14,
+    0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
+    0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4,
+    0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
+    0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+    0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
+    0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf,
+    0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
+    0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c,
+    0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+    0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
+    0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
+    0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc,
+    0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
+    0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+    0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
+    0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
+    0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
+    0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9,
+    0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+    0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a,
+    0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
+    0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
+    0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c
+];
+
+var T2 = [
+    0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d,
+    0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154,
+    0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d,
+    0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a,
+    0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
+    0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
+    0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea,
+    0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b,
+    0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a,
+    0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
+    0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908,
+    0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
+    0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e,
+    0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5,
+    0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
+    0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f,
+    0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e,
+    0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
+    0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce,
+    0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
+    0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c,
+    0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed,
+    0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b,
+    0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
+    0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
+    0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194,
+    0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81,
+    0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3,
+    0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a,
+    0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
+    0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263,
+    0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d,
+    0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,
+    0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39,
+    0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
+    0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
+    0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f,
+    0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83,
+    0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c,
+    0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
+    0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e,
+    0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
+    0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6,
+    0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b,
+    0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
+    0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0,
+    0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25,
+    0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
+    0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72,
+    0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
+    0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,
+    0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85,
+    0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa,
+    0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
+    0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
+    0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9,
+    0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233,
+    0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7,
+    0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920,
+    0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
+    0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17,
+    0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8,
+    0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11,
+    0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a
+];
+
+var T3 = [
+    0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b,
+    0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5,
+    0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b,
+    0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76,
+    0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
+    0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
+    0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf,
+    0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0,
+    0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26,
+    0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
+    0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1,
+    0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
+    0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3,
+    0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a,
+    0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
+    0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75,
+    0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a,
+    0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
+    0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3,
+    0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
+    0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced,
+    0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b,
+    0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39,
+    0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
+    0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
+    0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485,
+    0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f,
+    0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8,
+    0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f,
+    0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
+    0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321,
+    0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2,
+    0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,
+    0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917,
+    0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
+    0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
+    0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc,
+    0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388,
+    0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14,
+    0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
+    0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a,
+    0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
+    0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662,
+    0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79,
+    0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
+    0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9,
+    0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea,
+    0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
+    0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e,
+    0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
+    0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,
+    0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a,
+    0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66,
+    0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
+    0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
+    0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e,
+    0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311,
+    0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794,
+    0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9,
+    0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
+    0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d,
+    0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868,
+    0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f,
+    0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16
+];
+
+var T4 = [
+    0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b,
+    0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5,
+    0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b,
+    0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676,
+    0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
+    0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
+    0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf,
+    0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0,
+    0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626,
+    0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
+    0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1,
+    0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
+    0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3,
+    0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a,
+    0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
+    0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575,
+    0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a,
+    0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
+    0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3,
+    0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
+    0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded,
+    0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b,
+    0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939,
+    0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
+    0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
+    0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585,
+    0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f,
+    0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8,
+    0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f,
+    0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
+    0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121,
+    0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2,
+    0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,
+    0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717,
+    0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
+    0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
+    0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc,
+    0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888,
+    0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414,
+    0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
+    0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a,
+    0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
+    0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262,
+    0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979,
+    0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
+    0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9,
+    0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea,
+    0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
+    0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e,
+    0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
+    0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,
+    0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a,
+    0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666,
+    0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
+    0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
+    0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e,
+    0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111,
+    0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494,
+    0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9,
+    0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
+    0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d,
+    0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868,
+    0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f,
+    0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616
+];
+
+function B0(x) {
+  return (x & 255);
+}
+
+function B1(x) {
+  return ((x >> 8) & 255);
+}
+
+function B2(x) {
+  return ((x >> 16) & 255);
+}
+
+function B3(x) {
+  return ((x >> 24) & 255);
+}
+
+function F1(x0, x1, x2, x3) {
+  return B1(T1[x0 & 255]) | (B1(T1[(x1 >> 8) & 255]) << 8) | (B1(T1[(x2 >> 16) & 255]) << 16) | (B1(T1[x3 >>> 24]) <<
+    24);
+}
+
+function packBytes(octets) {
+  var i, j;
+  var len = octets.length;
+  var b = new Array(len / 4);
+
+  if (!octets || len % 4) return;
+
+  for (i = 0, j = 0; j < len; j += 4)
+    b[i++] = octets[j] | (octets[j + 1] << 8) | (octets[j + 2] << 16) | (octets[j + 3] << 24);
+
+  return b;
+}
+
+function unpackBytes(packed) {
+  var j;
+  var i = 0,
+    l = packed.length;
+  var r = new Array(l * 4);
+
+  for (j = 0; j < l; j++) {
+    r[i++] = B0(packed[j]);
+    r[i++] = B1(packed[j]);
+    r[i++] = B2(packed[j]);
+    r[i++] = B3(packed[j]);
+  }
+  return r;
+}
+
+// ------------------------------------------------
+
+var maxkc = 8;
+var maxrk = 14;
+
+function keyExpansion(key) {
+  var kc, i, j, r, t;
+  var rounds;
+  var keySched = new Array(maxrk + 1);
+  var keylen = key.length;
+  var k = new Array(maxkc);
+  var tk = new Array(maxkc);
+  var rconpointer = 0;
+
+  if (keylen == 16) {
+    rounds = 10;
+    kc = 4;
+  } else if (keylen == 24) {
+    rounds = 12;
+    kc = 6;
+  } else if (keylen == 32) {
+    rounds = 14;
+    kc = 8;
+  } else {
+    throw new Error('Invalid key-length for AES key:' + keylen);
+  }
+
+  for (i = 0; i < maxrk + 1; i++) keySched[i] = new Array(4);
+
+  for (i = 0, j = 0; j < keylen; j++, i += 4)
+    k[j] = key.charCodeAt(i) | (key.charCodeAt(i + 1) << 8) | (key.charCodeAt(i + 2) << 16) | (key.charCodeAt(i + 3) <<
+      24);
+
+  for (j = kc - 1; j >= 0; j--) tk[j] = k[j];
+
+  r = 0;
+  t = 0;
+  for (j = 0;
+  (j < kc) && (r < rounds + 1);) {
+    for (;
+    (j < kc) && (t < 4); j++, t++) {
+      keySched[r][t] = tk[j];
+    }
+    if (t == 4) {
+      r++;
+      t = 0;
+    }
+  }
+
+  while (r < rounds + 1) {
+    var temp = tk[kc - 1];
+
+    tk[0] ^= S[B1(temp)] | (S[B2(temp)] << 8) | (S[B3(temp)] << 16) | (S[B0(temp)] << 24);
+    tk[0] ^= Rcon[rconpointer++];
+
+    if (kc != 8) {
+      for (j = 1; j < kc; j++) tk[j] ^= tk[j - 1];
+    } else {
+      for (j = 1; j < kc / 2; j++) tk[j] ^= tk[j - 1];
+
+      temp = tk[kc / 2 - 1];
+      tk[kc / 2] ^= S[B0(temp)] | (S[B1(temp)] << 8) | (S[B2(temp)] << 16) | (S[B3(temp)] << 24);
+
+      for (j = kc / 2 + 1; j < kc; j++) tk[j] ^= tk[j - 1];
+    }
+
+    for (j = 0;
+    (j < kc) && (r < rounds + 1);) {
+      for (;
+      (j < kc) && (t < 4); j++, t++) {
+        keySched[r][t] = tk[j];
+      }
+      if (t == 4) {
+        r++;
+        t = 0;
+      }
+    }
+  }
+  this.rounds = rounds;
+  this.rk = keySched;
+  return this;
+}
+
+function AESencrypt(block, ctx) {
+  var r;
+  var t0, t1, t2, t3;
+
+  var b = packBytes(block);
+  var rounds = ctx.rounds;
+  var b0 = b[0];
+  var b1 = b[1];
+  var b2 = b[2];
+  var b3 = b[3];
+
+  for (r = 0; r < rounds - 1; r++) {
+    t0 = b0 ^ ctx.rk[r][0];
+    t1 = b1 ^ ctx.rk[r][1];
+    t2 = b2 ^ ctx.rk[r][2];
+    t3 = b3 ^ ctx.rk[r][3];
+
+    b0 = T1[t0 & 255] ^ T2[(t1 >> 8) & 255] ^ T3[(t2 >> 16) & 255] ^ T4[t3 >>> 24];
+    b1 = T1[t1 & 255] ^ T2[(t2 >> 8) & 255] ^ T3[(t3 >> 16) & 255] ^ T4[t0 >>> 24];
+    b2 = T1[t2 & 255] ^ T2[(t3 >> 8) & 255] ^ T3[(t0 >> 16) & 255] ^ T4[t1 >>> 24];
+    b3 = T1[t3 & 255] ^ T2[(t0 >> 8) & 255] ^ T3[(t1 >> 16) & 255] ^ T4[t2 >>> 24];
+  }
+
+  // last round is special
+  r = rounds - 1;
+
+  t0 = b0 ^ ctx.rk[r][0];
+  t1 = b1 ^ ctx.rk[r][1];
+  t2 = b2 ^ ctx.rk[r][2];
+  t3 = b3 ^ ctx.rk[r][3];
+
+  b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0];
+  b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1];
+  b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2];
+  b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3];
+
+  return unpackBytes(b);
+}
+
+function makeClass(length) {
+
+  var c = function(key) {
+    this.key = keyExpansion(key);
+
+    this.encrypt = function(block) {
+      return AESencrypt(block, this.key);
+    }
+  }
+
+  c.blockSize = c.prototype.blockSize = 16;
+  c.keySize = c.prototype.keySize = length / 8;
+
+  return c;
+}
+
+module.exports = {}
+
+var types = [128, 192, 256];
+
+for (var i in types) {
+  module.exports[types[i]] = makeClass(types[i]);
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/all_packets.js.html b/doc/all_packets.js.html new file mode 100644 index 00000000..a0e6c3f9 --- /dev/null +++ b/doc/all_packets.js.html @@ -0,0 +1,99 @@ + + + + + JSDoc: Source: packet/all_packets.js + + + + + + + + + + +
+ +

Source: packet/all_packets.js

+ + + + + +
+
+
/**
+ * @requires enums
+ * @module packet
+ */
+var enums = require('../enums.js');
+
+// This is pretty ugly, but browserify needs to have the requires explicitly written.
+
+module.exports = {
+  /** @see module:packet/compressed */
+  compressed: require('./compressed.js'),
+  /** @see module:packet/sym_encrypted_integrity_protected */
+  sym_encrypted_integrity_protected: require('./sym_encrypted_integrity_protected.js'),
+  /** @see module:packet/public_key_encrypted_session_key */
+  public_key_encrypted_session_key: require('./public_key_encrypted_session_key.js'),
+  /** @see module:packet/sym_encrypted_session_key */
+  sym_encrypted_session_key: require('./sym_encrypted_session_key.js'),
+  /** @see module:packet/literal */
+  literal: require('./literal.js'),
+  /** @see module:packet/public_key */
+  public_key: require('./public_key.js'),
+  /** @see module:packet/symmetrically_encrypted */
+  symmetrically_encrypted: require('./symmetrically_encrypted.js'),
+  /** @see module:packet/marker */
+  marker: require('./marker.js'),
+  /** @see module:packet/public_subkey */
+  public_subkey: require('./public_subkey.js'),
+  /** @see module:packet/user_attribute */
+  user_attribute: require('./user_attribute.js'),
+  /** @see module:packet/one_pass_signature */
+  one_pass_signature: require('./one_pass_signature.js'),
+  /** @see module:packet/secret_key */
+  secret_key: require('./secret_key.js'),
+  /** @see module:packet/userid */
+  userid: require('./userid.js'),
+  /** @see module:packet/secret_subkey */
+  secret_subkey: require('./secret_subkey.js'),
+  /** @see module:packet/signature */
+  signature: require('./signature.js'),
+  /** @see module:packet/trust */
+  trust: require('./trust.js')
+}
+
+for (var i in enums.packet) {
+  var packetClass = module.exports[i];
+
+  if (packetClass != undefined)
+    packetClass.prototype.tag = enums.packet[i];
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/armor.html b/doc/armor.html new file mode 100644 index 00000000..7f68f4be --- /dev/null +++ b/doc/armor.html @@ -0,0 +1,1373 @@ + + + + + JSDoc: Module: encoding/armor + + + + + + + + + + +
+ +

Module: encoding/armor

+ + + + + +
+ +
+

+ encoding/armor +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

<inner> crc_table

+ + +
+
+ +
+ Internal function to calculate a CRC-24 checksum over a given string (data) +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

<static> armor(messagetype, body, partindex, parttotal) → {String}

+ + +
+
+ + +
+ Armor an OpenPGP binary packet block +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
messagetype + + +Integer + + + + type of the message
body + +
partindex + + +Integer + + + +
parttotal + + +Integer + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Armored text +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> dearmor(text) → {Object}

+ + +
+
+ + +
+ DeArmor an OpenPGP armored message; verify the checksum and return +the encoded bytes +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + OpenPGP armored message
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ An object with attribute "text" containing the message text, +an attribute "data" containing the bytes and "type" for the ASCII armor type +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

<inner> addheader() → {String}

+ + +
+
+ + +
+ Add additional information to the armor version of an OpenPGP binary +packet block. +
+ + + + + + + + + +
+ + + +
Version:
+
  • 2011-12-16
+ + + + + + + + + +
Author:
+
+
    +
  • Alex
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The header information +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<inner> getCheckSum(data) → {String}

+ + +
+
+ + +
+ Calculates a checksum over the given data and returns it base64 encoded +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +String + + + + Data to create a CRC-24 checksum for
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Base64 encoded checksum +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<inner> getType(text) → {Integer}

+ + +
+
+ + +
+ Finds out which Ascii Armoring type is used. This is an internal function +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + [String] ascii armored text
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ 0 = MESSAGE PART n of m + 1 = MESSAGE PART n + 2 = SIGNED MESSAGE + 3 = PGP MESSAGE + 4 = PUBLIC KEY BLOCK + 5 = PRIVATE KEY BLOCK + null = unknown +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ + + +
+

<inner> splitChecksum(text) → {Boolean|Object}

+ + +
+
+ + +
+ Splits a message into two parts, the body and the checksum. This is an internal function +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + OpenPGP armored message part
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Either false in case of an error +or an object with attribute "body" containing the body +and an attribute "checksum" containing the checksum. +
+ + + +
+
+ Type +
+
+ +Boolean +| + +Object + + +
+
+ + + + +
+ + + +
+

<inner> splitHeaders(text) → {Boolean|Object}

+ + +
+
+ + +
+ Splits a message into two parts, the headers and the body. This is an internal function +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + OpenPGP armored message part
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Either false in case of an error +or an object with attribute "headers" containing the headers and +and an attribute "body" containing the body. +
+ + + +
+
+ Type +
+
+ +Boolean +| + +Object + + +
+
+ + + + +
+ + + +
+

<inner> verifyCheckSum(data, checksum) → {Boolean}

+ + +
+
+ + +
+ Calculates the checksum over the given data and compares it with the +given base64 encoded checksum +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +String + + + + Data to create a CRC-24 checksum for
checksum + + +String + + + + Base64 encoded checksum
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ True if the given checksum is correct; otherwise false +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/armor.js.html b/doc/armor.js.html new file mode 100644 index 00000000..8b6fc8de --- /dev/null +++ b/doc/armor.js.html @@ -0,0 +1,428 @@ + + + + + JSDoc: Source: encoding/armor.js + + + + + + + + + + +
+ +

Source: encoding/armor.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @requires encoding/base64
+ * @requires enums
+ * @requires config
+ * @module encoding/armor
+ */
+
+var base64 = require('./base64.js'),
+  enums = require('../enums.js'),
+  config = require('../config');
+
+/**
+ * Finds out which Ascii Armoring type is used. This is an internal function
+ * @param {String} text [String] ascii armored text
+ * @returns {Integer} 0 = MESSAGE PART n of m
+ *         1 = MESSAGE PART n
+ *         2 = SIGNED MESSAGE
+ *         3 = PGP MESSAGE
+ *         4 = PUBLIC KEY BLOCK
+ *         5 = PRIVATE KEY BLOCK
+ *         null = unknown
+ */
+function getType(text) {
+  var reHeader = /^-----([^-]+)-----$\n/m;
+
+  var header = text.match(reHeader);
+
+  // BEGIN PGP MESSAGE, PART X/Y
+  // Used for multi-part messages, where the armor is split amongst Y
+  // parts, and this is the Xth part out of Y.
+  if (header[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
+    return enums.armor.multipart_section;
+  } else
+  // BEGIN PGP MESSAGE, PART X
+  // Used for multi-part messages, where this is the Xth part of an
+  // unspecified number of parts. Requires the MESSAGE-ID Armor
+  // Header to be used.
+  if (header[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
+    return enums.armor.multipart_last;
+
+  } else
+  // BEGIN PGP SIGNATURE
+  // Used for detached signatures, OpenPGP/MIME signatures, and
+  // cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
+  // for detached signatures.
+  if (header[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
+    return enums.armor.signed;
+
+  } else
+  // BEGIN PGP MESSAGE
+  // Used for signed, encrypted, or compressed files.
+  if (header[1].match(/BEGIN PGP MESSAGE/)) {
+    return enums.armor.message;
+
+  } else
+  // BEGIN PGP PUBLIC KEY BLOCK
+  // Used for armoring public keys.
+  if (header[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
+    return enums.armor.public_key;
+
+  } else
+  // BEGIN PGP PRIVATE KEY BLOCK
+  // Used for armoring private keys.
+  if (header[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) {
+    return enums.armor.private_key;
+  }
+}
+
+/**
+ * Add additional information to the armor version of an OpenPGP binary
+ * packet block.
+ * @author  Alex
+ * @version 2011-12-16
+ * @returns {String} The header information
+ */
+function addheader() {
+  var result = "";
+  if (config.show_version) {
+    result += "Version: " + config.versionstring + '\r\n';
+  }
+  if (config.show_comment) {
+    result += "Comment: " + config.commentstring + '\r\n';
+  }
+  result += '\r\n';
+  return result;
+}
+
+
+
+/**
+ * Calculates a checksum over the given data and returns it base64 encoded
+ * @param {String} data Data to create a CRC-24 checksum for
+ * @return {String} Base64 encoded checksum
+ */
+function getCheckSum(data) {
+  var c = createcrc24(data);
+  var str = "" + String.fromCharCode(c >> 16) +
+    String.fromCharCode((c >> 8) & 0xFF) +
+    String.fromCharCode(c & 0xFF);
+  return base64.encode(str);
+}
+
+/**
+ * Calculates the checksum over the given data and compares it with the
+ * given base64 encoded checksum
+ * @param {String} data Data to create a CRC-24 checksum for
+ * @param {String} checksum Base64 encoded checksum
+ * @return {Boolean} True if the given checksum is correct; otherwise false
+ */
+function verifyCheckSum(data, checksum) {
+  var c = getCheckSum(data);
+  var d = checksum;
+  return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
+}
+/**
+ * Internal function to calculate a CRC-24 checksum over a given string (data)
+ * @param {String} data Data to create a CRC-24 checksum for
+ * @return {Integer} The CRC-24 checksum as number
+ */
+var crc_table = [
+    0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139,
+    0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
+    0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd,
+    0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
+    0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631,
+    0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
+    0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5,
+    0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
+    0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b,
+    0x315aa1a0,
+    0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f,
+    0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd,
+    0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3,
+    0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8,
+    0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67,
+    0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3,
+    0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d,
+    0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef,
+    0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340,
+    0x62330fbb,
+    0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195,
+    0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de,
+    0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11,
+    0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61,
+    0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff,
+    0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d,
+    0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092,
+    0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50,
+    0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7,
+    0x51f6d10c,
+    0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3,
+    0x57dd8538
+];
+
+function createcrc24(input) {
+  var crc = 0xB704CE;
+  var index = 0;
+
+  while ((input.length - index) > 16) {
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 1)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 2)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 3)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 4)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 5)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 6)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 7)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 8)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 9)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 10)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 11)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 12)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 13)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 14)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 15)) & 0xff];
+    index += 16;
+  }
+
+  for (var j = index; j < input.length; j++) {
+    crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff];
+  }
+  return crc & 0xffffff;
+}
+
+/**
+ * Splits a message into two parts, the headers and the body. This is an internal function
+ * @param {String} text OpenPGP armored message part
+ * @returns {(Boolean|Object)} Either false in case of an error
+ * or an object with attribute "headers" containing the headers and
+ * and an attribute "body" containing the body.
+ */
+function splitHeaders(text) {
+  var reEmptyLine = /^[\t ]*\n/m;
+  var headers = "";
+  var body = text;
+
+  var matchResult = reEmptyLine.exec(text);
+
+  if (matchResult != null) {
+    headers = text.slice(0, matchResult.index);
+    body = text.slice(matchResult.index + matchResult[0].length);
+  }
+
+  return { headers: headers, body: body };
+}
+
+/**
+ * Splits a message into two parts, the body and the checksum. This is an internal function
+ * @param {String} text OpenPGP armored message part
+ * @returns {(Boolean|Object)} Either false in case of an error
+ * or an object with attribute "body" containing the body
+ * and an attribute "checksum" containing the checksum.
+ */
+function splitChecksum(text) {
+  var reChecksumStart = /^=/m;
+  var body = text;
+  var checksum = "";
+
+  var matchResult = reChecksumStart.exec(text);
+
+  if (matchResult != null) {
+    body = text.slice(0, matchResult.index);
+    checksum = text.slice(matchResult.index + 1);
+  }
+
+  return { body: body, checksum: checksum };
+}
+
+/**
+ * DeArmor an OpenPGP armored message; verify the checksum and return
+ * the encoded bytes
+ * @param {String} text OpenPGP armored message
+ * @returns {Object} An object with attribute "text" containing the message text,
+ * an attribute "data" containing the bytes and "type" for the ASCII armor type
+ * @static
+ */
+function dearmor(text) {
+  var reSplit = /^-----[^-]+-----$\n/m;
+
+  text = text.replace(/\r/g, '');
+
+  var type = getType(text);
+  if (!type) {
+    throw new Error('Unknow ASCII armor type');
+  } 
+
+  var splittext = text.split(reSplit);
+
+  // IE has a bug in split with a re. If the pattern matches the beginning of the
+  // string it doesn't create an empty array element 0. So we need to detect this
+  // so we know the index of the data we are interested in.
+  var indexBase = 1;
+
+  var result, checksum;
+
+  if (text.search(reSplit) != splittext[0].length) {
+    indexBase = 0;
+  }
+
+  if (type != 2) {
+    var msg = splitHeaders(splittext[indexBase]);
+    var msg_sum = splitChecksum(msg.body);
+
+    result = {
+      data: base64.decode(msg_sum.body),
+      type: type
+    };
+
+    checksum = msg_sum.checksum;
+  } else {
+    // Reverse dash-escaping for msg and remove trailing whitespace at end of line
+    var msg = splitHeaders(splittext[indexBase].replace(/^- /mg, '').replace(/[\t ]+\n/g, "\n"));
+    var sig = splitHeaders(splittext[indexBase + 1].replace(/^- /mg, ''));
+    var sig_sum = splitChecksum(sig.body);
+
+    result = {
+      text:  msg.body.replace(/\n$/, '').replace(/\n/g, "\r\n"),
+      data: base64.decode(sig_sum.body),
+      type: type
+    };
+
+    checksum = sig_sum.checksum;
+  }
+
+  if (!verifyCheckSum(result.data, checksum)) {
+    throw new Error("Ascii armor integrity check on message failed: '"
+      + checksum
+      + "' should be '"
+      + getCheckSum(result) + "'");
+  } else {
+    return result;
+  }
+}
+
+
+/**
+ * Armor an OpenPGP binary packet block
+ * @param {Integer} messagetype type of the message
+ * @param body
+ * @param {Integer} partindex
+ * @param {Integer} parttotal
+ * @returns {String} Armored text
+ * @static
+ */
+function armor(messagetype, body, partindex, parttotal) {
+  var result = "";
+  switch (messagetype) {
+    case enums.armor.multipart_section:
+      result += "-----BEGIN PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n";
+      result += addheader();
+      result += base64.encode(body);
+      result += "\r\n=" + getCheckSum(body) + "\r\n";
+      result += "-----END PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n";
+      break;
+    case enums.armor.mutlipart_last:
+      result += "-----BEGIN PGP MESSAGE, PART " + partindex + "-----\r\n";
+      result += addheader();
+      result += base64.encode(body);
+      result += "\r\n=" + getCheckSum(body) + "\r\n";
+      result += "-----END PGP MESSAGE, PART " + partindex + "-----\r\n";
+      break;
+    case enums.armor.signed:
+      result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\n";
+      result += "Hash: " + body.hash + "\r\n\r\n";
+      result += body.text.replace(/\n-/g, "\n- -");
+      result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
+      result += addheader();
+      result += base64.encode(body.data);
+      result += "\r\n=" + getCheckSum(body.data) + "\r\n";
+      result += "-----END PGP SIGNATURE-----\r\n";
+      break;
+    case enums.armor.message:
+      result += "-----BEGIN PGP MESSAGE-----\r\n";
+      result += addheader();
+      result += base64.encode(body);
+      result += "\r\n=" + getCheckSum(body) + "\r\n";
+      result += "-----END PGP MESSAGE-----\r\n";
+      break;
+    case enums.armor.public_key:
+      result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
+      result += addheader();
+      result += base64.encode(body);
+      result += "\r\n=" + getCheckSum(body) + "\r\n";
+      result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
+      break;
+    case enums.armor.private_key:
+      result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
+      result += addheader();
+      result += base64.encode(body);
+      result += "\r\n=" + getCheckSum(body) + "\r\n";
+      result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
+      break;
+  }
+
+  return result;
+}
+
+module.exports = {
+  encode: armor,
+  decode: dearmor
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/base64.html b/doc/base64.html new file mode 100644 index 00000000..d2cd492d --- /dev/null +++ b/doc/base64.html @@ -0,0 +1,402 @@ + + + + + JSDoc: Module: encoding/base64 + + + + + + + + + + +
+ +

Module: encoding/base64

+ + + + + +
+ +
+

+ encoding/base64 +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

<static> r2s(t) → {string}

+ + +
+
+ + +
+ Convert radix-64 to binary string +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
t + + +String + + + + radix-64 string to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ binary version of input string +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + +
+ + + +
+

<static> s2r(t) → {string}

+ + +
+
+ + +
+ Convert binary string to radix-64 +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
t + + +String + + + + binary string to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ radix-64 version of input string +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/base64.js.html b/doc/base64.js.html new file mode 100644 index 00000000..0442407f --- /dev/null +++ b/doc/base64.js.html @@ -0,0 +1,151 @@ + + + + + JSDoc: Source: encoding/base64.js + + + + + + + + + + +
+ +

Source: encoding/base64.js

+ + + + + +
+
+
/* OpenPGP radix-64/base64 string encoding/decoding
+ * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
+ * version 1.0, check www.haneWIN.de for the latest version
+ *
+ * This software is provided as-is, without express or implied warranty.  
+ * Permission to use, copy, modify, distribute or sell this software, with or
+ * without fee, for any purpose and by any individual or organization, is hereby
+ * granted, provided that the above copyright notice and this paragraph appear 
+ * in all copies. Distribution as a part of an application or binary must
+ * include the above copyright notice in the documentation and/or other materials
+ * provided with the application or distribution.
+ */
+
+/**
+ * @module encoding/base64
+ */
+
+var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+/**
+ * Convert binary string to radix-64
+ * @param {String} t binary string to convert
+ * @returns {string} radix-64 version of input string
+ * @static
+ */
+function s2r(t) {
+  var a, c, n;
+  var r = '',
+    l = 0,
+    s = 0;
+  var tl = t.length;
+
+  for (n = 0; n < tl; n++) {
+    c = t.charCodeAt(n);
+    if (s == 0) {
+      r += b64s.charAt((c >> 2) & 63);
+      a = (c & 3) << 4;
+    } else if (s == 1) {
+      r += b64s.charAt((a | (c >> 4) & 15));
+      a = (c & 15) << 2;
+    } else if (s == 2) {
+      r += b64s.charAt(a | ((c >> 6) & 3));
+      l += 1;
+      if ((l % 60) == 0)
+        r += "\n";
+      r += b64s.charAt(c & 63);
+    }
+    l += 1;
+    if ((l % 60) == 0)
+      r += "\n";
+
+    s += 1;
+    if (s == 3)
+      s = 0;
+  }
+  if (s > 0) {
+    r += b64s.charAt(a);
+    l += 1;
+    if ((l % 60) == 0)
+      r += "\n";
+    r += '=';
+    l += 1;
+  }
+  if (s == 1) {
+    if ((l % 60) == 0)
+      r += "\n";
+    r += '=';
+  }
+
+  return r;
+}
+
+/**
+ * Convert radix-64 to binary string
+ * @param {String} t radix-64 string to convert
+ * @returns {string} binary version of input string
+ * @static
+ */
+function r2s(t) {
+  var c, n;
+  var r = '',
+    s = 0,
+    a = 0;
+  var tl = t.length;
+
+  for (n = 0; n < tl; n++) {
+    c = b64s.indexOf(t.charAt(n));
+    if (c >= 0) {
+      if (s)
+        r += String.fromCharCode(a | (c >> (6 - s)) & 255);
+      s = (s + 2) & 7;
+      a = (c << s) & 255;
+    }
+  }
+  return r;
+}
+
+module.exports = {
+  encode: s2r,
+  decode: r2s
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/blowfish.html b/doc/blowfish.html new file mode 100644 index 00000000..b311cbff --- /dev/null +++ b/doc/blowfish.html @@ -0,0 +1,120 @@ + + + + + JSDoc: Module: crypto/cipher/blowfish + + + + + + + + + + +
+ +

Module: crypto/cipher/blowfish

+ + + + + +
+ +
+

+ crypto/cipher/blowfish +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/blowfish.js.html b/doc/blowfish.js.html new file mode 100644 index 00000000..8fb76d56 --- /dev/null +++ b/doc/blowfish.js.html @@ -0,0 +1,466 @@ + + + + + JSDoc: Source: crypto/cipher/blowfish.js + + + + + + + + + + +
+ +

Source: crypto/cipher/blowfish.js

+ + + + + +
+
+
/* Modified by Recurity Labs GmbH 
+ * 
+ * Originally written by nklein software (nklein.com)
+ */
+
+/**
+ *  @module crypto/cipher/blowfish
+ */
+
+/* 
+ * Javascript implementation based on Bruce Schneier's reference implementation.
+ *
+ *
+ * The constructor doesn't do much of anything.  It's just here
+ * so we can start defining properties and methods and such.
+ */
+function Blowfish() {};
+
+/*
+ * Declare the block size so that protocols know what size
+ * Initialization Vector (IV) they will need.
+ */
+Blowfish.prototype.BLOCKSIZE = 8;
+
+/*
+ * These are the default SBOXES.
+ */
+Blowfish.prototype.SBOXES = [
+  [
+      0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+      0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+      0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+      0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+      0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+      0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+      0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+      0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+      0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+      0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+      0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+      0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+      0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+      0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+      0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+      0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+      0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+      0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+      0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+      0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+      0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+      0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+      0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+      0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+      0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+      0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+      0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+      0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+      0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+      0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+      0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+      0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+      0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+      0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+      0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+      0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+      0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+      0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+      0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+      0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+      0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+      0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+      0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
+  ],
+  [
+      0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+      0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+      0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+      0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+      0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+      0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+      0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+      0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+      0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+      0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+      0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+      0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+      0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+      0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+      0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+      0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+      0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+      0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+      0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+      0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+      0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+      0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+      0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+      0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+      0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+      0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+      0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+      0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+      0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+      0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+      0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+      0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+      0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+      0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+      0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+      0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+      0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+      0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+      0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+      0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+      0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+      0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+      0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
+  ],
+  [
+      0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+      0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+      0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+      0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+      0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+      0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+      0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+      0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+      0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+      0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+      0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+      0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+      0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+      0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+      0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+      0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+      0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+      0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+      0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+      0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+      0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+      0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+      0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+      0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+      0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+      0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+      0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+      0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+      0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+      0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+      0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+      0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+      0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+      0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+      0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+      0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+      0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+      0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+      0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+      0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+      0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+      0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+      0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
+  ],
+  [
+      0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+      0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+      0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+      0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+      0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+      0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+      0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+      0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+      0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+      0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+      0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+      0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+      0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+      0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+      0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+      0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+      0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+      0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+      0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+      0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+      0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+      0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+      0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+      0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+      0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+      0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+      0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+      0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+      0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+      0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+      0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+      0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+      0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+      0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+      0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+      0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+      0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+      0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+      0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+      0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+      0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+      0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+      0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
+  ]
+];
+
+//*
+//* This is the default PARRAY
+//*
+Blowfish.prototype.PARRAY = [
+    0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+    0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+    0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
+];
+
+//*
+//* This is the number of rounds the cipher will go
+//*
+Blowfish.prototype.NN = 16;
+
+//*
+//* This function is needed to get rid of problems
+//* with the high-bit getting set.  If we don't do
+//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not
+//* equal to ( bb & 0x00FFFFFFFF ) even when they
+//* agree bit-for-bit for the first 32 bits.
+//*
+Blowfish.prototype._clean = function(xx) {
+  if (xx < 0) {
+    var yy = xx & 0x7FFFFFFF;
+    xx = yy + 0x80000000;
+  }
+  return xx;
+};
+
+//*
+//* This is the mixing function that uses the sboxes
+//*
+Blowfish.prototype._F = function(xx) {
+  var aa;
+  var bb;
+  var cc;
+  var dd;
+  var yy;
+
+  dd = xx & 0x00FF;
+  xx >>>= 8;
+  cc = xx & 0x00FF;
+  xx >>>= 8;
+  bb = xx & 0x00FF;
+  xx >>>= 8;
+  aa = xx & 0x00FF;
+
+  yy = this.sboxes[0][aa] + this.sboxes[1][bb];
+  yy = yy ^ this.sboxes[2][cc];
+  yy = yy + this.sboxes[3][dd];
+
+  return yy;
+};
+
+//*
+//* This method takes an array with two values, left and right
+//* and does NN rounds of Blowfish on them.
+//*
+Blowfish.prototype._encrypt_block = function(vals) {
+  var dataL = vals[0];
+  var dataR = vals[1];
+
+  var ii;
+
+  for (ii = 0; ii < this.NN; ++ii) {
+    dataL = dataL ^ this.parray[ii];
+    dataR = this._F(dataL) ^ dataR;
+
+    var tmp = dataL;
+    dataL = dataR;
+    dataR = tmp;
+  }
+
+  dataL = dataL ^ this.parray[this.NN + 0];
+  dataR = dataR ^ this.parray[this.NN + 1];
+
+  vals[0] = this._clean(dataR);
+  vals[1] = this._clean(dataL);
+};
+
+//*
+//* This method takes a vector of numbers and turns them
+//* into long words so that they can be processed by the
+//* real algorithm.
+//*
+//* Maybe I should make the real algorithm above take a vector
+//* instead.  That will involve more looping, but it won't require
+//* the F() method to deconstruct the vector.
+//*
+Blowfish.prototype.encrypt_block = function(vector) {
+  var ii;
+  var vals = [0, 0];
+  var off = this.BLOCKSIZE / 2;
+  for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) {
+    vals[0] = (vals[0] << 8) | (vector[ii + 0] & 0x00FF);
+    vals[1] = (vals[1] << 8) | (vector[ii + off] & 0x00FF);
+  }
+
+  this._encrypt_block(vals);
+
+  var ret = [];
+  for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) {
+    ret[ii + 0] = (vals[0] >>> (24 - 8 * (ii)) & 0x00FF);
+    ret[ii + off] = (vals[1] >>> (24 - 8 * (ii)) & 0x00FF);
+    // vals[ 0 ] = ( vals[ 0 ] >>> 8 );
+    // vals[ 1 ] = ( vals[ 1 ] >>> 8 );
+  }
+
+  return ret;
+};
+
+//*
+//* This method takes an array with two values, left and right
+//* and undoes NN rounds of Blowfish on them.
+//*
+Blowfish.prototype._decrypt_block = function(vals) {
+  var dataL = vals[0];
+  var dataR = vals[1];
+
+  var ii;
+
+  for (ii = this.NN + 1; ii > 1; --ii) {
+    dataL = dataL ^ this.parray[ii];
+    dataR = this._F(dataL) ^ dataR;
+
+    var tmp = dataL;
+    dataL = dataR;
+    dataR = tmp;
+  }
+
+  dataL = dataL ^ this.parray[1];
+  dataR = dataR ^ this.parray[0];
+
+  vals[0] = this._clean(dataR);
+  vals[1] = this._clean(dataL);
+};
+
+//*
+//* This method takes a key array and initializes the
+//* sboxes and parray for this encryption.
+//*
+Blowfish.prototype.init = function(key) {
+  var ii;
+  var jj = 0;
+
+  this.parray = [];
+  for (ii = 0; ii < this.NN + 2; ++ii) {
+    var data = 0x00000000;
+    var kk;
+    for (kk = 0; kk < 4; ++kk) {
+      data = (data << 8) | (key[jj] & 0x00FF);
+      if (++jj >= key.length) {
+        jj = 0;
+      }
+    }
+    this.parray[ii] = this.PARRAY[ii] ^ data;
+  }
+
+  this.sboxes = [];
+  for (ii = 0; ii < 4; ++ii) {
+    this.sboxes[ii] = [];
+    for (jj = 0; jj < 256; ++jj) {
+      this.sboxes[ii][jj] = this.SBOXES[ii][jj];
+    }
+  }
+
+  var vals = [0x00000000, 0x00000000];
+
+  for (ii = 0; ii < this.NN + 2; ii += 2) {
+    this._encrypt_block(vals);
+    this.parray[ii + 0] = vals[0];
+    this.parray[ii + 1] = vals[1];
+  }
+
+  for (ii = 0; ii < 4; ++ii) {
+    for (jj = 0; jj < 256; jj += 2) {
+      this._encrypt_block(vals);
+      this.sboxes[ii][jj + 0] = vals[0];
+      this.sboxes[ii][jj + 1] = vals[1];
+    }
+  }
+};
+
+var util = require('../../util');
+
+// added by Recurity Labs
+
+function BFencrypt(block, key) {
+  var bf = new Blowfish();
+  bf.init(util.str2bin(key));
+  return bf.encrypt_block(block);
+}
+
+function BF(key) {
+  this.bf = new Blowfish();
+  this.bf.init(util.str2bin(key));
+
+  this.encrypt = function(block) {
+    return this.bf.encrypt_block(block);
+  }
+}
+
+
+module.exports = BF;
+module.exports.keySize = BF.prototype.keySize = 16;
+module.exports.blockSize = BF.prototype.blockSize = 16;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/cast5.html b/doc/cast5.html new file mode 100644 index 00000000..3089499d --- /dev/null +++ b/doc/cast5.html @@ -0,0 +1,120 @@ + + + + + JSDoc: Module: crypto/cipher/cast5 + + + + + + + + + + +
+ +

Module: crypto/cipher/cast5

+ + + + + +
+ +
+

+ crypto/cipher/cast5 +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/cast5.js.html b/doc/cast5.js.html new file mode 100644 index 00000000..8651ba82 --- /dev/null +++ b/doc/cast5.js.html @@ -0,0 +1,655 @@ + + + + + JSDoc: Source: crypto/cipher/cast5.js + + + + + + + + + + +
+ +

Source: crypto/cipher/cast5.js

+ + + + + +
+
+
// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copyright 2010 pjacobs@xeekr.com . All rights reserved.
+
+// Modified by Recurity Labs GmbH
+
+// fixed/modified by Herbert Hanewinkel, www.haneWIN.de
+// check www.haneWIN.de for the latest version
+
+// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144.
+// CAST-128 is a common OpenPGP cipher.
+
+
+// CAST5 constructor
+
+/** @module crypto/cipher/cast5 */
+
+
+
+function openpgp_symenc_cast5() {
+  this.BlockSize = 8;
+  this.KeySize = 16;
+
+  this.setKey = function(key) {
+    this.masking = new Array(16);
+    this.rotate = new Array(16);
+
+    this.reset();
+
+    if (key.length == this.KeySize) {
+      this.keySchedule(key);
+    } else {
+      throw new Error('CAST-128: keys must be 16 bytes');
+    }
+    return true;
+  };
+
+  this.reset = function() {
+    for (var i = 0; i < 16; i++) {
+      this.masking[i] = 0;
+      this.rotate[i] = 0;
+    }
+  };
+
+  this.getBlockSize = function() {
+    return BlockSize;
+  };
+
+  this.encrypt = function(src) {
+    var dst = new Array(src.length);
+
+    for (var i = 0; i < src.length; i += 8) {
+      var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3];
+      var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7];
+      var t;
+
+      t = r;
+      r = l ^ f1(r, this.masking[0], this.rotate[0]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[1], this.rotate[1]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[2], this.rotate[2]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[3], this.rotate[3]);
+      l = t;
+
+      t = r;
+      r = l ^ f2(r, this.masking[4], this.rotate[4]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[5], this.rotate[5]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[6], this.rotate[6]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[7], this.rotate[7]);
+      l = t;
+
+      t = r;
+      r = l ^ f3(r, this.masking[8], this.rotate[8]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[9], this.rotate[9]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[10], this.rotate[10]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[11], this.rotate[11]);
+      l = t;
+
+      t = r;
+      r = l ^ f1(r, this.masking[12], this.rotate[12]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[13], this.rotate[13]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[14], this.rotate[14]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[15], this.rotate[15]);
+      l = t;
+
+      dst[i] = (r >>> 24) & 255;
+      dst[i + 1] = (r >>> 16) & 255;
+      dst[i + 2] = (r >>> 8) & 255;
+      dst[i + 3] = r & 255;
+      dst[i + 4] = (l >>> 24) & 255;
+      dst[i + 5] = (l >>> 16) & 255;
+      dst[i + 6] = (l >>> 8) & 255;
+      dst[i + 7] = l & 255;
+    }
+
+    return dst;
+  };
+
+  this.decrypt = function(src) {
+    var dst = new Array(src.length);
+
+    for (var i = 0; i < src.length; i += 8) {
+      var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3];
+      var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7];
+      var t;
+
+      t = r;
+      r = l ^ f1(r, this.masking[15], this.rotate[15]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[14], this.rotate[14]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[13], this.rotate[13]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[12], this.rotate[12]);
+      l = t;
+
+      t = r;
+      r = l ^ f3(r, this.masking[11], this.rotate[11]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[10], this.rotate[10]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[9], this.rotate[9]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[8], this.rotate[8]);
+      l = t;
+
+      t = r;
+      r = l ^ f2(r, this.masking[7], this.rotate[7]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[6], this.rotate[6]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[5], this.rotate[5]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[4], this.rotate[4]);
+      l = t;
+
+      t = r;
+      r = l ^ f1(r, this.masking[3], this.rotate[3]);
+      l = t;
+      t = r;
+      r = l ^ f3(r, this.masking[2], this.rotate[2]);
+      l = t;
+      t = r;
+      r = l ^ f2(r, this.masking[1], this.rotate[1]);
+      l = t;
+      t = r;
+      r = l ^ f1(r, this.masking[0], this.rotate[0]);
+      l = t;
+
+      dst[i] = (r >>> 24) & 255;
+      dst[i + 1] = (r >>> 16) & 255;
+      dst[i + 2] = (r >>> 8) & 255;
+      dst[i + 3] = r & 255;
+      dst[i + 4] = (l >>> 24) & 255;
+      dst[i + 5] = (l >> 16) & 255;
+      dst[i + 6] = (l >> 8) & 255;
+      dst[i + 7] = l & 255;
+    }
+
+    return dst;
+  };
+  var scheduleA = new Array(4);
+
+  scheduleA[0] = new Array(4);
+  scheduleA[0][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 0x8);
+  scheduleA[0][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa);
+  scheduleA[0][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9);
+  scheduleA[0][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb);
+
+  scheduleA[1] = new Array(4);
+  scheduleA[1][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0);
+  scheduleA[1][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2);
+  scheduleA[1][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1);
+  scheduleA[1][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3);
+
+  scheduleA[2] = new Array(4);
+  scheduleA[2][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 8);
+  scheduleA[2][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa);
+  scheduleA[2][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9);
+  scheduleA[2][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb);
+
+
+  scheduleA[3] = new Array(4);
+  scheduleA[3][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0);
+  scheduleA[3][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2);
+  scheduleA[3][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1);
+  scheduleA[3][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3);
+
+  var scheduleB = new Array(4);
+
+  scheduleB[0] = new Array(4);
+  scheduleB[0][0] = new Array(16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2);
+  scheduleB[0][1] = new Array(16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6);
+  scheduleB[0][2] = new Array(16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9);
+  scheduleB[0][3] = new Array(16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc);
+
+  scheduleB[1] = new Array(4);
+  scheduleB[1][0] = new Array(3, 2, 0xc, 0xd, 8);
+  scheduleB[1][1] = new Array(1, 0, 0xe, 0xf, 0xd);
+  scheduleB[1][2] = new Array(7, 6, 8, 9, 3);
+  scheduleB[1][3] = new Array(5, 4, 0xa, 0xb, 7);
+
+
+  scheduleB[2] = new Array(4);
+  scheduleB[2][0] = new Array(16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9);
+  scheduleB[2][1] = new Array(16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc);
+  scheduleB[2][2] = new Array(16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2);
+  scheduleB[2][3] = new Array(16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6);
+
+
+  scheduleB[3] = new Array(4);
+  scheduleB[3][0] = new Array(8, 9, 7, 6, 3);
+  scheduleB[3][1] = new Array(0xa, 0xb, 5, 4, 7);
+  scheduleB[3][2] = new Array(0xc, 0xd, 3, 2, 8);
+  scheduleB[3][3] = new Array(0xe, 0xf, 1, 0, 0xd);
+
+  // changed 'in' to 'inn' (in javascript 'in' is a reserved word)
+  this.keySchedule = function(inn) {
+    var t = new Array(8);
+    var k = new Array(32);
+
+    for (var i = 0; i < 4; i++) {
+      var j = i * 4;
+      t[i] = inn[j] << 24 | inn[j + 1] << 16 | inn[j + 2] << 8 | inn[j + 3];
+    }
+
+    var x = [6, 7, 4, 5];
+    var ki = 0;
+
+    for (var half = 0; half < 2; half++) {
+      for (var round = 0; round < 4; round++) {
+        for (var j = 0; j < 4; j++) {
+          var a = scheduleA[round][j];
+          var w = t[a[1]];
+
+          w ^= sBox[4][(t[a[2] >>> 2] >>> (24 - 8 * (a[2] & 3))) & 0xff];
+          w ^= sBox[5][(t[a[3] >>> 2] >>> (24 - 8 * (a[3] & 3))) & 0xff];
+          w ^= sBox[6][(t[a[4] >>> 2] >>> (24 - 8 * (a[4] & 3))) & 0xff];
+          w ^= sBox[7][(t[a[5] >>> 2] >>> (24 - 8 * (a[5] & 3))) & 0xff];
+          w ^= sBox[x[j]][(t[a[6] >>> 2] >>> (24 - 8 * (a[6] & 3))) & 0xff];
+          t[a[0]] = w;
+        }
+
+        for (var j = 0; j < 4; j++) {
+          var b = scheduleB[round][j];
+          var w = sBox[4][(t[b[0] >>> 2] >>> (24 - 8 * (b[0] & 3))) & 0xff];
+
+          w ^= sBox[5][(t[b[1] >>> 2] >>> (24 - 8 * (b[1] & 3))) & 0xff];
+          w ^= sBox[6][(t[b[2] >>> 2] >>> (24 - 8 * (b[2] & 3))) & 0xff];
+          w ^= sBox[7][(t[b[3] >>> 2] >>> (24 - 8 * (b[3] & 3))) & 0xff];
+          w ^= sBox[4 + j][(t[b[4] >>> 2] >>> (24 - 8 * (b[4] & 3))) & 0xff];
+          k[ki] = w;
+          ki++;
+        }
+      }
+    }
+
+    for (var i = 0; i < 16; i++) {
+      this.masking[i] = k[i];
+      this.rotate[i] = k[16 + i] & 0x1f;
+    }
+  };
+
+  // These are the three 'f' functions. See RFC 2144, section 2.2.
+
+  function f1(d, m, r) {
+    var t = m + d;
+    var I = (t << r) | (t >>> (32 - r));
+    return ((sBox[0][I >>> 24] ^ sBox[1][(I >>> 16) & 255]) - sBox[2][(I >>> 8) & 255]) + sBox[3][I & 255];
+  }
+
+  function f2(d, m, r) {
+    var t = m ^ d;
+    var I = (t << r) | (t >>> (32 - r));
+    return ((sBox[0][I >>> 24] - sBox[1][(I >>> 16) & 255]) + sBox[2][(I >>> 8) & 255]) ^ sBox[3][I & 255];
+  }
+
+  function f3(d, m, r) {
+    var t = m - d;
+    var I = (t << r) | (t >>> (32 - r));
+    return ((sBox[0][I >>> 24] + sBox[1][(I >>> 16) & 255]) ^ sBox[2][(I >>> 8) & 255]) - sBox[3][I & 255];
+  }
+
+  var sBox = new Array(8);
+  sBox[0] = new Array(
+    0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+    0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+    0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+    0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+    0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+    0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+    0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+    0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+    0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+    0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+    0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+    0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+    0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+    0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+    0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+    0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+    0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+    0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+    0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+    0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+    0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+    0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+    0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+    0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+    0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+    0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+    0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+    0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+    0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+    0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+    0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+    0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf);
+
+  sBox[1] = new Array(
+    0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+    0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+    0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+    0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+    0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+    0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+    0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+    0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+    0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+    0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+    0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+    0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+    0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+    0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+    0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+    0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+    0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+    0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+    0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+    0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+    0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+    0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+    0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+    0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+    0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+    0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+    0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+    0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+    0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+    0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+    0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+    0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1);
+
+  sBox[2] = new Array(
+    0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+    0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+    0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+    0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+    0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+    0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+    0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+    0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+    0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+    0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+    0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+    0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+    0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+    0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+    0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+    0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+    0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+    0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+    0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+    0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+    0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+    0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+    0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+    0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+    0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+    0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+    0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+    0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+    0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+    0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+    0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+    0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783);
+
+  sBox[3] = new Array(
+    0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+    0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+    0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+    0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+    0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+    0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+    0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+    0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+    0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+    0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+    0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+    0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+    0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+    0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+    0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+    0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+    0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+    0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+    0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+    0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+    0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+    0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+    0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+    0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+    0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+    0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+    0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+    0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+    0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+    0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+    0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+    0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2);
+
+  sBox[4] = new Array(
+    0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+    0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+    0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+    0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+    0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+    0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+    0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+    0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+    0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+    0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+    0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+    0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+    0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+    0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+    0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+    0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+    0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+    0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+    0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+    0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+    0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+    0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+    0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+    0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+    0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+    0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+    0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+    0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+    0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+    0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+    0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+    0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4);
+
+  sBox[5] = new Array(
+    0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+    0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+    0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+    0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+    0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+    0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+    0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+    0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+    0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+    0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+    0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+    0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+    0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+    0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+    0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+    0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+    0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+    0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+    0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+    0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+    0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+    0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+    0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+    0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+    0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+    0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+    0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+    0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+    0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+    0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+    0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+    0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f);
+
+  sBox[6] = new Array(
+    0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+    0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+    0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+    0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+    0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+    0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+    0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+    0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+    0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+    0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+    0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+    0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+    0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+    0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+    0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+    0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+    0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+    0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+    0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+    0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+    0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+    0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+    0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+    0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+    0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+    0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+    0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+    0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+    0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+    0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+    0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+    0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3);
+
+  sBox[7] = new Array(
+    0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+    0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+    0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+    0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+    0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+    0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+    0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+    0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+    0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+    0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+    0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+    0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+    0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+    0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+    0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+    0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+    0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+    0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+    0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+    0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+    0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+    0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+    0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+    0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+    0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+    0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+    0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+    0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+    0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+    0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+    0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+    0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e);
+
+};
+
+var util = require('../../util');
+
+function cast5(key) {
+  this.cast5 = new openpgp_symenc_cast5();
+  this.cast5.setKey(util.str2bin(key));
+
+  this.encrypt = function(block) {
+    return this.cast5.encrypt(block);
+  }
+}
+
+module.exports = cast5;
+module.exports.blockSize = cast5.prototype.blockSize = 8;
+module.exports.keySize = cast5.prototype.keySize = 16;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/cfb.html b/doc/cfb.html new file mode 100644 index 00000000..c860d141 --- /dev/null +++ b/doc/cfb.html @@ -0,0 +1,777 @@ + + + + + JSDoc: Module: crypto/cfb + + + + + + + + + + +
+ +

Module: crypto/cfb

+ + + + + +
+ +
+

+ crypto/cfb +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

<static> decrypt(cipherfn, key, ciphertext, resync) → {String}

+ + +
+
+ + +
+ This function decrypts a given plaintext using the specified +blockcipher to decrypt a message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cipherfn + + +String + + + + the algorithm cipher class to decrypt + data in one block_size encryption, @see module:crypto/cipher.
key + + +String + + + + binary string representation of key to be used to decrypt the ciphertext. +This will be passed to the cipherfn
ciphertext + + +String + + + + to be decrypted provided as a string
resync + + +Boolean + + + + a boolean value specifying if a resync of the + IV should be used or not. The encrypteddatapacket uses the + "old" style with a resync. Decryption within an + encryptedintegrityprotecteddata packet is not resyncing the IV.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ a string with the plaintext data +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> encrypt(prefixrandom, cipherfn, plaintext, key, resync) → {String}

+ + +
+
+ + +
+ This function encrypts a given with the specified prefixrandom +using the specified blockcipher to encrypt a message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
prefixrandom + + +String + + + + random bytes of block_size length provided + as a string to be used in prefixing the data
cipherfn + + +String + + + + the algorithm cipher class to encrypt + data in one block_size encryption, @see module:crypto/cipher.
plaintext + + +String + + + + data to be encrypted provided as a string
key + + +String + + + + binary string representation of key to be used to encrypt the plaintext. +This will be passed to the cipherfn
resync + + +Boolean + + + + a boolean value specifying if a resync of the + IV should be used or not. The encrypteddatapacket uses the + "old" style with a resync. Encryption within an + encryptedintegrityprotecteddata packet is not resyncing the IV.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ a string with the encrypted data +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> mdc(key, ciphertext) → {String}

+ + +
+
+ + +
+ Decrypts the prefixed data for the Modification Detection Code (MDC) computation +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cipherfn.encrypt + + +String + + + + Cipher function to use,
key + + +String + + + + binary string representation of key to be used to check the mdc +This will be passed to the cipherfn
ciphertext + + +String + + + + The encrypted data
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+
    +
  • module:crypto/cipher.
  • +
+
+ + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ plaintext Data of D(ciphertext) with blocksize length +2 +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/cfb.js.html b/doc/cfb.js.html new file mode 100644 index 00000000..189c1415 --- /dev/null +++ b/doc/cfb.js.html @@ -0,0 +1,349 @@ + + + + + JSDoc: Source: crypto/cfb.js + + + + + + + + + + +
+ +

Source: crypto/cfb.js

+ + + + + +
+
+
// Modified by Recurity Labs GmbH 
+
+// modified version of http://www.hanewin.net/encrypt/PGdecode.js:
+
+/* OpenPGP encryption using RSA/AES
+ * Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de
+ * version 2.0, check www.haneWIN.de for the latest version
+
+ * This software is provided as-is, without express or implied warranty.  
+ * Permission to use, copy, modify, distribute or sell this software, with or
+ * without fee, for any purpose and by any individual or organization, is hereby
+ * granted, provided that the above copyright notice and this paragraph appear 
+ * in all copies. Distribution as a part of an application or binary must
+ * include the above copyright notice in the documentation and/or other
+ * materials provided with the application or distribution.
+ */
+
+/**
+ * @requires crypto/cipher
+ * @requires util
+ * @module crypto/cfb
+ */
+
+var util = require('../util'),
+  cipher = require('./cipher');
+
+module.exports = {
+
+  /**
+   * This function encrypts a given with the specified prefixrandom 
+   * using the specified blockcipher to encrypt a message
+   * @param {String} prefixrandom random bytes of block_size length provided 
+   *  as a string to be used in prefixing the data
+   * @param {String} cipherfn the algorithm cipher class to encrypt
+   *  data in one block_size encryption, @see module:crypto/cipher.
+   * @param {String} plaintext data to be encrypted provided as a string
+   * @param {String} key binary string representation of key to be used to encrypt the plaintext.
+   * This will be passed to the cipherfn
+   * @param {Boolean} resync a boolean value specifying if a resync of the
+   *  IV should be used or not. The encrypteddatapacket uses the 
+   *  "old" style with a resync. Encryption within an 
+   *  encryptedintegrityprotecteddata packet is not resyncing the IV.
+   * @return {String} a string with the encrypted data
+   */
+  encrypt: function(prefixrandom, cipherfn, plaintext, key, resync) {
+    cipherfn = new cipher[cipherfn](key);
+    var block_size = cipherfn.blockSize;
+
+    var FR = new Array(block_size);
+    var FRE = new Array(block_size);
+
+    prefixrandom = prefixrandom + prefixrandom.charAt(block_size - 2) + prefixrandom.charAt(block_size - 1);
+    util.print_debug("prefixrandom:" + util.hexstrdump(prefixrandom));
+    var ciphertext = "";
+    // 1.  The feedback register (FR) is set to the IV, which is all zeros.
+    for (var i = 0; i < block_size; i++) FR[i] = 0;
+
+    // 2.  FR is encrypted to produce FRE (FR Encrypted).  This is the
+    //     encryption of an all-zero value.
+    FRE = cipherfn.encrypt(FR);
+    // 3.  FRE is xored with the first BS octets of random data prefixed to
+    //     the plaintext to produce C[1] through C[BS], the first BS octets
+    //     of ciphertext.
+    for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i));
+
+    // 4.  FR is loaded with C[1] through C[BS].
+    for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
+
+    // 5.  FR is encrypted to produce FRE, the encryption of the first BS
+    // 	   octets of ciphertext.
+    FRE = cipherfn.encrypt(FR);
+
+    // 6.  The left two octets of FRE get xored with the next two octets of
+    //     data that were prefixed to the plaintext.  This produces C[BS+1]
+    //     and C[BS+2], the next two octets of ciphertext.
+    ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size));
+    ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size + 1));
+
+    if (resync) {
+      // 7.  (The resync step) FR is loaded with C3-C10.
+      for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i + 2);
+    } else {
+      for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
+    }
+    // 8.  FR is encrypted to produce FRE.
+    FRE = cipherfn.encrypt(FR, key);
+
+    if (resync) {
+      // 9.  FRE is xored with the first 8 octets of the given plaintext, now
+      //	   that we have finished encrypting the 10 octets of prefixed data.
+      // 	   This produces C11-C18, the next 8 octets of ciphertext.
+      for (var i = 0; i < block_size; i++)
+        ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
+      for (n = block_size + 2; n < plaintext.length; n += block_size) {
+        // 10. FR is loaded with C11-C18
+        for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n + i);
+
+        // 11. FR is encrypted to produce FRE.
+        FRE = cipherfn.encrypt(FR);
+
+        // 12. FRE is xored with the next 8 octets of plaintext, to produce the
+        // next 8 octets of ciphertext.  These are loaded into FR and the
+        // process is repeated until the plaintext is used up.
+        for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n - 2) +
+            i));
+      }
+    } else {
+      plaintext = "  " + plaintext;
+      // 9.  FRE is xored with the first 8 octets of the given plaintext, now
+      //	   that we have finished encrypting the 10 octets of prefixed data.
+      // 	   This produces C11-C18, the next 8 octets of ciphertext.
+      for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
+      var tempCiphertext = ciphertext.substring(0, 2 * block_size).split('');
+      var tempCiphertextString = ciphertext.substring(block_size);
+      for (n = block_size; n < plaintext.length; n += block_size) {
+        // 10. FR is loaded with C11-C18
+        for (var i = 0; i < block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i);
+        tempCiphertextString = '';
+
+        // 11. FR is encrypted to produce FRE.
+        FRE = cipherfn.encrypt(FR);
+
+        // 12. FRE is xored with the next 8 octets of plaintext, to produce the
+        //     next 8 octets of ciphertext.  These are loaded into FR and the
+        //     process is repeated until the plaintext is used up.
+        for (var i = 0; i < block_size; i++) {
+          tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i)));
+          tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i));
+        }
+      }
+      ciphertext = tempCiphertext.join('');
+
+    }
+
+    ciphertext = ciphertext.substring(0, plaintext.length + 2 + block_size);
+
+    return ciphertext;
+  },
+
+  /**
+   * Decrypts the prefixed data for the Modification Detection Code (MDC) computation
+   * @param {String} cipherfn.encrypt Cipher function to use,
+   *  @see module:crypto/cipher.
+   * @param {String} key binary string representation of key to be used to check the mdc
+   * This will be passed to the cipherfn
+   * @param {String} ciphertext The encrypted data
+   * @return {String} plaintext Data of D(ciphertext) with blocksize length +2
+   */
+  mdc: function(cipherfn, key, ciphertext) {
+    cipherfn = new cipher[cipherfn](key);
+    var block_size = cipherfn.blockSize;
+
+    var iblock = new Array(block_size);
+    var ablock = new Array(block_size);
+    var i;
+
+
+    // initialisation vector
+    for (i = 0; i < block_size; i++) iblock[i] = 0;
+
+    iblock = cipherfn.encrypt(iblock);
+    for (i = 0; i < block_size; i++) {
+      ablock[i] = ciphertext.charCodeAt(i);
+      iblock[i] ^= ablock[i];
+    }
+
+    ablock = cipherfn.encrypt(ablock);
+
+    return util.bin2str(iblock) +
+      String.fromCharCode(ablock[0] ^ ciphertext.charCodeAt(block_size)) +
+      String.fromCharCode(ablock[1] ^ ciphertext.charCodeAt(block_size + 1));
+  },
+  /**
+   * This function decrypts a given plaintext using the specified
+   * blockcipher to decrypt a message
+   * @param {String} cipherfn the algorithm cipher class to decrypt
+   *  data in one block_size encryption, @see module:crypto/cipher.
+   * @param {String} key binary string representation of key to be used to decrypt the ciphertext.
+   * This will be passed to the cipherfn
+   * @param {String} ciphertext to be decrypted provided as a string
+   * @param {Boolean} resync a boolean value specifying if a resync of the
+   *  IV should be used or not. The encrypteddatapacket uses the 
+   *  "old" style with a resync. Decryption within an 
+   *  encryptedintegrityprotecteddata packet is not resyncing the IV.
+   * @return {String} a string with the plaintext data
+   */
+
+  decrypt: function(cipherfn, key, ciphertext, resync) {
+    cipherfn = new cipher[cipherfn](key);
+    var block_size = cipherfn.blockSize;
+
+    var iblock = new Array(block_size);
+    var ablock = new Array(block_size);
+    var i, n = '';
+    var text = [];
+
+    // initialisation vector
+    for (i = 0; i < block_size; i++) iblock[i] = 0;
+
+    iblock = cipherfn.encrypt(iblock, key);
+    for (i = 0; i < block_size; i++) {
+      ablock[i] = ciphertext.charCodeAt(i);
+      iblock[i] ^= ablock[i];
+    }
+
+    ablock = cipherfn.encrypt(ablock, key);
+
+    // test check octets
+    if (iblock[block_size - 2] != (ablock[0] ^ ciphertext.charCodeAt(block_size)) || iblock[block_size - 1] != (ablock[
+      1] ^ ciphertext.charCodeAt(block_size + 1))) {
+      throw new Error('Invalid data.');
+    }
+
+    /*  RFC4880: Tag 18 and Resync:
+		 *  [...] Unlike the Symmetrically Encrypted Data Packet, no
+		 *  special CFB resynchronization is done after encrypting this prefix
+		 *  data.  See "OpenPGP CFB Mode" below for more details.
+
+		 */
+
+    if (resync) {
+      for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i + 2);
+      for (n = block_size + 2; n < ciphertext.length; n += block_size) {
+        ablock = cipherfn.encrypt(iblock);
+
+        for (i = 0; i < block_size && i + n < ciphertext.length; i++) {
+          iblock[i] = ciphertext.charCodeAt(n + i);
+          text.push(String.fromCharCode(ablock[i] ^ iblock[i]));
+        }
+      }
+    } else {
+      for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i);
+      for (n = block_size; n < ciphertext.length; n += block_size) {
+        ablock = cipherfn.encrypt(iblock);
+        for (i = 0; i < block_size && i + n < ciphertext.length; i++) {
+          iblock[i] = ciphertext.charCodeAt(n + i);
+          text.push(String.fromCharCode(ablock[i] ^ iblock[i]));
+        }
+      }
+    }
+
+    var n = resync ? 0 : 2;
+
+    text = text.join('');
+
+    text = text.substring(n, ciphertext.length - block_size - 2 + n);
+
+
+    return text;
+  },
+
+
+  normalEncrypt: function(cipherfn, key, plaintext, iv) {
+    cipherfn = new cipher[cipherfn](key);
+    var block_size = cipherfn.blockSize;
+
+    var blocki = "";
+    var blockc = "";
+    var pos = 0;
+    var cyphertext = [];
+    var tempBlock = [];
+    blockc = iv.substring(0, block_size);
+    while (plaintext.length > block_size * pos) {
+      var encblock = cipherfn.encrypt(util.str2bin(blockc));
+      blocki = plaintext.substring((pos * block_size), (pos * block_size) + block_size);
+      for (var i = 0; i < blocki.length; i++)
+        tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i]));
+      blockc = tempBlock.join('');
+      tempBlock = [];
+      cyphertext.push(blockc);
+      pos++;
+    }
+    return cyphertext.join('');
+  },
+
+  normalDecrypt: function(cipherfn, key, ciphertext, iv) {
+    cipherfn = new cipher[cipherfn](key);
+    var block_size = cipherfn.blockSize;
+
+    var blockp = "";
+    var pos = 0;
+    var plaintext = [];
+    var offset = 0;
+    if (iv == null)
+      for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0);
+    else
+      blockp = iv.substring(0, block_size);
+    while (ciphertext.length > (block_size * pos)) {
+      var decblock = cipherfn.encrypt(util.str2bin(blockp));
+      blockp = ciphertext.substring((pos * (block_size)) + offset, (pos * (block_size)) + (block_size) + offset);
+      for (var i = 0; i < blockp.length; i++) {
+        plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i]));
+      }
+      pos++;
+    }
+
+    return plaintext.join('');
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/cipher.html b/doc/cipher.html new file mode 100644 index 00000000..2bfea5bf --- /dev/null +++ b/doc/cipher.html @@ -0,0 +1,421 @@ + + + + + JSDoc: Module: crypto/cipher + + + + + + + + + + +
+ +

Module: crypto/cipher

+ + + + + +
+ +
+

+ crypto/cipher +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

<static> blowfish

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> cast5

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> des

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> originalDes

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> twofish

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ +
+ + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/cleartext.js.html b/doc/cleartext.js.html new file mode 100644 index 00000000..8af1a8ef --- /dev/null +++ b/doc/cleartext.js.html @@ -0,0 +1,200 @@ + + + + + JSDoc: Source: cleartext.js + + + + + + + + + + +
+ +

Source: cleartext.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @requires config
+ * @requires encoding/armor
+ * @requires enums
+ * @requires packet
+ * @module cleartext
+ */
+
+var config = require('./config'),
+  packet = require('./packet'),
+  enums = require('./enums.js'),
+  armor = require('./encoding/armor.js');
+
+/**
+ * @class
+ * @classdesc Class that represents an OpenPGP cleartext signed message.
+ * See http://tools.ietf.org/html/rfc4880#section-7
+ * @param  {String}     text       The cleartext of the signed message
+ * @param  {module:packet/packetlist} packetlist The packetlist with signature packets or undefined
+ *                                 if message not yet signed
+ */
+
+function CleartextMessage(text, packetlist) {
+  if (!(this instanceof CleartextMessage)) {
+    return new CleartextMessage(packetlist);
+  }
+  // normalize EOL to canonical form <CR><LF>
+  this.text = text.replace(/\r/g, '').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n");
+  this.packets = packetlist || new packet.list();
+}
+
+/**
+ * Returns the key IDs of the keys that signed the cleartext message
+ * @return {Array<module:type/keyid>} array of keyid objects
+ */
+CleartextMessage.prototype.getSigningKeyIds = function() {
+  var keyIds = [];
+  var signatureList = this.packets.filterByTag(enums.packet.signature);
+  signatureList.forEach(function(packet) {
+    keyIds.push(packet.issuerKeyId);
+  });
+  return keyIds;
+};
+
+/**
+ * Sign the cleartext message
+ * @param  {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
+ */
+CleartextMessage.prototype.sign = function(privateKeys) {
+  var packetlist = new packet.list();  
+  var literalDataPacket = new packet.literal();
+  literalDataPacket.setText(this.text);
+  for (var i = 0; i < privateKeys.length; i++) {
+    var signaturePacket = new packet.signature();
+    signaturePacket.signatureType = enums.signature.text;
+    signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
+    var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
+    signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
+    if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
+    signaturePacket.sign(signingKeyPacket, literalDataPacket);
+    packetlist.push(signaturePacket);
+  }
+  this.packets = packetlist;
+};
+
+/**
+ * Verify signatures of cleartext signed message
+ * @param {Array<module:key~Key>} publicKeys public keys to verify signatures
+ * @return {Array<{keyid: module:type/keyid, valid: Boolean}>} list of signer's keyid and validity of signature
+ */
+CleartextMessage.prototype.verify = function(publicKeys) {
+  var result = [];
+  var signatureList = this.packets.filterByTag(enums.packet.signature);
+  var literalDataPacket = new packet.literal();
+  // we assume that cleartext signature is generated based on UTF8 cleartext
+  literalDataPacket.setText(this.text);
+  publicKeys.forEach(function(pubKey) {
+    for (var i = 0; i < signatureList.length; i++) {
+      var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]);
+      if (publicKeyPacket) {
+        var verifiedSig = {};
+        verifiedSig.keyid = signatureList[i].issuerKeyId;
+        verifiedSig.valid = signatureList[i].verify(publicKeyPacket, literalDataPacket);
+        result.push(verifiedSig);
+        break;
+      }
+    }
+  });
+  return result;
+};
+
+/**
+ * Get cleartext
+ * @return {String} cleartext of message
+ */
+CleartextMessage.prototype.getText = function() {
+  // normalize end of line to \n
+  return this.text.replace(/\r\n/g,"\n");
+};
+
+/**
+ * Returns ASCII armored text of cleartext signed message
+ * @return {String} ASCII armor
+ */
+CleartextMessage.prototype.armor = function() {
+  var body = {
+    hash: enums.read(enums.hash, config.prefer_hash_algorithm).toUpperCase(),
+    text: this.text,
+    data: this.packets.write()
+  }
+  return armor.encode(enums.armor.signed, body);
+};
+
+
+/**
+ * reads an OpenPGP cleartext signed message and returns a CleartextMessage object
+ * @param {String} armoredText text to be parsed
+ * @return {module:cleartext~CleartextMessage} new cleartext message object
+ * @static
+ */
+function readArmored(armoredText) {
+  var input = armor.decode(armoredText);
+  if (input.type !== enums.armor.signed) {
+    throw new Error('No cleartext signed message.');
+  }
+  var packetlist = new packet.list();
+  packetlist.read(input.data);
+  var newMessage = new CleartextMessage(input.text, packetlist);
+  return newMessage;
+}
+
+exports.CleartextMessage = CleartextMessage;
+exports.readArmored = readArmored;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/compressed.html b/doc/compressed.html new file mode 100644 index 00000000..9f58e225 --- /dev/null +++ b/doc/compressed.html @@ -0,0 +1,749 @@ + + + + + JSDoc: Module: packet/compressed + + + + + + + + + + +
+ +

Module: packet/compressed

+ + + + + +
+ +
+

+ packet/compressed +

+ +
+ +
+
+ + +
Implementation of the Compressed Data Packet (Tag 8)
+
+RFC4880 5.6: The Compressed Data packet contains compressed data. Typically, +this packet is found as the contents of an encrypted packet, or following +a Signature or One-Pass Signature packet, and contains a literal data packet.
+ + +
+

new (require("packet/compressed"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

algorithm :compression

+ + +
+
+ +
+ Compression algorithm +
+ + + +
Type:
+
    +
  • + +compression + + +
  • +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

compressed :String

+ + +
+
+ +
+ Compressed packet data +
+ + + +
Type:
+
    +
  • + +String + + +
  • +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

packets :module:packet/packetlist

+ + +
+
+ +
+ List of packets +
+ + + +
Type:
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

compress()

+ + +
+
+ + +
+ Compress the packet data (member decompressedData) +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

decompress()

+ + +
+
+ + +
+ Decompression method for decompressing the compressed data +read by read_packet +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

read(bytes)

+ + +
+
+ + +
+ Parsing function for the packet. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bytes + + +String + + + + Payload of a tag 8 packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ Return the compressed packet. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ binary compressed packet +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/compressed.js.html b/doc/compressed.js.html new file mode 100644 index 00000000..b60c43ca --- /dev/null +++ b/doc/compressed.js.html @@ -0,0 +1,224 @@ + + + + + JSDoc: Source: packet/compressed.js + + + + + + + + + + +
+ +

Source: packet/compressed.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the Compressed Data Packet (Tag 8)<br/>
+ * <br/>
+ * RFC4880 5.6: The Compressed Data packet contains compressed data.  Typically,
+ * this packet is found as the contents of an encrypted packet, or following
+ * a Signature or One-Pass Signature packet, and contains a literal data packet.
+ * @requires compression/jxg
+ * @requires encoding/base64
+ * @requires enums
+ * @module packet/compressed
+ */
+
+var enums = require('../enums.js'),
+  JXG = require('../compression/jxg.js'),
+  base64 = require('../encoding/base64.js');
+
+/**
+ * @constructor
+ */
+module.exports = function compressed() {
+  /**
+   * List of packets
+   * @type {module:packet/packetlist}
+   */
+  this.packets = null;
+  /**
+   * Compression algorithm
+   * @type {compression}
+   */
+  this.algorithm = 'uncompressed';
+
+  /**
+   * Compressed packet data
+   * @type {String}
+   */
+  this.compressed = null;
+
+
+  /**
+   * Parsing function for the packet.
+   * @param {String} bytes Payload of a tag 8 packet
+   */
+  this.read = function(bytes) {
+    // One octet that gives the algorithm used to compress the packet.
+    this.algorithm = enums.read(enums.compression, bytes.charCodeAt(0));
+
+    // Compressed data, which makes up the remainder of the packet.
+    this.compressed = bytes.substr(1);
+
+    this.decompress();
+  }
+
+
+
+  /**
+   * Return the compressed packet.
+   * @return {String} binary compressed packet
+   */
+  this.write = function() {
+    if (this.compressed == null)
+      this.compress();
+
+    return String.fromCharCode(enums.write(enums.compression, this.algorithm)) + this.compressed;
+  }
+
+
+  /**
+   * Decompression method for decompressing the compressed data
+   * read by read_packet
+   */
+  this.decompress = function() {
+    var decompressed;
+
+    switch (this.algorithm) {
+      case 'uncompressed':
+        decompressed = this.compressed;
+        break;
+
+      case 'zip':
+        var compData = this.compressed;
+
+        var radix = base64.encode(compData).replace(/\n/g, "");
+        // no header in this case, directly call deflate
+        var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix));
+
+        decompressed = unescape(jxg_obj.deflate()[0][0]);
+        break;
+
+      case 'zlib':
+        //RFC 1950. Bits 0-3 Compression Method
+        var compressionMethod = this.compressed.charCodeAt(0) % 0x10;
+
+        //Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size.
+        // 2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary 
+        // (how is this defined). Basic checksum, and compression level.
+
+        if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951
+          // remove 4 bytes ADLER32 checksum from the end
+          var compData = this.compressed.substring(0, this.compressed.length - 4);
+          var radix = base64.encode(compData).replace(/\n/g, "");
+          //TODO check ADLER32 checksum
+          decompressed = JXG.decompress(radix);
+          break;
+
+        } else {
+          throw new Error("Compression algorithm ZLIB only supports " +
+            "DEFLATE compression method.");
+        }
+        break;
+
+      case 'bzip2':
+        // TODO: need to implement this
+        throw new Error('Compression algorithm BZip2 [BZ2] is not implemented.');
+        break;
+
+      default:
+        throw new Error("Compression algorithm unknown :" + this.alogrithm);
+        break;
+    }
+
+    this.packets.read(decompressed);
+  }
+
+  /**
+   * Compress the packet data (member decompressedData)
+   */
+  this.compress = function() {
+    switch (this.algorithm) {
+
+      case 'uncompressed':
+        // - Uncompressed
+        this.compressed = this.packets.write();
+        break;
+
+      case 'zip':
+        // - ZIP [RFC1951]
+        throw new Error("Compression algorithm ZIP [RFC1951] is not implemented.");
+        break;
+
+      case 'zlib':
+        // - ZLIB [RFC1950]
+        // TODO: need to implement this
+        throw new Error("Compression algorithm ZLIB [RFC1950] is not implemented.");
+        break;
+
+      case 'bzip2':
+        //  - BZip2 [BZ2]
+        // TODO: need to implement this
+        throw new Error("Compression algorithm BZip2 [BZ2] is not implemented.");
+        break;
+
+      default:
+        throw new Error("Compression algorithm unknown :" + this.type);
+        break;
+    }
+  }
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/config.html b/doc/config.html new file mode 100644 index 00000000..7469c56d --- /dev/null +++ b/doc/config.html @@ -0,0 +1,340 @@ + + + + + JSDoc: Module: config/config + + + + + + + + + + +
+ +

Module: config/config

+ + + + + +
+ +
+

+ config/config +

+ +
+ +
+
+ + + + +
This object contains configuration values.
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
prefer_hash_algorithm + + +Integer + + + +
encryption_cipher + + +Integer + + + +
compression + + +Integer + + + +
show_version + + +Boolean + + + +
show_comment + + +Boolean + + + +
integrity_protect + + +Boolean + + + +
keyserver + + +String + + + +
debug + + +Boolean + + + + If enabled, debug messages will be printed
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/config.js.html b/doc/config.js.html new file mode 100644 index 00000000..b7499701 --- /dev/null +++ b/doc/config.js.html @@ -0,0 +1,97 @@ + + + + + JSDoc: Source: config/config.js + + + + + + + + + + +
+ +

Source: config/config.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * This object contains configuration values.
+ * @requires enums
+ * @property {Integer} prefer_hash_algorithm
+ * @property {Integer} encryption_cipher
+ * @property {Integer} compression
+ * @property {Boolean} show_version
+ * @property {Boolean} show_comment
+ * @property {Boolean} integrity_protect
+ * @property {String} keyserver
+ * @property {Boolean} debug If enabled, debug messages will be printed
+ * @module config/config
+ */
+
+var enums = require('../enums.js');
+
+module.exports = {
+  prefer_hash_algorithm: enums.hash.sha256,
+  encryption_cipher: enums.symmetric.aes256,
+  compression: enums.compression.zip,
+  show_version: true,
+  show_comment: true,
+  integrity_protect: true,
+  keyserver: "keyserver.linux.it", // "pgp.mit.edu:11371"
+
+  versionstring: "OpenPGP.js VERSION",
+  commentstring: "http://openpgpjs.org",
+
+  debug: false
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/crypto.html b/doc/crypto.html new file mode 100644 index 00000000..16d37a92 --- /dev/null +++ b/doc/crypto.html @@ -0,0 +1,952 @@ + + + + + JSDoc: Module: crypto/crypto + + + + + + + + + + +
+ +

Module: crypto/crypto

+ + + + + +
+ +
+

+ crypto/crypto +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

<static> generateSessionKey(algo) → {String}

+ + +
+
+ + +
+ Generating a session key for the specified symmetric algorithm +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +Integer + + + + Algorithm to use (see RFC4880 9.2)
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Random bytes as a string to be used as a key +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> getPrefixRandom(algo) → {String}

+ + +
+
+ + +
+ generate random byte prefix as string for the specified algorithm +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +Integer + + + + Algorithm to use (see RFC4880 9.2)
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Random bytes with length equal to the block +size of the cipher +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> getPrivateMpiCount(algo) → {Integer}

+ + +
+
+ + +
+ Returns the number of integers comprising the private key of an algorithm +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +String + + + + The public key algorithm
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The number of integers. +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ + + +
+

<static> publicKeyDecrypt(algo, publicMPIs, secretMPIs, data) → {module:type/mpi}

+ + +
+
+ + +
+ Decrypts data using the specified public key multiprecision integers of the private key, +the specified secretMPIs of the private key and the specified algorithm. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +Integer + + + + Algorithm to be used (See RFC4880 9.1)
publicMPIs + + +Array.<module:type/mpi> + + + + Algorithm dependent multiprecision integers +of the public key part of the private key
secretMPIs + + +Array.<module:type/mpi> + + + + Algorithm dependent multiprecision integers +of the private key used
data + + +module:type/mpi + + + + Data to be encrypted as MPI
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ returns a big integer containing the decrypted data; otherwise null +
+ + + +
+
+ Type +
+
+ +module:type/mpi + + +
+
+ + + + +
+ + + +
+

<static> publicKeyEncrypt(algo, publicMPIs, data) → {Array.<module:type/mpi>}

+ + +
+
+ + +
+ Encrypts data using the specified public key multiprecision integers +and the specified algorithm. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +Integer + + + + Algorithm to be used (See RFC4880 9.1)
publicMPIs + + +Array.<module:type/mpi> + + + + Algorithm dependent multiprecision integers
data + + +module:type/mpi + + + + Data to be encrypted as MPI
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ if RSA an module:type/mpi; +if elgamal encryption an array of two module:type/mpi is returned; otherwise null +
+ + + +
+
+ Type +
+
+ +Array.<module:type/mpi> + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/crypto.js.html b/doc/crypto.js.html new file mode 100644 index 00000000..14d2a0d0 --- /dev/null +++ b/doc/crypto.js.html @@ -0,0 +1,273 @@ + + + + + JSDoc: Source: crypto/crypto.js + + + + + + + + + + +
+ +

Source: crypto/crypto.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+
+// The GPG4Browsers crypto interface
+
+/**
+ * @requires crypto/cipher
+ * @requires crypto/public_key
+ * @requires crypto/random
+ * @requires type/mpi
+ * @module crypto/crypto
+ */
+
+var random = require('./random.js'),
+  cipher = require('./cipher'),
+  publicKey = require('./public_key'),
+  type_mpi = require('../type/mpi.js');
+
+module.exports = {
+  /**
+   * Encrypts data using the specified public key multiprecision integers 
+   * and the specified algorithm.
+   * @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
+   * @param {Array<module:type/mpi>} publicMPIs Algorithm dependent multiprecision integers
+   * @param {module:type/mpi} data Data to be encrypted as MPI
+   * @return {Array<module:type/mpi>} if RSA an module:type/mpi; 
+   * if elgamal encryption an array of two module:type/mpi is returned; otherwise null
+   */
+  publicKeyEncrypt: function(algo, publicMPIs, data) {
+    var result = (function() {
+      switch (algo) {
+        case 'rsa_encrypt':
+        case 'rsa_encrypt_sign':
+          var rsa = new publicKey.rsa();
+          var n = publicMPIs[0].toBigInteger();
+          var e = publicMPIs[1].toBigInteger();
+          var m = data.toBigInteger();
+          return [rsa.encrypt(m, e, n)];
+
+        case 'elgamal':
+          var elgamal = new publicKey.elgamal();
+          var p = publicMPIs[0].toBigInteger();
+          var g = publicMPIs[1].toBigInteger();
+          var y = publicMPIs[2].toBigInteger();
+          var m = data.toBigInteger();
+          return elgamal.encrypt(m, g, p, y);
+
+        default:
+          return [];
+      }
+    })();
+
+    return result.map(function(bn) {
+      var mpi = new type_mpi();
+      mpi.fromBigInteger(bn);
+      return mpi;
+    });
+  },
+
+  /**
+   * Decrypts data using the specified public key multiprecision integers of the private key,
+   * the specified secretMPIs of the private key and the specified algorithm.
+   * @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
+   * @param {Array<module:type/mpi>} publicMPIs Algorithm dependent multiprecision integers 
+   * of the public key part of the private key
+   * @param {Array<module:type/mpi>} secretMPIs Algorithm dependent multiprecision integers 
+   * of the private key used
+   * @param {module:type/mpi} data Data to be encrypted as MPI
+   * @return {module:type/mpi} returns a big integer containing the decrypted data; otherwise null
+   */
+
+  publicKeyDecrypt: function(algo, keyIntegers, dataIntegers) {
+    var bn = (function() {
+      switch (algo) {
+        case 'rsa_encrypt_sign':
+        case 'rsa_encrypt':
+          var rsa = new publicKey.rsa();
+          // 0 and 1 are the public key.
+          var d = keyIntegers[2].toBigInteger();
+          var p = keyIntegers[3].toBigInteger();
+          var q = keyIntegers[4].toBigInteger();
+          var u = keyIntegers[5].toBigInteger();
+          var m = dataIntegers[0].toBigInteger();
+          return rsa.decrypt(m, d, p, q, u);
+        case 'elgamal':
+          var elgamal = new publicKey.elgamal();
+          var x = keyIntegers[3].toBigInteger();
+          var c1 = dataIntegers[0].toBigInteger();
+          var c2 = dataIntegers[1].toBigInteger();
+          var p = keyIntegers[0].toBigInteger();
+          return elgamal.decrypt(c1, c2, p, x);
+        default:
+          return null;
+      }
+    })();
+
+    var result = new type_mpi();
+    result.fromBigInteger(bn);
+    return result;
+  },
+
+  /** Returns the number of integers comprising the private key of an algorithm
+   * @param {String} algo The public key algorithm
+   * @return {Integer} The number of integers.
+   */
+  getPrivateMpiCount: function(algo) {
+    switch (algo) {
+      case 'rsa_encrypt':
+      case 'rsa_encrypt_sign':
+      case 'rsa_sign':
+        //   Algorithm-Specific Fields for RSA secret keys:
+        //   - multiprecision integer (MPI) of RSA secret exponent d.
+        //   - MPI of RSA secret prime value p.
+        //   - MPI of RSA secret prime value q (p < q).
+        //   - MPI of u, the multiplicative inverse of p, mod q.
+        return 4;
+      case 'elgamal':
+        // Algorithm-Specific Fields for Elgamal secret keys:
+        //   - MPI of Elgamal secret exponent x.
+        return 1;
+      case 'dsa':
+        // Algorithm-Specific Fields for DSA secret keys:
+        //   - MPI of DSA secret exponent x.
+        return 1;
+      default:
+        throw new Error('Unknown algorithm');
+    }
+  },
+
+  getPublicMpiCount: function(algo) {
+    // - A series of multiprecision integers comprising the key material:
+    //   Algorithm-Specific Fields for RSA public keys:
+    //       - a multiprecision integer (MPI) of RSA public modulus n;
+    //       - an MPI of RSA public encryption exponent e.
+    switch (algo) {
+      case 'rsa_encrypt':
+      case 'rsa_encrypt_sign':
+      case 'rsa_sign':
+        return 2;
+
+        //   Algorithm-Specific Fields for Elgamal public keys:
+        //     - MPI of Elgamal prime p;
+        //     - MPI of Elgamal group generator g;
+        //     - MPI of Elgamal public key value y (= g**x mod p where x  is secret).
+      case 'elgamal':
+        return 3;
+
+        //   Algorithm-Specific Fields for DSA public keys:
+        //       - MPI of DSA prime p;
+        //       - MPI of DSA group order q (q is a prime divisor of p-1);
+        //       - MPI of DSA group generator g;
+        //       - MPI of DSA public-key value y (= g**x mod p where x  is secret).
+      case 'dsa':
+        return 4;
+
+      default:
+        throw new Error('Unknown algorithm.');
+    }
+  },
+
+  generateMpi: function(algo, bits) {
+    var result = (function() {
+      switch (algo) {
+        case 'rsa_encrypt':
+        case 'rsa_encrypt_sign':
+        case 'rsa_sign':
+          //remember "publicKey" refers to the crypto/public_key dir
+          var rsa = new publicKey.rsa();
+          var keyObject = rsa.generate(bits, "10001");
+          var output = [];
+          output.push(keyObject.n);
+          output.push(keyObject.ee);
+          output.push(keyObject.d);
+          output.push(keyObject.p);
+          output.push(keyObject.q);
+          output.push(keyObject.u);
+          return output;
+        default:
+          throw new Error('Unsupported algorithm for key generation.');
+      }
+    })();
+
+    return result.map(function(bn) {
+      var mpi = new type_mpi();
+      mpi.fromBigInteger(bn);
+      return mpi;
+    });
+  },
+
+
+  /**
+   * generate random byte prefix as string for the specified algorithm
+   * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
+   * @return {String} Random bytes with length equal to the block
+   * size of the cipher
+   */
+  getPrefixRandom: function(algo) {
+    return random.getRandomBytes(cipher[algo].blockSize);
+  },
+
+  /**
+   * Generating a session key for the specified symmetric algorithm
+   * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
+   * @return {String} Random bytes as a string to be used as a key
+   */
+  generateSessionKey: function(algo) {
+    return random.getRandomBytes(cipher[algo].keySize);
+  }
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/des.html b/doc/des.html new file mode 100644 index 00000000..0d832eaf --- /dev/null +++ b/doc/des.html @@ -0,0 +1,224 @@ + + + + + JSDoc: Module: crypto/cipher/des + + + + + + + + + + +
+ +

Module: crypto/cipher/des

+ + + + + +
+ +
+

+ crypto/cipher/des +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + +

Members

+ +
+ +
+

<static> des

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static> originalDes

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/des.js.html b/doc/des.js.html new file mode 100644 index 00000000..3ace6958 --- /dev/null +++ b/doc/des.js.html @@ -0,0 +1,459 @@ + + + + + JSDoc: Source: crypto/cipher/des.js + + + + + + + + + + +
+ +

Source: crypto/cipher/des.js

+ + + + + +
+
+
//Paul Tero, July 2001
+//http://www.tero.co.uk/des/
+//
+//Optimised for performance with large blocks by Michael Hayworth, November 2001
+//http://www.netdealing.com
+//
+// Modified by Recurity Labs GmbH
+
+//THIS SOFTWARE IS PROVIDED "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+//SUCH DAMAGE.
+
+//des
+//this takes the key, the message, and whether to encrypt or decrypt
+
+/**
+ * @module crypto/cipher/des
+ */
+
+
+function des(keys, message, encrypt, mode, iv, padding) {
+  //declaring this locally speeds things up a bit
+  var spfunction1 = new Array(0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400,
+    0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000,
+    0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4,
+    0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404,
+    0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400,
+    0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004);
+  var spfunction2 = new Array(-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, -
+    0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020, -
+    0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, -
+    0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, -
+    0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0,
+    0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0, -
+    0x7fef7fe0, 0x108000);
+  var spfunction3 = new Array(0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008,
+    0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000,
+    0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000,
+    0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0,
+    0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208,
+    0x8020000, 0x20208, 0x8, 0x8020008, 0x20200);
+  var spfunction4 = new Array(0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000,
+    0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080,
+    0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0,
+    0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001,
+    0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080);
+  var spfunction5 = new Array(0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000,
+    0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000,
+    0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100,
+    0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100,
+    0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100,
+    0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0,
+    0x40080000, 0x2080100, 0x40000100);
+  var spfunction6 = new Array(0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000,
+    0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010,
+    0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000,
+    0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000,
+    0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000,
+    0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010);
+  var spfunction7 = new Array(0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802,
+    0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002,
+    0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000,
+    0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000,
+    0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0,
+    0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002);
+  var spfunction8 = new Array(0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000,
+    0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000,
+    0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040,
+    0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040,
+    0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000,
+    0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000);
+
+  //create the 16 or 48 subkeys we will need
+  var m = 0,
+    i, j, temp, temp2, right1, right2, left, right, looping;
+  var cbcleft, cbcleft2, cbcright, cbcright2
+  var endloop, loopinc;
+  var len = message.length;
+  var chunk = 0;
+  //set up the loops for single and triple des
+  var iterations = keys.length == 32 ? 3 : 9; //single or triple des
+  if (iterations == 3) {
+    looping = encrypt ? new Array(0, 32, 2) : new Array(30, -2, -2);
+  } else {
+    looping = encrypt ? new Array(0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array(94, 62, -2, 32, 64, 2, 30, -2, -2);
+  }
+
+  //pad the message depending on the padding parameter
+  //only add padding if encrypting - note that you need to use the same padding option for both encrypt and decrypt
+  if (encrypt) {
+    message = des_addPadding(message, padding);
+    len = message.length;
+  }
+
+  //store the result here
+  result = "";
+  tempresult = "";
+
+  if (mode == 1) { //CBC mode
+    cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
+    cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
+    m = 0;
+  }
+
+  //loop through each 64 bit chunk of the message
+  while (m < len) {
+    left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message
+      .charCodeAt(m++);
+    right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) |
+      message.charCodeAt(m++);
+
+    //for Cipher Block Chaining mode, xor the message with the previous result
+    if (mode == 1) {
+      if (encrypt) {
+        left ^= cbcleft;
+        right ^= cbcright;
+      } else {
+        cbcleft2 = cbcleft;
+        cbcright2 = cbcright;
+        cbcleft = left;
+        cbcright = right;
+      }
+    }
+
+    //first each 64 but chunk of the message must be permuted according to IP
+    temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
+    right ^= temp;
+    left ^= (temp << 4);
+    temp = ((left >>> 16) ^ right) & 0x0000ffff;
+    right ^= temp;
+    left ^= (temp << 16);
+    temp = ((right >>> 2) ^ left) & 0x33333333;
+    left ^= temp;
+    right ^= (temp << 2);
+    temp = ((right >>> 8) ^ left) & 0x00ff00ff;
+    left ^= temp;
+    right ^= (temp << 8);
+    temp = ((left >>> 1) ^ right) & 0x55555555;
+    right ^= temp;
+    left ^= (temp << 1);
+
+    left = ((left << 1) | (left >>> 31));
+    right = ((right << 1) | (right >>> 31));
+
+    //do this either 1 or 3 times for each chunk of the message
+    for (j = 0; j < iterations; j += 3) {
+      endloop = looping[j + 1];
+      loopinc = looping[j + 2];
+      //now go through and perform the encryption or decryption  
+      for (i = looping[j]; i != endloop; i += loopinc) { //for efficiency
+        right1 = right ^ keys[i];
+        right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1];
+        //the result is attained by passing these bytes through the S selection functions
+        temp = left;
+        left = right;
+        right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f] | spfunction6[(right1 >>>
+          8) & 0x3f] | spfunction8[right1 & 0x3f] | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) &
+          0x3f] | spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);
+      }
+      temp = left;
+      left = right;
+      right = temp; //unreverse left and right
+    } //for either 1 or 3 iterations
+
+    //move then each one bit to the right
+    left = ((left >>> 1) | (left << 31));
+    right = ((right >>> 1) | (right << 31));
+
+    //now perform IP-1, which is IP in the opposite direction
+    temp = ((left >>> 1) ^ right) & 0x55555555;
+    right ^= temp;
+    left ^= (temp << 1);
+    temp = ((right >>> 8) ^ left) & 0x00ff00ff;
+    left ^= temp;
+    right ^= (temp << 8);
+    temp = ((right >>> 2) ^ left) & 0x33333333;
+    left ^= temp;
+    right ^= (temp << 2);
+    temp = ((left >>> 16) ^ right) & 0x0000ffff;
+    right ^= temp;
+    left ^= (temp << 16);
+    temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
+    right ^= temp;
+    left ^= (temp << 4);
+
+    //for Cipher Block Chaining mode, xor the message with the previous result
+    if (mode == 1) {
+      if (encrypt) {
+        cbcleft = left;
+        cbcright = right;
+      } else {
+        left ^= cbcleft2;
+        right ^= cbcright2;
+      }
+    }
+    tempresult += String.fromCharCode((left >>> 24), ((left >>> 16) & 0xff), ((left >>> 8) & 0xff), (left & 0xff), (
+      right >>> 24), ((right >>> 16) & 0xff), ((right >>> 8) & 0xff), (right & 0xff));
+
+    chunk += 8;
+    if (chunk == 512) {
+      result += tempresult;
+      tempresult = "";
+      chunk = 0;
+    }
+  } //for every 8 characters, or 64 bits in the message
+
+  //return the result as an array
+  result += tempresult;
+
+  //only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt
+  if (!encrypt) {
+    result = des_removePadding(result, padding);
+  }
+
+  return result;
+} //end of des
+
+
+
+//des_createKeys
+//this takes as input a 64 bit key (even though only 56 bits are used)
+//as an array of 2 integers, and returns 16 48 bit keys
+
+function des_createKeys(key) {
+  //declaring this locally speeds things up a bit
+  pc2bytes0 = new Array(0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204,
+    0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204);
+  pc2bytes1 = new Array(0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100,
+    0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101);
+  pc2bytes2 = new Array(0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808,
+    0x1000000, 0x1000008, 0x1000800, 0x1000808);
+  pc2bytes3 = new Array(0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000,
+    0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000);
+  pc2bytes4 = new Array(0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000,
+    0x41000, 0x1010, 0x41010);
+  pc2bytes5 = new Array(0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420,
+    0x2000000, 0x2000400, 0x2000020, 0x2000420);
+  pc2bytes6 = new Array(0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000,
+    0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002);
+  pc2bytes7 = new Array(0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000,
+    0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800);
+  pc2bytes8 = new Array(0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000,
+    0x2000002, 0x2040002, 0x2000002, 0x2040002);
+  pc2bytes9 = new Array(0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408,
+    0x10000408, 0x400, 0x10000400, 0x408, 0x10000408);
+  pc2bytes10 = new Array(0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020,
+    0x102000, 0x102020, 0x102000, 0x102020);
+  pc2bytes11 = new Array(0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000,
+    0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200);
+  pc2bytes12 = new Array(0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010,
+    0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010);
+  pc2bytes13 = new Array(0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105);
+
+  //how many iterations (1 for des, 3 for triple des)
+  var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys
+  //stores the return keys
+  var keys = new Array(32 * iterations);
+  //now define the left shifts which need to be done
+  var shifts = new Array(0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
+  //other variables
+  var lefttemp, righttemp, m = 0,
+    n = 0,
+    temp;
+
+  for (var j = 0; j < iterations; j++) { //either 1 or 3 iterations
+    left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
+    right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
+
+    temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
+    right ^= temp;
+    left ^= (temp << 4);
+    temp = ((right >>> -16) ^ left) & 0x0000ffff;
+    left ^= temp;
+    right ^= (temp << -16);
+    temp = ((left >>> 2) ^ right) & 0x33333333;
+    right ^= temp;
+    left ^= (temp << 2);
+    temp = ((right >>> -16) ^ left) & 0x0000ffff;
+    left ^= temp;
+    right ^= (temp << -16);
+    temp = ((left >>> 1) ^ right) & 0x55555555;
+    right ^= temp;
+    left ^= (temp << 1);
+    temp = ((right >>> 8) ^ left) & 0x00ff00ff;
+    left ^= temp;
+    right ^= (temp << 8);
+    temp = ((left >>> 1) ^ right) & 0x55555555;
+    right ^= temp;
+    left ^= (temp << 1);
+
+    //the right side needs to be shifted and to get the last four bits of the left side
+    temp = (left << 8) | ((right >>> 20) & 0x000000f0);
+    //left needs to be put upside down
+    left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);
+    right = temp;
+
+    //now go through and perform these shifts on the left and right keys
+    for (i = 0; i < shifts.length; i++) {
+      //shift the keys either one or two bits to the left
+      if (shifts[i]) {
+        left = (left << 2) | (left >>> 26);
+        right = (right << 2) | (right >>> 26);
+      } else {
+        left = (left << 1) | (left >>> 27);
+        right = (right << 1) | (right >>> 27);
+      }
+      left &= -0xf;
+      right &= -0xf;
+
+      //now apply PC-2, in such a way that E is easier when encrypting or decrypting
+      //this conversion will look like PC-2 except only the last 6 bits of each byte are used
+      //rather than 48 consecutive bits and the order of lines will be according to 
+      //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
+      lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(
+        left >>> 16) & 0xf] | pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | pc2bytes6[(left >>> 4) &
+        0xf];
+      righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | pc2bytes9[(right >>> 20) & 0xf] |
+        pc2bytes10[(right >>> 16) & 0xf] | pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] |
+        pc2bytes13[(right >>> 4) & 0xf];
+      temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;
+      keys[n++] = lefttemp ^ temp;
+      keys[n++] = righttemp ^ (temp << 16);
+    }
+  } //for each iterations
+  //return the keys we've created
+  return keys;
+} //end of des_createKeys
+
+
+function des_addPadding(message, padding) {
+  var padLength = 8 - (message.length % 8);
+  if ((padding == 2) && (padLength < 8)) { //pad the message with spaces
+    message += "        ".substr(0, padLength);
+  } else if (padding == 1) { //PKCS7 padding
+    message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength,
+      padLength).substr(0, padLength);
+  } else if (!padding && (padLength < 8)) { //pad the message out with null bytes
+    message += "\0\0\0\0\0\0\0\0".substr(0, padLength);
+  }
+  return message;
+}
+
+function des_removePadding(message, padding) {
+  if (padding == 2) { // space padded
+    message = message.replace(/ *$/g, "");
+  } else if (padding == 1) { // PKCS7
+    var padCount = message.charCodeAt(message.length - 1);
+    message = message.substr(0, message.length - padCount);
+  } else if (!padding) { // null padding
+    message = message.replace(/\0*$/g, "");
+  }
+  return message;
+}
+
+
+var util = require('../../util');
+
+// added by Recurity Labs
+
+function Des(key) {
+  this.key = [];
+
+  for (var i = 0; i < 3; i++) {
+    this.key.push(key.substr(i * 8, 8));
+  }
+
+  this.encrypt = function(block) {
+    return util.str2bin(des(des_createKeys(this.key[2]),
+      des(des_createKeys(this.key[1]),
+      des(des_createKeys(this.key[0]),
+      util.bin2str(block), true, 0, null, null),
+      false, 0, null, null), true, 0, null, null));
+  }
+}
+
+Des.keySize = Des.prototype.keySize = 24;
+Des.blockSize = Des.prototype.blockSize = 8;
+
+// This is "original" DES - Des is actually Triple DES.
+// This is only exported so we can unit test.
+
+function OriginalDes(key) {
+  this.key = key;
+
+  this.encrypt = function(block, padding) {
+    var keys = des_createKeys(this.key);
+    return util.str2bin(des(keys, util.bin2str(block), true, 0, null, padding));
+  }
+
+  this.decrypt = function(block, padding) {
+    var keys = des_createKeys(this.key);
+    return util.str2bin(des(keys, util.bin2str(block), false, 0, null, padding));
+  }
+}
+
+module.exports = {
+  /** @static */
+  des: Des,
+  /** @static */
+  originalDes: OriginalDes
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/dsa.html b/doc/dsa.html new file mode 100644 index 00000000..80815f6e --- /dev/null +++ b/doc/dsa.html @@ -0,0 +1,132 @@ + + + + + JSDoc: Module: crypto/public_key/dsa + + + + + + + + + + +
+ +

Module: crypto/public_key/dsa

+ + + + + +
+ +
+

+ crypto/public_key/dsa +

+ +
+ + + +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/dsa.js.html b/doc/dsa.js.html new file mode 100644 index 00000000..b0f0fab1 --- /dev/null +++ b/doc/dsa.js.html @@ -0,0 +1,221 @@ + + + + + JSDoc: Source: crypto/public_key/dsa.js + + + + + + + + + + +
+ +

Source: crypto/public_key/dsa.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// A Digital signature algorithm implementation
+
+/**
+ * @requires crypto/hash
+ * @requires crypto/public_key/jsbn
+ * @requires crypto/random
+ * @requires util
+ * @module crypto/public_key/dsa
+ */
+
+var BigInteger = require('./jsbn.js'),
+  random = require('../random.js'),
+  hashModule = require('../hash'),
+  util = require('../../util'),
+  config = require('../../config');
+
+function DSA() {
+  // s1 = ((g**s) mod p) mod q
+  // s1 = ((s**-1)*(sha-1(m)+(s1*x) mod q)
+  function sign(hashalgo, m, g, p, q, x) {
+    // If the output size of the chosen hash is larger than the number of
+    // bits of q, the hash result is truncated to fit by taking the number
+    // of leftmost bits equal to the number of bits of q.  This (possibly
+    // truncated) hash function result is treated as a number and used
+    // directly in the DSA signature algorithm.
+    var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength());
+    var hash = new BigInteger(util.hexstrdump(hashed_data), 16);
+    var k = random.getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE));
+    var s1 = (g.modPow(k, p)).mod(q);
+    var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q);
+    var result = new Array();
+    result[0] = s1.toMPI();
+    result[1] = s2.toMPI();
+    return result;
+  }
+
+  function select_hash_algorithm(q) {
+    var usersetting = config.prefer_hash_algorithm;
+    /*
+     * 1024-bit key, 160-bit q, SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512 hash
+     * 2048-bit key, 224-bit q, SHA-224, SHA-256, SHA-384, or SHA-512 hash
+     * 2048-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash
+     * 3072-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash
+     */
+    switch (Math.round(q.bitLength() / 8)) {
+      case 20:
+        // 1024 bit
+        if (usersetting != 2 &&
+          usersetting > 11 &&
+          usersetting != 10 &&
+          usersetting < 8)
+          return 2; // prefer sha1
+        return usersetting;
+      case 28:
+        // 2048 bit
+        if (usersetting > 11 &&
+          usersetting < 8)
+          return 11;
+        return usersetting;
+      case 32:
+        // 4096 bit // prefer sha224
+        if (usersetting > 10 &&
+          usersetting < 8)
+          return 8; // prefer sha256
+        return usersetting;
+      default:
+        util.print_debug("DSA select hash algorithm: returning null for an unknown length of q");
+        return null;
+
+    }
+  }
+  this.select_hash_algorithm = select_hash_algorithm;
+
+  function verify(hashalgo, s1, s2, m, p, q, g, y) {
+    var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength());
+    var hash = new BigInteger(util.hexstrdump(hashed_data), 16);
+    if (BigInteger.ZERO.compareTo(s1) > 0 ||
+      s1.compareTo(q) > 0 ||
+      BigInteger.ZERO.compareTo(s2) > 0 ||
+      s2.compareTo(q) > 0) {
+      util.print_debug("invalid DSA Signature");
+      return null;
+    }
+    var w = s2.modInverse(q);
+    var u1 = hash.multiply(w).mod(q);
+    var u2 = s1.multiply(w).mod(q);
+    return g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q);
+  }
+
+  /*
+	 * unused code. This can be used as a start to write a key generator
+	 * function.
+	
+	function generateKey(bitcount) {
+	    var qi = new BigInteger(bitcount, primeCenterie);
+	    var pi = generateP(q, 512);
+	    var gi = generateG(p, q, bitcount);
+	    var xi;
+	    do {
+	        xi = new BigInteger(q.bitCount(), rand);
+	    } while (x.compareTo(BigInteger.ZERO) != 1 && x.compareTo(q) != -1);
+	    var yi = g.modPow(x, p);
+	    return {x: xi, q: qi, p: pi, g: gi, y: yi};
+	}
+
+	function generateP(q, bitlength, randomfn) {
+	    if (bitlength % 64 != 0) {
+	    	return false;
+	    }
+	    var pTemp;
+	    var pTemp2;
+	    do {
+	        pTemp = randomfn(bitcount, true);
+	        pTemp2 = pTemp.subtract(BigInteger.ONE);
+	        pTemp = pTemp.subtract(pTemp2.remainder(q));
+	    } while (!pTemp.isProbablePrime(primeCenterie) || pTemp.bitLength() != l);
+	    return pTemp;
+	}
+	
+	function generateG(p, q, bitlength, randomfn) {
+	    var aux = p.subtract(BigInteger.ONE);
+	    var pow = aux.divide(q);
+	    var gTemp;
+	    do {
+	        gTemp = randomfn(bitlength);
+	    } while (gTemp.compareTo(aux) != -1 && gTemp.compareTo(BigInteger.ONE) != 1);
+	    return gTemp.modPow(pow, p);
+	}
+
+	function generateK(q, bitlength, randomfn) {
+	    var tempK;
+	    do {
+	        tempK = randomfn(bitlength, false);
+	    } while (tempK.compareTo(q) != -1 && tempK.compareTo(BigInteger.ZERO) != 1);
+	    return tempK;
+	}
+
+	function generateR(q,p) {
+	    k = generateK(q);
+	    var r = g.modPow(k, p).mod(q);
+	    return r;
+	}
+
+	function generateS(hashfn,k,r,m,q,x) {
+        var hash = hashfn(m);
+        s = (k.modInverse(q).multiply(hash.add(x.multiply(r)))).mod(q);
+	    return s;
+	} */
+  this.sign = sign;
+  this.verify = verify;
+  // this.generate = generateKey;
+}
+
+module.exports = DSA;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/elgamal.html b/doc/elgamal.html new file mode 100644 index 00000000..4a80def7 --- /dev/null +++ b/doc/elgamal.html @@ -0,0 +1,130 @@ + + + + + JSDoc: Module: crypto/public_key/elgamal + + + + + + + + + + +
+ +

Module: crypto/public_key/elgamal

+ + + + + +
+ +
+

+ crypto/public_key/elgamal +

+ +
+ + + +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/elgamal.js.html b/doc/elgamal.js.html new file mode 100644 index 00000000..bad86554 --- /dev/null +++ b/doc/elgamal.js.html @@ -0,0 +1,110 @@ + + + + + JSDoc: Source: crypto/public_key/elgamal.js + + + + + + + + + + +
+ +

Source: crypto/public_key/elgamal.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// ElGamal implementation
+
+/**
+ * @requires crypto/public_key/jsbn
+ * @requires crypto/random
+ * @requires util
+ * @module crypto/public_key/elgamal
+ */
+
+var BigInteger = require('./jsbn.js'),
+  random = require('../random.js'),
+  util = require('../../util');
+
+function Elgamal() {
+
+  function encrypt(m, g, p, y) {
+    //  choose k in {2,...,p-2}
+    var two = BigInteger.ONE.add(BigInteger.ONE);
+    var pMinus2 = p.subtract(two);
+    var k = random.getRandomBigIntegerInRange(two, pMinus2);
+    k = k.mod(pMinus2).add(BigInteger.ONE);
+    var c = [];
+    c[0] = g.modPow(k, p);
+    c[1] = y.modPow(k, p).multiply(m).mod(p);
+    return c;
+  }
+
+  function decrypt(c1, c2, p, x) {
+    util.print_debug("Elgamal Decrypt:\nc1:" + util.hexstrdump(c1.toMPI()) + "\n" +
+      "c2:" + util.hexstrdump(c2.toMPI()) + "\n" +
+      "p:" + util.hexstrdump(p.toMPI()) + "\n" +
+      "x:" + util.hexstrdump(x.toMPI()));
+    return (c1.modPow(x, p).modInverse(p)).multiply(c2).mod(p);
+    //var c = c1.pow(x).modInverse(p); // c0^-a mod p
+    //return c.multiply(c2).mod(p);
+  }
+
+  // signing and signature verification using Elgamal is not required by OpenPGP.
+  this.encrypt = encrypt;
+  this.decrypt = decrypt;
+}
+
+module.exports = Elgamal;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/enums.js.html b/doc/enums.js.html new file mode 100644 index 00000000..e6bd811b --- /dev/null +++ b/doc/enums.js.html @@ -0,0 +1,367 @@ + + + + + JSDoc: Source: enums.js + + + + + + + + + + +
+ +

Source: enums.js

+ + + + + +
+
+
/**
+ * @module enums
+ */
+
+module.exports = {
+
+  /** A string to key specifier type
+   * @enum {Integer}
+   * @readonly
+   */
+  s2k: {
+    simple: 0,
+    salted: 1,
+    iterated: 3,
+    gnu: 101
+  },
+
+  /** RFC4880, section 9.1
+   * @enum {Integer}
+   * @readonly
+   */
+  publicKey: {
+    rsa_encrypt_sign: 1,
+    rsa_encrypt: 2,
+    rsa_sign: 3,
+    elgamal: 16,
+    dsa: 17
+  },
+
+  /** RFC4880, section 9.2
+   * @enum {Integer}
+   * @readonly
+   */
+  symmetric: {
+    plaintext: 0,
+    /** Not implemented! */
+    idea: 1,
+    tripledes: 2,
+    cast5: 3,
+    blowfish: 4,
+    aes128: 7,
+    aes192: 8,
+    aes256: 9,
+    twofish: 10
+  },
+
+  /** RFC4880, section 9.3
+   * @enum {Integer}
+   * @readonly
+   */
+  compression: {
+    uncompressed: 0,
+    /** RFC1951 */
+    zip: 1,
+    /** RFC1950 */
+    zlib: 2,
+    bzip2: 3
+  },
+
+  /** RFC4880, section 9.4
+   * @enum {Integer}
+   * @readonly
+   */
+  hash: {
+    md5: 1,
+    sha1: 2,
+    ripemd: 3,
+    sha256: 8,
+    sha384: 9,
+    sha512: 10,
+    sha224: 11
+  },
+
+  /** A list of packet types and numeric tags associated with them.
+   * @enum {Integer}
+   * @readonly
+   */
+  packet: {
+    public_key_encrypted_session_key: 1,
+    signature: 2,
+    sym_encrypted_session_key: 3,
+    one_pass_signature: 4,
+    secret_key: 5,
+    public_key: 6,
+    secret_subkey: 7,
+    compressed: 8,
+    symmetrically_encrypted: 9,
+    marker: 10,
+    literal: 11,
+    trust: 12,
+    userid: 13,
+    public_subkey: 14,
+    user_attribute: 17,
+    sym_encrypted_integrity_protected: 18,
+    modification_detection_code: 19
+  },
+
+  /** Data types in the literal packet
+   * @enum {Integer}
+   * @readonly
+   */
+  literal: {
+    /** Binary data 'b' */
+    binary: 'b'.charCodeAt(),
+    /** Text data 't' */
+    text: 't'.charCodeAt(),
+    /** Utf8 data 'u' */
+    utf8: 'u'.charCodeAt()
+  },
+
+
+  /** One pass signature packet type
+   * @enum {Integer}
+   * @readonly
+   */
+  signature: {
+    /** 0x00: Signature of a binary document. */
+    binary: 0,
+    /** 0x01: Signature of a canonical text document.<br/>
+     * Canonicalyzing the document by converting line endings. */
+    text: 1,
+    /** 0x02: Standalone signature.<br/>
+     * This signature is a signature of only its own subpacket contents.
+     * It is calculated identically to a signature over a zero-lengh
+     * binary document.  Note that it doesn't make sense to have a V3
+     * standalone signature. */
+    standalone: 2,
+    /** 0x10: Generic certification of a User ID and Public-Key packet.<br/>
+     * The issuer of this certification does not make any particular
+     * assertion as to how well the certifier has checked that the owner
+     * of the key is in fact the person described by the User ID. */
+    cert_generic: 16,
+    /** 0x11: Persona certification of a User ID and Public-Key packet.<br/>
+     * The issuer of this certification has not done any verification of
+     * the claim that the owner of this key is the User ID specified. */
+    cert_persona: 17,
+    /** 0x12: Casual certification of a User ID and Public-Key packet.<br/>
+     * The issuer of this certification has done some casual
+     * verification of the claim of identity. */
+    cert_casual: 18,
+    /** 0x13: Positive certification of a User ID and Public-Key packet.<br/>
+     * The issuer of this certification has done substantial
+     * verification of the claim of identity.<br/>
+     * <br/>
+     * Most OpenPGP implementations make their "key signatures" as 0x10
+     * certifications.  Some implementations can issue 0x11-0x13
+     * certifications, but few differentiate between the types. */
+    cert_positive: 19,
+    /** 0x30: Certification revocation signature<br/>
+     * This signature revokes an earlier User ID certification signature
+     * (signature class 0x10 through 0x13) or direct-key signature
+     * (0x1F).  It should be issued by the same key that issued the
+     * revoked signature or an authorized revocation key.  The signature
+     * is computed over the same data as the certificate that it
+     * revokes, and should have a later creation date than that
+     * certificate. */
+    cert_revocation: 48,
+    /** 0x18: Subkey Binding Signature<br/>
+     * This signature is a statement by the top-level signing key that
+     * indicates that it owns the subkey.  This signature is calculated
+     * directly on the primary key and subkey, and not on any User ID or
+     * other packets.  A signature that binds a signing subkey MUST have
+     * an Embedded Signature subpacket in this binding signature that
+     * contains a 0x19 signature made by the signing subkey on the
+     * primary key and subkey. */
+    subkey_binding: 24,
+    /** 0x19: Primary Key Binding Signature<br/>
+     * This signature is a statement by a signing subkey, indicating
+     * that it is owned by the primary key and subkey.  This signature
+     * is calculated the same way as a 0x18 signature: directly on the
+     * primary key and subkey, and not on any User ID or other packets.<br/>
+     * <br/>
+     * When a signature is made over a key, the hash data starts with the
+     * octet 0x99, followed by a two-octet length of the key, and then body
+     * of the key packet.  (Note that this is an old-style packet header for
+     * a key packet with two-octet length.)  A subkey binding signature
+     * (type 0x18) or primary key binding signature (type 0x19) then hashes
+     * the subkey using the same format as the main key (also using 0x99 as
+     * the first octet). */
+    key_binding: 25,
+    /** 0x1F: Signature directly on a key<br/>
+     * This signature is calculated directly on a key.  It binds the
+     * information in the Signature subpackets to the key, and is
+     * appropriate to be used for subpackets that provide information
+     * about the key, such as the Revocation Key subpacket.  It is also
+     * appropriate for statements that non-self certifiers want to make
+     * about the key itself, rather than the binding between a key and a
+     * name. */
+    key: 31,
+    /** 0x20: Key revocation signature<br/>
+     * The signature is calculated directly on the key being revoked.  A
+     * revoked key is not to be used.  Only revocation signatures by the
+     * key being revoked, or by an authorized revocation key, should be
+     * considered valid revocation signatures.a */
+    key_revocation: 32,
+    /** 0x28: Subkey revocation signature<br/>
+     * The signature is calculated directly on the subkey being revoked.
+     * A revoked subkey is not to be used.  Only revocation signatures
+     * by the top-level signature key that is bound to this subkey, or
+     * by an authorized revocation key, should be considered valid
+     * revocation signatures.<br/>
+     * <br/>
+     * Key revocation signatures (types 0x20 and 0x28)
+     * hash only the key being revoked. */
+    subkey_revocation: 40,
+    /** 0x40: Timestamp signature.<br/>
+     * This signature is only meaningful for the timestamp contained in
+     * it. */
+    timestamp: 64,
+    /** 0x50: Third-Party Confirmation signature.<br/>
+     * This signature is a signature over some other OpenPGP Signature
+     * packet(s).  It is analogous to a notary seal on the signed data.
+     * A third-party signature SHOULD include Signature Target
+     * subpacket(s) to give easy identification.  Note that we really do
+     * mean SHOULD.  There are plausible uses for this (such as a blind
+     * party that only sees the signature, not the key or source
+     * document) that cannot include a target subpacket. */
+    third_party: 80
+  },
+
+  /** Signature subpacket type
+   * @enum {Integer}
+   * @readonly
+   */
+  signatureSubpacket: {
+    signature_creation_time: 2,
+    signature_expiration_time: 3,
+    exportable_certification: 4,
+    trust_signature: 5,
+    regular_expression: 6,
+    revocable: 7,
+    key_expiration_time: 9,
+    placeholder_backwards_compatibility: 10,
+    preferred_symmetric_algorithms: 11,
+    revocation_key: 12,
+    issuer: 16,
+    notation_data: 20,
+    preferred_hash_algorithms: 21,
+    preferred_compression_algorithms: 22,
+    key_server_preferences: 23,
+    preferred_key_server: 24,
+    primary_user_id: 25,
+    policy_uri: 26,
+    key_flags: 27,
+    signers_user_id: 28,
+    reason_for_revocation: 29,
+    features: 30,
+    signature_target: 31,
+    embedded_signature: 32
+  },
+
+  /** Key flags
+   * @enum {Integer}
+   * @readonly
+   */
+  keyFlags: {
+    /** 0x01 - This key may be used to certify other keys. */
+    certify_keys: 1,
+    /** 0x02 - This key may be used to sign data. */
+    sign_data: 2,
+    /** 0x04 - This key may be used to encrypt communications. */
+    encrypt_communication: 4,
+    /** 0x08 - This key may be used to encrypt storage. */
+    encrypt_storage: 8,
+    /** 0x10 - The private component of this key may have been split
+     *        by a secret-sharing mechanism. */
+    split_private_key: 16,
+    /** 0x20 - This key may be used for authentication. */
+    authentication: 32,
+    /** 0x80 - The private component of this key may be in the
+     *        possession of more than one person. */
+    shared_private_key: 128
+  },
+
+  /** Key status
+   * @enum {Integer}
+   * @readonly
+   */
+  keyStatus: {
+    invalid:      0,
+    expired:      1,
+    revoked:      2,
+    valid:        3,
+    no_self_cert: 4
+  },
+
+  /** Armor type
+   * @enum {Integer}
+   * @readonly
+   */
+  armor: {
+    multipart_section: 0,
+    multipart_last: 1,
+    signed: 2,
+    message: 3,
+    public_key: 4,
+    private_key: 5
+  },
+
+  /** Asserts validity and converts from string/integer to integer. */
+  write: function(type, e) {
+    if (typeof e == 'number') {
+      e = this.read(type, e);
+    }
+
+    if (type[e] !== undefined) {
+      return type[e];
+    } else throw new Error('Invalid enum value.');
+  },
+  /** Converts from an integer to string. */
+  read: function(type, e) {
+    for (var i in type)
+      if (type[i] == e) return i;
+
+    throw new Error('Invalid enum value.');
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/global.html b/doc/global.html deleted file mode 100644 index 00f12dcf..00000000 --- a/doc/global.html +++ /dev/null @@ -1,8227 +0,0 @@ - - - - - JSDoc: Global - - - - - - - - - - -
- -

Global

- - - - - -
- -
-

- -

- -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - - - - - - - -

Members

- -
- -
-

bin2str

- - -
-
- -
- Convert an array of integers(0.255) to a string -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

crc_table

- - -
-
- -
- Internal function to calculate a CRC-24 checksum over a given string (data) -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

hash_headers

- - -
-
- -
- ASN1 object identifiers for hashes (See RFC4880 5.2.2) -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

Uint8Array2str

- - -
-
- -
- Convert a Uint8Array to a string. This currently functions -the same as bin2str. -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

util

- - -
-
- -
- an instance that should be used. -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- -
- - - -

Methods

- -
- -
-

calc_checksum(text) → {Integer}

- - -
-
- - -
- Calculates a 16bit sum of a string by adding each character -codes modulus 65535 -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
text - - -String - - - - String to create a sum of
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- An integer containing the sum of all character -codes % 65535 -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

decode_utf8(utf8) → {String}

- - -
-
- - -
- Convert a string of utf8 bytes to a native javascript string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
utf8 - - -String - - - - A valid squence of utf8 bytes
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A native javascript string -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

encode_utf8(str) → {String}

- - -
-
- - -
- Convert a native javascript string to a string of utf8 bytes -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - The string to convert
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A valid squence of utf8 bytes -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

get_hashAlgorithmString() → {String}

- - -
-
- - -
- Return the algorithm type as string -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String representing the message type -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

getCheckSum(data) → {String}

- - -
-
- - -
- Calculates a checksum over the given data and returns it base64 encoded -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -String - - - - Data to create a CRC-24 checksum for
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Base64 encoded checksum -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

getPGPMessageType(text) → {Integer}

- - -
-
- - -
- Finds out which Ascii Armoring type is used. This is an internal function -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
text - - -String - - - - [String] ascii armored text
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- 0 = MESSAGE PART n of m - 1 = MESSAGE PART n - 2 = SIGNED MESSAGE - 3 = PGP MESSAGE - 4 = PUBLIC KEY BLOCK - 5 = PRIVATE KEY BLOCK - null = unknown -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

hex2bin(str) → {String}

- - -
-
- - -
- Create binary string from a hex encoded string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - Hex string to convert
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String containing the binary values -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

hexidump(str) → {String}

- - -
-
- - -
- Creating a hex string from an binary array of integers (0..255) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - Array of bytes to convert
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Hexadecimal representation of the array -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

hexstrdump(str) → {String}

- - -
-
- - -
- Create hexstring from a binary -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - String to convert
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String containing the hexadecimal values -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

MD5()

- - -
-
- - -
- A fast MD5 JavaScript implementation -Copyright (c) 2012 Joseph Myers -http://www.myersdaily.org/joseph/javascript/md5-text.html - -Permission to use, copy, modify, and distribute this software -and its documentation for any purposes and without -fee is hereby granted provided that this copyright notice -appears in all copies. - -Of course, this soft is provided "as is" without express or implied -warranty of any kind. -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

openpgp_cfb_decrypt(blockcipherfn, block_size, plaintext, key, resync) → {String}

- - -
-
- - -
- This function decrypts a given plaintext using the specified -blockcipher to decrypt a message -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockcipherfn - - -openpgp_cipher_block_fn - - - - The algorithm _encrypt_ function to encrypt - data in one block_size encryption.
block_size - - -Integer - - - - the block size in bytes of the algorithm used
plaintext - - -String - - - - ciphertext to be decrypted provided as a string
key - - -openpgp_byte_array - - - - key to be used to decrypt the ciphertext. This will be passed to the - blockcipherfn
resync - - -Boolean - - - - a boolean value specifying if a resync of the - IV should be used or not. The encrypteddatapacket uses the - "old" style with a resync. Decryption within an - encryptedintegrityprotecteddata packet is not resyncing the IV.
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a string with the plaintext data -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_cfb_encrypt(prefixrandom, blockcipherfn, block_size, plaintext, key, resync) → {String}

- - -
-
- - -
- This function encrypts a given with the specified prefixrandom -using the specified blockcipher to encrypt a message -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
prefixrandom - - -String - - - - random bytes of block_size length provided - as a string to be used in prefixing the data
blockcipherfn - - -openpgp_cipher_block_fn - - - - the algorithm encrypt function to encrypt - data in one block_size encryption.
block_size - - -Integer - - - - the block size in bytes of the algorithm used
plaintext - - -String - - - - data to be encrypted provided as a string
key - - -openpgp_byte_array - - - - key to be used to encrypt the data. This will be passed to the - blockcipherfn
resync - - -Boolean - - - - a boolean value specifying if a resync of the - IV should be used or not. The encrypteddatapacket uses the - "old" style with a resync. Encryption within an - encryptedintegrityprotecteddata packet is not resyncing the IV.
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a string with the encrypted data -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_cfb_mdc(blockcipherencryptfn, block_size, key, ciphertext) → {String}

- - -
-
- - -
- Decrypts the prefixed data for the Modification Detection Code (MDC) computation -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockcipherencryptfn - - -openpgp_block_cipher_fn - - - - Cipher function to use
block_size - - -Integer - - - - Blocksize of the algorithm
key - - -openpgp_byte_array - - - - The key for encryption
ciphertext - - -String - - - - The encrypted data
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- plaintext Data of D(ciphertext) with blocksize length +2 -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_asymetricDecrypt(algo, publicMPIs, secretMPIs, data) → {BigInteger}

- - -
-
- - -
- Decrypts data using the specified public key multiprecision integers of the private key, -the specified secretMPIs of the private key and the specified algorithm. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Algorithm to be used (See RFC4880 9.1)
publicMPIs - - -openpgp_type_mpi[] - - - - Algorithm dependent multiprecision integers -of the public key part of the private key
secretMPIs - - -openpgp_type_mpi[] - - - - Algorithm dependent multiprecision integers -of the private key used
data - - -openpgp_type_mpi - - - - Data to be encrypted as MPI
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- returns a big integer containing the decrypted data; otherwise null -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - -
- - - -
-

openpgp_crypto_asymetricEncrypt(algo, publicMPIs, data) → {openpgp_type_mpi|Array.<openpgp_type_mpi>}

- - -
-
- - -
- Encrypts data using the specified public key multiprecision integers -and the specified algorithm. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Algorithm to be used (See RFC4880 9.1)
publicMPIs - - -openpgp_type_mpi[] - - - - Algorithm dependent multiprecision integers
data - - -openpgp_type_mpi - - - - Data to be encrypted as MPI
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- if RSA an openpgp_type_mpi; -if elgamal encryption an array of two openpgp_type_mpi is returned; otherwise null -
- - - -
-
- Type -
-
- -openpgp_type_mpi -| - -Array.<openpgp_type_mpi> - - -
-
- - - - -
- - - -
-

openpgp_crypto_generateKeyPair(keyType, numBits) → {openpgp_keypair}

- - -
-
- - -
- Calls the necessary crypto functions to generate a keypair. -Called directly by openpgp.js -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyType - - -Integer - - - - Follows OpenPGP algorithm convention.
numBits - - -Integer - - - - Number of bits to make the key to be generated
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -openpgp_keypair - - -
-
- - - - -
- - - -
-

openpgp_crypto_generateSessionKey(algo) → {String}

- - -
-
- - -
- Generating a session key for the specified symmetric algorithm -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Algorithm to use (see RFC4880 9.2)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Random bytes as a string to be used as a key -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_getHashByteLength(algo) → {Integer}

- - -
-
- - -
- Returns the hash size in bytes of the specified hash algorithm type -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Hash algorithm type (See RFC4880 9.4)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Size in bytes of the resulting hash -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

openpgp_crypto_getPrefixRandom(algo) → {String}

- - -
-
- - -
- generate random byte prefix as string for the specified algorithm -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Algorithm to use (see RFC4880 9.2)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Random bytes with length equal to the block -size of the cipher -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_getPseudoRandom(from, to) → {Integer}

- - -
-
- - -
- Return a pseudo-random number in the specified range -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
from - - -Integer - - - - Min of the random number
to - - -Integer - - - - Max of the random number (max 32bit)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A pseudo random number -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

openpgp_crypto_getRandomBigInteger(bits) → {BigInteger}

- - -
-
- - -
- Create a secure random big integer of bits length -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
bits - - -Integer - - - - Bit length of the MPI to create
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Resulting big integer -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - -
- - - -
-

openpgp_crypto_getRandomBytes(length) → {String}

- - -
-
- - -
- Retrieve secure random byte string of the specified length -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
length - - -Integer - - - - Length in bytes to generate
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Random byte string -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_getSecureRandom(from, to) → {Integer}

- - -
-
- - -
- Return a secure random number in the specified range -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
from - - -Integer - - - - Min of the random number
to - - -Integer - - - - Max of the random number (max 32bit)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A secure random number -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

openpgp_crypto_hashData(algo, data) → {String}

- - -
-
- - -
- Create a hash on the specified data using the specified algorithm -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Hash algorithm type (see RFC4880 9.4)
data - - -String - - - - Data to be hashed
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- hash value -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_MDCSystemBytes(algo, key, data) → {String}

- - -
-
- - -
- retrieve the MDC prefixed bytes by decrypting them -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Algorithm to use (see RFC4880 9.2)
key - - -String - - - - Key as string. length is depending on the algorithm used
data - - -String - - - - Encrypted data where the prefix is decrypted from
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Plain text data of the prefixed data -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, data) → {String|openpgp_type_mpi}

- - -
-
- - -
- Create a signature on data using the specified algorithm -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
hash_algo - - -Integer - - - - hash Algorithm to use (See RFC4880 9.4)
algo - - -Integer - - - - Asymmetric cipher algorithm to use (See RFC4880 9.1)
publicMPIs - - -openpgp_type_mpi[] - - - - Public key multiprecision integers -of the private key
secretMPIs - - -openpgp_type_mpi[] - - - - Private key multiprecision -integers which is used to sign the data
data - - -String - - - - Data to be signed
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String -| - -openpgp_type_mpi - - -
-
- - - - -
- - - -
-

openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) → {String}

- - -
-
- - -
- Symmetrically decrypts data using a key with length depending on the -algorithm in openpgp_cfb mode with or without resync (MDC style) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Algorithm to use (see RFC4880 9.2)
key - - -String - - - - Key as string. length is depending on the algorithm used
data - - -String - - - - Data to be decrypted
openpgp_cfb - - -Boolean - - - - If true use the resync (for encrypteddata); -otherwise use without the resync (for MDC encrypted data)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Plaintext data -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_cfb) → {String}

- - -
-
- - -
- Symmetrically encrypts data using prefixedrandom, a key with length -depending on the algorithm in openpgp_cfb mode with or without resync -(MDC style) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
prefixrandom - - -String - - - - Secure random bytes as string in -length equal to the block size of the algorithm used (use -openpgp_crypto_getPrefixRandom(algo) to retrieve that string
algo - - -Integer - - - - Algorithm to use (see RFC4880 9.2)
key - - -String - - - - Key as string. length is depending on the algorithm used
data - - -String - - - - Data to encrypt
openpgp_cfb - - -Boolean - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Encrypted data -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_crypto_verifySignature(algo, hash_algo, msg_MPIs, publickey_MPIs, data) → {Boolean}

- - -
-
- - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - public Key algorithm
hash_algo - - -Integer - - - - Hash algorithm
msg_MPIs - - -openpgp_type_mpi[] - - - - Signature multiprecision integers
publickey_MPIs - - -openpgp_type_mpi[] - - - - Public key multiprecision integers
data - - -String - - - - Data on where the signature was computed on.
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- true if signature (sig_data was equal to data over hash) -
- - - -
-
- Type -
-
- -Boolean - - -
-
- - - - -
- - - -
-

openpgp_encoding_armor(messagetype, data, partindex, parttotal) → {String}

- - -
-
- - -
- Armor an OpenPGP binary packet block -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
messagetype - - -Integer - - - - type of the message
data - -
partindex - - -Integer - - - -
parttotal - - -Integer - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Armored text -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_armor_addheader() → {String}

- - -
-
- - -
- Add additional information to the armor version of an OpenPGP binary -packet block. -
- - - - - - - - - -
- - - -
Version:
-
  • 2011-12-16
- - - - - - - - - -
Author:
-
-
    -
  • Alex
  • -
-
- - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The header information -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_base64_decode(message) → {String}

- - -
-
- - -
- Wrapper function for the base64 codec. -This function decodes a String(message) in base64 (radix-64) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - -String - - - - Base64 encoded data
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Raw data after decoding -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_base64_encode(message) → {String}

- - -
-
- - -
- Wrapper function for the base64 codec. -This function encodes a String (message) in base64 (radix-64) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - -String - - - - The message to encode
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The base64 encoded data -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_deArmor(text) → {String|Object}

- - -
-
- - -
- DeArmor an OpenPGP armored message; verify the checksum and return -the encoded bytes -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
text - - -String - - - - OpenPGP armored message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Either the bytes of the decoded message -or an object with attribute "text" containing the message text -and an attribute "openpgp" containing the bytes. -
- - - -
-
- Type -
-
- -String -| - -Object - - -
-
- - - - -
- - - -
-

openpgp_encoding_eme_pkcs1_decode(message) → {String}

- - -
-
- - -
- decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - -String - - - - EME-PKCS1 padded message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- decoded message -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_eme_pkcs1_encode(message, length) → {String}

- - -
-
- - -
- create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - -String - - - - message to be padded
length - - -Integer - - - - Length to the resulting message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- EME-PKCS1 padded message -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_emsa_pkcs1_decode(data) → {String}

- - -
-
- - -
- extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -String - - - - Hash in pkcs1 encoding
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The hash as string -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_emsa_pkcs1_encode(algo, data, keylength) → {String}

- - -
-
- - -
- create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Hash algorithm type used
data - - -String - - - - Data to be hashed
keylength - - -Integer - - - - Key size of the public mpi in bytes
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Hashcode with pkcs1padding as string -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

openpgp_encoding_html_encode(message) → {String}

- - -
-
- - -
- Wrapper function for jquery library. -This function escapes HTML characters within a string. This is used -to prevent XSS. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - -String - - - - Message to escape
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Html encoded string -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
- - - -
-
- - -
- Helper function to print a debug message. Debug -messages are only printed if -openpgp.config.debug is set to true. The calling -Javascript context MUST define -a "showMessages(text)" function. Line feeds ('\n') -are automatically converted to HTML line feeds '
' -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - String of the debug message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- An HTML tt entity containing a paragraph with a -style attribute where the debug message is HTMLencoded in. -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
- - - -
-
- - -
- Helper function to print a debug message. Debug -messages are only printed if -openpgp.config.debug is set to true. The calling -Javascript context MUST define -a "showMessages(text)" function. Line feeds ('\n') -are automatically converted to HTML line feeds '
' -Different than print_debug because will call hexstrdump iff necessary. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - String of the debug message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- An HTML tt entity containing a paragraph with a -style attribute where the debug message is HTMLencoded in. -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
- - - -
-
- - -
- Helper function to print an error message. -The calling Javascript context MUST define -a "showMessages(text)" function. Line feeds ('\n') -are automatically converted to HTML line feeds '
' -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - String of the error message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A HTML paragraph entity with a style attribute -containing the HTML encoded error message -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
- - - -
-
- - -
- Helper function to print an info message. -The calling Javascript context MUST define -a "showMessages(text)" function. Line feeds ('\n') -are automatically converted to HTML line feeds '
'. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - String of the info message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A HTML paragraph entity with a style attribute -containing the HTML encoded info message -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

shiftRight(value, bitcount) → {String}

- - -
-
- - -
- Shifting a string to n bits right -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
value - - -String - - - - The string to shift
bitcount - - -Integer - - - - Amount of bits to shift (MUST be smaller -than 9)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Resulting string. -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

str2bin(str) → {Integer[]}

- - -
-
- - -
- Convert a string to an array of integers(0.255) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - String to convert
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- An array of (binary) integers -
- - - -
-
- Type -
-
- -Integer[] - - -
-
- - - - -
- - - -
-

str2Uint8Array(str) → {Uint8Array}

- - -
-
- - -
- Convert a string to a Uint8Array -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - String to convert
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The array of (binary) integers -
- - - -
-
- Type -
-
- -Uint8Array - - -
-
- - - - -
- - - -
-

verifyCheckSum(data, checksum) → {Boolean}

- - -
-
- - -
- Calculates the checksum over the given data and compares it with the -given base64 encoded checksum -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -String - - - - Data to create a CRC-24 checksum for
checksum - - -String - - - - Base64 encoded checksum
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- True if the given checksum is correct; otherwise false -
- - - -
-
- Type -
-
- -Boolean - - -
-
- - - - -
- -
- - - -

Type Definitions

- -
- -
-

openpgp_byte_array

- - -
-
- -
- An array of bytes, that is integers with values from 0 to 255 -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

openpgp_cipher_block_fn(block, key) → {openpgp_byte_array}

- - -
-
- - -
- Block cipher function -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
block - - -openpgp_byte_array - - - - A block to perform operations on
key - - -openpgp_byte_array - - - - to use in encryption/decryption
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Encrypted/decrypted block -
- - - -
-
- Type -
-
- -openpgp_byte_array - - -
-
- - - - -
- - - -
-

openpgp_keypair

- - -
-
- - - -
- - -
Properties:
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
privateKey - - -openpgp_packet_keymaterial - - - -
publicKey - - -openpgp_packet_keymaterial - - - -
- - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- -
- - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) -
- - - - diff --git a/doc/hash.html b/doc/hash.html new file mode 100644 index 00000000..da528cab --- /dev/null +++ b/doc/hash.html @@ -0,0 +1,834 @@ + + + + + JSDoc: Module: crypto/hash + + + + + + + + + + +
+ +

Module: crypto/hash

+ + + + + +
+ +
+

+ crypto/hash +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

<static> md5

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> ripemd

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> sha1

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> sha224

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> sha256

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> sha384

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> sha512

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

<static> digest(algo, data) → {String}

+ + +
+
+ + +
+ Create a hash on the specified data using the specified algorithm +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +Integer + + + + Hash algorithm type (see RFC4880 9.4)
data + + +String + + + + Data to be hashed
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ hash value +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> getHashByteLength(algo) → {Integer}

+ + +
+
+ + +
+ Returns the hash size in bytes of the specified hash algorithm type +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +Integer + + + + Hash algorithm type (See RFC4880 9.4)
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Size in bytes of the resulting hash +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/index.html b/doc/index.html index 8448e9c3..35a9596f 100644 --- a/doc/index.html +++ b/doc/index.html @@ -40,6 +40,48 @@ +
+

[Build Status

+ +

What is OpenPGP.js?

+ +

OpenPGP.js is a Javascript implementation of the OpenPGP protocol. This is defined in RFC 4880.

+ +

How do I use it?

+ +

As a developer, the best place to start is in the resources/ directory. Within this you will find a basic example implementation and the "binary" files for this library. It is likely that you will want to use resources/openpgp.min.js on your site, this is a minified version of our library.

+ +

I need some help

+ +

Mailing List

+ +

You can sign up for our mailing list and ask for help there. We've recently worked on getting our archive up and running.

+ +

Documentation

+ +

A jsdoc build of our code comments is available at doc/index.html. Public calls should generally be made through the OpenPGP object doc/openpgp.html.

+ +

How do I get involved?

+ +

You want to help, great! Go ahead and fork our repo, make your changes and make a pull request. Please be sure that you run make minify from the root directory to concatenate and minify the library into the resources/ directory.

+ +

It is extra awesome if you write tests for the code you change. Our test coverage is relatively weak, so if you can add cases that is great.

+ +

What License do you use?

+ +

GNU Lesser General Public License (2.1). Please take a look at the LICENSE file for more information.

+ +

What are the requirements to use it?

+ +

OpenPGP.js currently only fully supports Chrome. Firefox support should be coming soon with the advent of Firefox 23 with native javascript support for window.crypto.getRandomValues. If you can help us support more browsers and situations, please chip in!

+ +

Resources

+ +

Below is a collection of resources, many of these were projects that were in someway a precursor to the current OpenPGP.js project. If you'd like to add your link here, please do so in a pull request or email to the list.

+ +
+
+ @@ -62,7 +104,7 @@ -
The openpgp base class should provide all of the functionality +
The openpgp base module should provide all of the functionality to consume the openpgp.js library. All additional classes are documented for extending and developing on top of the base library.
@@ -90,7 +132,7 @@ for extending and developing on top of the base library.
Source:
@@ -133,15 +175,16 @@ for extending and developing on top of the base library.
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) + Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST)
+ - + \ No newline at end of file diff --git a/doc/index.js.html b/doc/index.js.html new file mode 100644 index 00000000..902d6691 --- /dev/null +++ b/doc/index.js.html @@ -0,0 +1,89 @@ + + + + + JSDoc: Source: index.js + + + + + + + + + + +
+ +

Source: index.js

+ + + + + +
+
+

+module.exports = require('./openpgp.js');
+
+module.exports.key = require('./key.js');
+module.exports.message = require('./message.js');
+module.exports.cleartext = require('./cleartext.js');
+/**
+ * @see module:util/util
+ * @module util
+ */
+module.exports.util = require('./util/util.js');
+module.exports.packet = require('./packet');
+/**
+ * @see module:type/mpi
+ * @module mpi
+ */
+module.exports.mpi = require('./type/mpi.js');
+/**
+ * @see module:type/s2k
+ * @module s2k
+ */
+module.exports.s2k = require('./type/s2k.js');
+/**
+ * @see module:type/keyid
+ * @module keyid
+ */
+module.exports.keyid = require('./type/keyid.js');
+/**
+ * @see module:encoding/armor
+ * @module armor
+ */
+module.exports.armor = require('./encoding/armor.js');
+module.exports.enums = require('./enums.js');
+/**
+ * @see module:config/config
+ * @module config
+ */
+module.exports.config = require('./config/config.js');
+module.exports.crypto = require('./crypto');
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/index.js_.html b/doc/index.js_.html new file mode 100644 index 00000000..55766af2 --- /dev/null +++ b/doc/index.js_.html @@ -0,0 +1,76 @@ + + + + + JSDoc: Source: crypto/index.js + + + + + + + + + + +
+ +

Source: crypto/index.js

+ + + + + +
+
+
/**
+ * @see module:crypto/crypto
+ * @module crypto
+ */
+module.exports = {
+  /** @see module:crypto/cipher */
+  cipher: require('./cipher'),
+  /** @see module:crypto/hash */
+  hash: require('./hash'),
+  /** @see module:crypto/cfb */
+  cfb: require('./cfb.js'),
+  /** @see module:crypto/public_key */
+  publicKey: require('./public_key'),
+  /** @see module:crypto/signature */
+  signature: require('./signature.js'),
+  /** @see module:crypto/random */
+  random: require('./random.js'),
+  /** @see module:crypto/pkcs1 */
+  pkcs1: require('./pkcs1.js')
+
+}
+
+var crypto = require('./crypto.js');
+
+for (var i in crypto)
+  module.exports[i] = crypto[i];
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/index.js__.html b/doc/index.js__.html new file mode 100644 index 00000000..c302f9d9 --- /dev/null +++ b/doc/index.js__.html @@ -0,0 +1,78 @@ + + + + + JSDoc: Source: crypto/cipher/index.js + + + + + + + + + + +
+ +

Source: crypto/cipher/index.js

+ + + + + +
+
+
/**
+ * @requires crypto/cipher/aes
+ * @requires crypto/cipher/blowfish
+ * @requires crypto/cipher/cast5
+ * @requires crypto/cipher/twofish
+ * @module crypto/cipher
+ */
+
+var desModule = require('./des.js');
+
+module.exports = {
+  /** @see module:crypto/cipher/des.des */
+  des: desModule['des'],
+  /** @see module:crypto/cipher/des.originalDes */
+  originalDes: desModule['originalDes'],
+  /** @see module:crypto/cipher/cast5 */
+  cast5: require('./cast5.js'),
+  /** @see module:crypto/cipher/twofish */
+  twofish: require('./twofish.js'),
+  /** @see module:crypto/cipher/blowfish */
+  blowfish: require('./blowfish.js')
+}
+
+var aes = require('./aes.js');
+
+for (var i in aes) {
+  module.exports['aes' + i] = aes[i];
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/index.js___.html b/doc/index.js___.html new file mode 100644 index 00000000..f622a880 --- /dev/null +++ b/doc/index.js___.html @@ -0,0 +1,138 @@ + + + + + JSDoc: Source: crypto/hash/index.js + + + + + + + + + + +
+ +

Source: crypto/hash/index.js

+ + + + + +
+
+
/**
+ * @requires crypto/hash/sha
+ * @module crypto/hash
+ */
+var sha = require('./sha.js');
+
+module.exports = {
+  /** @see module:crypto/hash/md5 */
+  md5: require('./md5.js'),
+  /** @see module:crypto/hash/sha.sha1 */
+  sha1: sha.sha1,
+  /** @see module:crypto/hash/sha.sha224 */
+  sha224: sha.sha224,
+  /** @see module:crypto/hash/sha.sha256 */
+  sha256: sha.sha256,
+  /** @see module:crypto/hash/sha.sha384 */
+  sha384: sha.sha384,
+  /** @see module:crypto/hash/sha.sha512 */
+  sha512: sha.sha512,
+  /** @see module:crypto/hash/ripe-md */
+  ripemd: require('./ripe-md.js'),
+
+  /**
+   * Create a hash on the specified data using the specified algorithm
+   * @param {Integer} algo Hash algorithm type (see RFC4880 9.4)
+   * @param {String} data Data to be hashed
+   * @return {String} hash value
+   */
+  digest: function(algo, data) {
+    switch (algo) {
+      case 1:
+        // - MD5 [HAC]
+        return this.md5(data);
+      case 2:
+        // - SHA-1 [FIPS180]
+        return this.sha1(data);
+      case 3:
+        // - RIPE-MD/160 [HAC]
+        return this.ripemd(data);
+      case 8:
+        // - SHA256 [FIPS180]
+        return this.sha256(data);
+      case 9:
+        // - SHA384 [FIPS180]
+        return this.sha384(data);
+      case 10:
+        // - SHA512 [FIPS180]
+        return this.sha512(data);
+      case 11:
+        // - SHA224 [FIPS180]
+        return this.sha224(data);
+      default:
+        throw new Error('Invalid hash function.');
+    }
+  },
+
+  /**
+   * Returns the hash size in bytes of the specified hash algorithm type
+   * @param {Integer} algo Hash algorithm type (See RFC4880 9.4)
+   * @return {Integer} Size in bytes of the resulting hash
+   */
+  getHashByteLength: function(algo) {
+    switch (algo) {
+      case 1:
+        // - MD5 [HAC]
+        return 16;
+      case 2:
+        // - SHA-1 [FIPS180]
+      case 3:
+        // - RIPE-MD/160 [HAC]
+        return 20;
+      case 8:
+        // - SHA256 [FIPS180]
+        return 32;
+      case 9:
+        // - SHA384 [FIPS180]
+        return 48
+      case 10:
+        // - SHA512 [FIPS180]
+        return 64;
+      case 11:
+        // - SHA224 [FIPS180]
+        return 28;
+      default:
+        throw new Error('Invalid hash algorithm.');
+    }
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/index.js____.html b/doc/index.js____.html new file mode 100644 index 00000000..05e4110b --- /dev/null +++ b/doc/index.js____.html @@ -0,0 +1,64 @@ + + + + + JSDoc: Source: crypto/public_key/index.js + + + + + + + + + + +
+ +

Source: crypto/public_key/index.js

+ + + + + +
+
+
/**
+ * @requires crypto/public_key/dsa
+ * @requires crypto/public_key/elgamal
+ * @requires crypto/public_key/rsa
+ * @module crypto/public_key
+ */
+module.exports = {
+  /** @see module:crypto/public_key/rsa */
+  rsa: require('./rsa.js'),
+  /** @see module:crypto/public_key/elgamal */
+  elgamal: require('./elgamal.js'),
+  /** @see module:crypto/public_key/dsa */
+  dsa: require('./dsa.js')
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/jsbn.html b/doc/jsbn.html new file mode 100644 index 00000000..b38910fa --- /dev/null +++ b/doc/jsbn.html @@ -0,0 +1,126 @@ + + + + + JSDoc: Module: crypto/public_key/jsbn + + + + + + + + + + +
+ +

Module: crypto/public_key/jsbn

+ + + + + +
+ +
+

+ crypto/public_key/jsbn +

+ +
+ + + +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/jsbn.js.html b/doc/jsbn.js.html new file mode 100644 index 00000000..01fd1900 --- /dev/null +++ b/doc/jsbn.js.html @@ -0,0 +1,1760 @@ + + + + + JSDoc: Source: crypto/public_key/jsbn.js + + + + + + + + + + +
+ +

Source: crypto/public_key/jsbn.js

+ + + + + +
+
+
/*
+ * Copyright (c) 2003-2005  Tom Wu (tjw@cs.Stanford.EDU) 
+ * All Rights Reserved.
+ *
+ * Modified by Recurity Labs GmbH 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ *
+ * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following condition applies:
+ *
+ * All redistributions must retain an intact copy of this copyright notice
+ * and disclaimer.
+ */
+
+
+/**
+ * @requires util
+ * @module crypto/public_key/jsbn
+ */
+
+var util = require('../../util');
+
+// Basic JavaScript BN library - subset useful for RSA encryption.
+
+// Bits per digit
+var dbits;
+
+// JavaScript engine analysis
+var canary = 0xdeadbeefcafe;
+var j_lm = ((canary & 0xffffff) == 0xefcafe);
+
+// (public) Constructor
+
+function BigInteger(a, b, c) {
+  if (a != null)
+    if ("number" == typeof a) this.fromNumber(a, b, c);
+    else if (b == null && "string" != typeof a) this.fromString(a, 256);
+  else this.fromString(a, b);
+}
+
+// return new, unset BigInteger
+
+function nbi() {
+  return new BigInteger(null);
+}
+
+// am: Compute w_j += (x*this_i), propagate carries,
+// c is initial carry, returns final carry.
+// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+// We need to select the fastest one that works in this environment.
+
+// am1: use a single mult and divide to get the high bits,
+// max digit bits should be 26 because
+// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+
+function am1(i, x, w, j, c, n) {
+  while (--n >= 0) {
+    var v = x * this[i++] + w[j] + c;
+    c = Math.floor(v / 0x4000000);
+    w[j++] = v & 0x3ffffff;
+  }
+  return c;
+}
+// am2 avoids a big mult-and-extract completely.
+// Max digit bits should be <= 30 because we do bitwise ops
+// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+
+function am2(i, x, w, j, c, n) {
+  var xl = x & 0x7fff,
+    xh = x >> 15;
+  while (--n >= 0) {
+    var l = this[i] & 0x7fff;
+    var h = this[i++] >> 15;
+    var m = xh * l + h * xl;
+    l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
+    c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
+    w[j++] = l & 0x3fffffff;
+  }
+  return c;
+}
+// Alternately, set max digit bits to 28 since some
+// browsers slow down when dealing with 32-bit numbers.
+
+function am3(i, x, w, j, c, n) {
+  var xl = x & 0x3fff,
+    xh = x >> 14;
+  while (--n >= 0) {
+    var l = this[i] & 0x3fff;
+    var h = this[i++] >> 14;
+    var m = xh * l + h * xl;
+    l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
+    c = (l >> 28) + (m >> 14) + xh * h;
+    w[j++] = l & 0xfffffff;
+  }
+  return c;
+}
+/*if(j_lm && (navigator != undefined && 
+	navigator.appName == "Microsoft Internet Explorer")) {
+  BigInteger.prototype.am = am2;
+  dbits = 30;
+}
+else if(j_lm && (navigator != undefined && navigator.appName != "Netscape")) {*/
+BigInteger.prototype.am = am1;
+dbits = 26;
+/*}
+else { // Mozilla/Netscape seems to prefer am3
+  BigInteger.prototype.am = am3;
+  dbits = 28;
+}*/
+
+BigInteger.prototype.DB = dbits;
+BigInteger.prototype.DM = ((1 << dbits) - 1);
+BigInteger.prototype.DV = (1 << dbits);
+
+var BI_FP = 52;
+BigInteger.prototype.FV = Math.pow(2, BI_FP);
+BigInteger.prototype.F1 = BI_FP - dbits;
+BigInteger.prototype.F2 = 2 * dbits - BI_FP;
+
+// Digit conversions
+var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+var BI_RC = new Array();
+var rr, vv;
+rr = "0".charCodeAt(0);
+for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
+rr = "a".charCodeAt(0);
+for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+rr = "A".charCodeAt(0);
+for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+
+function int2char(n) {
+  return BI_RM.charAt(n);
+}
+
+function intAt(s, i) {
+  var c = BI_RC[s.charCodeAt(i)];
+  return (c == null) ? -1 : c;
+}
+
+// (protected) copy this to r
+
+function bnpCopyTo(r) {
+  for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
+  r.t = this.t;
+  r.s = this.s;
+}
+
+// (protected) set from integer value x, -DV <= x < DV
+
+function bnpFromInt(x) {
+  this.t = 1;
+  this.s = (x < 0) ? -1 : 0;
+  if (x > 0) this[0] = x;
+  else if (x < -1) this[0] = x + DV;
+  else this.t = 0;
+}
+
+// return bigint initialized to value
+
+function nbv(i) {
+  var r = nbi();
+  r.fromInt(i);
+  return r;
+}
+
+// (protected) set from string and radix
+
+function bnpFromString(s, b) {
+  var k;
+  if (b == 16) k = 4;
+  else if (b == 8) k = 3;
+  else if (b == 256) k = 8; // byte array
+  else if (b == 2) k = 1;
+  else if (b == 32) k = 5;
+  else if (b == 4) k = 2;
+  else {
+    this.fromRadix(s, b);
+    return;
+  }
+  this.t = 0;
+  this.s = 0;
+  var i = s.length,
+    mi = false,
+    sh = 0;
+  while (--i >= 0) {
+    var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
+    if (x < 0) {
+      if (s.charAt(i) == "-") mi = true;
+      continue;
+    }
+    mi = false;
+    if (sh == 0)
+      this[this.t++] = x;
+    else if (sh + k > this.DB) {
+      this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
+      this[this.t++] = (x >> (this.DB - sh));
+    } else
+      this[this.t - 1] |= x << sh;
+    sh += k;
+    if (sh >= this.DB) sh -= this.DB;
+  }
+  if (k == 8 && (s[0] & 0x80) != 0) {
+    this.s = -1;
+    if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
+  }
+  this.clamp();
+  if (mi) BigInteger.ZERO.subTo(this, this);
+}
+
+// (protected) clamp off excess high words
+
+function bnpClamp() {
+  var c = this.s & this.DM;
+  while (this.t > 0 && this[this.t - 1] == c)--this.t;
+}
+
+// (public) return string representation in given radix
+
+function bnToString(b) {
+  if (this.s < 0) return "-" + this.negate().toString(b);
+  var k;
+  if (b == 16) k = 4;
+  else if (b == 8) k = 3;
+  else if (b == 2) k = 1;
+  else if (b == 32) k = 5;
+  else if (b == 4) k = 2;
+  else return this.toRadix(b);
+  var km = (1 << k) - 1,
+    d, m = false,
+    r = "",
+    i = this.t;
+  var p = this.DB - (i * this.DB) % k;
+  if (i-- > 0) {
+    if (p < this.DB && (d = this[i] >> p) > 0) {
+      m = true;
+      r = int2char(d);
+    }
+    while (i >= 0) {
+      if (p < k) {
+        d = (this[i] & ((1 << p) - 1)) << (k - p);
+        d |= this[--i] >> (p += this.DB - k);
+      } else {
+        d = (this[i] >> (p -= k)) & km;
+        if (p <= 0) {
+          p += this.DB;
+          --i;
+        }
+      }
+      if (d > 0) m = true;
+      if (m) r += int2char(d);
+    }
+  }
+  return m ? r : "0";
+}
+
+// (public) -this
+
+function bnNegate() {
+  var r = nbi();
+  BigInteger.ZERO.subTo(this, r);
+  return r;
+}
+
+// (public) |this|
+
+function bnAbs() {
+  return (this.s < 0) ? this.negate() : this;
+}
+
+// (public) return + if this > a, - if this < a, 0 if equal
+
+function bnCompareTo(a) {
+  var r = this.s - a.s;
+  if (r != 0) return r;
+  var i = this.t;
+  r = i - a.t;
+  if (r != 0) return r;
+  while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
+  return 0;
+}
+
+// returns bit length of the integer x
+
+function nbits(x) {
+  var r = 1,
+    t;
+  if ((t = x >>> 16) != 0) {
+    x = t;
+    r += 16;
+  }
+  if ((t = x >> 8) != 0) {
+    x = t;
+    r += 8;
+  }
+  if ((t = x >> 4) != 0) {
+    x = t;
+    r += 4;
+  }
+  if ((t = x >> 2) != 0) {
+    x = t;
+    r += 2;
+  }
+  if ((t = x >> 1) != 0) {
+    x = t;
+    r += 1;
+  }
+  return r;
+}
+
+// (public) return the number of bits in "this"
+
+function bnBitLength() {
+  if (this.t <= 0) return 0;
+  return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
+}
+
+// (protected) r = this << n*DB
+
+function bnpDLShiftTo(n, r) {
+  var i;
+  for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
+  for (i = n - 1; i >= 0; --i) r[i] = 0;
+  r.t = this.t + n;
+  r.s = this.s;
+}
+
+// (protected) r = this >> n*DB
+
+function bnpDRShiftTo(n, r) {
+  for (var i = n; i < this.t; ++i) r[i - n] = this[i];
+  r.t = Math.max(this.t - n, 0);
+  r.s = this.s;
+}
+
+// (protected) r = this << n
+
+function bnpLShiftTo(n, r) {
+  var bs = n % this.DB;
+  var cbs = this.DB - bs;
+  var bm = (1 << cbs) - 1;
+  var ds = Math.floor(n / this.DB),
+    c = (this.s << bs) & this.DM,
+    i;
+  for (i = this.t - 1; i >= 0; --i) {
+    r[i + ds + 1] = (this[i] >> cbs) | c;
+    c = (this[i] & bm) << bs;
+  }
+  for (i = ds - 1; i >= 0; --i) r[i] = 0;
+  r[ds] = c;
+  r.t = this.t + ds + 1;
+  r.s = this.s;
+  r.clamp();
+}
+
+// (protected) r = this >> n
+
+function bnpRShiftTo(n, r) {
+  r.s = this.s;
+  var ds = Math.floor(n / this.DB);
+  if (ds >= this.t) {
+    r.t = 0;
+    return;
+  }
+  var bs = n % this.DB;
+  var cbs = this.DB - bs;
+  var bm = (1 << bs) - 1;
+  r[0] = this[ds] >> bs;
+  for (var i = ds + 1; i < this.t; ++i) {
+    r[i - ds - 1] |= (this[i] & bm) << cbs;
+    r[i - ds] = this[i] >> bs;
+  }
+  if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs;
+  r.t = this.t - ds;
+  r.clamp();
+}
+
+// (protected) r = this - a
+
+function bnpSubTo(a, r) {
+  var i = 0,
+    c = 0,
+    m = Math.min(a.t, this.t);
+  while (i < m) {
+    c += this[i] - a[i];
+    r[i++] = c & this.DM;
+    c >>= this.DB;
+  }
+  if (a.t < this.t) {
+    c -= a.s;
+    while (i < this.t) {
+      c += this[i];
+      r[i++] = c & this.DM;
+      c >>= this.DB;
+    }
+    c += this.s;
+  } else {
+    c += this.s;
+    while (i < a.t) {
+      c -= a[i];
+      r[i++] = c & this.DM;
+      c >>= this.DB;
+    }
+    c -= a.s;
+  }
+  r.s = (c < 0) ? -1 : 0;
+  if (c < -1) r[i++] = this.DV + c;
+  else if (c > 0) r[i++] = c;
+  r.t = i;
+  r.clamp();
+}
+
+// (protected) r = this * a, r != this,a (HAC 14.12)
+// "this" should be the larger one if appropriate.
+
+function bnpMultiplyTo(a, r) {
+  var x = this.abs(),
+    y = a.abs();
+  var i = x.t;
+  r.t = i + y.t;
+  while (--i >= 0) r[i] = 0;
+  for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
+  r.s = 0;
+  r.clamp();
+  if (this.s != a.s) BigInteger.ZERO.subTo(r, r);
+}
+
+// (protected) r = this^2, r != this (HAC 14.16)
+
+function bnpSquareTo(r) {
+  var x = this.abs();
+  var i = r.t = 2 * x.t;
+  while (--i >= 0) r[i] = 0;
+  for (i = 0; i < x.t - 1; ++i) {
+    var c = x.am(i, x[i], r, 2 * i, 0, 1);
+    if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
+      r[i + x.t] -= x.DV;
+      r[i + x.t + 1] = 1;
+    }
+  }
+  if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
+  r.s = 0;
+  r.clamp();
+}
+
+// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+// r != q, this != m.  q or r may be null.
+
+function bnpDivRemTo(m, q, r) {
+  var pm = m.abs();
+  if (pm.t <= 0) return;
+  var pt = this.abs();
+  if (pt.t < pm.t) {
+    if (q != null) q.fromInt(0);
+    if (r != null) this.copyTo(r);
+    return;
+  }
+  if (r == null) r = nbi();
+  var y = nbi(),
+    ts = this.s,
+    ms = m.s;
+  var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
+  if (nsh > 0) {
+    pm.lShiftTo(nsh, y);
+    pt.lShiftTo(nsh, r);
+  } else {
+    pm.copyTo(y);
+    pt.copyTo(r);
+  }
+  var ys = y.t;
+  var y0 = y[ys - 1];
+  if (y0 == 0) return;
+  var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
+  var d1 = this.FV / yt,
+    d2 = (1 << this.F1) / yt,
+    e = 1 << this.F2;
+  var i = r.t,
+    j = i - ys,
+    t = (q == null) ? nbi() : q;
+  y.dlShiftTo(j, t);
+  if (r.compareTo(t) >= 0) {
+    r[r.t++] = 1;
+    r.subTo(t, r);
+  }
+  BigInteger.ONE.dlShiftTo(ys, t);
+  t.subTo(y, y); // "negative" y so we can replace sub with am later
+  while (y.t < ys) y[y.t++] = 0;
+  while (--j >= 0) {
+    // Estimate quotient digit
+    var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
+    if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out
+      y.dlShiftTo(j, t);
+      r.subTo(t, r);
+      while (r[i] < --qd) r.subTo(t, r);
+    }
+  }
+  if (q != null) {
+    r.drShiftTo(ys, q);
+    if (ts != ms) BigInteger.ZERO.subTo(q, q);
+  }
+  r.t = ys;
+  r.clamp();
+  if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder
+  if (ts < 0) BigInteger.ZERO.subTo(r, r);
+}
+
+// (public) this mod a
+
+function bnMod(a) {
+  var r = nbi();
+  this.abs().divRemTo(a, null, r);
+  if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);
+  return r;
+}
+
+// Modular reduction using "classic" algorithm
+
+function Classic(m) {
+  this.m = m;
+}
+
+function cConvert(x) {
+  if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
+  else return x;
+}
+
+function cRevert(x) {
+  return x;
+}
+
+function cReduce(x) {
+  x.divRemTo(this.m, null, x);
+}
+
+function cMulTo(x, y, r) {
+  x.multiplyTo(y, r);
+  this.reduce(r);
+}
+
+function cSqrTo(x, r) {
+  x.squareTo(r);
+  this.reduce(r);
+}
+
+Classic.prototype.convert = cConvert;
+Classic.prototype.revert = cRevert;
+Classic.prototype.reduce = cReduce;
+Classic.prototype.mulTo = cMulTo;
+Classic.prototype.sqrTo = cSqrTo;
+
+// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+// justification:
+//         xy == 1 (mod m)
+//         xy =  1+km
+//   xy(2-xy) = (1+km)(1-km)
+// x[y(2-xy)] = 1-k^2m^2
+// x[y(2-xy)] == 1 (mod m^2)
+// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+// JS multiply "overflows" differently from C/C++, so care is needed here.
+
+function bnpInvDigit() {
+  if (this.t < 1) return 0;
+  var x = this[0];
+  if ((x & 1) == 0) return 0;
+  var y = x & 3; // y == 1/x mod 2^2
+  y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
+  y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
+  y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
+  // last step - calculate inverse mod DV directly;
+  // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+  y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
+  // we really want the negative inverse, and -DV < y < DV
+  return (y > 0) ? this.DV - y : -y;
+}
+
+// Montgomery reduction
+
+function Montgomery(m) {
+  this.m = m;
+  this.mp = m.invDigit();
+  this.mpl = this.mp & 0x7fff;
+  this.mph = this.mp >> 15;
+  this.um = (1 << (m.DB - 15)) - 1;
+  this.mt2 = 2 * m.t;
+}
+
+// xR mod m
+
+function montConvert(x) {
+  var r = nbi();
+  x.abs().dlShiftTo(this.m.t, r);
+  r.divRemTo(this.m, null, r);
+  if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);
+  return r;
+}
+
+// x/R mod m
+
+function montRevert(x) {
+  var r = nbi();
+  x.copyTo(r);
+  this.reduce(r);
+  return r;
+}
+
+// x = x/R mod m (HAC 14.32)
+
+function montReduce(x) {
+  while (x.t <= this.mt2) // pad x so am has enough room later
+    x[x.t++] = 0;
+  for (var i = 0; i < this.m.t; ++i) {
+    // faster way of calculating u0 = x[i]*mp mod DV
+    var j = x[i] & 0x7fff;
+    var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
+    // use am to combine the multiply-shift-add into one call
+    j = i + this.m.t;
+    x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
+    // propagate carry
+    while (x[j] >= x.DV) {
+      x[j] -= x.DV;
+      x[++j]++;
+    }
+  }
+  x.clamp();
+  x.drShiftTo(this.m.t, x);
+  if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
+}
+
+// r = "x^2/R mod m"; x != r
+
+function montSqrTo(x, r) {
+  x.squareTo(r);
+  this.reduce(r);
+}
+
+// r = "xy/R mod m"; x,y != r
+
+function montMulTo(x, y, r) {
+  x.multiplyTo(y, r);
+  this.reduce(r);
+}
+
+Montgomery.prototype.convert = montConvert;
+Montgomery.prototype.revert = montRevert;
+Montgomery.prototype.reduce = montReduce;
+Montgomery.prototype.mulTo = montMulTo;
+Montgomery.prototype.sqrTo = montSqrTo;
+
+// (protected) true iff this is even
+
+function bnpIsEven() {
+  return ((this.t > 0) ? (this[0] & 1) : this.s) == 0;
+}
+
+// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+
+function bnpExp(e, z) {
+  if (e > 0xffffffff || e < 1) return BigInteger.ONE;
+  var r = nbi(),
+    r2 = nbi(),
+    g = z.convert(this),
+    i = nbits(e) - 1;
+  g.copyTo(r);
+  while (--i >= 0) {
+    z.sqrTo(r, r2);
+    if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
+    else {
+      var t = r;
+      r = r2;
+      r2 = t;
+    }
+  }
+  return z.revert(r);
+}
+
+// (public) this^e % m, 0 <= e < 2^32
+
+function bnModPowInt(e, m) {
+  var z;
+  if (e < 256 || m.isEven()) z = new Classic(m);
+  else z = new Montgomery(m);
+  return this.exp(e, z);
+}
+
+// protected
+BigInteger.prototype.copyTo = bnpCopyTo;
+BigInteger.prototype.fromInt = bnpFromInt;
+BigInteger.prototype.fromString = bnpFromString;
+BigInteger.prototype.clamp = bnpClamp;
+BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
+BigInteger.prototype.drShiftTo = bnpDRShiftTo;
+BigInteger.prototype.lShiftTo = bnpLShiftTo;
+BigInteger.prototype.rShiftTo = bnpRShiftTo;
+BigInteger.prototype.subTo = bnpSubTo;
+BigInteger.prototype.multiplyTo = bnpMultiplyTo;
+BigInteger.prototype.squareTo = bnpSquareTo;
+BigInteger.prototype.divRemTo = bnpDivRemTo;
+BigInteger.prototype.invDigit = bnpInvDigit;
+BigInteger.prototype.isEven = bnpIsEven;
+BigInteger.prototype.exp = bnpExp;
+
+// public
+BigInteger.prototype.toString = bnToString;
+BigInteger.prototype.negate = bnNegate;
+BigInteger.prototype.abs = bnAbs;
+BigInteger.prototype.compareTo = bnCompareTo;
+BigInteger.prototype.bitLength = bnBitLength;
+BigInteger.prototype.mod = bnMod;
+BigInteger.prototype.modPowInt = bnModPowInt;
+
+// "constants"
+BigInteger.ZERO = nbv(0);
+BigInteger.ONE = nbv(1);
+
+module.exports = BigInteger;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * Copyright (c) 2003-2005  Tom Wu (tjw@cs.Stanford.EDU) 
+ * All Rights Reserved.
+ *
+ * Modified by Recurity Labs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ *
+ * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following condition applies:
+ *
+ * All redistributions must retain an intact copy of this copyright notice
+ * and disclaimer.
+ */
+
+
+// Extended JavaScript BN functions, required for RSA private ops.
+
+// Version 1.1: new BigInteger("0", 10) returns "proper" zero
+// Version 1.2: square() API, isProbablePrime fix
+
+// (public)
+function bnClone() {
+  var r = nbi();
+  this.copyTo(r);
+  return r;
+}
+
+// (public) return value as integer
+
+function bnIntValue() {
+  if (this.s < 0) {
+    if (this.t == 1) return this[0] - this.DV;
+    else if (this.t == 0) return -1;
+  } else if (this.t == 1) return this[0];
+  else if (this.t == 0) return 0;
+  // assumes 16 < DB < 32
+  return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
+}
+
+// (public) return value as byte
+
+function bnByteValue() {
+  return (this.t == 0) ? this.s : (this[0] << 24) >> 24;
+}
+
+// (public) return value as short (assumes DB>=16)
+
+function bnShortValue() {
+  return (this.t == 0) ? this.s : (this[0] << 16) >> 16;
+}
+
+// (protected) return x s.t. r^x < DV
+
+function bnpChunkSize(r) {
+  return Math.floor(Math.LN2 * this.DB / Math.log(r));
+}
+
+// (public) 0 if this == 0, 1 if this > 0
+
+function bnSigNum() {
+  if (this.s < 0) return -1;
+  else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
+  else return 1;
+}
+
+// (protected) convert to radix string
+
+function bnpToRadix(b) {
+  if (b == null) b = 10;
+  if (this.signum() == 0 || b < 2 || b > 36) return "0";
+  var cs = this.chunkSize(b);
+  var a = Math.pow(b, cs);
+  var d = nbv(a),
+    y = nbi(),
+    z = nbi(),
+    r = "";
+  this.divRemTo(d, y, z);
+  while (y.signum() > 0) {
+    r = (a + z.intValue()).toString(b).substr(1) + r;
+    y.divRemTo(d, y, z);
+  }
+  return z.intValue().toString(b) + r;
+}
+
+// (protected) convert from radix string
+
+function bnpFromRadix(s, b) {
+  this.fromInt(0);
+  if (b == null) b = 10;
+  var cs = this.chunkSize(b);
+  var d = Math.pow(b, cs),
+    mi = false,
+    j = 0,
+    w = 0;
+  for (var i = 0; i < s.length; ++i) {
+    var x = intAt(s, i);
+    if (x < 0) {
+      if (s.charAt(i) == "-" && this.signum() == 0) mi = true;
+      continue;
+    }
+    w = b * w + x;
+    if (++j >= cs) {
+      this.dMultiply(d);
+      this.dAddOffset(w, 0);
+      j = 0;
+      w = 0;
+    }
+  }
+  if (j > 0) {
+    this.dMultiply(Math.pow(b, j));
+    this.dAddOffset(w, 0);
+  }
+  if (mi) BigInteger.ZERO.subTo(this, this);
+}
+
+// (protected) alternate constructor
+
+function bnpFromNumber(a, b, c) {
+  if ("number" == typeof b) {
+    // new BigInteger(int,int,RNG)
+    if (a < 2) this.fromInt(1);
+    else {
+      this.fromNumber(a, c);
+      if (!this.testBit(a - 1)) // force MSB set
+        this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
+      if (this.isEven()) this.dAddOffset(1, 0); // force odd
+      while (!this.isProbablePrime(b)) {
+        this.dAddOffset(2, 0);
+        if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);
+      }
+    }
+  } else {
+    // new BigInteger(int,RNG)
+    var x = new Array(),
+      t = a & 7;
+    x.length = (a >> 3) + 1;
+    b.nextBytes(x);
+    if (t > 0) x[0] &= ((1 << t) - 1);
+    else x[0] = 0;
+    this.fromString(x, 256);
+  }
+}
+
+// (public) convert to bigendian byte array
+
+function bnToByteArray() {
+  var i = this.t,
+    r = new Array();
+  r[0] = this.s;
+  var p = this.DB - (i * this.DB) % 8,
+    d, k = 0;
+  if (i-- > 0) {
+    if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p)
+      r[k++] = d | (this.s << (this.DB - p));
+    while (i >= 0) {
+      if (p < 8) {
+        d = (this[i] & ((1 << p) - 1)) << (8 - p);
+        d |= this[--i] >> (p += this.DB - 8);
+      } else {
+        d = (this[i] >> (p -= 8)) & 0xff;
+        if (p <= 0) {
+          p += this.DB;
+          --i;
+        }
+      }
+      //if((d&0x80) != 0) d |= -256;
+      //if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
+      if (k > 0 || d != this.s) r[k++] = d;
+    }
+  }
+  return r;
+}
+
+function bnEquals(a) {
+  return (this.compareTo(a) == 0);
+}
+
+function bnMin(a) {
+  return (this.compareTo(a) < 0) ? this : a;
+}
+
+function bnMax(a) {
+  return (this.compareTo(a) > 0) ? this : a;
+}
+
+// (protected) r = this op a (bitwise)
+
+function bnpBitwiseTo(a, op, r) {
+  var i, f, m = Math.min(a.t, this.t);
+  for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]);
+  if (a.t < this.t) {
+    f = a.s & this.DM;
+    for (i = m; i < this.t; ++i) r[i] = op(this[i], f);
+    r.t = this.t;
+  } else {
+    f = this.s & this.DM;
+    for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
+    r.t = a.t;
+  }
+  r.s = op(this.s, a.s);
+  r.clamp();
+}
+
+// (public) this & a
+
+function op_and(x, y) {
+  return x & y;
+}
+
+function bnAnd(a) {
+  var r = nbi();
+  this.bitwiseTo(a, op_and, r);
+  return r;
+}
+
+// (public) this | a
+
+function op_or(x, y) {
+  return x | y;
+}
+
+function bnOr(a) {
+  var r = nbi();
+  this.bitwiseTo(a, op_or, r);
+  return r;
+}
+
+// (public) this ^ a
+
+function op_xor(x, y) {
+  return x ^ y;
+}
+
+function bnXor(a) {
+  var r = nbi();
+  this.bitwiseTo(a, op_xor, r);
+  return r;
+}
+
+// (public) this & ~a
+
+function op_andnot(x, y) {
+  return x & ~y;
+}
+
+function bnAndNot(a) {
+  var r = nbi();
+  this.bitwiseTo(a, op_andnot, r);
+  return r;
+}
+
+// (public) ~this
+
+function bnNot() {
+  var r = nbi();
+  for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
+  r.t = this.t;
+  r.s = ~this.s;
+  return r;
+}
+
+// (public) this << n
+
+function bnShiftLeft(n) {
+  var r = nbi();
+  if (n < 0) this.rShiftTo(-n, r);
+  else this.lShiftTo(n, r);
+  return r;
+}
+
+// (public) this >> n
+
+function bnShiftRight(n) {
+  var r = nbi();
+  if (n < 0) this.lShiftTo(-n, r);
+  else this.rShiftTo(n, r);
+  return r;
+}
+
+// return index of lowest 1-bit in x, x < 2^31
+
+function lbit(x) {
+  if (x == 0) return -1;
+  var r = 0;
+  if ((x & 0xffff) == 0) {
+    x >>= 16;
+    r += 16;
+  }
+  if ((x & 0xff) == 0) {
+    x >>= 8;
+    r += 8;
+  }
+  if ((x & 0xf) == 0) {
+    x >>= 4;
+    r += 4;
+  }
+  if ((x & 3) == 0) {
+    x >>= 2;
+    r += 2;
+  }
+  if ((x & 1) == 0)++r;
+  return r;
+}
+
+// (public) returns index of lowest 1-bit (or -1 if none)
+
+function bnGetLowestSetBit() {
+  for (var i = 0; i < this.t; ++i)
+    if (this[i] != 0) return i * this.DB + lbit(this[i]);
+  if (this.s < 0) return this.t * this.DB;
+  return -1;
+}
+
+// return number of 1 bits in x
+
+function cbit(x) {
+  var r = 0;
+  while (x != 0) {
+    x &= x - 1;
+    ++r;
+  }
+  return r;
+}
+
+// (public) return number of set bits
+
+function bnBitCount() {
+  var r = 0,
+    x = this.s & this.DM;
+  for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
+  return r;
+}
+
+// (public) true iff nth bit is set
+
+function bnTestBit(n) {
+  var j = Math.floor(n / this.DB);
+  if (j >= this.t) return (this.s != 0);
+  return ((this[j] & (1 << (n % this.DB))) != 0);
+}
+
+// (protected) this op (1<<n)
+
+function bnpChangeBit(n, op) {
+  var r = BigInteger.ONE.shiftLeft(n);
+  this.bitwiseTo(r, op, r);
+  return r;
+}
+
+// (public) this | (1<<n)
+
+function bnSetBit(n) {
+  return this.changeBit(n, op_or);
+}
+
+// (public) this & ~(1<<n)
+
+function bnClearBit(n) {
+  return this.changeBit(n, op_andnot);
+}
+
+// (public) this ^ (1<<n)
+
+function bnFlipBit(n) {
+  return this.changeBit(n, op_xor);
+}
+
+// (protected) r = this + a
+
+function bnpAddTo(a, r) {
+  var i = 0,
+    c = 0,
+    m = Math.min(a.t, this.t);
+  while (i < m) {
+    c += this[i] + a[i];
+    r[i++] = c & this.DM;
+    c >>= this.DB;
+  }
+  if (a.t < this.t) {
+    c += a.s;
+    while (i < this.t) {
+      c += this[i];
+      r[i++] = c & this.DM;
+      c >>= this.DB;
+    }
+    c += this.s;
+  } else {
+    c += this.s;
+    while (i < a.t) {
+      c += a[i];
+      r[i++] = c & this.DM;
+      c >>= this.DB;
+    }
+    c += a.s;
+  }
+  r.s = (c < 0) ? -1 : 0;
+  if (c > 0) r[i++] = c;
+  else if (c < -1) r[i++] = this.DV + c;
+  r.t = i;
+  r.clamp();
+}
+
+// (public) this + a
+
+function bnAdd(a) {
+  var r = nbi();
+  this.addTo(a, r);
+  return r;
+}
+
+// (public) this - a
+
+function bnSubtract(a) {
+  var r = nbi();
+  this.subTo(a, r);
+  return r;
+}
+
+// (public) this * a
+
+function bnMultiply(a) {
+  var r = nbi();
+  this.multiplyTo(a, r);
+  return r;
+}
+
+// (public) this^2
+
+function bnSquare() {
+  var r = nbi();
+  this.squareTo(r);
+  return r;
+}
+
+// (public) this / a
+
+function bnDivide(a) {
+  var r = nbi();
+  this.divRemTo(a, r, null);
+  return r;
+}
+
+// (public) this % a
+
+function bnRemainder(a) {
+  var r = nbi();
+  this.divRemTo(a, null, r);
+  return r;
+}
+
+// (public) [this/a,this%a]
+
+function bnDivideAndRemainder(a) {
+  var q = nbi(),
+    r = nbi();
+  this.divRemTo(a, q, r);
+  return new Array(q, r);
+}
+
+// (protected) this *= n, this >= 0, 1 < n < DV
+
+function bnpDMultiply(n) {
+  this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
+  ++this.t;
+  this.clamp();
+}
+
+// (protected) this += n << w words, this >= 0
+
+function bnpDAddOffset(n, w) {
+  if (n == 0) return;
+  while (this.t <= w) this[this.t++] = 0;
+  this[w] += n;
+  while (this[w] >= this.DV) {
+    this[w] -= this.DV;
+    if (++w >= this.t) this[this.t++] = 0;
+    ++this[w];
+  }
+}
+
+// A "null" reducer
+
+function NullExp() {}
+
+function nNop(x) {
+  return x;
+}
+
+function nMulTo(x, y, r) {
+  x.multiplyTo(y, r);
+}
+
+function nSqrTo(x, r) {
+  x.squareTo(r);
+}
+
+NullExp.prototype.convert = nNop;
+NullExp.prototype.revert = nNop;
+NullExp.prototype.mulTo = nMulTo;
+NullExp.prototype.sqrTo = nSqrTo;
+
+// (public) this^e
+
+function bnPow(e) {
+  return this.exp(e, new NullExp());
+}
+
+// (protected) r = lower n words of "this * a", a.t <= n
+// "this" should be the larger one if appropriate.
+
+function bnpMultiplyLowerTo(a, n, r) {
+  var i = Math.min(this.t + a.t, n);
+  r.s = 0; // assumes a,this >= 0
+  r.t = i;
+  while (i > 0) r[--i] = 0;
+  var j;
+  for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
+  for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
+  r.clamp();
+}
+
+// (protected) r = "this * a" without lower n words, n > 0
+// "this" should be the larger one if appropriate.
+
+function bnpMultiplyUpperTo(a, n, r) {
+  --n;
+  var i = r.t = this.t + a.t - n;
+  r.s = 0; // assumes a,this >= 0
+  while (--i >= 0) r[i] = 0;
+  for (i = Math.max(n - this.t, 0); i < a.t; ++i)
+    r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
+  r.clamp();
+  r.drShiftTo(1, r);
+}
+
+// Barrett modular reduction
+
+function Barrett(m) {
+  // setup Barrett
+  this.r2 = nbi();
+  this.q3 = nbi();
+  BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
+  this.mu = this.r2.divide(m);
+  this.m = m;
+}
+
+function barrettConvert(x) {
+  if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
+  else if (x.compareTo(this.m) < 0) return x;
+  else {
+    var r = nbi();
+    x.copyTo(r);
+    this.reduce(r);
+    return r;
+  }
+}
+
+function barrettRevert(x) {
+  return x;
+}
+
+// x = x mod m (HAC 14.42)
+
+function barrettReduce(x) {
+  x.drShiftTo(this.m.t - 1, this.r2);
+  if (x.t > this.m.t + 1) {
+    x.t = this.m.t + 1;
+    x.clamp();
+  }
+  this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
+  this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
+  while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);
+  x.subTo(this.r2, x);
+  while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
+}
+
+// r = x^2 mod m; x != r
+
+function barrettSqrTo(x, r) {
+  x.squareTo(r);
+  this.reduce(r);
+}
+
+// r = x*y mod m; x,y != r
+
+function barrettMulTo(x, y, r) {
+  x.multiplyTo(y, r);
+  this.reduce(r);
+}
+
+Barrett.prototype.convert = barrettConvert;
+Barrett.prototype.revert = barrettRevert;
+Barrett.prototype.reduce = barrettReduce;
+Barrett.prototype.mulTo = barrettMulTo;
+Barrett.prototype.sqrTo = barrettSqrTo;
+
+// (public) this^e % m (HAC 14.85)
+
+function bnModPow(e, m) {
+  var i = e.bitLength(),
+    k, r = nbv(1),
+    z;
+  if (i <= 0) return r;
+  else if (i < 18) k = 1;
+  else if (i < 48) k = 3;
+  else if (i < 144) k = 4;
+  else if (i < 768) k = 5;
+  else k = 6;
+  if (i < 8)
+    z = new Classic(m);
+  else if (m.isEven())
+    z = new Barrett(m);
+  else
+    z = new Montgomery(m);
+
+  // precomputation
+  var g = new Array(),
+    n = 3,
+    k1 = k - 1,
+    km = (1 << k) - 1;
+  g[1] = z.convert(this);
+  if (k > 1) {
+    var g2 = nbi();
+    z.sqrTo(g[1], g2);
+    while (n <= km) {
+      g[n] = nbi();
+      z.mulTo(g2, g[n - 2], g[n]);
+      n += 2;
+    }
+  }
+
+  var j = e.t - 1,
+    w, is1 = true,
+    r2 = nbi(),
+    t;
+  i = nbits(e[j]) - 1;
+  while (j >= 0) {
+    if (i >= k1) w = (e[j] >> (i - k1)) & km;
+    else {
+      w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
+      if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
+    }
+
+    n = k;
+    while ((w & 1) == 0) {
+      w >>= 1;
+      --n;
+    }
+    if ((i -= n) < 0) {
+      i += this.DB;
+      --j;
+    }
+    if (is1) { // ret == 1, don't bother squaring or multiplying it
+      g[w].copyTo(r);
+      is1 = false;
+    } else {
+      while (n > 1) {
+        z.sqrTo(r, r2);
+        z.sqrTo(r2, r);
+        n -= 2;
+      }
+      if (n > 0) z.sqrTo(r, r2);
+      else {
+        t = r;
+        r = r2;
+        r2 = t;
+      }
+      z.mulTo(r2, g[w], r);
+    }
+
+    while (j >= 0 && (e[j] & (1 << i)) == 0) {
+      z.sqrTo(r, r2);
+      t = r;
+      r = r2;
+      r2 = t;
+      if (--i < 0) {
+        i = this.DB - 1;
+        --j;
+      }
+    }
+  }
+  return z.revert(r);
+}
+
+// (public) gcd(this,a) (HAC 14.54)
+
+function bnGCD(a) {
+  var x = (this.s < 0) ? this.negate() : this.clone();
+  var y = (a.s < 0) ? a.negate() : a.clone();
+  if (x.compareTo(y) < 0) {
+    var t = x;
+    x = y;
+    y = t;
+  }
+  var i = x.getLowestSetBit(),
+    g = y.getLowestSetBit();
+  if (g < 0) return x;
+  if (i < g) g = i;
+  if (g > 0) {
+    x.rShiftTo(g, x);
+    y.rShiftTo(g, y);
+  }
+  while (x.signum() > 0) {
+    if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
+    if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
+    if (x.compareTo(y) >= 0) {
+      x.subTo(y, x);
+      x.rShiftTo(1, x);
+    } else {
+      y.subTo(x, y);
+      y.rShiftTo(1, y);
+    }
+  }
+  if (g > 0) y.lShiftTo(g, y);
+  return y;
+}
+
+// (protected) this % n, n < 2^26
+
+function bnpModInt(n) {
+  if (n <= 0) return 0;
+  var d = this.DV % n,
+    r = (this.s < 0) ? n - 1 : 0;
+  if (this.t > 0)
+    if (d == 0) r = this[0] % n;
+    else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
+  return r;
+}
+
+// (public) 1/this % m (HAC 14.61)
+
+function bnModInverse(m) {
+  var ac = m.isEven();
+  if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
+  var u = m.clone(),
+    v = this.clone();
+  var a = nbv(1),
+    b = nbv(0),
+    c = nbv(0),
+    d = nbv(1);
+  while (u.signum() != 0) {
+    while (u.isEven()) {
+      u.rShiftTo(1, u);
+      if (ac) {
+        if (!a.isEven() || !b.isEven()) {
+          a.addTo(this, a);
+          b.subTo(m, b);
+        }
+        a.rShiftTo(1, a);
+      } else if (!b.isEven()) b.subTo(m, b);
+      b.rShiftTo(1, b);
+    }
+    while (v.isEven()) {
+      v.rShiftTo(1, v);
+      if (ac) {
+        if (!c.isEven() || !d.isEven()) {
+          c.addTo(this, c);
+          d.subTo(m, d);
+        }
+        c.rShiftTo(1, c);
+      } else if (!d.isEven()) d.subTo(m, d);
+      d.rShiftTo(1, d);
+    }
+    if (u.compareTo(v) >= 0) {
+      u.subTo(v, u);
+      if (ac) a.subTo(c, a);
+      b.subTo(d, b);
+    } else {
+      v.subTo(u, v);
+      if (ac) c.subTo(a, c);
+      d.subTo(b, d);
+    }
+  }
+  if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
+  if (d.compareTo(m) >= 0) return d.subtract(m);
+  if (d.signum() < 0) d.addTo(m, d);
+  else return d;
+  if (d.signum() < 0) return d.add(m);
+  else return d;
+}
+
+var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
+    103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
+    229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
+    367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
+    503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647,
+    653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
+    821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971,
+    977, 983, 991, 997
+];
+var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
+
+// (public) test primality with certainty >= 1-.5^t
+
+function bnIsProbablePrime(t) {
+  var i, x = this.abs();
+  if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
+    for (i = 0; i < lowprimes.length; ++i)
+      if (x[0] == lowprimes[i]) return true;
+    return false;
+  }
+  if (x.isEven()) return false;
+  i = 1;
+  while (i < lowprimes.length) {
+    var m = lowprimes[i],
+      j = i + 1;
+    while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];
+    m = x.modInt(m);
+    while (i < j) if (m % lowprimes[i++] == 0) return false;
+  }
+  return x.millerRabin(t);
+}
+
+/* added by Recurity Labs */
+
+function nbits(x) {
+  var n = 1,
+    t;
+  if ((t = x >>> 16) != 0) {
+    x = t;
+    n += 16;
+  }
+  if ((t = x >> 8) != 0) {
+    x = t;
+    n += 8;
+  }
+  if ((t = x >> 4) != 0) {
+    x = t;
+    n += 4;
+  }
+  if ((t = x >> 2) != 0) {
+    x = t;
+    n += 2;
+  }
+  if ((t = x >> 1) != 0) {
+    x = t;
+    n += 1;
+  }
+  return n;
+}
+
+function bnToMPI() {
+  var ba = this.toByteArray();
+  var size = (ba.length - 1) * 8 + nbits(ba[0]);
+  var result = "";
+  result += String.fromCharCode((size & 0xFF00) >> 8);
+  result += String.fromCharCode(size & 0xFF);
+  result += util.bin2str(ba);
+  return result;
+}
+/* END of addition */
+
+// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
+function bnpMillerRabin(t) {
+  var n1 = this.subtract(BigInteger.ONE);
+  var k = n1.getLowestSetBit();
+  if (k <= 0) return false;
+  var r = n1.shiftRight(k);
+  t = (t + 1) >> 1;
+  if (t > lowprimes.length) t = lowprimes.length;
+  var a = nbi();
+  var j, bases = [];
+  for (var i = 0; i < t; ++i) {
+    //Pick bases at random, instead of starting at 2
+    for (;;) {
+      j = lowprimes[Math.floor(Math.random() * lowprimes.length)];
+      if (bases.indexOf(j) == -1) break;
+    }
+    bases.push(j);
+    a.fromInt(j);
+    var y = a.modPow(r, this);
+    if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
+      var j = 1;
+      while (j++ < k && y.compareTo(n1) != 0) {
+        y = y.modPowInt(2, this);
+        if (y.compareTo(BigInteger.ONE) == 0) return false;
+      }
+      if (y.compareTo(n1) != 0) return false;
+    }
+  }
+  return true;
+}
+
+var BigInteger = require('./jsbn.js');
+
+// protected
+BigInteger.prototype.chunkSize = bnpChunkSize;
+BigInteger.prototype.toRadix = bnpToRadix;
+BigInteger.prototype.fromRadix = bnpFromRadix;
+BigInteger.prototype.fromNumber = bnpFromNumber;
+BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
+BigInteger.prototype.changeBit = bnpChangeBit;
+BigInteger.prototype.addTo = bnpAddTo;
+BigInteger.prototype.dMultiply = bnpDMultiply;
+BigInteger.prototype.dAddOffset = bnpDAddOffset;
+BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
+BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
+BigInteger.prototype.modInt = bnpModInt;
+BigInteger.prototype.millerRabin = bnpMillerRabin;
+
+// public
+BigInteger.prototype.clone = bnClone;
+BigInteger.prototype.intValue = bnIntValue;
+BigInteger.prototype.byteValue = bnByteValue;
+BigInteger.prototype.shortValue = bnShortValue;
+BigInteger.prototype.signum = bnSigNum;
+BigInteger.prototype.toByteArray = bnToByteArray;
+BigInteger.prototype.equals = bnEquals;
+BigInteger.prototype.min = bnMin;
+BigInteger.prototype.max = bnMax;
+BigInteger.prototype.and = bnAnd;
+BigInteger.prototype.or = bnOr;
+BigInteger.prototype.xor = bnXor;
+BigInteger.prototype.andNot = bnAndNot;
+BigInteger.prototype.not = bnNot;
+BigInteger.prototype.shiftLeft = bnShiftLeft;
+BigInteger.prototype.shiftRight = bnShiftRight;
+BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
+BigInteger.prototype.bitCount = bnBitCount;
+BigInteger.prototype.testBit = bnTestBit;
+BigInteger.prototype.setBit = bnSetBit;
+BigInteger.prototype.clearBit = bnClearBit;
+BigInteger.prototype.flipBit = bnFlipBit;
+BigInteger.prototype.add = bnAdd;
+BigInteger.prototype.subtract = bnSubtract;
+BigInteger.prototype.multiply = bnMultiply;
+BigInteger.prototype.divide = bnDivide;
+BigInteger.prototype.remainder = bnRemainder;
+BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
+BigInteger.prototype.modPow = bnModPow;
+BigInteger.prototype.modInverse = bnModInverse;
+BigInteger.prototype.pow = bnPow;
+BigInteger.prototype.gcd = bnGCD;
+BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
+BigInteger.prototype.toMPI = bnToMPI;
+
+// JSBN-specific extension
+BigInteger.prototype.square = bnSquare;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/jsxcompressor.js.html b/doc/jsxcompressor.js.html deleted file mode 100644 index 9cd6bcb7..00000000 --- a/doc/jsxcompressor.js.html +++ /dev/null @@ -1,1275 +0,0 @@ - - - - - JSDoc: Source: compression/zlib/jsxcompressor.js - - - - - - - - - - -
- -

Source: compression/zlib/jsxcompressor.js

- - - - - -
-
-
JXG = {exists: (function(undefined){return function(v){return !(v===undefined || v===null);}})()};
-JXG.decompress = function(str) {return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip()[0][0]);};
-/*
-    Copyright 2008-2012
-        Matthias Ehmann,
-        Michael Gerhaeuser,
-        Carsten Miller,
-        Bianca Valentin,
-        Alfred Wassermann,
-        Peter Wilfahrt
-
-    This file is part of JSXGraph.
-    
-    Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses.
-
-    You should have received a copy of the GNU Lesser General Public License
-    along with JSXCompressor.  If not, see <http://www.gnu.org/licenses/>.
-    
-    You should have received a copy of the Apache License along with JSXCompressor.  
-    If not, see <http://www.apache.org/licenses/>.
-
-*/
-
-/**
-  * @class Util class
-  * @classdesc Utilities for uncompressing and base64 decoding
-  * Class for gunzipping, unzipping and base64 decoding of files.
-  * It is used for reading GEONExT, Geogebra and Intergeo files.
-  *
-  * Only Huffman codes are decoded in gunzip.
-  * The code is based on the source code for gunzip.c by Pasi Ojala 
-  * {@link http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c}
-  * {@link http://www.cs.tut.fi/~albert}
-  */
-JXG.Util = {};
-                                 
-/**
- * Unzip zip files
- */
-JXG.Util.Unzip = function (barray){
-    var outputArr = [],
-        output = "",
-        debug = false,
-        gpflags,
-        files = 0,
-        unzipped = [],
-        crc,
-        buf32k = new Array(32768),
-        bIdx = 0,
-        modeZIP=false,
-
-        CRC, SIZE,
-    
-        bitReverse = [
-        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
-        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
-        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
-        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
-        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
-        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
-        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
-        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
-        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
-        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
-        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
-        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
-        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
-        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
-        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
-        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
-        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
-        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
-        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
-        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
-        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
-        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
-        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
-        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
-        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
-        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
-        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
-        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
-        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
-        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
-        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
-        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
-    ],
-    
-    cplens = [
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
-    ],
-
-    cplext = [
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
-    ], /* 99==invalid */
-
-    cpdist = [
-        0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d,
-        0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1,
-        0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01,
-        0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
-    ],
-
-    cpdext = [
-        0,  0,  0,  0,  1,  1,  2,  2,
-        3,  3,  4,  4,  5,  5,  6,  6,
-        7,  7,  8,  8,  9,  9, 10, 10,
-        11, 11, 12, 12, 13, 13
-    ],
-    
-    border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
-    
-    bA = barray,
-
-    bytepos=0,
-    bitpos=0,
-    bb = 1,
-    bits=0,
-    
-    NAMEMAX = 256,
-    
-    nameBuf = [],
-    
-    fileout;
-    
-    function readByte(){
-        bits+=8;
-        if (bytepos<bA.length){
-            //if (debug)
-            //    document.write(bytepos+": "+bA[bytepos]+"<br>");
-            return bA[bytepos++];
-        } else
-            return -1;
-    };
-
-    function byteAlign(){
-        bb = 1;
-    };
-    
-    function readBit(){
-        var carry;
-        bits++;
-        carry = (bb & 1);
-        bb >>= 1;
-        if (bb==0){
-            bb = readByte();
-            carry = (bb & 1);
-            bb = (bb>>1) | 0x80;
-        }
-        return carry;
-    };
-
-    function readBits(a) {
-        var res = 0,
-            i = a;
-    
-        while(i--) {
-            res = (res<<1) | readBit();
-        }
-        if(a) {
-            res = bitReverse[res]>>(8-a);
-        }
-        return res;
-    };
-        
-    function flushBuffer(){
-        //document.write('FLUSHBUFFER:'+buf32k);
-        bIdx = 0;
-    };
-    function addBuffer(a){
-        SIZE++;
-        //CRC=updcrc(a,crc);
-        buf32k[bIdx++] = a;
-        outputArr.push(String.fromCharCode(a));
-        //output+=String.fromCharCode(a);
-        if(bIdx==0x8000){
-            //document.write('ADDBUFFER:'+buf32k);
-            bIdx=0;
-        }
-    };
-    
-    function HufNode() {
-        this.b0=0;
-        this.b1=0;
-        this.jump = null;
-        this.jumppos = -1;
-    };
-
-    var LITERALS = 288;
-    
-    var literalTree = new Array(LITERALS);
-    var distanceTree = new Array(32);
-    var treepos=0;
-    var Places = null;
-    var Places2 = null;
-    
-    var impDistanceTree = new Array(64);
-    var impLengthTree = new Array(64);
-    
-    var len = 0;
-    var fpos = new Array(17);
-    fpos[0]=0;
-    var flens;
-    var fmax;
-    
-    function IsPat() {
-        while (1) {
-            if (fpos[len] >= fmax)
-                return -1;
-            if (flens[fpos[len]] == len)
-                return fpos[len]++;
-            fpos[len]++;
-        }
-    };
-
-    function Rec() {
-        var curplace = Places[treepos];
-        var tmp;
-        if (debug)
-    		document.write("<br>len:"+len+" treepos:"+treepos);
-        if(len==17) { //war 17
-            return -1;
-        }
-        treepos++;
-        len++;
-    	
-        tmp = IsPat();
-        if (debug)
-        	document.write("<br>IsPat "+tmp);
-        if(tmp >= 0) {
-            curplace.b0 = tmp;    /* leaf cell for 0-bit */
-            if (debug)
-            	document.write("<br>b0 "+curplace.b0);
-        } else {
-        /* Not a Leaf cell */
-        curplace.b0 = 0x8000;
-        if (debug)
-        	document.write("<br>b0 "+curplace.b0);
-        if(Rec())
-            return -1;
-        }
-        tmp = IsPat();
-        if(tmp >= 0) {
-            curplace.b1 = tmp;    /* leaf cell for 1-bit */
-            if (debug)
-            	document.write("<br>b1 "+curplace.b1);
-            curplace.jump = null;    /* Just for the display routine */
-        } else {
-            /* Not a Leaf cell */
-            curplace.b1 = 0x8000;
-            if (debug)
-            	document.write("<br>b1 "+curplace.b1);
-            curplace.jump = Places[treepos];
-            curplace.jumppos = treepos;
-            if(Rec())
-                return -1;
-        }
-        len--;
-        return 0;
-    };
-
-    function CreateTree(currentTree, numval, lengths, show) {
-        var i;
-        /* Create the Huffman decode tree/table */
-        //document.write("<br>createtree<br>");
-        if (debug)
-        	document.write("currentTree "+currentTree+" numval "+numval+" lengths "+lengths+" show "+show);
-        Places = currentTree;
-        treepos=0;
-        flens = lengths;
-        fmax  = numval;
-        for (i=0;i<17;i++)
-            fpos[i] = 0;
-        len = 0;
-        if(Rec()) {
-            //fprintf(stderr, "invalid huffman tree\n");
-            if (debug)
-            	alert("invalid huffman tree\n");
-            return -1;
-        }
-        if (debug){
-        	document.write('<br>Tree: '+Places.length);
-        	for (var a=0;a<32;a++){
-            	document.write("Places["+a+"].b0="+Places[a].b0+"<br>");
-            	document.write("Places["+a+"].b1="+Places[a].b1+"<br>");
-        	}
-        }
-    
-        /*if(show) {
-            var tmp;
-            for(tmp=currentTree;tmp<Places;tmp++) {
-                fprintf(stdout, "0x%03x  0x%03x (0x%04x)",tmp-currentTree, tmp->jump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0);
-                if(!(tmp.b0 & 0x8000)) {
-                    //fprintf(stdout, "  0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�');
-                }
-                if(!(tmp.b1 & 0x8000)) {
-                    if((tmp.b0 & 0x8000))
-                        fprintf(stdout, "           ");
-                    fprintf(stdout, "  0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�');
-                }
-                fprintf(stdout, "\n");
-            }
-        }*/
-        return 0;
-    };
-    
-    function DecodeValue(currentTree) {
-        var len, i,
-            xtreepos=0,
-            X = currentTree[xtreepos],
-            b;
-
-        /* decode one symbol of the data */
-        while(1) {
-            b=readBit();
-            if (debug)
-            	document.write("b="+b);
-            if(b) {
-                if(!(X.b1 & 0x8000)){
-                	if (debug)
-                    	document.write("ret1");
-                    return X.b1;    /* If leaf node, return data */
-                }
-                X = X.jump;
-                len = currentTree.length;
-                for (i=0;i<len;i++){
-                    if (currentTree[i]===X){
-                        xtreepos=i;
-                        break;
-                    }
-                }
-                //xtreepos++;
-            } else {
-                if(!(X.b0 & 0x8000)){
-                	if (debug)
-                    	document.write("ret2");
-                    return X.b0;    /* If leaf node, return data */
-                }
-                //X++; //??????????????????
-                xtreepos++;
-                X = currentTree[xtreepos];
-            }
-        }
-        if (debug)
-        	document.write("ret3");
-        return -1;
-    };
-    
-    function DeflateLoop() {
-    var last, c, type, i, len;
-
-    do {
-        /*if((last = readBit())){
-            fprintf(errfp, "Last Block: ");
-        } else {
-            fprintf(errfp, "Not Last Block: ");
-        }*/
-        last = readBit();
-        type = readBits(2);
-        switch(type) {
-            case 0:
-            	if (debug)
-                	alert("Stored\n");
-                break;
-            case 1:
-            	if (debug)
-                	alert("Fixed Huffman codes\n");
-                break;
-            case 2:
-            	if (debug)
-                	alert("Dynamic Huffman codes\n");
-                break;
-            case 3:
-            	if (debug)
-                	alert("Reserved block type!!\n");
-                break;
-            default:
-            	if (debug)
-                	alert("Unexpected value %d!\n", type);
-                break;
-        }
-
-        if(type==0) {
-            var blockLen, cSum;
-
-            // Stored 
-            byteAlign();
-            blockLen = readByte();
-            blockLen |= (readByte()<<8);
-
-            cSum = readByte();
-            cSum |= (readByte()<<8);
-
-            if(((blockLen ^ ~cSum) & 0xffff)) {
-                document.write("BlockLen checksum mismatch\n");
-            }
-            while(blockLen--) {
-                c = readByte();
-                addBuffer(c);
-            }
-        } else if(type==1) {
-            var j;
-
-            /* Fixed Huffman tables -- fixed decode routine */
-            while(1) {
-            /*
-                256    0000000        0
-                :   :     :
-                279    0010111        23
-                0   00110000    48
-                :    :      :
-                143    10111111    191
-                280 11000000    192
-                :    :      :
-                287 11000111    199
-                144    110010000    400
-                :    :       :
-                255    111111111    511
-    
-                Note the bit order!
-                */
-
-            j = (bitReverse[readBits(7)]>>1);
-            if(j > 23) {
-                j = (j<<1) | readBit();    /* 48..255 */
-
-                if(j > 199) {    /* 200..255 */
-                    j -= 128;    /*  72..127 */
-                    j = (j<<1) | readBit();        /* 144..255 << */
-                } else {        /*  48..199 */
-                    j -= 48;    /*   0..151 */
-                    if(j > 143) {
-                        j = j+136;    /* 280..287 << */
-                        /*   0..143 << */
-                    }
-                }
-            } else {    /*   0..23 */
-                j += 256;    /* 256..279 << */
-            }
-            if(j < 256) {
-                addBuffer(j);
-                //document.write("out:"+String.fromCharCode(j));
-                /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/
-            } else if(j == 256) {
-                /* EOF */
-                break;
-            } else {
-                var len, dist;
-
-                j -= 256 + 1;    /* bytes + EOF */
-                len = readBits(cplext[j]) + cplens[j];
-
-                j = bitReverse[readBits(5)]>>3;
-                if(cpdext[j] > 8) {
-                    dist = readBits(8);
-                    dist |= (readBits(cpdext[j]-8)<<8);
-                } else {
-                    dist = readBits(cpdext[j]);
-                }
-                dist += cpdist[j];
-
-                /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/
-                for(j=0;j<len;j++) {
-                    var c = buf32k[(bIdx - dist) & 0x7fff];
-                    addBuffer(c);
-                }
-            }
-            } // while
-        } else if(type==2) {
-            var j, n, literalCodes, distCodes, lenCodes;
-            var ll = new Array(288+32);    // "static" just to preserve stack
-    
-            // Dynamic Huffman tables 
-    
-            literalCodes = 257 + readBits(5);
-            distCodes = 1 + readBits(5);
-            lenCodes = 4 + readBits(4);
-            //document.write("<br>param: "+literalCodes+" "+distCodes+" "+lenCodes+"<br>");
-            for(j=0; j<19; j++) {
-                ll[j] = 0;
-            }
-    
-            // Get the decode tree code lengths
-    
-            //document.write("<br>");
-            for(j=0; j<lenCodes; j++) {
-                ll[border[j]] = readBits(3);
-                //document.write(ll[border[j]]+" ");
-            }
-            //fprintf(errfp, "\n");
-            //document.write('<br>ll:'+ll);
-            len = distanceTree.length;
-            for (i=0; i<len; i++)
-                distanceTree[i]=new HufNode();
-            if(CreateTree(distanceTree, 19, ll, 0)) {
-                flushBuffer();
-                return 1;
-            }
-            if (debug){
-            	document.write("<br>distanceTree");
-            	for(var a=0;a<distanceTree.length;a++){
-                	document.write("<br>"+distanceTree[a].b0+" "+distanceTree[a].b1+" "+distanceTree[a].jump+" "+distanceTree[a].jumppos);
-                	/*if (distanceTree[a].jumppos!=-1)
-                    	document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1);
-                	*/
-            	}
-            }
-            //document.write('<BR>tree created');
-    
-            //read in literal and distance code lengths
-            n = literalCodes + distCodes;
-            i = 0;
-            var z=-1;
-            if (debug)
-            	document.write("<br>n="+n+" bits: "+bits+"<br>");
-            while(i < n) {
-                z++;
-                j = DecodeValue(distanceTree);
-                if (debug)
-                	document.write("<br>"+z+" i:"+i+" decode: "+j+"    bits "+bits+"<br>");
-                if(j<16) {    // length of code in bits (0..15)
-                       ll[i++] = j;
-                } else if(j==16) {    // repeat last length 3 to 6 times 
-                       var l;
-                    j = 3 + readBits(2);
-                    if(i+j > n) {
-                        flushBuffer();
-                        return 1;
-                    }
-                    l = i ? ll[i-1] : 0;
-                    while(j--) {
-                        ll[i++] = l;
-                    }
-                } else {
-                    if(j==17) {        // 3 to 10 zero length codes
-                        j = 3 + readBits(3);
-                    } else {        // j == 18: 11 to 138 zero length codes 
-                        j = 11 + readBits(7);
-                    }
-                    if(i+j > n) {
-                        flushBuffer();
-                        return 1;
-                    }
-                    while(j--) {
-                        ll[i++] = 0;
-                    }
-                }
-            }
-            /*for(j=0; j<literalCodes+distCodes; j++) {
-                //fprintf(errfp, "%d ", ll[j]);
-                if ((j&7)==7)
-                    fprintf(errfp, "\n");
-            }
-            fprintf(errfp, "\n");*/
-            // Can overwrite tree decode tree as it is not used anymore
-            len = literalTree.length;
-            for (i=0; i<len; i++)
-                literalTree[i]=new HufNode();
-            if(CreateTree(literalTree, literalCodes, ll, 0)) {
-                flushBuffer();
-                return 1;
-            }
-            len = literalTree.length;
-            for (i=0; i<len; i++)
-                distanceTree[i]=new HufNode();
-            var ll2 = new Array();
-            for (i=literalCodes; i <ll.length; i++){
-                ll2[i-literalCodes]=ll[i];
-            }    
-            if(CreateTree(distanceTree, distCodes, ll2, 0)) {
-                flushBuffer();
-                return 1;
-            }
-            if (debug)
-           		document.write("<br>literalTree");
-            outer:
-            while(1) {
-                j = DecodeValue(literalTree);
-                if(j >= 256) {        // In C64: if carry set
-                    var len, dist;
-                    j -= 256;
-                    if(j == 0) {
-                        // EOF
-                        break;
-                    }
-                    j--;
-                    len = readBits(cplext[j]) + cplens[j];
-    
-                    j = DecodeValue(distanceTree);
-                    if(cpdext[j] > 8) {
-                        dist = readBits(8);
-                        dist |= (readBits(cpdext[j]-8)<<8);
-                    } else {
-                        dist = readBits(cpdext[j]);
-                    }
-                    dist += cpdist[j];
-                    while(len--) {
-                        if(bIdx - dist < 0) {
-                            break outer;
-                        }
-                        var c = buf32k[(bIdx - dist) & 0x7fff];
-                        addBuffer(c);
-                    }
-                } else {
-                    addBuffer(j);
-                }
-            }
-        }
-    } while(!last);
-    flushBuffer();
-
-    byteAlign();
-    return 0;
-};
-
-JXG.Util.Unzip.prototype.unzipFile = function(name) {
-    var i;
-	this.unzip();
-	//alert(unzipped[0][1]);
-	for (i=0;i<unzipped.length;i++){
-		if(unzipped[i][1]==name) {
-			return unzipped[i][0];
-		}
-	}
-	
-  };
-
-JXG.Util.Unzip.prototype.deflate = function() {
-    outputArr = [];
-    var tmp = [];
-    modeZIP = false;
-    DeflateLoop();
-    if (debug)
-        alert(outputArr.join(''));
-    unzipped[files] = new Array(2);
-    unzipped[files][0] = outputArr.join('');
-    unzipped[files][1] = "DEFLATE";
-    files++;
-    return unzipped;
-}    
-    
-JXG.Util.Unzip.prototype.unzip = function() {
-	//convertToByteArray(input);
-	if (debug)
-		alert(bA);
-	/*for (i=0;i<bA.length*8;i++){
-		document.write(readBit());
-		if ((i+1)%8==0)
-			document.write(" ");
-	}*/
-	/*for (i=0;i<bA.length;i++){
-		document.write(readByte()+" ");
-		if ((i+1)%8==0)
-			document.write(" ");
-	}
-	for (i=0;i<bA.length;i++){
-		document.write(bA[i]+" ");
-		if ((i+1)%16==0)
-			document.write("<br>");
-	}	
-	*/
-	//alert(bA);
-	nextFile();
-	return unzipped;
-  };
-    
- function nextFile(){
- 	if (debug)
- 		alert("NEXTFILE");
- 	outputArr = [];
- 	var tmp = [];
- 	modeZIP = false;
-	tmp[0] = readByte();
-	tmp[1] = readByte();
-	if (debug)
-		alert("type: "+tmp[0]+" "+tmp[1]);
-	if (tmp[0] == parseInt("78",16) && tmp[1] == parseInt("da",16)){ //GZIP
-		if (debug)
-			alert("GEONExT-GZIP");
-		DeflateLoop();
-		if (debug)
-			alert(outputArr.join(''));
-		unzipped[files] = new Array(2);
-    	unzipped[files][0] = outputArr.join('');
-    	unzipped[files][1] = "geonext.gxt";
-    	files++;
-	}
-	if (tmp[0] == parseInt("78",16) && tmp[1] == parseInt("9c",16)){ //ZLIB
-		if (debug)
-			alert("ZLIB");
-		DeflateLoop();
-		if (debug)
-			alert(outputArr.join(''));
-		unzipped[files] = new Array(2);
-    	unzipped[files][0] = outputArr.join('');
-    	unzipped[files][1] = "ZLIB";
-    	files++;
-	}
-	if (tmp[0] == parseInt("1f",16) && tmp[1] == parseInt("8b",16)){ //GZIP
-		if (debug)
-			alert("GZIP");
-		//DeflateLoop();
-		skipdir();
-		if (debug)
-			alert(outputArr.join(''));
-		unzipped[files] = new Array(2);
-    	unzipped[files][0] = outputArr.join('');
-    	unzipped[files][1] = "file";
-    	files++;
-	}
-	if (tmp[0] == parseInt("50",16) && tmp[1] == parseInt("4b",16)){ //ZIP
-		modeZIP = true;
-		tmp[2] = readByte();
-		tmp[3] = readByte();
-		if (tmp[2] == parseInt("3",16) && tmp[3] == parseInt("4",16)){
-			//MODE_ZIP
-			tmp[0] = readByte();
-			tmp[1] = readByte();
-			if (debug)
-				alert("ZIP-Version: "+tmp[1]+" "+tmp[0]/10+"."+tmp[0]%10);
-			
-			gpflags = readByte();
-			gpflags |= (readByte()<<8);
-			if (debug)
-				alert("gpflags: "+gpflags);
-			
-			var method = readByte();
-			method |= (readByte()<<8);
-			if (debug)
-				alert("method: "+method);
-			
-			readByte();
-			readByte();
-			readByte();
-			readByte();
-			
-			var crc = readByte();
-			crc |= (readByte()<<8);
-			crc |= (readByte()<<16);
-			crc |= (readByte()<<24);
-			
-			var compSize = readByte();
-			compSize |= (readByte()<<8);
-			compSize |= (readByte()<<16);
-			compSize |= (readByte()<<24);
-			
-			var size = readByte();
-			size |= (readByte()<<8);
-			size |= (readByte()<<16);
-			size |= (readByte()<<24);
-			
-			if (debug)
-				alert("local CRC: "+crc+"\nlocal Size: "+size+"\nlocal CompSize: "+compSize);
-			
-			var filelen = readByte();
-			filelen |= (readByte()<<8);
-			
-			var extralen = readByte();
-			extralen |= (readByte()<<8);
-			
-			if (debug)
-				alert("filelen "+filelen);
-			i = 0;
-			nameBuf = [];
-			while (filelen--){ 
-				var c = readByte();
-				if (c == "/" | c ==":"){
-					i = 0;
-				} else if (i < NAMEMAX-1)
-					nameBuf[i++] = String.fromCharCode(c);
-			}
-			if (debug)
-				alert("nameBuf: "+nameBuf);
-			
-			//nameBuf[i] = "\0";
-			if (!fileout)
-				fileout = nameBuf;
-			
-			var i = 0;
-			while (i < extralen){
-				c = readByte();
-				i++;
-			}
-				
-			CRC = 0xffffffff;
-			SIZE = 0;
-			
-			if (size = 0 && fileOut.charAt(fileout.length-1)=="/"){
-				//skipdir
-				if (debug)
-					alert("skipdir");
-			}
-			if (method == 8){
-				DeflateLoop();
-				if (debug)
-					alert(outputArr.join(''));
-				unzipped[files] = new Array(2);
-				unzipped[files][0] = outputArr.join('');
-    			unzipped[files][1] = nameBuf.join('');
-    			files++;
-				//return outputArr.join('');
-			}
-			skipdir();
-		}
-	}
- };
-	
-function skipdir(){
-    var crc, 
-        tmp = [],
-        compSize, size, os, i, c;
-    
-	if ((gpflags & 8)) {
-		tmp[0] = readByte();
-		tmp[1] = readByte();
-		tmp[2] = readByte();
-		tmp[3] = readByte();
-		
-		if (tmp[0] == parseInt("50",16) && 
-            tmp[1] == parseInt("4b",16) && 
-            tmp[2] == parseInt("07",16) && 
-            tmp[3] == parseInt("08",16))
-        {
-            crc = readByte();
-            crc |= (readByte()<<8);
-            crc |= (readByte()<<16);
-            crc |= (readByte()<<24);
-		} else {
-			crc = tmp[0] | (tmp[1]<<8) | (tmp[2]<<16) | (tmp[3]<<24);
-		}
-		
-		compSize = readByte();
-		compSize |= (readByte()<<8);
-		compSize |= (readByte()<<16);
-		compSize |= (readByte()<<24);
-		
-		size = readByte();
-		size |= (readByte()<<8);
-		size |= (readByte()<<16);
-		size |= (readByte()<<24);
-		
-		if (debug)
-			alert("CRC:");
-	}
-
-	if (modeZIP)
-		nextFile();
-	
-	tmp[0] = readByte();
-	if (tmp[0] != 8) {
-		if (debug)
-			alert("Unknown compression method!");
-        return 0;	
-	}
-	
-	gpflags = readByte();
-	if (debug){
-		if ((gpflags & ~(parseInt("1f",16))))
-			alert("Unknown flags set!");
-	}
-	
-	readByte();
-	readByte();
-	readByte();
-	readByte();
-	
-	readByte();
-	os = readByte();
-	
-	if ((gpflags & 4)){
-		tmp[0] = readByte();
-		tmp[2] = readByte();
-		len = tmp[0] + 256*tmp[1];
-		if (debug)
-			alert("Extra field size: "+len);
-		for (i=0;i<len;i++)
-			readByte();
-	}
-	
-	if ((gpflags & 8)){
-		i=0;
-		nameBuf=[];
-		while (c=readByte()){
-			if(c == "7" || c == ":")
-				i=0;
-			if (i<NAMEMAX-1)
-				nameBuf[i++] = c;
-		}
-		//nameBuf[i] = "\0";
-		if (debug)
-			alert("original file name: "+nameBuf);
-	}
-		
-	if ((gpflags & 16)){
-		while (c=readByte()){
-			//FILE COMMENT
-		}
-	}
-	
-	if ((gpflags & 2)){
-		readByte();
-		readByte();
-	}
-	
-	DeflateLoop();
-	
-	crc = readByte();
-	crc |= (readByte()<<8);
-	crc |= (readByte()<<16);
-	crc |= (readByte()<<24);
-	
-	size = readByte();
-	size |= (readByte()<<8);
-	size |= (readByte()<<16);
-	size |= (readByte()<<24);
-	
-	if (modeZIP)
-		nextFile();
-	
-};
-
-};
-
-/**
-*  Base64 encoding / decoding
-*  {@link http://www.webtoolkit.info/}
-*/
-JXG.Util.Base64 = {
-
-    // private property
-    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
-
-    // public method for encoding
-    encode : function (input) {
-        var output = [],
-            chr1, chr2, chr3, enc1, enc2, enc3, enc4,
-            i = 0;
-
-        input = JXG.Util.Base64._utf8_encode(input);
-
-        while (i < input.length) {
-
-            chr1 = input.charCodeAt(i++);
-            chr2 = input.charCodeAt(i++);
-            chr3 = input.charCodeAt(i++);
-
-            enc1 = chr1 >> 2;
-            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
-            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
-            enc4 = chr3 & 63;
-
-            if (isNaN(chr2)) {
-                enc3 = enc4 = 64;
-            } else if (isNaN(chr3)) {
-                enc4 = 64;
-            }
-
-            output.push([this._keyStr.charAt(enc1),
-                         this._keyStr.charAt(enc2),
-                         this._keyStr.charAt(enc3),
-                         this._keyStr.charAt(enc4)].join(''));
-        }
-
-        return output.join('');
-    },
-
-    // public method for decoding
-    decode : function (input, utf8) {
-        var output = [],
-            chr1, chr2, chr3,
-            enc1, enc2, enc3, enc4,
-            i = 0;
-
-        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
-
-        while (i < input.length) {
-
-            enc1 = this._keyStr.indexOf(input.charAt(i++));
-            enc2 = this._keyStr.indexOf(input.charAt(i++));
-            enc3 = this._keyStr.indexOf(input.charAt(i++));
-            enc4 = this._keyStr.indexOf(input.charAt(i++));
-
-            chr1 = (enc1 << 2) | (enc2 >> 4);
-            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
-            chr3 = ((enc3 & 3) << 6) | enc4;
-
-            output.push(String.fromCharCode(chr1));
-
-            if (enc3 != 64) {
-                output.push(String.fromCharCode(chr2));
-            }
-            if (enc4 != 64) {
-                output.push(String.fromCharCode(chr3));
-            }
-        }
-        
-        output = output.join(''); 
-        
-        if (utf8) {
-            output = JXG.Util.Base64._utf8_decode(output);
-        }
-        return output;
-
-    },
-
-    // private method for UTF-8 encoding
-    _utf8_encode : function (string) {
-        string = string.replace(/\r\n/g,"\n");
-        var utftext = "";
-
-        for (var n = 0; n < string.length; n++) {
-
-            var c = string.charCodeAt(n);
-
-            if (c < 128) {
-                utftext += String.fromCharCode(c);
-            }
-            else if((c > 127) && (c < 2048)) {
-                utftext += String.fromCharCode((c >> 6) | 192);
-                utftext += String.fromCharCode((c & 63) | 128);
-            }
-            else {
-                utftext += String.fromCharCode((c >> 12) | 224);
-                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
-                utftext += String.fromCharCode((c & 63) | 128);
-            }
-
-        }
-
-        return utftext;
-    },
-
-    // private method for UTF-8 decoding
-    _utf8_decode : function (utftext) {
-        var string = [],
-            i = 0,
-            c = 0, c2 = 0, c3 = 0;
-
-        while ( i < utftext.length ) {
-            c = utftext.charCodeAt(i);
-            if (c < 128) {
-                string.push(String.fromCharCode(c));
-                i++;
-            }
-            else if((c > 191) && (c < 224)) {
-                c2 = utftext.charCodeAt(i+1);
-                string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
-                i += 2;
-            }
-            else {
-                c2 = utftext.charCodeAt(i+1);
-                c3 = utftext.charCodeAt(i+2);
-                string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
-                i += 3;
-            }
-        }
-        return string.join('');
-    },
-    
-    _destrip: function (stripped, wrap){
-        var lines = [], lineno, i,
-            destripped = [];
-        
-        if (wrap==null) 
-            wrap = 76;
-            
-        stripped.replace(/ /g, "");
-        lineno = stripped.length / wrap;
-        for (i = 0; i < lineno; i++)
-            lines[i]=stripped.substr(i * wrap, wrap);
-        if (lineno != stripped.length / wrap)
-            lines[lines.length]=stripped.substr(lineno * wrap, stripped.length-(lineno * wrap));
-            
-        for (i = 0; i < lines.length; i++)
-            destripped.push(lines[i]);
-        return destripped.join('\n');
-    },
-    
-    decodeAsArray: function (input){
-        var dec = this.decode(input),
-            ar = [], i;
-        for (i=0;i<dec.length;i++){
-            ar[i]=dec.charCodeAt(i);
-        }
-        return ar;
-    },
-    
-    decodeGEONExT : function (input) {
-        return decodeAsArray(destrip(input),false);
-    }
-};
-
-/**
- * @private
- */
-JXG.Util.asciiCharCodeAt = function(str,i){
-	var c = str.charCodeAt(i);
-	if (c>255){
-    	switch (c) {
-			case 8364: c=128;
-	    	break;
-	    	case 8218: c=130;
-	    	break;
-	    	case 402: c=131;
-	    	break;
-	    	case 8222: c=132;
-	    	break;
-	    	case 8230: c=133;
-	    	break;
-	    	case 8224: c=134;
-	    	break;
-	    	case 8225: c=135;
-	    	break;
-	    	case 710: c=136;
-	    	break;
-	    	case 8240: c=137;
-	    	break;
-	    	case 352: c=138;
-	    	break;
-	    	case 8249: c=139;
-	    	break;
-	    	case 338: c=140;
-	    	break;
-	    	case 381: c=142;
-	    	break;
-	    	case 8216: c=145;
-	    	break;
-	    	case 8217: c=146;
-	    	break;
-	    	case 8220: c=147;
-	    	break;
-	    	case 8221: c=148;
-	    	break;
-	    	case 8226: c=149;
-	    	break;
-	    	case 8211: c=150;
-	    	break;
-	    	case 8212: c=151;
-	    	break;
-	    	case 732: c=152;
-	    	break;
-	    	case 8482: c=153;
-	    	break;
-	    	case 353: c=154;
-	    	break;
-	    	case 8250: c=155;
-	    	break;
-	    	case 339: c=156;
-	    	break;
-	    	case 382: c=158;
-	    	break;
-	    	case 376: c=159;
-	    	break;
-	    	default:
-	    	break;
-	    }
-	}
-	return c;
-};
-
-/**
- * Decoding string into utf-8
- * @param {String} string to decode
- * @return {String} utf8 decoded string
- */
-JXG.Util.utf8Decode = function(utftext) {
-  var string = [];
-  var i = 0;
-  var c = 0, c1 = 0, c2 = 0, c3;
-  if (!JXG.exists(utftext)) return '';
-  
-  while ( i < utftext.length ) {
-    c = utftext.charCodeAt(i);
-
-    if (c < 128) {
-      string.push(String.fromCharCode(c));
-      i++;
-    } else if((c > 191) && (c < 224)) {
-      c2 = utftext.charCodeAt(i+1);
-      string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
-      i += 2;
-    } else {
-      c2 = utftext.charCodeAt(i+1);
-      c3 = utftext.charCodeAt(i+2);
-      string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
-      i += 3;
-    }
-  };
-  return string.join('');
-};
-
-/**
- * Generate a random uuid.
- * http://www.broofa.com
- * mailto:robert@broofa.com
- *
- * Copyright (c) 2010 Robert Kieffer
- * Dual licensed under the MIT and GPL licenses.
- *
- * EXAMPLES:
- *   >>> Math.uuid()
- *   "92329D39-6F5C-4520-ABFC-AAB64544E172"
- */
-JXG.Util.genUUID = function() {
-    // Private array of chars to use
-    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
-        uuid = new Array(36), rnd=0, r;
-
-    for (var i = 0; i < 36; i++) {
-      if (i==8 || i==13 ||  i==18 || i==23) {
-        uuid[i] = '-';
-      } else if (i==14) {
-        uuid[i] = '4';
-      } else {
-        if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
-        r = rnd & 0xf;
-        rnd = rnd >> 4;
-        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
-      }
-    }
-
-    return uuid.join('');
-};
-
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/jxg.js.html b/doc/jxg.js.html new file mode 100644 index 00000000..54b8047b --- /dev/null +++ b/doc/jxg.js.html @@ -0,0 +1,1317 @@ + + + + + JSDoc: Source: compression/jxg.js + + + + + + + + + + +
+ +

Source: compression/jxg.js

+ + + + + +
+
+
JXG = {
+  exists: (function(undefined) {
+    return function(v) {
+      return !(v === undefined || v === null);
+    }
+  })()
+};
+JXG.decompress = function(str) {
+  return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip()[0][0]);
+};
+/*
+    Copyright 2008-2012
+        Matthias Ehmann,
+        Michael Gerhaeuser,
+        Carsten Miller,
+        Bianca Valentin,
+        Alfred Wassermann,
+        Peter Wilfahrt
+
+    This file is part of JSXGraph.
+    
+    Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with JSXCompressor.  If not, see <http://www.gnu.org/licenses/>.
+    
+    You should have received a copy of the Apache License along with JSXCompressor.  
+    If not, see <http://www.apache.org/licenses/>.
+
+*/
+
+/**
+ * @class Util class
+ * @classdesc Utilities for uncompressing and base64 decoding
+ * Class for gunzipping, unzipping and base64 decoding of files.
+ * It is used for reading GEONExT, Geogebra and Intergeo files.
+ *
+ * Only Huffman codes are decoded in gunzip.
+ * The code is based on the source code for gunzip.c by Pasi Ojala 
+ * {@link http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c}
+ * {@link http://www.cs.tut.fi/~albert}
+ */
+JXG.Util = {};
+
+/**
+ * Unzip zip files
+ */
+JXG.Util.Unzip = function(barray) {
+  var outputArr = [],
+    output = "",
+    debug = false,
+    gpflags,
+    files = 0,
+    unzipped = [],
+    crc,
+    buf32k = new Array(32768),
+    bIdx = 0,
+    modeZIP = false,
+
+    CRC, SIZE,
+
+    bitReverse = [
+        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+    ],
+
+    cplens = [
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+    ],
+
+    cplext = [
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
+    ],
+    /* 99==invalid */
+
+    cpdist = [
+        0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d,
+        0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1,
+        0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01,
+        0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
+    ],
+
+    cpdext = [
+        0, 0, 0, 0, 1, 1, 2, 2,
+        3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10,
+        11, 11, 12, 12, 13, 13
+    ],
+
+    border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
+
+    bA = barray,
+
+    bytepos = 0,
+    bitpos = 0,
+    bb = 1,
+    bits = 0,
+
+    NAMEMAX = 256,
+
+    nameBuf = [],
+
+    fileout;
+
+  function readByte() {
+    bits += 8;
+    if (bytepos < bA.length) {
+      //if (debug)
+      //    document.write(bytepos+": "+bA[bytepos]+"<br>");
+      return bA[bytepos++];
+    } else
+      return -1;
+  };
+
+  function byteAlign() {
+    bb = 1;
+  };
+
+  function readBit() {
+    var carry;
+    bits++;
+    carry = (bb & 1);
+    bb >>= 1;
+    if (bb == 0) {
+      bb = readByte();
+      carry = (bb & 1);
+      bb = (bb >> 1) | 0x80;
+    }
+    return carry;
+  };
+
+  function readBits(a) {
+    var res = 0,
+      i = a;
+
+    while (i--) {
+      res = (res << 1) | readBit();
+    }
+    if (a) {
+      res = bitReverse[res] >> (8 - a);
+    }
+    return res;
+  };
+
+  function flushBuffer() {
+    //document.write('FLUSHBUFFER:'+buf32k);
+    bIdx = 0;
+  };
+
+  function addBuffer(a) {
+    SIZE++;
+    //CRC=updcrc(a,crc);
+    buf32k[bIdx++] = a;
+    outputArr.push(String.fromCharCode(a));
+    //output+=String.fromCharCode(a);
+    if (bIdx == 0x8000) {
+      //document.write('ADDBUFFER:'+buf32k);
+      bIdx = 0;
+    }
+  };
+
+  function HufNode() {
+    this.b0 = 0;
+    this.b1 = 0;
+    this.jump = null;
+    this.jumppos = -1;
+  };
+
+  var LITERALS = 288;
+
+  var literalTree = new Array(LITERALS);
+  var distanceTree = new Array(32);
+  var treepos = 0;
+  var Places = null;
+  var Places2 = null;
+
+  var impDistanceTree = new Array(64);
+  var impLengthTree = new Array(64);
+
+  var len = 0;
+  var fpos = new Array(17);
+  fpos[0] = 0;
+  var flens;
+  var fmax;
+
+  function IsPat() {
+    while (1) {
+      if (fpos[len] >= fmax)
+        return -1;
+      if (flens[fpos[len]] == len)
+        return fpos[len]++;
+      fpos[len]++;
+    }
+  };
+
+  function Rec() {
+    var curplace = Places[treepos];
+    var tmp;
+    if (debug)
+      document.write("<br>len:" + len + " treepos:" + treepos);
+    if (len == 17) { //war 17
+      return -1;
+    }
+    treepos++;
+    len++;
+
+    tmp = IsPat();
+    if (debug)
+      document.write("<br>IsPat " + tmp);
+    if (tmp >= 0) {
+      curplace.b0 = tmp; /* leaf cell for 0-bit */
+      if (debug)
+        document.write("<br>b0 " + curplace.b0);
+    } else {
+      /* Not a Leaf cell */
+      curplace.b0 = 0x8000;
+      if (debug)
+        document.write("<br>b0 " + curplace.b0);
+      if (Rec())
+        return -1;
+    }
+    tmp = IsPat();
+    if (tmp >= 0) {
+      curplace.b1 = tmp; /* leaf cell for 1-bit */
+      if (debug)
+        document.write("<br>b1 " + curplace.b1);
+      curplace.jump = null; /* Just for the display routine */
+    } else {
+      /* Not a Leaf cell */
+      curplace.b1 = 0x8000;
+      if (debug)
+        document.write("<br>b1 " + curplace.b1);
+      curplace.jump = Places[treepos];
+      curplace.jumppos = treepos;
+      if (Rec())
+        return -1;
+    }
+    len--;
+    return 0;
+  };
+
+  function CreateTree(currentTree, numval, lengths, show) {
+    var i;
+    /* Create the Huffman decode tree/table */
+    //document.write("<br>createtree<br>");
+    if (debug)
+      document.write("currentTree " + currentTree + " numval " + numval + " lengths " + lengths + " show " + show);
+    Places = currentTree;
+    treepos = 0;
+    flens = lengths;
+    fmax = numval;
+    for (i = 0; i < 17; i++)
+      fpos[i] = 0;
+    len = 0;
+    if (Rec()) {
+      //fprintf(stderr, "invalid huffman tree\n");
+      if (debug)
+        alert("invalid huffman tree\n");
+      return -1;
+    }
+    if (debug) {
+      document.write('<br>Tree: ' + Places.length);
+      for (var a = 0; a < 32; a++) {
+        document.write("Places[" + a + "].b0=" + Places[a].b0 + "<br>");
+        document.write("Places[" + a + "].b1=" + Places[a].b1 + "<br>");
+      }
+    }
+
+    /*if(show) {
+            var tmp;
+            for(tmp=currentTree;tmp<Places;tmp++) {
+                fprintf(stdout, "0x%03x  0x%03x (0x%04x)",tmp-currentTree, tmp->jump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0);
+                if(!(tmp.b0 & 0x8000)) {
+                    //fprintf(stdout, "  0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�');
+                }
+                if(!(tmp.b1 & 0x8000)) {
+                    if((tmp.b0 & 0x8000))
+                        fprintf(stdout, "           ");
+                    fprintf(stdout, "  0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�');
+                }
+                fprintf(stdout, "\n");
+            }
+        }*/
+    return 0;
+  };
+
+  function DecodeValue(currentTree) {
+    var len, i,
+      xtreepos = 0,
+      X = currentTree[xtreepos],
+      b;
+
+    /* decode one symbol of the data */
+    while (1) {
+      b = readBit();
+      if (debug)
+        document.write("b=" + b);
+      if (b) {
+        if (!(X.b1 & 0x8000)) {
+          if (debug)
+            document.write("ret1");
+          return X.b1; /* If leaf node, return data */
+        }
+        X = X.jump;
+        len = currentTree.length;
+        for (i = 0; i < len; i++) {
+          if (currentTree[i] === X) {
+            xtreepos = i;
+            break;
+          }
+        }
+        //xtreepos++;
+      } else {
+        if (!(X.b0 & 0x8000)) {
+          if (debug)
+            document.write("ret2");
+          return X.b0; /* If leaf node, return data */
+        }
+        //X++; //??????????????????
+        xtreepos++;
+        X = currentTree[xtreepos];
+      }
+    }
+  };
+
+  function DeflateLoop() {
+    var last, c, type, i, len;
+
+    do {
+      /*if((last = readBit())){
+            fprintf(errfp, "Last Block: ");
+        } else {
+            fprintf(errfp, "Not Last Block: ");
+        }*/
+      last = readBit();
+      type = readBits(2);
+      switch (type) {
+        case 0:
+          if (debug)
+            alert("Stored\n");
+          break;
+        case 1:
+          if (debug)
+            alert("Fixed Huffman codes\n");
+          break;
+        case 2:
+          if (debug)
+            alert("Dynamic Huffman codes\n");
+          break;
+        case 3:
+          if (debug)
+            alert("Reserved block type!!\n");
+          break;
+        default:
+          if (debug)
+            alert("Unexpected value %d!\n", type);
+          break;
+      }
+
+      if (type == 0) {
+        var blockLen, cSum;
+
+        // Stored 
+        byteAlign();
+        blockLen = readByte();
+        blockLen |= (readByte() << 8);
+
+        cSum = readByte();
+        cSum |= (readByte() << 8);
+
+        if (((blockLen ^ ~cSum) & 0xffff)) {
+          document.write("BlockLen checksum mismatch\n");
+        }
+        while (blockLen--) {
+          c = readByte();
+          addBuffer(c);
+        }
+      } else if (type == 1) {
+        var j;
+
+        /* Fixed Huffman tables -- fixed decode routine */
+        while (1) {
+          /*
+                256    0000000        0
+                :   :     :
+                279    0010111        23
+                0   00110000    48
+                :    :      :
+                143    10111111    191
+                280 11000000    192
+                :    :      :
+                287 11000111    199
+                144    110010000    400
+                :    :       :
+                255    111111111    511
+    
+                Note the bit order!
+                */
+
+          j = (bitReverse[readBits(7)] >> 1);
+          if (j > 23) {
+            j = (j << 1) | readBit(); /* 48..255 */
+
+            if (j > 199) { /* 200..255 */
+              j -= 128; /*  72..127 */
+              j = (j << 1) | readBit(); /* 144..255 << */
+            } else { /*  48..199 */
+              j -= 48; /*   0..151 */
+              if (j > 143) {
+                j = j + 136; /* 280..287 << */
+                /*   0..143 << */
+              }
+            }
+          } else { /*   0..23 */
+            j += 256; /* 256..279 << */
+          }
+          if (j < 256) {
+            addBuffer(j);
+            //document.write("out:"+String.fromCharCode(j));
+            /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/
+          } else if (j == 256) {
+            /* EOF */
+            break;
+          } else {
+            var len, dist;
+
+            j -= 256 + 1; /* bytes + EOF */
+            len = readBits(cplext[j]) + cplens[j];
+
+            j = bitReverse[readBits(5)] >> 3;
+            if (cpdext[j] > 8) {
+              dist = readBits(8);
+              dist |= (readBits(cpdext[j] - 8) << 8);
+            } else {
+              dist = readBits(cpdext[j]);
+            }
+            dist += cpdist[j];
+
+            /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/
+            for (j = 0; j < len; j++) {
+              var c = buf32k[(bIdx - dist) & 0x7fff];
+              addBuffer(c);
+            }
+          }
+        } // while
+      } else if (type == 2) {
+        var j, n, literalCodes, distCodes, lenCodes;
+        var ll = new Array(288 + 32); // "static" just to preserve stack
+
+        // Dynamic Huffman tables 
+
+        literalCodes = 257 + readBits(5);
+        distCodes = 1 + readBits(5);
+        lenCodes = 4 + readBits(4);
+        //document.write("<br>param: "+literalCodes+" "+distCodes+" "+lenCodes+"<br>");
+        for (j = 0; j < 19; j++) {
+          ll[j] = 0;
+        }
+
+        // Get the decode tree code lengths
+
+        //document.write("<br>");
+        for (j = 0; j < lenCodes; j++) {
+          ll[border[j]] = readBits(3);
+          //document.write(ll[border[j]]+" ");
+        }
+        //fprintf(errfp, "\n");
+        //document.write('<br>ll:'+ll);
+        len = distanceTree.length;
+        for (i = 0; i < len; i++)
+          distanceTree[i] = new HufNode();
+        if (CreateTree(distanceTree, 19, ll, 0)) {
+          flushBuffer();
+          return 1;
+        }
+        if (debug) {
+          document.write("<br>distanceTree");
+          for (var a = 0; a < distanceTree.length; a++) {
+            document.write("<br>" + distanceTree[a].b0 + " " + distanceTree[a].b1 + " " + distanceTree[a].jump + " " +
+              distanceTree[a].jumppos);
+            /*if (distanceTree[a].jumppos!=-1)
+                    	document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1);
+                	*/
+          }
+        }
+        //document.write('<BR>tree created');
+
+        //read in literal and distance code lengths
+        n = literalCodes + distCodes;
+        i = 0;
+        var z = -1;
+        if (debug)
+          document.write("<br>n=" + n + " bits: " + bits + "<br>");
+        while (i < n) {
+          z++;
+          j = DecodeValue(distanceTree);
+          if (debug)
+            document.write("<br>" + z + " i:" + i + " decode: " + j + "    bits " + bits + "<br>");
+          if (j < 16) { // length of code in bits (0..15)
+            ll[i++] = j;
+          } else if (j == 16) { // repeat last length 3 to 6 times 
+            var l;
+            j = 3 + readBits(2);
+            if (i + j > n) {
+              flushBuffer();
+              return 1;
+            }
+            l = i ? ll[i - 1] : 0;
+            while (j--) {
+              ll[i++] = l;
+            }
+          } else {
+            if (j == 17) { // 3 to 10 zero length codes
+              j = 3 + readBits(3);
+            } else { // j == 18: 11 to 138 zero length codes 
+              j = 11 + readBits(7);
+            }
+            if (i + j > n) {
+              flushBuffer();
+              return 1;
+            }
+            while (j--) {
+              ll[i++] = 0;
+            }
+          }
+        }
+        /*for(j=0; j<literalCodes+distCodes; j++) {
+                //fprintf(errfp, "%d ", ll[j]);
+                if ((j&7)==7)
+                    fprintf(errfp, "\n");
+            }
+            fprintf(errfp, "\n");*/
+        // Can overwrite tree decode tree as it is not used anymore
+        len = literalTree.length;
+        for (i = 0; i < len; i++)
+          literalTree[i] = new HufNode();
+        if (CreateTree(literalTree, literalCodes, ll, 0)) {
+          flushBuffer();
+          return 1;
+        }
+        len = literalTree.length;
+        for (i = 0; i < len; i++)
+          distanceTree[i] = new HufNode();
+        var ll2 = new Array();
+        for (i = literalCodes; i < ll.length; i++) {
+          ll2[i - literalCodes] = ll[i];
+        }
+        if (CreateTree(distanceTree, distCodes, ll2, 0)) {
+          flushBuffer();
+          return 1;
+        }
+        if (debug)
+          document.write("<br>literalTree");
+        outer: while (1) {
+          j = DecodeValue(literalTree);
+          if (j >= 256) { // In C64: if carry set
+            var len, dist;
+            j -= 256;
+            if (j == 0) {
+              // EOF
+              break;
+            }
+            j--;
+            len = readBits(cplext[j]) + cplens[j];
+
+            j = DecodeValue(distanceTree);
+            if (cpdext[j] > 8) {
+              dist = readBits(8);
+              dist |= (readBits(cpdext[j] - 8) << 8);
+            } else {
+              dist = readBits(cpdext[j]);
+            }
+            dist += cpdist[j];
+            while (len--) {
+              if (bIdx - dist < 0) {
+                break outer;
+              }
+              var c = buf32k[(bIdx - dist) & 0x7fff];
+              addBuffer(c);
+            }
+          } else {
+            addBuffer(j);
+          }
+        }
+      }
+    } while (!last);
+    flushBuffer();
+
+    byteAlign();
+    return 0;
+  };
+
+  JXG.Util.Unzip.prototype.unzipFile = function(name) {
+    var i;
+    this.unzip();
+    //alert(unzipped[0][1]);
+    for (i = 0; i < unzipped.length; i++) {
+      if (unzipped[i][1] == name) {
+        return unzipped[i][0];
+      }
+    }
+
+  };
+
+  JXG.Util.Unzip.prototype.deflate = function() {
+    outputArr = [];
+    var tmp = [];
+    modeZIP = false;
+    DeflateLoop();
+    if (debug)
+      alert(outputArr.join(''));
+    unzipped[files] = new Array(2);
+    unzipped[files][0] = outputArr.join('');
+    unzipped[files][1] = "DEFLATE";
+    files++;
+    return unzipped;
+  }
+
+  JXG.Util.Unzip.prototype.unzip = function() {
+    //convertToByteArray(input);
+    if (debug)
+      alert(bA);
+    /*for (i=0;i<bA.length*8;i++){
+		document.write(readBit());
+		if ((i+1)%8==0)
+			document.write(" ");
+	}*/
+    /*for (i=0;i<bA.length;i++){
+		document.write(readByte()+" ");
+		if ((i+1)%8==0)
+			document.write(" ");
+	}
+	for (i=0;i<bA.length;i++){
+		document.write(bA[i]+" ");
+		if ((i+1)%16==0)
+			document.write("<br>");
+	}	
+	*/
+    //alert(bA);
+    nextFile();
+    return unzipped;
+  };
+
+  function nextFile() {
+    if (debug)
+      alert("NEXTFILE");
+    outputArr = [];
+    var tmp = [];
+    modeZIP = false;
+    tmp[0] = readByte();
+    tmp[1] = readByte();
+    if (debug)
+      alert("type: " + tmp[0] + " " + tmp[1]);
+    if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("da", 16)) { //GZIP
+      if (debug)
+        alert("GEONExT-GZIP");
+      DeflateLoop();
+      if (debug)
+        alert(outputArr.join(''));
+      unzipped[files] = new Array(2);
+      unzipped[files][0] = outputArr.join('');
+      unzipped[files][1] = "geonext.gxt";
+      files++;
+    }
+    if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("9c", 16)) { //ZLIB
+      if (debug)
+        alert("ZLIB");
+      DeflateLoop();
+      if (debug)
+        alert(outputArr.join(''));
+      unzipped[files] = new Array(2);
+      unzipped[files][0] = outputArr.join('');
+      unzipped[files][1] = "ZLIB";
+      files++;
+    }
+    if (tmp[0] == parseInt("1f", 16) && tmp[1] == parseInt("8b", 16)) { //GZIP
+      if (debug)
+        alert("GZIP");
+      //DeflateLoop();
+      skipdir();
+      if (debug)
+        alert(outputArr.join(''));
+      unzipped[files] = new Array(2);
+      unzipped[files][0] = outputArr.join('');
+      unzipped[files][1] = "file";
+      files++;
+    }
+    if (tmp[0] == parseInt("50", 16) && tmp[1] == parseInt("4b", 16)) { //ZIP
+      modeZIP = true;
+      tmp[2] = readByte();
+      tmp[3] = readByte();
+      if (tmp[2] == parseInt("3", 16) && tmp[3] == parseInt("4", 16)) {
+        //MODE_ZIP
+        tmp[0] = readByte();
+        tmp[1] = readByte();
+        if (debug)
+          alert("ZIP-Version: " + tmp[1] + " " + tmp[0] / 10 + "." + tmp[0] % 10);
+
+        gpflags = readByte();
+        gpflags |= (readByte() << 8);
+        if (debug)
+          alert("gpflags: " + gpflags);
+
+        var method = readByte();
+        method |= (readByte() << 8);
+        if (debug)
+          alert("method: " + method);
+
+        readByte();
+        readByte();
+        readByte();
+        readByte();
+
+        var crc = readByte();
+        crc |= (readByte() << 8);
+        crc |= (readByte() << 16);
+        crc |= (readByte() << 24);
+
+        var compSize = readByte();
+        compSize |= (readByte() << 8);
+        compSize |= (readByte() << 16);
+        compSize |= (readByte() << 24);
+
+        var size = readByte();
+        size |= (readByte() << 8);
+        size |= (readByte() << 16);
+        size |= (readByte() << 24);
+
+        if (debug)
+          alert("local CRC: " + crc + "\nlocal Size: " + size + "\nlocal CompSize: " + compSize);
+
+        var filelen = readByte();
+        filelen |= (readByte() << 8);
+
+        var extralen = readByte();
+        extralen |= (readByte() << 8);
+
+        if (debug)
+          alert("filelen " + filelen);
+        i = 0;
+        nameBuf = [];
+        while (filelen--) {
+          var c = readByte();
+          if (c == "/" | c == ":") {
+            i = 0;
+          } else if (i < NAMEMAX - 1)
+            nameBuf[i++] = String.fromCharCode(c);
+        }
+        if (debug)
+          alert("nameBuf: " + nameBuf);
+
+        //nameBuf[i] = "\0";
+        if (!fileout)
+          fileout = nameBuf;
+
+        var i = 0;
+        while (i < extralen) {
+          c = readByte();
+          i++;
+        }
+
+        CRC = 0xffffffff;
+        SIZE = 0;
+
+        if (size == 0 && fileOut.charAt(fileout.length - 1) == "/") {
+          //skipdir
+          if (debug)
+            alert("skipdir");
+        }
+        if (method == 8) {
+          DeflateLoop();
+          if (debug)
+            alert(outputArr.join(''));
+          unzipped[files] = new Array(2);
+          unzipped[files][0] = outputArr.join('');
+          unzipped[files][1] = nameBuf.join('');
+          files++;
+          //return outputArr.join('');
+        }
+        skipdir();
+      }
+    }
+  };
+
+  function skipdir() {
+    var crc,
+      tmp = [],
+      compSize, size, os, i, c;
+
+    if ((gpflags & 8)) {
+      tmp[0] = readByte();
+      tmp[1] = readByte();
+      tmp[2] = readByte();
+      tmp[3] = readByte();
+
+      if (tmp[0] == parseInt("50", 16) &&
+        tmp[1] == parseInt("4b", 16) &&
+        tmp[2] == parseInt("07", 16) &&
+        tmp[3] == parseInt("08", 16)) {
+        crc = readByte();
+        crc |= (readByte() << 8);
+        crc |= (readByte() << 16);
+        crc |= (readByte() << 24);
+      } else {
+        crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24);
+      }
+
+      compSize = readByte();
+      compSize |= (readByte() << 8);
+      compSize |= (readByte() << 16);
+      compSize |= (readByte() << 24);
+
+      size = readByte();
+      size |= (readByte() << 8);
+      size |= (readByte() << 16);
+      size |= (readByte() << 24);
+
+      if (debug)
+        alert("CRC:");
+    }
+
+    if (modeZIP)
+      nextFile();
+
+    tmp[0] = readByte();
+    if (tmp[0] != 8) {
+      if (debug)
+        alert("Unknown compression method!");
+      return 0;
+    }
+
+    gpflags = readByte();
+    if (debug) {
+      if ((gpflags & ~(parseInt("1f", 16))))
+        alert("Unknown flags set!");
+    }
+
+    readByte();
+    readByte();
+    readByte();
+    readByte();
+
+    readByte();
+    os = readByte();
+
+    if ((gpflags & 4)) {
+      tmp[0] = readByte();
+      tmp[2] = readByte();
+      len = tmp[0] + 256 * tmp[1];
+      if (debug)
+        alert("Extra field size: " + len);
+      for (i = 0; i < len; i++)
+        readByte();
+    }
+
+    if ((gpflags & 8)) {
+      i = 0;
+      nameBuf = [];
+      while (c = readByte()) {
+        if (c == "7" || c == ":")
+          i = 0;
+        if (i < NAMEMAX - 1)
+          nameBuf[i++] = c;
+      }
+      //nameBuf[i] = "\0";
+      if (debug)
+        alert("original file name: " + nameBuf);
+    }
+
+    if ((gpflags & 16)) {
+      while (c = readByte()) {
+        //FILE COMMENT
+      }
+    }
+
+    if ((gpflags & 2)) {
+      readByte();
+      readByte();
+    }
+
+    DeflateLoop();
+
+    crc = readByte();
+    crc |= (readByte() << 8);
+    crc |= (readByte() << 16);
+    crc |= (readByte() << 24);
+
+    size = readByte();
+    size |= (readByte() << 8);
+    size |= (readByte() << 16);
+    size |= (readByte() << 24);
+
+    if (modeZIP)
+      nextFile();
+
+  };
+
+};
+
+/**
+ *  Base64 encoding / decoding
+ *  {@link http://www.webtoolkit.info/}
+ */
+JXG.Util.Base64 = {
+
+  // private property
+  _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+
+  // public method for encoding
+  encode: function(input) {
+    var output = [],
+      chr1, chr2, chr3, enc1, enc2, enc3, enc4,
+      i = 0;
+
+    input = JXG.Util.Base64._utf8_encode(input);
+
+    while (i < input.length) {
+
+      chr1 = input.charCodeAt(i++);
+      chr2 = input.charCodeAt(i++);
+      chr3 = input.charCodeAt(i++);
+
+      enc1 = chr1 >> 2;
+      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+      enc4 = chr3 & 63;
+
+      if (isNaN(chr2)) {
+        enc3 = enc4 = 64;
+      } else if (isNaN(chr3)) {
+        enc4 = 64;
+      }
+
+      output.push([this._keyStr.charAt(enc1),
+          this._keyStr.charAt(enc2),
+          this._keyStr.charAt(enc3),
+          this._keyStr.charAt(enc4)
+      ].join(''));
+    }
+
+    return output.join('');
+  },
+
+  // public method for decoding
+  decode: function(input, utf8) {
+    var output = [],
+      chr1, chr2, chr3,
+      enc1, enc2, enc3, enc4,
+      i = 0;
+
+    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+    while (i < input.length) {
+
+      enc1 = this._keyStr.indexOf(input.charAt(i++));
+      enc2 = this._keyStr.indexOf(input.charAt(i++));
+      enc3 = this._keyStr.indexOf(input.charAt(i++));
+      enc4 = this._keyStr.indexOf(input.charAt(i++));
+
+      chr1 = (enc1 << 2) | (enc2 >> 4);
+      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+      chr3 = ((enc3 & 3) << 6) | enc4;
+
+      output.push(String.fromCharCode(chr1));
+
+      if (enc3 != 64) {
+        output.push(String.fromCharCode(chr2));
+      }
+      if (enc4 != 64) {
+        output.push(String.fromCharCode(chr3));
+      }
+    }
+
+    output = output.join('');
+
+    if (utf8) {
+      output = JXG.Util.Base64._utf8_decode(output);
+    }
+    return output;
+
+  },
+
+  // private method for UTF-8 encoding
+  _utf8_encode: function(string) {
+    string = string.replace(/\r\n/g, "\n");
+    var utftext = "";
+
+    for (var n = 0; n < string.length; n++) {
+
+      var c = string.charCodeAt(n);
+
+      if (c < 128) {
+        utftext += String.fromCharCode(c);
+      } else if ((c > 127) && (c < 2048)) {
+        utftext += String.fromCharCode((c >> 6) | 192);
+        utftext += String.fromCharCode((c & 63) | 128);
+      } else {
+        utftext += String.fromCharCode((c >> 12) | 224);
+        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+        utftext += String.fromCharCode((c & 63) | 128);
+      }
+
+    }
+
+    return utftext;
+  },
+
+  // private method for UTF-8 decoding
+  _utf8_decode: function(utftext) {
+    var string = [],
+      i = 0,
+      c = 0,
+      c2 = 0,
+      c3 = 0;
+
+    while (i < utftext.length) {
+      c = utftext.charCodeAt(i);
+      if (c < 128) {
+        string.push(String.fromCharCode(c));
+        i++;
+      } else if ((c > 191) && (c < 224)) {
+        c2 = utftext.charCodeAt(i + 1);
+        string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
+        i += 2;
+      } else {
+        c2 = utftext.charCodeAt(i + 1);
+        c3 = utftext.charCodeAt(i + 2);
+        string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
+        i += 3;
+      }
+    }
+    return string.join('');
+  },
+
+  _destrip: function(stripped, wrap) {
+    var lines = [],
+      lineno, i,
+      destripped = [];
+
+    if (wrap == null)
+      wrap = 76;
+
+    stripped.replace(/ /g, "");
+    lineno = stripped.length / wrap;
+    for (i = 0; i < lineno; i++)
+      lines[i] = stripped.substr(i * wrap, wrap);
+    if (lineno != stripped.length / wrap)
+      lines[lines.length] = stripped.substr(lineno * wrap, stripped.length - (lineno * wrap));
+
+    for (i = 0; i < lines.length; i++)
+      destripped.push(lines[i]);
+    return destripped.join('\n');
+  },
+
+  decodeAsArray: function(input) {
+    var dec = this.decode(input),
+      ar = [],
+      i;
+    for (i = 0; i < dec.length; i++) {
+      ar[i] = dec.charCodeAt(i);
+    }
+    return ar;
+  },
+
+  decodeGEONExT: function(input) {
+    return decodeAsArray(destrip(input), false);
+  }
+};
+
+/**
+ * @private
+ */
+JXG.Util.asciiCharCodeAt = function(str, i) {
+  var c = str.charCodeAt(i);
+  if (c > 255) {
+    switch (c) {
+      case 8364:
+        c = 128;
+        break;
+      case 8218:
+        c = 130;
+        break;
+      case 402:
+        c = 131;
+        break;
+      case 8222:
+        c = 132;
+        break;
+      case 8230:
+        c = 133;
+        break;
+      case 8224:
+        c = 134;
+        break;
+      case 8225:
+        c = 135;
+        break;
+      case 710:
+        c = 136;
+        break;
+      case 8240:
+        c = 137;
+        break;
+      case 352:
+        c = 138;
+        break;
+      case 8249:
+        c = 139;
+        break;
+      case 338:
+        c = 140;
+        break;
+      case 381:
+        c = 142;
+        break;
+      case 8216:
+        c = 145;
+        break;
+      case 8217:
+        c = 146;
+        break;
+      case 8220:
+        c = 147;
+        break;
+      case 8221:
+        c = 148;
+        break;
+      case 8226:
+        c = 149;
+        break;
+      case 8211:
+        c = 150;
+        break;
+      case 8212:
+        c = 151;
+        break;
+      case 732:
+        c = 152;
+        break;
+      case 8482:
+        c = 153;
+        break;
+      case 353:
+        c = 154;
+        break;
+      case 8250:
+        c = 155;
+        break;
+      case 339:
+        c = 156;
+        break;
+      case 382:
+        c = 158;
+        break;
+      case 376:
+        c = 159;
+        break;
+      default:
+        break;
+    }
+  }
+  return c;
+};
+
+/**
+ * Decoding string into utf-8
+ * @param {String} string to decode
+ * @return {String} utf8 decoded string
+ */
+JXG.Util.utf8Decode = function(utftext) {
+  var string = [];
+  var i = 0;
+  var c = 0,
+    c1 = 0,
+    c2 = 0,
+    c3;
+  if (!JXG.exists(utftext)) return '';
+
+  while (i < utftext.length) {
+    c = utftext.charCodeAt(i);
+
+    if (c < 128) {
+      string.push(String.fromCharCode(c));
+      i++;
+    } else if ((c > 191) && (c < 224)) {
+      c2 = utftext.charCodeAt(i + 1);
+      string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
+      i += 2;
+    } else {
+      c2 = utftext.charCodeAt(i + 1);
+      c3 = utftext.charCodeAt(i + 2);
+      string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
+      i += 3;
+    }
+  };
+  return string.join('');
+};
+
+/**
+ * Generate a random uuid.
+ * http://www.broofa.com
+ * mailto:robert@broofa.com
+ *
+ * Copyright (c) 2010 Robert Kieffer
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ * EXAMPLES:
+ *   >>> Math.uuid()
+ *   "92329D39-6F5C-4520-ABFC-AAB64544E172"
+ */
+JXG.Util.genUUID = function() {
+  // Private array of chars to use
+  var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
+    uuid = new Array(36),
+    rnd = 0,
+    r;
+
+  for (var i = 0; i < 36; i++) {
+    if (i == 8 || i == 13 || i == 18 || i == 23) {
+      uuid[i] = '-';
+    } else if (i == 14) {
+      uuid[i] = '4';
+    } else {
+      if (rnd <= 0x02) rnd = 0x2000000 + (Math.random() * 0x1000000) | 0;
+      r = rnd & 0xf;
+      rnd = rnd >> 4;
+      uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
+    }
+  }
+
+  return uuid.join('');
+};
+
+
+module.exports = JXG;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/key.js.html b/doc/key.js.html new file mode 100644 index 00000000..300d7691 --- /dev/null +++ b/doc/key.js.html @@ -0,0 +1,816 @@ + + + + + JSDoc: Source: key.js + + + + + + + + + + +
+ +

Source: key.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @requires config
+ * @requires encoding/armor
+ * @requires enums
+ * @requires packet
+ * @module key
+ */
+
+var packet = require('./packet'),
+  enums = require('./enums.js'),
+  armor = require('./encoding/armor.js'),
+  config = require('./config');
+
+/**
+ * @class
+ * @classdesc Class that represents an OpenPGP key. Must contain a primary key.
+ * Can contain additional subkeys, signatures, user ids, user attributes.
+ * @param  {module:packet/packetlist} packetlist The packets that form this key
+ */
+
+function Key(packetlist) {
+  if (!(this instanceof Key)) {
+    return new Key(packetlist);
+  }
+  // same data as in packetlist but in structured form
+  this.primaryKey = null;
+  this.revocationSignature = null;
+  this.directSignatures = null;
+  this.users = null;
+  this.subKeys = null;
+  this.packetlist2structure(packetlist);
+  if (!this.primaryKey || !this.users) {
+    throw new Error('Invalid key: need at least key and user ID packet');
+  }
+}
+
+/**
+ * Transforms packetlist to structured key data
+ * @param  {module:packet/packetlist} packetlist The packets that form a key
+ */
+Key.prototype.packetlist2structure = function(packetlist) {
+  var user, primaryKeyId, subKey;
+  for (var i = 0; i < packetlist.length; i++) {
+    switch (packetlist[i].tag) {
+      case enums.packet.public_key:
+      case enums.packet.secret_key:
+        this.primaryKey = packetlist[i];
+        primaryKeyId = this.primaryKey.getKeyId();
+        break;
+      case enums.packet.userid:
+      case enums.packet.user_attribute:
+        user = new User(packetlist[i]);
+        if (!this.users) this.users = [];
+        this.users.push(user);
+        break;
+      case enums.packet.public_subkey:
+      case enums.packet.secret_subkey:
+        user = null;
+        if (!this.subKeys) this.subKeys = [];
+        subKey = new SubKey(packetlist[i]);
+        this.subKeys.push(subKey);
+        break;
+      case enums.packet.signature:
+        switch (packetlist[i].signatureType) {
+          case enums.signature.cert_generic:
+          case enums.signature.cert_persona:
+          case enums.signature.cert_casual:
+          case enums.signature.cert_positive:
+            if (packetlist[i].issuerKeyId.equals(primaryKeyId)) {
+              if (!user.selfCertifications) user.selfCertifications = [];
+              user.selfCertifications.push(packetlist[i]);
+            } else {
+              if (!user.otherCertifications) user.otherCertifications = [];
+              user.otherCertifications.push(packetlist[i]);
+            }
+            break;
+          case enums.signature.cert_revocation:
+            if (user) {
+              if (!user.revocationCertifications) user.revocationCertifications = [];
+              user.revocationCertifications.push(packetlist[i]);
+            } else {
+              if (!this.directSignatures) this.directSignatures = [];
+              this.directSignatures.push(packetlist[i]);
+            }
+            break;
+          case enums.signature.key:
+            if (!this.directSignatures) this.directSignatures = [];
+            this.directSignatures.push(packetlist[i]);
+            break;
+          case enums.signature.subkey_binding:
+            subKey.bindingSignature = packetlist[i];
+            break;
+          case enums.signature.key_revocation:
+            this.revocationSignature = packetlist[i];
+            break;
+          case enums.signature.subkey_revocation:
+            subKey.revocationSignature = packetlist[i];
+            break;
+        }
+        break;
+    }
+  }
+};
+
+/**
+ * Transforms structured key data to packetlist
+ * @return {module:packet/packetlist} The packets that form a key
+ */
+Key.prototype.toPacketlist = function() {
+  var packetlist = new packet.list();
+  packetlist.push(this.primaryKey);
+  packetlist.push(this.revocationSignature);
+  packetlist.concat(this.directSignatures);
+  for (var i = 0; i < this.users.length; i++) {
+    packetlist.concat(this.users[i].toPacketlist());
+  }
+  if (this.subKeys) {
+    for (var i = 0; i < this.subKeys.length; i++) {
+      packetlist.concat(this.subKeys[i].toPacketlist());
+    } 
+  }
+  return packetlist;
+};
+
+/** 
+ * Returns the primary key packet (secret or public)
+ * @returns {(module:packet/secret_key|module:packet/public_key|null)} 
+ */
+Key.prototype.getKeyPacket = function() {
+  return this.primaryKey;
+};
+
+/** 
+ * Returns all the private and public subkey packets
+ * @returns {Array<(module:packet/public_subkey|module:packet/secret_subkey)>} 
+ */
+Key.prototype.getSubkeyPackets = function() {
+  var subKeys = [];
+  if (this.subKeys) {
+    for (var i = 0; i < this.subKeys.length; i++) {
+      subKeys.push(this.subKeys[i].subKey);
+    }
+  }
+  return subKeys;
+};
+
+/** 
+ * Returns all the private and public key and subkey packets
+ * @returns {Array<(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key)>} 
+ */
+Key.prototype.getAllKeyPackets = function() {
+  return [this.getKeyPacket()].concat(this.getSubkeyPackets());
+};
+
+/** 
+ * Returns key IDs of all key packets
+ * @returns {Array<module:type/keyid>} 
+ */
+Key.prototype.getKeyIds = function() {
+  var keyIds = [];
+  var keys = this.getAllKeyPackets();
+  for (var i = 0; i < keys.length; i++) {
+    keyIds.push(keys[i].getKeyId());
+  }
+  return keyIds;
+};
+
+function findKey(keys, keyIds) {
+  for (var i = 0; i < keys.length; i++) {
+    var keyId = keys[i].getKeyId(); 
+    for (var j = 0; j < keyIds.length; j++) {
+      if (keyId.equals(keyIds[j])) {
+        return keys[i];
+      }
+    }
+  }
+  return null;
+}
+
+/**
+ * Returns first public key packet for given array of key IDs
+ * @param  {Array<module:type/keyid>} keyIds 
+ * @return {(module:packet/public_subkey|module:packet/public_key|null)}
+ */
+Key.prototype.getPublicKeyPacket = function(keyIds) {
+  if (this.primaryKey.tag == enums.packet.public_key) {
+    return findKey(this.getAllKeyPackets(), keyIds);  
+  } else {
+    return null;
+  }  
+};
+
+/**
+ * Returns first private key packet for given array of key IDs
+ * @param  {Array<module:type/keyid>} keyIds
+ * @return {(module:packet/secret_subkey|module:packet/secret_key|null)}
+ */
+Key.prototype.getPrivateKeyPacket = function(keyIds) {
+  if (this.primaryKey.tag == enums.packet.secret_key) {
+    return findKey(this.getAllKeyPackets(), keyIds);  
+  } else {
+    return null;
+  }
+};
+
+/**
+ * Returns userids
+ * @return {Array<string>} array of userids
+ */
+Key.prototype.getUserIds = function() {
+  var userids = [];
+  for (var i = 0; i < this.users.length; i++) {
+    if (this.users[i].userId) {
+      userids.push(this.users[i].userId.write());
+    }
+  }
+  return userids;
+};
+
+/**
+ * Returns true if this is a public key
+ * @return {Boolean}
+ */
+Key.prototype.isPublic = function() {
+  return this.primaryKey.tag == enums.packet.public_key;
+};
+
+/**
+ * Returns true if this is a private key
+ * @return {Boolean}
+ */
+Key.prototype.isPrivate = function() {
+  return this.primaryKey.tag == enums.packet.secret_key;
+};
+
+/**
+ * Returns key as public key (shallow copy)
+ * @return {module:key~Key} new public Key
+ */
+Key.prototype.toPublic = function() {
+  var packetlist = new packet.list();
+  var keyPackets = this.toPacketlist();
+  for (var i = 0; i < keyPackets.length; i++) {
+    switch (keyPackets[i].tag) {
+      case enums.packet.secret_key:
+        var bytes = keyPackets[i].writePublicKey();
+        var pubKeyPacket = new packet.public_key();
+        pubKeyPacket.read(bytes);
+        packetlist.push(pubKeyPacket);
+        break;
+      case enums.packet.secret_subkey:
+        var bytes = keyPackets[i].writePublicKey();
+        var pubSubkeyPacket = new packet.public_subkey();
+        pubSubkeyPacket.read(bytes);
+        packetlist.push(pubSubkeyPacket);
+        break;
+      default:
+        packetlist.push(keyPackets[i]);
+    }
+  }
+  return new Key(packetlist);
+};
+
+/**
+ * Returns ASCII armored text of key
+ * @return {String} ASCII armor
+ */
+Key.prototype.armor = function() {
+  var type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key;
+  return armor.encode(type, this.toPacketlist().write());
+};
+
+/**
+ * Returns first key packet that is available for signing
+ * @return {(module:packet/secret_subkey|module:packet/secret_key|null)} key packet or null if no signing key has been found
+ */
+Key.prototype.getSigningKeyPacket = function() {
+  if (this.isPublic()) {
+    throw new Error('Need private key for signing');
+  }
+  var primaryUser = this.getPrimaryUser();
+  if (primaryUser && 
+      isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate)) {
+    return this.primaryKey;
+  }
+  if (this.subKeys) {
+    for (var i = 0; i < this.subKeys.length; i++) {
+      if (this.subKeys[i].isValidSigningKey(this.primaryKey)) {
+        return this.subKeys[i].subKey;
+      }
+    }
+  }
+  return null;
+};
+
+/**
+ * Returns preferred signature hash algorithm of this key
+ * @return {String}
+ */
+Key.prototype.getPreferredHashAlgorithm = function() {
+  var primaryUser = this.getPrimaryUser();
+  if (primaryUser && primaryUser.selfCertificate.preferredHashAlgorithms) {
+    return primaryUser.selfCertificate.preferredHashAlgorithms[0];
+  }
+  return config.prefer_hash_algorithm;
+};
+
+function isValidEncryptionKeyPacket(keyPacket, signature) {
+  return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) &&
+         keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_sign) &&
+         ((signature.keyFlags & enums.keyFlags.encrypt_communication) !== 0 ||
+          (signature.keyFlags & enums.keyFlags.encrypt_storage) !== 0 ||
+          !signature.keyFlags);
+};
+
+function isValidSigningKeyPacket(keyPacket, signature) {
+  return (keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.dsa) ||
+          keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.rsa_sign) ||
+          keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.rsa_encrypt_sign)) &&
+         ((signature.keyFlags & enums.keyFlags.sign_data) !== 0 ||
+          !signature.keyFlags);
+};
+
+/**
+ * Returns the first valid encryption key packet for this key
+ * @returns {(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key|null)} key packet or null if no encryption key has been found
+ */
+Key.prototype.getEncryptionKeyPacket = function() {
+  // V4: by convention subkeys are prefered for encryption service
+  // V3: keys MUST NOT have subkeys
+  if (this.subKeys) {
+    for (var i = 0; i < this.subKeys.length; i++) {
+      if (this.subKeys[i].isValidEncryptionKey(this.primaryKey)) {
+        return this.subKeys[i].subKey;
+      }
+    }
+  }
+  // if no valid subkey for encryption, evaluate primary key
+  var primaryUser = this.getPrimaryUser();
+  if (primaryUser && 
+      isValidEncryptionKeyPacket(this.primaryKey, primaryUser.selfCertificate)) {
+    return this.primaryKey;
+  }
+  return null;
+};
+
+/**
+ * Decrypts all secret key and subkey packets
+ * @param  {String} passphrase 
+ * @return {Boolean} true if all key and subkey packets decrypted successfully
+ */
+Key.prototype.decrypt = function(passphrase) {
+  if (this.isPrivate()) {
+    var keys = this.getAllKeyPackets();
+    for (var i = 0; i < keys.length; i++) {
+      var success = keys[i].decrypt(passphrase);
+      if (!success) return false;
+    }
+  } else {
+    throw new Error("Nothing to decrypt in a public key");
+  }
+  return true;
+};
+
+/**
+ * Decrypts specific key packets by key ID
+ * @param  {Array<module:type/keyid>} keyIds
+ * @param  {String} passphrase 
+ * @return {Boolean} true if all key packets decrypted successfully
+ */
+Key.prototype.decryptKeyPacket = function(keyIds, passphrase) {
+  if (this.isPrivate()) {
+    var keys = this.getAllKeyPackets();
+    for (var i = 0; i < keys.length; i++) {
+      var keyId = keys[i].getKeyId(); 
+      for (var j = 0; j < keyIds.length; j++) {
+        if (keyId.equals(keyIds[j])) {
+          var success = keys[i].decrypt(passphrase);
+          if (!success) return false;
+        }
+      }
+    }
+  } else {
+    throw new Error("Nothing to decrypt in a public key");
+  }
+  return true;
+};
+
+/**
+ * Verify primary key. Checks for revocation signatures, expiration time
+ * and valid self signature
+ * @return {module:enums.keyStatus} The status of the primary key
+ */
+Key.prototype.verifyPrimaryKey = function() {
+  // check revocation signature
+  if (this.revocationSignature && !this.revocationSignature.isExpired() && 
+     (this.revocationSignature.verified || 
+      this.revocationSignature.verify(this.primaryKey, {key: this.primaryKey}))) {
+    return enums.keyStatus.revoked;
+  }
+  // check V3 expiration time
+  if (this.primaryKey.version == 3 && this.primaryKey.expirationTimeV3 !== 0 &&
+    Date.now() > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) {
+    return enums.keyStatus.expired;
+  }
+  // check for at least one self signature. Self signature of user ID not mandatory
+  // See http://tools.ietf.org/html/rfc4880#section-11.1
+  var selfSigned = false;
+  for (var i = 0; i < this.users.length; i++) {
+    if (this.users[i].userId && this.users[i].selfCertifications) {
+      selfSigned = true;
+    }
+  }
+  if (!selfSigned) {
+    return enums.keyStatus.no_self_cert;
+  }
+  // check for valid self signature
+  var primaryUser = this.getPrimaryUser();
+  if (!primaryUser) {
+    return enums.keyStatus.invalid;
+  }
+  // check V4 expiration time
+  if (this.primaryKey.version == 4 && primaryUser.selfCertificate.keyNeverExpires === false &&
+    Date.now() > (primaryUser.selfCertificate.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) {
+    return enums.keyStatus.expired;
+  }
+  return enums.keyStatus.valid;
+};
+
+/**
+ * Returns primary user and most significant (latest valid) self signature
+ * - if multiple users are marked as primary users returns the one with the latest self signature
+ * - if no primary user is found returns the user with the latest self signature
+ * @return {{user: Array<module:packet/User>, selfCertificate: Array<module:packet/signature>}} The primary user and the self signature
+ */
+Key.prototype.getPrimaryUser = function() {
+  var user = null;
+  var userSelfCert;
+  for (var i = 0; i < this.users.length; i++) {
+    if (!this.users[i].userId) {
+      continue;
+    }
+    var selfCert = this.users[i].getValidSelfCertificate(this.primaryKey);
+    if (!selfCert) {
+      continue;
+    }
+    if (!user || 
+        !userSelfCert.isPrimaryUserID && selfCert.isPrimaryUserID ||
+         userSelfCert.created < selfCert.created) {
+      user = this.users[i];
+      userSelfCert = selfCert;
+    }
+  }
+  return user ? {user: user, selfCertificate: userSelfCert} : null;
+}
+
+// TODO
+Key.prototype.revoke = function() {
+
+};
+
+/**
+ * @class
+ * @classdesc Class that represents an user ID or attribute packet and the relevant signatures.
+ */
+function User(userPacket) {
+  if (!(this instanceof User)) {
+    return new User(userPacket);
+  }
+  this.userId = userPacket.tag == enums.packet.userid ? userPacket : null;
+  this.userAttribute = userPacket.tag == enums.packet.user_attribute ? userPacket : null
+  this.selfCertifications = null;
+  this.otherCertifications = null;
+  this.revocationCertifications = null;
+}
+
+/**
+ * Transforms structured user data to packetlist
+ * @return {module:packet/packetlist}
+ */
+User.prototype.toPacketlist = function() {
+  var packetlist = new packet.list();
+  packetlist.push(this.userId || this.userAttribute);
+  packetlist.concat(this.revocationCertifications);
+  packetlist.concat(this.selfCertifications);
+  packetlist.concat(this.otherCertifications);
+  return packetlist;
+};
+
+/**
+ * Checks if a self signature of the user is revoked
+ * @param  {module:packet/signature}                    certificate
+ * @param  {module:packet/secret_key|module:packet/public_key} primaryKey  The primary key packet
+ * @return {Boolean}                                         True if the certificate is revoked
+ */
+User.prototype.isRevoked = function(certificate, primaryKey) {
+  if (this.revocationCertifications) {
+    var that = this;
+    return this.revocationCertifications.some(function(revCert) {
+             return revCert.issuerKeyId.equals(certificate.issuerKeyId) &&
+                    !revCert.isExpired() && 
+                    (revCert.verified || 
+                     revCert.verify(primaryKey, {userid: that.userId || that.userAttribute, key: primaryKey}));
+          });
+  } else {
+    return false;
+  }
+};
+
+/**
+ * Returns the most significant (latest valid) self signature of the user
+ * @param  {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
+ * @return {module:packet/signature}                               The self signature
+ */
+User.prototype.getValidSelfCertificate = function(primaryKey) {
+  if (!this.selfCertifications) {
+    return null;
+  }
+  var validCert = [];
+  for (var i = 0; i < this.selfCertifications.length; i++) {
+    if (this.isRevoked(this.selfCertifications[i], primaryKey)) {
+      continue;
+    }
+    if (!this.selfCertifications[i].isExpired() &&
+       (this.selfCertifications[i].verified || 
+        this.selfCertifications[i].verify(primaryKey, {userid: this.userId || this.userAttribute, key: primaryKey}))) {
+      validCert.push(this.selfCertifications[i]);
+    }
+  }
+  // most recent first
+  validCert = validCert.sort(function(a, b) {
+    a = a.created;
+    b = b.created;
+    return a>b ? -1 : a<b ? 1 : 0;
+  });
+  return validCert[0];
+};
+
+/**
+ * Verify User. Checks for existence of self signatures, revocation signatures
+ * and validity of self signature
+ * @param  {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
+ * @return {module:enums.keyStatus} status of user    
+ */
+User.prototype.verify = function(primaryKey) {
+  if (!this.selfCertifications) {
+    return enums.keyStatus.no_self_cert;
+  }
+  var status;
+  for (var i = 0; i < this.selfCertifications.length; i++) {
+    if (this.isRevoked(this.selfCertifications[i], primaryKey)) {
+      status = enums.keyStatus.revoked;
+      continue;
+    }
+    if (!(this.selfCertifications[i].verified || 
+        this.selfCertifications[i].verify(primaryKey, {userid: this.userId || this.userAttribute, key: primaryKey}))) {
+      status = enums.keyStatus.invalid;
+      continue;
+    }
+    if (this.selfCertifications[i].isExpired()) {
+      status = enums.keyStatus.expired;
+      continue;
+    }
+    status = enums.keyStatus.valid;
+    break;
+  }
+  return status;
+};
+
+/**
+ * @class
+ * @classdesc Class that represents a subkey packet and the relevant signatures.
+ */
+function SubKey(subKeyPacket) {
+  if (!(this instanceof SubKey)) {
+    return new SubKey(subKeyPacket);
+  }
+  this.subKey = subKeyPacket;
+  this.bindingSignature = null;
+  this.revocationSignature = null;
+}
+
+/**
+ * Transforms structured subkey data to packetlist
+ * @return {module:packet/packetlist}
+ */
+SubKey.prototype.toPacketlist = function() {
+  var packetlist = new packet.list();
+  packetlist.push(this.subKey);
+  packetlist.push(this.revocationSignature);
+  packetlist.push(this.bindingSignature);
+  return packetlist;
+};
+
+/**
+ * Returns true if the subkey can be used for encryption
+ * @param  {module:packet/secret_key|module:packet/public_key}  primaryKey The primary key packet
+ * @return {Boolean}
+ */
+SubKey.prototype.isValidEncryptionKey = function(primaryKey) {
+  return this.verify(primaryKey) == enums.keyStatus.valid &&
+         isValidEncryptionKeyPacket(this.subKey, this.bindingSignature);
+};
+
+/**
+ * Returns true if the subkey can be used for signing of data
+ * @param  {module:packet/secret_key|module:packet/public_key}  primaryKey The primary key packet
+ * @return {Boolean}
+ */
+SubKey.prototype.isValidSigningKey = function(primaryKey) {
+  return this.verify(primaryKey) == enums.keyStatus.valid &&
+         isValidSigningKeyPacket(this.subKey, this.bindingSignature);
+};
+
+/**
+ * Verify subkey. Checks for revocation signatures, expiration time
+ * and valid binding signature
+ * @return {module:enums.keyStatus} The status of the subkey
+ */
+SubKey.prototype.verify = function(primaryKey) {
+  // check subkey revocation signature
+  if (this.revocationSignature && !this.revocationSignature.isExpired() && 
+     (this.revocationSignature.verified || 
+      this.revocationSignature.verify(primaryKey, {key: this.subKey}))) {
+    return enums.keyStatus.revoked;
+  }
+  // check V3 expiration time
+  if (this.subKey.version == 3 && this.subKey.expirationTimeV3 !== 0 &&
+      Date.now() > (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) {
+    return enums.keyStatus.expired;
+  }
+  // check subkey binding signature
+  if (!this.bindingSignature) {
+    return enums.keyStatus.invalid;
+  }
+  if (this.bindingSignature.isExpired()) {
+    return enums.keyStatus.expired;
+  }
+  if (!(this.bindingSignature.verified ||
+        this.bindingSignature.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) {
+    return enums.keyStatus.invalid;
+  }
+  // check V4 expiration time
+  if (this.subKey.version == 4 &&
+      this.bindingSignature.keyNeverExpires === false &&
+      Date.now() > (this.subKey.created.getTime() + this.bindingSignature.keyExpirationTime*1000)) {
+    return enums.keyStatus.expired;
+  }
+  return enums.keyStatus.valid;
+};
+
+/**
+ * Reads an OpenPGP armored text and returns one or multiple key objects
+ * @param {String} armoredText text to be parsed
+ * @return {{keys: Array<module:key~Key>, err: (Array<Error>|null)}} result object with key and error arrays
+ * @static
+ */
+function readArmored(armoredText) {
+  var result = {};
+  result.keys = [];
+  try {
+    var input = armor.decode(armoredText);
+    if (!(input.type == enums.armor.public_key || input.type == enums.armor.private_key)) {
+      throw new Error('Armored text not of type key');
+    }
+    var packetlist = new packet.list();
+    packetlist.read(input.data);
+    var keyIndex = packetlist.indexOfTag(enums.packet.public_key, enums.packet.secret_key);
+    if (keyIndex.length == 0) {
+      throw new Error('No key packet found in armored text')
+    }
+    for (var i = 0; i < keyIndex.length; i++) {
+      var oneKeyList = packetlist.slice(keyIndex[i], keyIndex[i + 1]);
+      try {
+        var newKey = new Key(oneKeyList);
+        result.keys.push(newKey);
+      } catch (e) {
+        result.err = result.err || [];
+        result.err.push(e); 
+      }
+    }
+  } catch (e) {
+    result.err = result.err || [];
+    result.err.push(e); 
+  }
+  return result;
+}
+
+/**
+ * Generates a new OpenPGP key. Currently only supports RSA keys.
+ * Primary and subkey will be of same type.
+ * @param {Integer} keyType    to indicate what type of key to make. 
+ *                             RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1
+ * @param {Integer} numBits    number of bits for the key creation.
+ * @param {String}  userId     assumes already in form of "User Name <username@email.com>"
+ * @param {String}  passphrase The passphrase used to encrypt the resulting private key
+ * @return {module:key~Key}
+ * @static
+ */
+function generate(keyType, numBits, userId, passphrase) {
+  var packetlist = new packet.list();
+
+  var secretKeyPacket = new packet.secret_key();
+  secretKeyPacket.algorithm = enums.read(enums.publicKey, keyType);
+  secretKeyPacket.generate(numBits);
+  secretKeyPacket.encrypt(passphrase);
+
+  var userIdPacket = new packet.userid();
+  userIdPacket.read(userId);
+
+  var dataToSign = {};
+  dataToSign.userid = userIdPacket;
+  dataToSign.key = secretKeyPacket;
+  var signaturePacket = new packet.signature();
+  signaturePacket.signatureType = enums.signature.cert_generic;
+  signaturePacket.publicKeyAlgorithm = keyType;
+  //TODO we should load preferred hash from config, or as input to this function
+  signaturePacket.hashAlgorithm = enums.hash.sha256;
+  signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
+  signaturePacket.sign(secretKeyPacket, dataToSign);
+
+  var secretSubkeyPacket = new packet.secret_subkey();
+  secretSubkeyPacket.algorithm = enums.read(enums.publicKey, keyType);
+  secretSubkeyPacket.generate(numBits);
+  secretSubkeyPacket.encrypt(passphrase);
+
+  dataToSign = {};
+  dataToSign.key = secretKeyPacket;
+  dataToSign.bind = secretSubkeyPacket;
+  var subkeySignaturePacket = new packet.signature();
+  subkeySignaturePacket.signatureType = enums.signature.subkey_binding;
+  subkeySignaturePacket.publicKeyAlgorithm = keyType;
+  //TODO we should load preferred hash from config, or as input to this function
+  subkeySignaturePacket.hashAlgorithm = enums.hash.sha256;
+  subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage];
+  subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
+
+  packetlist.push(secretKeyPacket);
+  packetlist.push(userIdPacket);
+  packetlist.push(signaturePacket);
+  packetlist.push(secretSubkeyPacket);
+  packetlist.push(subkeySignaturePacket);
+
+  return new Key(packetlist);
+}
+
+exports.Key = Key;
+exports.readArmored = readArmored;
+exports.generate = generate;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/keyid.html b/doc/keyid.html new file mode 100644 index 00000000..4f6d1b15 --- /dev/null +++ b/doc/keyid.html @@ -0,0 +1,320 @@ + + + + + JSDoc: Module: type/keyid + + + + + + + + + + +
+ +

Module: type/keyid

+ + + + + +
+ +
+

+ type/keyid +

+ +
+ +
+
+ + +
Implementation of type key id (RFC4880 3.3)
+
+A Key ID is an eight-octet scalar that identifies a key. +Implementations SHOULD NOT assume that Key IDs are unique. The +section "Enhanced Key Formats" below describes how Key IDs are +formed.
+ + +
+

new (require("type/keyid"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

read(input)

+ + +
+
+ + +
+ Parsing method for a key id +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Input to read the key id from
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/keyid.js.html b/doc/keyid.js.html new file mode 100644 index 00000000..8cf723c1 --- /dev/null +++ b/doc/keyid.js.html @@ -0,0 +1,116 @@ + + + + + JSDoc: Source: type/keyid.js + + + + + + + + + + +
+ +

Source: type/keyid.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of type key id (RFC4880 3.3)<br/>
+ * <br/>
+ * A Key ID is an eight-octet scalar that identifies a key.
+ * Implementations SHOULD NOT assume that Key IDs are unique.  The
+ * section "Enhanced Key Formats" below describes how Key IDs are
+ * formed.
+ * @requires util
+ * @module type/keyid
+ */
+
+var util = require('../util');
+
+/**
+ * @constructor
+ */
+module.exports = function keyid() {
+
+  this.bytes = '';
+
+
+  /**
+   * Parsing method for a key id
+   * @param {String} input Input to read the key id from 
+   */
+  this.read = function(bytes) {
+    this.bytes = bytes.substr(0, 8);
+  };
+
+  this.write = function() {
+    return this.bytes;
+  };
+
+  this.toHex = function() {
+    return util.hexstrdump(this.bytes);
+  };
+
+  this.equals = function(keyid) {
+    return this.bytes == keyid.bytes;
+  };
+
+  this.isNull = function() {
+    return this.bytes === '';
+  };
+};
+
+module.exports.mapToHex = function(keyId) {
+  return keyId.toHex();
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/keyring.html b/doc/keyring.html new file mode 100644 index 00000000..561bada9 --- /dev/null +++ b/doc/keyring.html @@ -0,0 +1,2050 @@ + + + + + JSDoc: Module: keyring/keyring + + + + + + + + + + +
+ +

Module: keyring/keyring

+ + + + + +
+ +
+

+ keyring/keyring +

+ +
+ +
+
+ + +
The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
+ + +
+

new (require("keyring/keyring"))(storeHandler)

+ + +
+
+ + +
+ Initialization routine for the keyring. This method reads the +keyring from HTML5 local storage and initializes this instance. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
storeHandler + + +class + + + + + + <optional>
+ + + + + +
class implementing load() and store() methods
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

clear()

+ + +
+
+ + +
+ Clear the keyring - erase all the keys +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

exportKey(index) → {String}

+ + +
+
+ + +
+ returns the armored message representation of the key at key ring index +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
index + + +Integer + + + + the index of the key within the array
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ armored message representing the key object +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

exportPublicKey(index) → {String}

+ + +
+
+ + +
+ returns the armored message representation of the public key portion of the key at key ring index +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
index + + +Integer + + + + the index of the key within the array
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ armored message representing the public key object +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getKeysForKeyId(keyId) → {Array.<module:key~Key>}

+ + +
+
+ + +
+ Searches the keyring for public keys having the specified key id +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keyId + + +String + + + + provided as string of hex number (lowercase)
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ public keys found +
+ + + +
+
+ Type +
+
+ +Array.<module:key~Key> + + +
+
+ + + + +
+ + + +
+

getPrivateKeyForAddress(email) → {Array.<module:key~Key>}

+ + +
+
+ + +
+ Searches the keyring for a private key containing the specified email address +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
email + + +String + + + + email address to search for
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ private keys found +
+ + + +
+
+ Type +
+
+ +Array.<module:key~Key> + + +
+
+ + + + +
+ + + +
+

getPublicKeyForAddress(email) → {Array.<module:key~Key>}

+ + +
+
+ + +
+ searches all public keys in the keyring matching the address or address part of the user ids +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
email + + +String + + + + email address to search for
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The public keys associated with provided email address. +
+ + + +
+
+ Type +
+
+ +Array.<module:key~Key> + + +
+
+ + + + +
+ + + +
+

importKey(armored)

+ + +
+
+ + +
+ Imports a key from an ascii armored message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
armored + + +String + + + + message to read the keys/key from
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

removeKey(index) → {module:key~Key}

+ + +
+
+ + +
+ Removes a public key from the public key keyring at the specified index +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
index + + +Integer + + + + the index of the public key within the publicKeys array
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The public key object which has been removed +
+ + + +
+
+ Type +
+
+ +module:key~Key + + +
+
+ + + + +
+ + + +
+

store()

+ + +
+
+ + +
+ Calls the storeHandler to save the keys +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

<inner> checkForIdentityAndKeyTypeMatch(keys, identityFunction, identityInput, keyType) → {Array.<module:key~Key>}

+ + +
+
+ + +
+ searches all public keys in the keyring matching the address or address part of the user ids +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keys + + +Array.<module:key~Key> + + + + array of keys to search
identityFunction + + +module:keyring/keyring.checkCallback + + + + callback function which checks for a match
identityInput + + +String + + + + input to check against
keyType + + +module:enums.packet + + + + packet types of keys to check
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ array of keys which match +
+ + + +
+
+ Type +
+
+ +Array.<module:key~Key> + + +
+
+ + + + +
+ + + +
+

<inner> emailCheck(email, key) → {Boolean}

+ + +
+
+ + +
+ Checks a key to see if it matches the specified email address +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
email + + +String + + + + email address to search for
key + + +module:key~Key + + + + The key to be checked.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ True if the email address is defined in the specified key +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

<inner> idCheck(id, key) → {Boolean}

+ + +
+
+ + +
+ Checks a key to see if it matches the specified keyid +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
id + + +String + + + + hex string keyid to search for
key + + +module:key~Key + + + + the key to be checked.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ true if the email address is defined in the specified key +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ +
+ + + +

Type Definitions

+ +
+ +
+

checkCallback(input, key) → {Boolean}

+ + +
+
+ + +
+ Callback to check if a key matches the input +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + input to search for
key + + +module:key~Key + + + + The key to be checked.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ True if the input matches the specified key +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ +
+ + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/keyring.js.html b/doc/keyring.js.html new file mode 100644 index 00000000..a80c80ef --- /dev/null +++ b/doc/keyring.js.html @@ -0,0 +1,240 @@ + + + + + JSDoc: Source: keyring/keyring.js + + + + + + + + + + +
+ +

Source: keyring/keyring.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
+ * @requires openpgp
+ * @module keyring/keyring
+ */
+
+var openpgp = require('openpgp');
+
+/**
+ * Callback to check if a key matches the input
+ * @callback module:keyring/keyring.checkCallback
+ * @param {String} input input to search for
+ * @param {module:key~Key} key The key to be checked.
+ * @return {Boolean} True if the input matches the specified key
+ */
+
+/**
+ * Initialization routine for the keyring. This method reads the
+ * keyring from HTML5 local storage and initializes this instance.
+ * @constructor
+ * @param {class} [storeHandler] class implementing load() and store() methods
+ */
+module.exports = function(storeHandler) {
+  if (!storeHandler) {
+    storeHandler = new (require('./localstore.js'))();
+  }
+  this.storeHandler = storeHandler;
+  this.keys = this.storeHandler.load();
+
+  /**
+   * Calls the storeHandler to save the keys
+   */
+  this.store = function () {
+    this.storeHandler.store(this.keys);
+  };
+
+  /**
+   * Clear the keyring - erase all the keys
+   */
+  this.clear = function() {
+    this.keys = [];
+  };
+
+  /**
+   * Checks a key to see if it matches the specified email address
+   * @param {String} email email address to search for
+   * @param {module:key~Key} key The key to be checked.
+   * @return {Boolean} True if the email address is defined in the specified key
+   */
+  function emailCheck(email, key) {
+    email = email.toLowerCase();
+    var keyEmails = key.getUserIds();
+    for (var i; i < keyEmails.length; i++) {
+      //we need to get just the email from the userid key
+      keyEmail = keyEmails[i].split('<')[1].split('>')[0].trim().toLowerCase();
+      if (keyEmail == email) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Checks a key to see if it matches the specified keyid
+   * @param {String} id hex string keyid to search for
+   * @param {module:key~Key} key the key to be checked.
+   * @return {Boolean} true if the email address is defined in the specified key
+   * @inner
+   */
+  function idCheck(id, key) {
+    var keyids = key.getKeyIds();
+    for (var i = 0; i < keyids.length; i++) {
+      if (openpgp.util.hexstrdump(keyids[i].write()) == id) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * searches all public keys in the keyring matching the address or address part of the user ids
+   * @param {Array<module:key~Key>} keys array of keys to search
+   * @param {module:keyring/keyring.checkCallback} identityFunction callback function which checks for a match
+   * @param {String} identityInput input to check against
+   * @param {module:enums.packet} keyType packet types of keys to check
+   * @return {Array<module:key~Key>} array of keys which match
+   */
+  function checkForIdentityAndKeyTypeMatch(keys, identityFunction, identityInput, keyType) {
+    var results = [];
+    for (var p = 0; p < keys.length; p++) {
+      var key = keys[p];
+      switch (keyType) {
+        case openpgp.enums.packet.public_key:
+          if (key.isPublic() && identityFunction(identityInput, key)) {
+            results.push(key);
+          }
+          break;
+        case openpgp.enums.packet.private_key:
+          if (key.isPrivate() && identityFunction(identityInput, key)) {
+            results.push(key);
+          }
+          break;
+      }
+    }
+    return results;
+  }
+
+  /**
+   * searches all public keys in the keyring matching the address or address part of the user ids
+   * @param {String} email email address to search for
+   * @return {Array<module:key~Key>} The public keys associated with provided email address.
+   */
+  this.getPublicKeyForAddress = function (email) {
+    return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, openpgp.enums.packet.public_key);
+  };
+
+  /**
+   * Searches the keyring for a private key containing the specified email address
+   * @param {String} email email address to search for
+   * @return {Array<module:key~Key>} private keys found
+   */
+  this.getPrivateKeyForAddress = function (email) {
+    return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, openpgp.enums.packet.secret_key);
+  };
+
+  /**
+   * Searches the keyring for public keys having the specified key id
+   * @param {String} keyId provided as string of hex number (lowercase)
+   * @return {Array<module:key~Key>} public keys found
+   */
+  this.getKeysForKeyId = function (keyId) {
+    return checkForIdentityAndKeyTypeMatch(this.keys, idCheck, keyId, openpgp.enums.packet.public_key);
+  };
+
+  /**
+   * Imports a key from an ascii armored message
+   * @param {String} armored message to read the keys/key from
+   */
+  this.importKey = function (armored) {
+    this.keys = this.keys.concat(openpgp.key.readArmored(armored).keys);
+
+    return true;
+  };
+
+  /**
+   * returns the armored message representation of the key at key ring index
+   * @param {Integer} index the index of the key within the array
+   * @return {String} armored message representing the key object
+   */
+  this.exportKey = function (index) {
+    return this.keys[index].armor();
+  };
+
+  /**
+   * Removes a public key from the public key keyring at the specified index
+   * @param {Integer} index the index of the public key within the publicKeys array
+   * @return {module:key~Key} The public key object which has been removed
+   */
+  this.removeKey = function (index) {
+    var removed = this.keys.splice(index, 1);
+
+    return removed;
+  };
+
+  /**
+   * returns the armored message representation of the public key portion of the key at key ring index
+   * @param {Integer} index the index of the key within the array
+   * @return {String} armored message representing the public key object
+   */
+  this.exportPublicKey = function (index) {
+    return this.keys[index].toPublic().armor();
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/literal.html b/doc/literal.html new file mode 100644 index 00000000..70fe457c --- /dev/null +++ b/doc/literal.html @@ -0,0 +1,975 @@ + + + + + JSDoc: Module: packet/literal + + + + + + + + + + +
+ +

Module: packet/literal

+ + + + + +
+ +
+

+ packet/literal +

+ +
+ +
+
+ + +
Implementation of the Literal Data Packet (Tag 11)
+
+RFC4880 5.9: A Literal Data packet contains the body of a message; data that +is not to be further interpreted.
+ + +
+

new (require("packet/literal"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

getBytes() → {String}

+ + +
+
+ + +
+ Get the byte sequence representing the literal packet data +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A sequence of bytes +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getText() → {String}

+ + +
+
+ + +
+ Returns literal data packets as native JavaScript string +with normalized end of line to \n +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ literal data as text +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(input, position, len) → {module:packet/literal}

+ + +
+
+ + +
+ Parsing function for a literal data packet (tag 11). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Payload of a tag 11 packet
position + + +Integer + + + + Position to start reading from the input string
len + + +Integer + + + + Length of the packet or the remaining length of + input at position
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ object representation +
+ + + +
+
+ Type +
+
+ +module:packet/literal + + +
+
+ + + + +
+ + + +
+

setBytes(bytes, format)

+ + +
+
+ + +
+ Set the packet data to value represented by the provided string of bytes. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bytes + + +String + + + + The string of bytes
format + + +utf8 +| + +binary +| + +text + + + + The format of the string of bytes
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

setText(text)

+ + +
+
+ + +
+ Set the packet data to a javascript native string, end of line +will be normalized to \r\n and by default text is converted to UTF8 +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + Any native javascript string
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

write(data) → {String}

+ + +
+
+ + +
+ Creates a string representation of the packet +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +String + + + + The data to be inserted as body
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ string-representation of the packet +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/literal.js.html b/doc/literal.js.html new file mode 100644 index 00000000..9fd3c59a --- /dev/null +++ b/doc/literal.js.html @@ -0,0 +1,179 @@ + + + + + JSDoc: Source: packet/literal.js + + + + + + + + + + +
+ +

Source: packet/literal.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the Literal Data Packet (Tag 11)<br/>
+ * <br/>
+ * RFC4880 5.9: A Literal Data packet contains the body of a message; data that
+ * is not to be further interpreted.
+ * @requires enums
+ * @requires util
+ * @module packet/literal
+ */
+
+var util = require('../util'),
+  enums = require('../enums.js');
+
+/**
+ * @constructor
+ */
+module.exports = function literal() {
+  this.format = 'utf8'; // default format for literal data packets
+  this.data = ''; // literal data representation as native JavaScript string or bytes
+  this.date = new Date();
+
+
+  /**
+   * Set the packet data to a javascript native string, end of line 
+   * will be normalized to \r\n and by default text is converted to UTF8
+   * @param {String} text Any native javascript string
+   */
+  this.setText = function (text) {
+    // normalize EOL to \r\n
+    text = text.replace(/\r/g, '').replace(/\n/g, '\r\n');
+    // encode UTF8
+    this.data = this.format == 'utf8' ? util.encode_utf8(text) : text;
+  }
+
+  /**
+   * Returns literal data packets as native JavaScript string
+   * with normalized end of line to \n
+   * @return {String} literal data as text
+   */
+  this.getText = function () {
+    // decode UTF8
+    var text = util.decode_utf8(this.data);
+    // normalize EOL to \n
+    return text.replace(/\r\n/g, '\n');
+  }
+
+  /**
+   * Set the packet data to value represented by the provided string of bytes.
+   * @param {String} bytes The string of bytes
+   * @param {utf8|binary|text} format The format of the string of bytes
+   */
+  this.setBytes = function (bytes, format) {
+    this.format = format;
+    this.data = bytes;
+  }
+
+
+  /**
+   * Get the byte sequence representing the literal packet data
+   * @returns {String} A sequence of bytes
+   */
+  this.getBytes = function () {
+    return this.data;
+  }
+
+
+  /**
+   * Parsing function for a literal data packet (tag 11).
+   * 
+   * @param {String} input Payload of a tag 11 packet
+   * @param {Integer} position
+   *            Position to start reading from the input string
+   * @param {Integer} len
+   *            Length of the packet or the remaining length of
+   *            input at position
+   * @return {module:packet/literal} object representation
+   */
+  this.read = function (bytes) {
+    // - A one-octet field that describes how the data is formatted.
+
+    var format = enums.read(enums.literal, bytes.charCodeAt(0));
+
+    var filename_len = bytes.charCodeAt(1);
+    this.filename = util.decode_utf8(bytes.substr(2, filename_len));
+
+    this.date = util.readDate(bytes.substr(2 + filename_len, 4));
+
+    var data = bytes.substring(6 + filename_len);
+
+    this.setBytes(data, format);
+  }
+
+  /**
+   * Creates a string representation of the packet
+   * 
+   * @param {String} data The data to be inserted as body
+   * @return {String} string-representation of the packet
+   */
+  this.write = function () {
+    var filename = util.encode_utf8("msg.txt");
+
+    var data = this.getBytes();
+
+    var result = '';
+    result += String.fromCharCode(enums.write(enums.literal, this.format));
+    result += String.fromCharCode(filename.length);
+    result += filename;
+    result += util.writeDate(this.date);
+    result += data;
+    return result;
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/localStorage.html b/doc/localStorage.html new file mode 100644 index 00000000..a66d2ac9 --- /dev/null +++ b/doc/localStorage.html @@ -0,0 +1,332 @@ + + + + + JSDoc: Module: config/localStorage + + + + + + + + + + +
+ +

Module: config/localStorage

+ + + + + +
+ +
+

+ config/localStorage +

+ +
+ +
+
+ + +
This object storing and retrieving configuration from HTML5 local storage.
+ + +
+

new (require("config/localStorage"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

read()

+ + +
+
+ + +
+ Reads the config out of the HTML5 local storage +and initializes the object config. +if config is null the default config will be used +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

write()

+ + +
+
+ + +
+ Writes the config to HTML5 local storage +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/localStorage.js.html b/doc/localStorage.js.html new file mode 100644 index 00000000..b5df0561 --- /dev/null +++ b/doc/localStorage.js.html @@ -0,0 +1,81 @@ + + + + + JSDoc: Source: config/localStorage.js + + + + + + + + + + +
+ +

Source: config/localStorage.js

+ + + + + +
+
+
/**
+ * This object storing and retrieving configuration from HTML5 local storage.
+ * @module config/localStorage
+ */
+
+/**
+ * @constructor
+ */
+module.exports = function localStorage() {
+
+  /**
+   * Reads the config out of the HTML5 local storage
+   * and initializes the object config.
+   * if config is null the default config will be used
+   */
+  this.read = function () {
+    var cf = JSON.parse(window.localStorage.getItem("config"));
+    if (cf === null) {
+      this.config = this.default_config;
+      this.write();
+    } else
+      this.config = cf;
+  }
+
+  /**
+   * Writes the config to HTML5 local storage
+   */
+  this.write = function () {
+    window.localStorage.setItem("config", JSON.stringify(this.config));
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/localstore.html b/doc/localstore.html new file mode 100644 index 00000000..c41a639e --- /dev/null +++ b/doc/localstore.html @@ -0,0 +1,341 @@ + + + + + JSDoc: Module: keyring/localstore + + + + + + + + + + +
+ +

Module: keyring/localstore

+ + + + + +
+ +
+

+ keyring/localstore +

+ +
+ +
+
+ + + + +
The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

<static> load() → {Array.<module:key~Key>}

+ + +
+
+ + +
+ Load the keyring from HTML5 local storage and initializes this instance. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ array of keys retrieved from localstore +
+ + + +
+
+ Type +
+
+ +Array.<module:key~Key> + + +
+
+ + + + +
+ + + +
+

<static> store(keys)

+ + +
+
+ + +
+ Saves the current state of the keyring to HTML5 local storage. +The privateKeys array and publicKeys array gets Stringified using JSON +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keys + + +Array.<module:key~Key> + + + + array of keys to save in localstore
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/localstore.js.html b/doc/localstore.js.html new file mode 100644 index 00000000..e2f1a9be --- /dev/null +++ b/doc/localstore.js.html @@ -0,0 +1,106 @@ + + + + + JSDoc: Source: keyring/localstore.js + + + + + + + + + + +
+ +

Source: keyring/localstore.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
+ * @requires openpgp
+ * @module keyring/localstore
+ */
+
+var openpgp = require('openpgp');
+
+module.exports = function () {
+  /**
+   * Load the keyring from HTML5 local storage and initializes this instance.
+   * @return {Array<module:key~Key>} array of keys retrieved from localstore
+   */
+  this.load = function () {
+    var armoredKeys = JSON.parse(window.localStorage.getItem("armoredKeys"));
+    var keys = [];
+    if (armoredKeys !== null && armoredKeys.length !== 0) {
+      var key;
+      for (var i = 0; i < armoredKeys.length; i++) {
+        key = openpgp.key.readArmored(armoredKeys[i]);
+        keys.push(key);
+      }
+    }
+    return keys;
+  }
+
+  /**
+   * Saves the current state of the keyring to HTML5 local storage.
+   * The privateKeys array and publicKeys array gets Stringified using JSON
+   * @param {Array<module:key~Key>} keys array of keys to save in localstore
+   */
+  this.store = function (keys) {
+    var armoredKeys = [];
+    for (var i = 0; i < keys.length; i++) {
+      armoredKeys.push(keys[i].armor());
+    }
+    window.localStorage.setItem("armoredKeys", JSON.stringify(armoredKeys));
+  }
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/marker.html b/doc/marker.html new file mode 100644 index 00000000..de21e0d9 --- /dev/null +++ b/doc/marker.html @@ -0,0 +1,385 @@ + + + + + JSDoc: Module: packet/marker + + + + + + + + + + +
+ +

Module: packet/marker

+ + + + + +
+ +
+

+ packet/marker +

+ +
+ +
+
+ + +
Implementation of the strange "Marker packet" (Tag 10)
+
+RFC4880 5.8: An experimental version of PGP used this packet as the Literal +packet, but no released version of PGP generated Literal packets with this +tag. With PGP 5.x, this packet has been reassigned and is reserved for use as +the Marker packet.
+
+Such a packet MUST be ignored when received.
+ + +
+

new (require("packet/marker"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

read(input, position, len) → {module:packet/marker}

+ + +
+
+ + +
+ Parsing function for a literal data packet (tag 10). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Payload of a tag 10 packet
position + + +Integer + + + + Position to start reading from the input string
len + + +Integer + + + + Length of the packet or the remaining length of + input at position
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Object representation +
+ + + +
+
+ Type +
+
+ +module:packet/marker + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/marker.js.html b/doc/marker.js.html new file mode 100644 index 00000000..0d7d8d83 --- /dev/null +++ b/doc/marker.js.html @@ -0,0 +1,104 @@ + + + + + JSDoc: Source: packet/marker.js + + + + + + + + + + +
+ +

Source: packet/marker.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+/**
+ * Implementation of the strange "Marker packet" (Tag 10)<br/>
+ * <br/>
+ * RFC4880 5.8: An experimental version of PGP used this packet as the Literal
+ * packet, but no released version of PGP generated Literal packets with this
+ * tag. With PGP 5.x, this packet has been reassigned and is reserved for use as
+ * the Marker packet.<br/>
+ * <br/>
+ * Such a packet MUST be ignored when received.
+ * @module packet/marker
+ */
+
+/**
+ * @constructor
+ */
+module.exports = function marker() {
+  /**
+   * Parsing function for a literal data packet (tag 10).
+   * 
+   * @param {String} input Payload of a tag 10 packet
+   * @param {Integer} position
+   *            Position to start reading from the input string
+   * @param {Integer} len
+   *            Length of the packet or the remaining length of
+   *            input at position
+   * @return {module:packet/marker} Object representation
+   */
+  this.read = function (bytes) {
+    if (bytes.charCodeAt(0) == 0x50 && // P
+    bytes.charCodeAt(1) == 0x47 && // G
+    bytes.charCodeAt(2) == 0x50) // P
+      return true;
+    // marker packet does not contain "PGP"
+    return false;
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/md5.html b/doc/md5.html new file mode 100644 index 00000000..8c77e0ef --- /dev/null +++ b/doc/md5.html @@ -0,0 +1,244 @@ + + + + + JSDoc: Module: crypto/hash/md5 + + + + + + + + + + +
+ +

Module: crypto/hash/md5

+ + + + + +
+ +
+

+ crypto/hash/md5 +

+ +
+ +
+
+ + + +
+

require("crypto/hash/md5")(entree)

+ + +
+
+ + +
+ MD5 hash +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
entree + + +String + + + + string to hash
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/md5.js.html b/doc/md5.js.html index b9fc7228..596d8779 100644 --- a/doc/md5.js.html +++ b/doc/md5.js.html @@ -2,7 +2,7 @@ - JSDoc: Source: ciphers/hash/md5.js + JSDoc: Source: crypto/hash/md5.js @@ -17,7 +17,7 @@
-

Source: ciphers/hash/md5.js

+

Source: crypto/hash/md5.js

@@ -39,130 +39,145 @@ * warranty of any kind. */ -function MD5(entree) { - var hex = md5(entree); - var bin = util.hex2bin(hex); - return bin; +/** + * @requires util + * @module crypto/hash/md5 + */ + +var util = require('../../util'); + +/** + * MD5 hash + * @param {String} entree string to hash + */ +module.exports = function (entree) { + var hex = md5(entree); + var bin = util.hex2bin(hex); + return bin; } function md5cycle(x, k) { -var a = x[0], b = x[1], c = x[2], d = x[3]; + var a = x[0], + b = x[1], + c = x[2], + d = x[3]; -a = ff(a, b, c, d, k[0], 7, -680876936); -d = ff(d, a, b, c, k[1], 12, -389564586); -c = ff(c, d, a, b, k[2], 17, 606105819); -b = ff(b, c, d, a, k[3], 22, -1044525330); -a = ff(a, b, c, d, k[4], 7, -176418897); -d = ff(d, a, b, c, k[5], 12, 1200080426); -c = ff(c, d, a, b, k[6], 17, -1473231341); -b = ff(b, c, d, a, k[7], 22, -45705983); -a = ff(a, b, c, d, k[8], 7, 1770035416); -d = ff(d, a, b, c, k[9], 12, -1958414417); -c = ff(c, d, a, b, k[10], 17, -42063); -b = ff(b, c, d, a, k[11], 22, -1990404162); -a = ff(a, b, c, d, k[12], 7, 1804603682); -d = ff(d, a, b, c, k[13], 12, -40341101); -c = ff(c, d, a, b, k[14], 17, -1502002290); -b = ff(b, c, d, a, k[15], 22, 1236535329); + a = ff(a, b, c, d, k[0], 7, -680876936); + d = ff(d, a, b, c, k[1], 12, -389564586); + c = ff(c, d, a, b, k[2], 17, 606105819); + b = ff(b, c, d, a, k[3], 22, -1044525330); + a = ff(a, b, c, d, k[4], 7, -176418897); + d = ff(d, a, b, c, k[5], 12, 1200080426); + c = ff(c, d, a, b, k[6], 17, -1473231341); + b = ff(b, c, d, a, k[7], 22, -45705983); + a = ff(a, b, c, d, k[8], 7, 1770035416); + d = ff(d, a, b, c, k[9], 12, -1958414417); + c = ff(c, d, a, b, k[10], 17, -42063); + b = ff(b, c, d, a, k[11], 22, -1990404162); + a = ff(a, b, c, d, k[12], 7, 1804603682); + d = ff(d, a, b, c, k[13], 12, -40341101); + c = ff(c, d, a, b, k[14], 17, -1502002290); + b = ff(b, c, d, a, k[15], 22, 1236535329); -a = gg(a, b, c, d, k[1], 5, -165796510); -d = gg(d, a, b, c, k[6], 9, -1069501632); -c = gg(c, d, a, b, k[11], 14, 643717713); -b = gg(b, c, d, a, k[0], 20, -373897302); -a = gg(a, b, c, d, k[5], 5, -701558691); -d = gg(d, a, b, c, k[10], 9, 38016083); -c = gg(c, d, a, b, k[15], 14, -660478335); -b = gg(b, c, d, a, k[4], 20, -405537848); -a = gg(a, b, c, d, k[9], 5, 568446438); -d = gg(d, a, b, c, k[14], 9, -1019803690); -c = gg(c, d, a, b, k[3], 14, -187363961); -b = gg(b, c, d, a, k[8], 20, 1163531501); -a = gg(a, b, c, d, k[13], 5, -1444681467); -d = gg(d, a, b, c, k[2], 9, -51403784); -c = gg(c, d, a, b, k[7], 14, 1735328473); -b = gg(b, c, d, a, k[12], 20, -1926607734); + a = gg(a, b, c, d, k[1], 5, -165796510); + d = gg(d, a, b, c, k[6], 9, -1069501632); + c = gg(c, d, a, b, k[11], 14, 643717713); + b = gg(b, c, d, a, k[0], 20, -373897302); + a = gg(a, b, c, d, k[5], 5, -701558691); + d = gg(d, a, b, c, k[10], 9, 38016083); + c = gg(c, d, a, b, k[15], 14, -660478335); + b = gg(b, c, d, a, k[4], 20, -405537848); + a = gg(a, b, c, d, k[9], 5, 568446438); + d = gg(d, a, b, c, k[14], 9, -1019803690); + c = gg(c, d, a, b, k[3], 14, -187363961); + b = gg(b, c, d, a, k[8], 20, 1163531501); + a = gg(a, b, c, d, k[13], 5, -1444681467); + d = gg(d, a, b, c, k[2], 9, -51403784); + c = gg(c, d, a, b, k[7], 14, 1735328473); + b = gg(b, c, d, a, k[12], 20, -1926607734); -a = hh(a, b, c, d, k[5], 4, -378558); -d = hh(d, a, b, c, k[8], 11, -2022574463); -c = hh(c, d, a, b, k[11], 16, 1839030562); -b = hh(b, c, d, a, k[14], 23, -35309556); -a = hh(a, b, c, d, k[1], 4, -1530992060); -d = hh(d, a, b, c, k[4], 11, 1272893353); -c = hh(c, d, a, b, k[7], 16, -155497632); -b = hh(b, c, d, a, k[10], 23, -1094730640); -a = hh(a, b, c, d, k[13], 4, 681279174); -d = hh(d, a, b, c, k[0], 11, -358537222); -c = hh(c, d, a, b, k[3], 16, -722521979); -b = hh(b, c, d, a, k[6], 23, 76029189); -a = hh(a, b, c, d, k[9], 4, -640364487); -d = hh(d, a, b, c, k[12], 11, -421815835); -c = hh(c, d, a, b, k[15], 16, 530742520); -b = hh(b, c, d, a, k[2], 23, -995338651); + a = hh(a, b, c, d, k[5], 4, -378558); + d = hh(d, a, b, c, k[8], 11, -2022574463); + c = hh(c, d, a, b, k[11], 16, 1839030562); + b = hh(b, c, d, a, k[14], 23, -35309556); + a = hh(a, b, c, d, k[1], 4, -1530992060); + d = hh(d, a, b, c, k[4], 11, 1272893353); + c = hh(c, d, a, b, k[7], 16, -155497632); + b = hh(b, c, d, a, k[10], 23, -1094730640); + a = hh(a, b, c, d, k[13], 4, 681279174); + d = hh(d, a, b, c, k[0], 11, -358537222); + c = hh(c, d, a, b, k[3], 16, -722521979); + b = hh(b, c, d, a, k[6], 23, 76029189); + a = hh(a, b, c, d, k[9], 4, -640364487); + d = hh(d, a, b, c, k[12], 11, -421815835); + c = hh(c, d, a, b, k[15], 16, 530742520); + b = hh(b, c, d, a, k[2], 23, -995338651); -a = ii(a, b, c, d, k[0], 6, -198630844); -d = ii(d, a, b, c, k[7], 10, 1126891415); -c = ii(c, d, a, b, k[14], 15, -1416354905); -b = ii(b, c, d, a, k[5], 21, -57434055); -a = ii(a, b, c, d, k[12], 6, 1700485571); -d = ii(d, a, b, c, k[3], 10, -1894986606); -c = ii(c, d, a, b, k[10], 15, -1051523); -b = ii(b, c, d, a, k[1], 21, -2054922799); -a = ii(a, b, c, d, k[8], 6, 1873313359); -d = ii(d, a, b, c, k[15], 10, -30611744); -c = ii(c, d, a, b, k[6], 15, -1560198380); -b = ii(b, c, d, a, k[13], 21, 1309151649); -a = ii(a, b, c, d, k[4], 6, -145523070); -d = ii(d, a, b, c, k[11], 10, -1120210379); -c = ii(c, d, a, b, k[2], 15, 718787259); -b = ii(b, c, d, a, k[9], 21, -343485551); + a = ii(a, b, c, d, k[0], 6, -198630844); + d = ii(d, a, b, c, k[7], 10, 1126891415); + c = ii(c, d, a, b, k[14], 15, -1416354905); + b = ii(b, c, d, a, k[5], 21, -57434055); + a = ii(a, b, c, d, k[12], 6, 1700485571); + d = ii(d, a, b, c, k[3], 10, -1894986606); + c = ii(c, d, a, b, k[10], 15, -1051523); + b = ii(b, c, d, a, k[1], 21, -2054922799); + a = ii(a, b, c, d, k[8], 6, 1873313359); + d = ii(d, a, b, c, k[15], 10, -30611744); + c = ii(c, d, a, b, k[6], 15, -1560198380); + b = ii(b, c, d, a, k[13], 21, 1309151649); + a = ii(a, b, c, d, k[4], 6, -145523070); + d = ii(d, a, b, c, k[11], 10, -1120210379); + c = ii(c, d, a, b, k[2], 15, 718787259); + b = ii(b, c, d, a, k[9], 21, -343485551); -x[0] = add32(a, x[0]); -x[1] = add32(b, x[1]); -x[2] = add32(c, x[2]); -x[3] = add32(d, x[3]); + x[0] = add32(a, x[0]); + x[1] = add32(b, x[1]); + x[2] = add32(c, x[2]); + x[3] = add32(d, x[3]); } function cmn(q, a, b, x, s, t) { -a = add32(add32(a, q), add32(x, t)); -return add32((a << s) | (a >>> (32 - s)), b); + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); } function ff(a, b, c, d, x, s, t) { -return cmn((b & c) | ((~b) & d), a, b, x, s, t); + return cmn((b & c) | ((~b) & d), a, b, x, s, t); } function gg(a, b, c, d, x, s, t) { -return cmn((b & d) | (c & (~d)), a, b, x, s, t); + return cmn((b & d) | (c & (~d)), a, b, x, s, t); } function hh(a, b, c, d, x, s, t) { -return cmn(b ^ c ^ d, a, b, x, s, t); + return cmn(b ^ c ^ d, a, b, x, s, t); } function ii(a, b, c, d, x, s, t) { -return cmn(c ^ (b | (~d)), a, b, x, s, t); + return cmn(c ^ (b | (~d)), a, b, x, s, t); } function md51(s) { -txt = ''; -var n = s.length, -state = [1732584193, -271733879, -1732584194, 271733878], i; -for (i=64; i<=s.length; i+=64) { -md5cycle(state, md5blk(s.substring(i-64, i))); -} -s = s.substring(i-64); -var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; -for (i=0; i<s.length; i++) -tail[i>>2] |= s.charCodeAt(i) << ((i%4) << 3); -tail[i>>2] |= 0x80 << ((i%4) << 3); -if (i > 55) { -md5cycle(state, tail); -for (i=0; i<16; i++) tail[i] = 0; -} -tail[14] = n*8; -md5cycle(state, tail); -return state; + txt = ''; + var n = s.length, + state = [1732584193, -271733879, -1732584194, 271733878], + i; + for (i = 64; i <= s.length; i += 64) { + md5cycle(state, md5blk(s.substring(i - 64, i))); + } + s = s.substring(i - 64); + var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < s.length; i++) + tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3); + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i++) tail[i] = 0; + } + tail[14] = n * 8; + md5cycle(state, tail); + return state; } /* there needs to be support for Unicode here, @@ -181,35 +196,33 @@ return state; * 8-bit unsigned value arrays. */ function md5blk(s) { /* I figured global was faster. */ -var md5blks = [], i; /* Andy King said do it this way. */ -for (i=0; i<64; i+=4) { -md5blks[i>>2] = s.charCodeAt(i) -+ (s.charCodeAt(i+1) << 8) -+ (s.charCodeAt(i+2) << 16) -+ (s.charCodeAt(i+3) << 24); -} -return md5blks; + var md5blks = [], + i; /* Andy King said do it this way. */ + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << + 24); + } + return md5blks; } var hex_chr = '0123456789abcdef'.split(''); -function rhex(n) -{ -var s='', j=0; -for(; j<4; j++) -s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] -+ hex_chr[(n >> (j * 8)) & 0x0F]; -return s; +function rhex(n) { + var s = '', + j = 0; + for (; j < 4; j++) + s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F]; + return s; } function hex(x) { -for (var i=0; i<x.length; i++) -x[i] = rhex(x[i]); -return x.join(''); + for (var i = 0; i < x.length; i++) + x[i] = rhex(x[i]); + return x.join(''); } function md5(s) { -return hex(md51(s)); + return hex(md51(s)); } /* this function is much faster, @@ -219,15 +232,15 @@ need the idiotic second function, generated by an if clause. */ function add32(a, b) { -return (a + b) & 0xFFFFFFFF; + return (a + b) & 0xFFFFFFFF; } if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') { -function add32(x, y) { -var lsw = (x & 0xFFFF) + (y & 0xFFFF), -msw = (x >> 16) + (y >> 16) + (lsw >> 16); -return (msw << 16) | (lsw & 0xFFFF); -} + function add32(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } } @@ -239,15 +252,16 @@ return (msw << 16) | (lsw & 0xFFFF);

- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) + Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST)
+ diff --git a/doc/message.js.html b/doc/message.js.html new file mode 100644 index 00000000..8dd189e3 --- /dev/null +++ b/doc/message.js.html @@ -0,0 +1,366 @@ + + + + + JSDoc: Source: message.js + + + + + + + + + + +
+ +

Source: message.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @requires config
+ * @requires crypto
+ * @requires encoding/armor
+ * @requires enums
+ * @requires packet
+ * @module message
+ */
+
+var packet = require('./packet'),
+  enums = require('./enums.js'),
+  armor = require('./encoding/armor.js'),
+  config = require('./config'),
+  crypto = require('./crypto');
+
+/**
+ * @class
+ * @classdesc Class that represents an OpenPGP message.
+ * Can be an encrypted message, signed message, compressed message or literal message
+ * @param  {module:packet/packetlist} packetlist The packets that form this message
+ * See http://tools.ietf.org/html/rfc4880#section-11.3
+ */
+
+function Message(packetlist) {
+  if (!(this instanceof Message)) {
+    return new Message(packetlist);
+  }
+  this.packets = packetlist || new packet.list();
+}
+
+/**
+ * Returns the key IDs of the keys to which the session key is encrypted
+ * @return {Array<module:type/keyid>} array of keyid objects
+ */
+Message.prototype.getEncryptionKeyIds = function() {
+  var keyIds = [];
+  var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
+  pkESKeyPacketlist.forEach(function(packet) {
+    keyIds.push(packet.publicKeyId);
+  });
+  return keyIds;
+};
+
+/**
+ * Returns the key IDs of the keys that signed the message
+ * @return {Array<module:type/keyid>} array of keyid objects
+ */
+Message.prototype.getSigningKeyIds = function() {
+  var keyIds = [];
+  var msg = this.unwrapCompressed();
+  // search for one pass signatures
+  var onePassSigList = msg.packets.filterByTag(enums.packet.one_pass_signature);
+  onePassSigList.forEach(function(packet) {
+    keyIds.push(packet.signingKeyId);
+  });
+  // if nothing found look for signature packets
+  if (!keyIds.length) {
+    var signatureList = msg.packets.filterByTag(enums.packet.signature);
+    signatureList.forEach(function(packet) {
+      keyIds.push(packet.issuerKeyId);
+    });
+  }
+  return keyIds;
+};
+
+/**
+ * Decrypt the message
+ * @param {module:key~Key} privateKey private key with decrypted secret data           
+ * @return {Array<module:message~Message>} new message with decrypted content
+ */
+Message.prototype.decrypt = function(privateKey) {
+  var encryptionKeyIds = this.getEncryptionKeyIds();
+  if (!encryptionKeyIds.length) {
+    // nothing to decrypt return unmodified message
+    return this;
+  }
+  var privateKeyPacket = privateKey.getPrivateKeyPacket(encryptionKeyIds);
+  if (!privateKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
+  var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
+  var pkESKeyPacket;
+  for (var i = 0; i < pkESKeyPacketlist.length; i++) {
+    if (pkESKeyPacketlist[i].publicKeyId.equals(privateKeyPacket.getKeyId())) {
+      pkESKeyPacket = pkESKeyPacketlist[i];
+      pkESKeyPacket.decrypt(privateKeyPacket);
+      break;
+    }
+  }
+  if (pkESKeyPacket) {
+    var symEncryptedPacketlist = this.packets.filterByTag(enums.packet.symmetrically_encrypted, enums.packet.sym_encrypted_integrity_protected);
+    if (symEncryptedPacketlist.length !== 0) {
+      var symEncryptedPacket = symEncryptedPacketlist[0];
+      symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey);
+      return new Message(symEncryptedPacket.packets);
+    }
+  }
+};
+
+/**
+ * Get literal data that is the body of the message
+ * @return {(String|null)} literal body of the message as string
+ */
+Message.prototype.getLiteralData = function() {
+  var literal = this.packets.findPacket(enums.packet.literal);
+  return literal && literal.data || null;
+};
+
+/**
+ * Get literal data as text
+ * @return {(String|null)} literal body of the message interpreted as text
+ */
+Message.prototype.getText = function() {
+  var literal = this.packets.findPacket(enums.packet.literal);
+  if (literal) {
+    return literal.getText();
+  } else {
+    return null;
+  }
+};
+
+/**
+ * Encrypt the message
+ * @param  {Array<module:key~Key>} keys array of keys, used to encrypt the message
+ * @return {Array<module:message~Message>} new message with encrypted content
+ */
+Message.prototype.encrypt = function(keys) {
+  var packetlist = new packet.list();
+  //TODO get preferred algo from signature
+  var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, config.encryption_cipher));
+  keys.forEach(function(key) {
+    var encryptionKeyPacket = key.getEncryptionKeyPacket();
+    if (encryptionKeyPacket) {
+      var pkESKeyPacket = new packet.public_key_encrypted_session_key();
+      pkESKeyPacket.publicKeyId = encryptionKeyPacket.getKeyId();
+      pkESKeyPacket.publicKeyAlgorithm = encryptionKeyPacket.algorithm;
+      pkESKeyPacket.sessionKey = sessionKey;
+      //TODO get preferred algo from signature
+      pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, config.encryption_cipher);
+      pkESKeyPacket.encrypt(encryptionKeyPacket);
+      packetlist.push(pkESKeyPacket);
+    } else {
+      throw new Error('Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex());
+    }
+  });
+  var symEncryptedPacket;
+  if (config.integrity_protect) {
+    symEncryptedPacket = new packet.sym_encrypted_integrity_protected();
+  } else {
+    symEncryptedPacket = new packet.symmetrically_encrypted();
+  }
+  symEncryptedPacket.packets = this.packets;
+  //TODO get preferred algo from signature
+  symEncryptedPacket.encrypt(enums.read(enums.symmetric, config.encryption_cipher), sessionKey);
+  packetlist.push(symEncryptedPacket);
+  return new Message(packetlist);
+};
+
+/**
+ * Sign the message (the literal data packet of the message)
+ * @param  {Array<module:key~Key>} privateKey private keys with decrypted secret key data for signing
+ * @return {module:message~Message}      new message with signed content
+ */
+Message.prototype.sign = function(privateKeys) {
+
+  var packetlist = new packet.list();
+
+  var literalDataPacket = this.packets.findPacket(enums.packet.literal);
+  if (!literalDataPacket) throw new Error('No literal data packet to sign.');
+  
+  var literalFormat = enums.write(enums.literal, literalDataPacket.format);
+  var signatureType = literalFormat == enums.literal.binary 
+                      ? enums.signature.binary : enums.signature.text; 
+  
+  for (var i = 0; i < privateKeys.length; i++) {
+    var onePassSig = new packet.one_pass_signature();
+    onePassSig.type = signatureType;
+    //TODO get preferred hashg algo from key signature
+    onePassSig.hashAlgorithm = config.prefer_hash_algorithm;
+    var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
+    if (!signingKeyPacket) {
+      throw new Error('Could not find valid key packet for signing in key ' + privateKeys[i].primaryKey.getKeyId().toHex());
+    }
+    onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm;
+    onePassSig.signingKeyId = signingKeyPacket.getKeyId();
+    packetlist.push(onePassSig);
+  }
+
+  packetlist.push(literalDataPacket);
+  
+  for (var i = privateKeys.length - 1; i >= 0; i--) {
+    var signaturePacket = new packet.signature();
+    signaturePacket.signatureType = signatureType;
+    signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
+    signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
+    if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
+    signaturePacket.sign(signingKeyPacket, literalDataPacket);
+    packetlist.push(signaturePacket);
+  }
+
+  return new Message(packetlist);
+};
+
+/**
+ * Verify message signatures
+ * @param {Array<module:key~Key>} publicKeys public keys to verify signatures
+ * @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
+ */
+Message.prototype.verify = function(publicKeys) {
+  var result = [];
+  var msg = this.unwrapCompressed();
+  var literalDataList = msg.packets.filterByTag(enums.packet.literal);
+  if (literalDataList.length !== 1) throw new Error('Can only verify message with one literal data packet.');
+  var signatureList = msg.packets.filterByTag(enums.packet.signature);
+  publicKeys.forEach(function(pubKey) {
+    for (var i = 0; i < signatureList.length; i++) {
+      var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]);
+      if (publicKeyPacket) {
+        var verifiedSig = {};
+        verifiedSig.keyid = signatureList[i].issuerKeyId;
+        verifiedSig.valid = signatureList[i].verify(publicKeyPacket, literalDataList[0]);
+        result.push(verifiedSig);
+        break;
+      }
+    }
+  });
+  return result;
+};
+
+/**
+ * Unwrap compressed message
+ * @return {module:message~Message} message Content of compressed message
+ */
+Message.prototype.unwrapCompressed = function() {
+  var compressed = this.packets.filterByTag(enums.packet.compressed);
+  if (compressed.length) {
+    return new Message(compressed[0].packets);
+  } else {
+    return this;
+  }
+};
+
+/**
+ * Returns ASCII armored text of message
+ * @return {String} ASCII armor
+ */
+Message.prototype.armor = function() {
+  return armor.encode(enums.armor.message, this.packets.write());
+};
+
+/**
+ * reads an OpenPGP armored message and returns a message object
+ * @param {String} armoredText text to be parsed
+ * @return {module:message~Message} new message object
+ * @static
+ */
+function readArmored(armoredText) {
+  //TODO how do we want to handle bad text? Exception throwing
+  //TODO don't accept non-message armored texts
+  var input = armor.decode(armoredText).data;
+  var packetlist = new packet.list();
+  packetlist.read(input);
+  var newMessage = new Message(packetlist);
+  return newMessage;
+}
+
+/**
+ * creates new message object from text
+ * @param {String} text
+ * @return {module:message~Message} new message object
+ * @static
+ */
+function fromText(text) {
+  var literalDataPacket = new packet.literal();
+  // text will be converted to UTF8
+  literalDataPacket.setText(text);
+  var literalDataPacketlist = new packet.list();
+  literalDataPacketlist.push(literalDataPacket);
+  var newMessage = new Message(literalDataPacketlist);
+  return newMessage;
+}
+
+/**
+ * creates new message object from binary data
+ * @param {String} bytes
+ * @return {module:message~Message} new message object
+ * @static
+ */
+function fromBinary(bytes) {
+  var literalDataPacket = new packet.literal();
+  literalDataPacket.setBytes(bytes, enums.read(enums.literal, enums.literal.binary));
+  var literalDataPacketlist = new packet.list();
+  literalDataPacketlist.push(literalDataPacket);
+  var newMessage = new Message(literalDataPacketlist);
+  return newMessage;
+}
+
+exports.Message = Message;
+exports.readArmored = readArmored;
+exports.fromText = fromText;
+exports.fromBinary = fromBinary;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/module-armor.html b/doc/module-armor.html new file mode 100644 index 00000000..d5816512 --- /dev/null +++ b/doc/module-armor.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Module: armor + + + + + + + + + + +
+ +

Module: armor

+ + + + + +
+ +
+

+ armor +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-cleartext-CleartextMessage.html b/doc/module-cleartext-CleartextMessage.html new file mode 100644 index 00000000..700e6030 --- /dev/null +++ b/doc/module-cleartext-CleartextMessage.html @@ -0,0 +1,756 @@ + + + + + JSDoc: Class: CleartextMessage + + + + + + + + + + +
+ +

Class: CleartextMessage

+ + + + + +
+ +
+

+ cleartext~ + + CleartextMessage +

+ +
Class that represents an OpenPGP cleartext signed message. +See http://tools.ietf.org/html/rfc4880#section-7
+ +
+ +
+
+ + + + +
+

new CleartextMessage(text, packetlist)

+ + +
+
+ + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + The cleartext of the signed message
packetlist + + +module:packet/packetlist + + + + The packetlist with signature packets or undefined + if message not yet signed
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

armor() → {String}

+ + +
+
+ + +
+ Returns ASCII armored text of cleartext signed message +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ ASCII armor +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getSigningKeyIds() → {Array.<module:type/keyid>}

+ + +
+
+ + +
+ Returns the key IDs of the keys that signed the cleartext message +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ array of keyid objects +
+ + + +
+
+ Type +
+
+ +Array.<module:type/keyid> + + +
+
+ + + + +
+ + + +
+

getText() → {String}

+ + +
+
+ + +
+ Get cleartext +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ cleartext of message +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

sign(privateKeys)

+ + +
+
+ + +
+ Sign the cleartext message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
privateKeys + + +Array.<module:key~Key> + + + + private keys with decrypted secret key data for signing
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

verify(publicKeys) → {Array.<{keyid: module:type/keyid, valid: Boolean}>}

+ + +
+
+ + +
+ Verify signatures of cleartext signed message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
publicKeys + + +Array.<module:key~Key> + + + + public keys to verify signatures
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ list of signer's keyid and validity of signature +
+ + + +
+
+ Type +
+
+ +Array.<{keyid: module:type/keyid, valid: Boolean}> + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-cleartext.html b/doc/module-cleartext.html new file mode 100644 index 00000000..8f66e4f8 --- /dev/null +++ b/doc/module-cleartext.html @@ -0,0 +1,282 @@ + + + + + JSDoc: Module: cleartext + + + + + + + + + + +
+ +

Module: cleartext

+ + + + + +
+ +
+

+ cleartext +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + +

Classes

+ +
+
CleartextMessage
+
+
+ + + + + + + +

Methods

+ +
+ +
+

<static> readArmored(armoredText) → {module:cleartext~CleartextMessage}

+ + +
+
+ + +
+ reads an OpenPGP cleartext signed message and returns a CleartextMessage object +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
armoredText + + +String + + + + text to be parsed
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new cleartext message object +
+ + + +
+
+ Type +
+
+ +module:cleartext~CleartextMessage + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-config.html b/doc/module-config.html new file mode 100644 index 00000000..c2381b1b --- /dev/null +++ b/doc/module-config.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Module: config + + + + + + + + + + +
+ +

Module: config

+ + + + + +
+ +
+

+ config +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-crypto.html b/doc/module-crypto.html new file mode 100644 index 00000000..39c1b5bf --- /dev/null +++ b/doc/module-crypto.html @@ -0,0 +1,530 @@ + + + + + JSDoc: Module: crypto + + + + + + + + + + +
+ +

Module: crypto

+ + + + + +
+ +
+

+ crypto +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + +
+ + + + + + + + + + + + +

Members

+ +
+ +
+

<static> cfb

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> cipher

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> hash

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> pkcs1

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> publicKey

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> random

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> signature

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ +
+ + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-enums.html b/doc/module-enums.html new file mode 100644 index 00000000..6d847f60 --- /dev/null +++ b/doc/module-enums.html @@ -0,0 +1,4542 @@ + + + + + JSDoc: Module: enums + + + + + + + + + + +
+ +

Module: enums

+ + + + + +
+ +
+

+ enums +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + +

Members

+ +
+ +
+

<static, readonly> armor :Integer

+ + +
+
+ +
+ Armor type +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
multipart_section + + +Integer + + + + + + 0 + +
multipart_last + + +Integer + + + + + + 1 + +
signed + + +Integer + + + + + + 2 + +
message + + +Integer + + + + + + 3 + +
public_key + + +Integer + + + + + + 4 + +
private_key + + +Integer + + + + + + 5 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> compression :Integer

+ + +
+
+ +
+ RFC4880, section 9.3 +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uncompressed + + +Integer + + + + + + 0 + +
zip + + +Integer + + + + + + 1 + + RFC1951
zlib + + +Integer + + + + + + 2 + + RFC1950
bzip2 + + +Integer + + + + + + 3 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> hash :Integer

+ + +
+
+ +
+ RFC4880, section 9.4 +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
md5 + + +Integer + + + + + + 1 + +
sha1 + + +Integer + + + + + + 2 + +
ripemd + + +Integer + + + + + + 3 + +
sha256 + + +Integer + + + + + + 8 + +
sha384 + + +Integer + + + + + + 9 + +
sha512 + + +Integer + + + + + + 10 + +
sha224 + + +Integer + + + + + + 11 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> keyFlags :Integer

+ + +
+
+ +
+ Key flags +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
certify_keys + + +Integer + + + + + + 1 + + 0x01 - This key may be used to certify other keys.
sign_data + + +Integer + + + + + + 2 + + 0x02 - This key may be used to sign data.
encrypt_communication + + +Integer + + + + + + 4 + + 0x04 - This key may be used to encrypt communications.
encrypt_storage + + +Integer + + + + + + 8 + + 0x08 - This key may be used to encrypt storage.
split_private_key + + +Integer + + + + + + 16 + + 0x10 - The private component of this key may have been split + by a secret-sharing mechanism.
authentication + + +Integer + + + + + + 32 + + 0x20 - This key may be used for authentication.
shared_private_key + + +Integer + + + + + + 128 + + 0x80 - The private component of this key may be in the + possession of more than one person.
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> keyStatus :Integer

+ + +
+
+ +
+ Key status +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
invalid + + +Integer + + + + + + 0 + +
expired + + +Integer + + + + + + 1 + +
revoked + + +Integer + + + + + + 2 + +
valid + + +Integer + + + + + + 3 + +
no_self_cert + + +Integer + + + + + + 4 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> literal :Integer

+ + +
+
+ +
+ Data types in the literal packet +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
binary + + +Integer + + + + + + CALL + + Binary data 'b'
text + + +Integer + + + + + + CALL + + Text data 't'
utf8 + + +Integer + + + + + + CALL + + Utf8 data 'u'
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> packet :Integer

+ + +
+
+ +
+ A list of packet types and numeric tags associated with them. +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
public_key_encrypted_session_key + + +Integer + + + + + + 1 + +
signature + + +Integer + + + + + + 2 + +
sym_encrypted_session_key + + +Integer + + + + + + 3 + +
one_pass_signature + + +Integer + + + + + + 4 + +
secret_key + + +Integer + + + + + + 5 + +
public_key + + +Integer + + + + + + 6 + +
secret_subkey + + +Integer + + + + + + 7 + +
compressed + + +Integer + + + + + + 8 + +
symmetrically_encrypted + + +Integer + + + + + + 9 + +
marker + + +Integer + + + + + + 10 + +
literal + + +Integer + + + + + + 11 + +
trust + + +Integer + + + + + + 12 + +
userid + + +Integer + + + + + + 13 + +
public_subkey + + +Integer + + + + + + 14 + +
user_attribute + + +Integer + + + + + + 17 + +
sym_encrypted_integrity_protected + + +Integer + + + + + + 18 + +
modification_detection_code + + +Integer + + + + + + 19 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> publicKey :Integer

+ + +
+
+ +
+ RFC4880, section 9.1 +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
rsa_encrypt_sign + + +Integer + + + + + + 1 + +
rsa_encrypt + + +Integer + + + + + + 2 + +
rsa_sign + + +Integer + + + + + + 3 + +
elgamal + + +Integer + + + + + + 16 + +
dsa + + +Integer + + + + + + 17 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> s2k :Integer

+ + +
+
+ +
+ A string to key specifier type +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
simple + + +Integer + + + + + + 0 + +
salted + + +Integer + + + + + + 1 + +
iterated + + +Integer + + + + + + 3 + +
gnu + + +Integer + + + + + + 101 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> signature :Integer

+ + +
+
+ +
+ One pass signature packet type +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
binary + + +Integer + + + + + + 0 + + 0x00: Signature of a binary document.
text + + +Integer + + + + + + 1 + + 0x01: Signature of a canonical text document.
+Canonicalyzing the document by converting line endings.
standalone + + +Integer + + + + + + 2 + + 0x02: Standalone signature.
+This signature is a signature of only its own subpacket contents. +It is calculated identically to a signature over a zero-lengh +binary document. Note that it doesn't make sense to have a V3 +standalone signature.
cert_generic + + +Integer + + + + + + 16 + + 0x10: Generic certification of a User ID and Public-Key packet.
+The issuer of this certification does not make any particular +assertion as to how well the certifier has checked that the owner +of the key is in fact the person described by the User ID.
cert_persona + + +Integer + + + + + + 17 + + 0x11: Persona certification of a User ID and Public-Key packet.
+The issuer of this certification has not done any verification of +the claim that the owner of this key is the User ID specified.
cert_casual + + +Integer + + + + + + 18 + + 0x12: Casual certification of a User ID and Public-Key packet.
+The issuer of this certification has done some casual +verification of the claim of identity.
cert_positive + + +Integer + + + + + + 19 + + 0x13: Positive certification of a User ID and Public-Key packet.
+The issuer of this certification has done substantial +verification of the claim of identity.
+
+Most OpenPGP implementations make their "key signatures" as 0x10 +certifications. Some implementations can issue 0x11-0x13 +certifications, but few differentiate between the types.
cert_revocation + + +Integer + + + + + + 48 + + 0x30: Certification revocation signature
+This signature revokes an earlier User ID certification signature +(signature class 0x10 through 0x13) or direct-key signature +(0x1F). It should be issued by the same key that issued the +revoked signature or an authorized revocation key. The signature +is computed over the same data as the certificate that it +revokes, and should have a later creation date than that +certificate.
subkey_binding + + +Integer + + + + + + 24 + + 0x18: Subkey Binding Signature
+This signature is a statement by the top-level signing key that +indicates that it owns the subkey. This signature is calculated +directly on the primary key and subkey, and not on any User ID or +other packets. A signature that binds a signing subkey MUST have +an Embedded Signature subpacket in this binding signature that +contains a 0x19 signature made by the signing subkey on the +primary key and subkey.
key_binding + + +Integer + + + + + + 25 + + 0x19: Primary Key Binding Signature
+This signature is a statement by a signing subkey, indicating +that it is owned by the primary key and subkey. This signature +is calculated the same way as a 0x18 signature: directly on the +primary key and subkey, and not on any User ID or other packets.
+
+When a signature is made over a key, the hash data starts with the +octet 0x99, followed by a two-octet length of the key, and then body +of the key packet. (Note that this is an old-style packet header for +a key packet with two-octet length.) A subkey binding signature +(type 0x18) or primary key binding signature (type 0x19) then hashes +the subkey using the same format as the main key (also using 0x99 as +the first octet).
key + + +Integer + + + + + + 31 + + 0x1F: Signature directly on a key
+This signature is calculated directly on a key. It binds the +information in the Signature subpackets to the key, and is +appropriate to be used for subpackets that provide information +about the key, such as the Revocation Key subpacket. It is also +appropriate for statements that non-self certifiers want to make +about the key itself, rather than the binding between a key and a +name.
key_revocation + + +Integer + + + + + + 32 + + 0x20: Key revocation signature
+The signature is calculated directly on the key being revoked. A +revoked key is not to be used. Only revocation signatures by the +key being revoked, or by an authorized revocation key, should be +considered valid revocation signatures.a
subkey_revocation + + +Integer + + + + + + 40 + + 0x28: Subkey revocation signature
+The signature is calculated directly on the subkey being revoked. +A revoked subkey is not to be used. Only revocation signatures +by the top-level signature key that is bound to this subkey, or +by an authorized revocation key, should be considered valid +revocation signatures.
+
+Key revocation signatures (types 0x20 and 0x28) +hash only the key being revoked.
timestamp + + +Integer + + + + + + 64 + + 0x40: Timestamp signature.
+This signature is only meaningful for the timestamp contained in +it.
third_party + + +Integer + + + + + + 80 + + 0x50: Third-Party Confirmation signature.
+This signature is a signature over some other OpenPGP Signature +packet(s). It is analogous to a notary seal on the signed data. +A third-party signature SHOULD include Signature Target +subpacket(s) to give easy identification. Note that we really do +mean SHOULD. There are plausible uses for this (such as a blind +party that only sees the signature, not the key or source +document) that cannot include a target subpacket.
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> signatureSubpacket :Integer

+ + +
+
+ +
+ Signature subpacket type +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
signature_creation_time + + +Integer + + + + + + 2 + +
signature_expiration_time + + +Integer + + + + + + 3 + +
exportable_certification + + +Integer + + + + + + 4 + +
trust_signature + + +Integer + + + + + + 5 + +
regular_expression + + +Integer + + + + + + 6 + +
revocable + + +Integer + + + + + + 7 + +
key_expiration_time + + +Integer + + + + + + 9 + +
placeholder_backwards_compatibility + + +Integer + + + + + + 10 + +
preferred_symmetric_algorithms + + +Integer + + + + + + 11 + +
revocation_key + + +Integer + + + + + + 12 + +
issuer + + +Integer + + + + + + 16 + +
notation_data + + +Integer + + + + + + 20 + +
preferred_hash_algorithms + + +Integer + + + + + + 21 + +
preferred_compression_algorithms + + +Integer + + + + + + 22 + +
key_server_preferences + + +Integer + + + + + + 23 + +
preferred_key_server + + +Integer + + + + + + 24 + +
primary_user_id + + +Integer + + + + + + 25 + +
policy_uri + + +Integer + + + + + + 26 + +
key_flags + + +Integer + + + + + + 27 + +
signers_user_id + + +Integer + + + + + + 28 + +
reason_for_revocation + + +Integer + + + + + + 29 + +
features + + +Integer + + + + + + 30 + +
signature_target + + +Integer + + + + + + 31 + +
embedded_signature + + +Integer + + + + + + 32 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

<static, readonly> symmetric :Integer

+ + +
+
+ +
+ RFC4880, section 9.2 +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + +
Properties:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
plaintext + + +Integer + + + + + + 0 + +
idea + + +Integer + + + + + + 1 + + Not implemented!
tripledes + + +Integer + + + + + + 2 + +
cast5 + + +Integer + + + + + + 3 + +
blowfish + + +Integer + + + + + + 4 + +
aes128 + + +Integer + + + + + + 7 + +
aes192 + + +Integer + + + + + + 8 + +
aes256 + + +Integer + + + + + + 9 + +
twofish + + +Integer + + + + + + 10 + +
+ + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

<static> read()

+ + +
+
+ + +
+ Converts from an integer to string. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

<static> write()

+ + +
+
+ + +
+ Asserts validity and converts from string/integer to integer. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-key-Key.html b/doc/module-key-Key.html new file mode 100644 index 00000000..2a4ec89c --- /dev/null +++ b/doc/module-key-Key.html @@ -0,0 +1,2267 @@ + + + + + JSDoc: Class: Key + + + + + + + + + + +
+ +

Class: Key

+ + + + + +
+ +
+

+ key~ + + Key +

+ +
Class that represents an OpenPGP key. Must contain a primary key. +Can contain additional subkeys, signatures, user ids, user attributes.
+ +
+ +
+
+ + + + +
+

new Key(packetlist)

+ + +
+
+ + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
packetlist + + +module:packet/packetlist + + + + The packets that form this key
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

armor() → {String}

+ + +
+
+ + +
+ Returns ASCII armored text of key +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ ASCII armor +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

decrypt(passphrase) → {Boolean}

+ + +
+
+ + +
+ Decrypts all secret key and subkey packets +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
passphrase + + +String + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ true if all key and subkey packets decrypted successfully +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

decryptKeyPacket(keyIds, passphrase) → {Boolean}

+ + +
+
+ + +
+ Decrypts specific key packets by key ID +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keyIds + + +Array.<module:type/keyid> + + + +
passphrase + + +String + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ true if all key packets decrypted successfully +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

getAllKeyPackets() → {Array.<(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key)>}

+ + +
+
+ + +
+ Returns all the private and public key and subkey packets +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key)> + + +
+
+ + + + +
+ + + +
+

getEncryptionKeyPacket() → {module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key|null}

+ + +
+
+ + +
+ Returns the first valid encryption key packet for this key +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ key packet or null if no encryption key has been found +
+ + + +
+
+ Type +
+
+ +module:packet/public_subkey +| + +module:packet/secret_subkey +| + +module:packet/secret_key +| + +module:packet/public_key +| + +null + + +
+
+ + + + +
+ + + +
+

getKeyIds() → {Array.<module:type/keyid>}

+ + +
+
+ + +
+ Returns key IDs of all key packets +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<module:type/keyid> + + +
+
+ + + + +
+ + + +
+

getKeyPacket() → {module:packet/secret_key|module:packet/public_key|null}

+ + +
+
+ + +
+ Returns the primary key packet (secret or public) +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +module:packet/secret_key +| + +module:packet/public_key +| + +null + + +
+
+ + + + +
+ + + +
+

getPreferredHashAlgorithm() → {String}

+ + +
+
+ + +
+ Returns preferred signature hash algorithm of this key +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getPrimaryUser() → {Object}

+ + +
+
+ + +
+ Returns primary user and most significant (latest valid) self signature +- if multiple users are marked as primary users returns the one with the latest self signature +- if no primary user is found returns the user with the latest self signature +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The primary user and the self signature +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

getPrivateKeyPacket(keyIds) → {module:packet/secret_subkey|module:packet/secret_key|null}

+ + +
+
+ + +
+ Returns first private key packet for given array of key IDs +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keyIds + + +Array.<module:type/keyid> + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +module:packet/secret_subkey +| + +module:packet/secret_key +| + +null + + +
+
+ + + + +
+ + + +
+

getPublicKeyPacket(keyIds) → {module:packet/public_subkey|module:packet/public_key|null}

+ + +
+
+ + +
+ Returns first public key packet for given array of key IDs +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keyIds + + +Array.<module:type/keyid> + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +module:packet/public_subkey +| + +module:packet/public_key +| + +null + + +
+
+ + + + +
+ + + +
+

getSigningKeyPacket() → {module:packet/secret_subkey|module:packet/secret_key|null}

+ + +
+
+ + +
+ Returns first key packet that is available for signing +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ key packet or null if no signing key has been found +
+ + + +
+
+ Type +
+
+ +module:packet/secret_subkey +| + +module:packet/secret_key +| + +null + + +
+
+ + + + +
+ + + +
+

getSubkeyPackets() → {Array.<(module:packet/public_subkey|module:packet/secret_subkey)>}

+ + +
+
+ + +
+ Returns all the private and public subkey packets +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<(module:packet/public_subkey|module:packet/secret_subkey)> + + +
+
+ + + + +
+ + + +
+

getUserIds() → {Array.<string>}

+ + +
+
+ + +
+ Returns userids +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ array of userids +
+ + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + +
+ + + +
+

isPrivate() → {Boolean}

+ + +
+
+ + +
+ Returns true if this is a private key +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

isPublic() → {Boolean}

+ + +
+
+ + +
+ Returns true if this is a public key +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

packetlist2structure(packetlist)

+ + +
+
+ + +
+ Transforms packetlist to structured key data +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
packetlist + + +module:packet/packetlist + + + + The packets that form a key
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

toPacketlist() → {module:packet/packetlist}

+ + +
+
+ + +
+ Transforms structured key data to packetlist +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The packets that form a key +
+ + + +
+
+ Type +
+
+ +module:packet/packetlist + + +
+
+ + + + +
+ + + +
+

toPublic() → {module:key~Key}

+ + +
+
+ + +
+ Returns key as public key (shallow copy) +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new public Key +
+ + + +
+
+ Type +
+
+ +module:key~Key + + +
+
+ + + + +
+ + + +
+

verifyPrimaryKey() → {module:enums.keyStatus}

+ + +
+
+ + +
+ Verify primary key. Checks for revocation signatures, expiration time +and valid self signature +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The status of the primary key +
+ + + +
+
+ Type +
+
+ +module:enums.keyStatus + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-key-SubKey.html b/doc/module-key-SubKey.html new file mode 100644 index 00000000..ca977352 --- /dev/null +++ b/doc/module-key-SubKey.html @@ -0,0 +1,609 @@ + + + + + JSDoc: Class: SubKey + + + + + + + + + + +
+ +

Class: SubKey

+ + + + + +
+ +
+

+ key~ + + SubKey +

+ +
Class that represents a subkey packet and the relevant signatures.
+ +
+ +
+
+ + + + +
+

new SubKey()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

isValidEncryptionKey(primaryKey) → {Boolean}

+ + +
+
+ + +
+ Returns true if the subkey can be used for encryption +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
primaryKey + + +module:packet/secret_key +| + +module:packet/public_key + + + + The primary key packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

isValidSigningKey(primaryKey) → {Boolean}

+ + +
+
+ + +
+ Returns true if the subkey can be used for signing of data +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
primaryKey + + +module:packet/secret_key +| + +module:packet/public_key + + + + The primary key packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

toPacketlist() → {module:packet/packetlist}

+ + +
+
+ + +
+ Transforms structured subkey data to packetlist +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +module:packet/packetlist + + +
+
+ + + + +
+ + + +
+

verify() → {module:enums.keyStatus}

+ + +
+
+ + +
+ Verify subkey. Checks for revocation signatures, expiration time +and valid binding signature +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The status of the subkey +
+ + + +
+
+ Type +
+
+ +module:enums.keyStatus + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-key-User.html b/doc/module-key-User.html new file mode 100644 index 00000000..cb0d7724 --- /dev/null +++ b/doc/module-key-User.html @@ -0,0 +1,691 @@ + + + + + JSDoc: Class: User + + + + + + + + + + +
+ +

Class: User

+ + + + + +
+ +
+

+ key~ + + User +

+ +
Class that represents an user ID or attribute packet and the relevant signatures.
+ +
+ +
+
+ + + + +
+

new User()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

getValidSelfCertificate(primaryKey) → {module:packet/signature}

+ + +
+
+ + +
+ Returns the most significant (latest valid) self signature of the user +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
primaryKey + + +module:packet/secret_key +| + +module:packet/public_key + + + + The primary key packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The self signature +
+ + + +
+
+ Type +
+
+ +module:packet/signature + + +
+
+ + + + +
+ + + +
+

isRevoked(certificate, primaryKey) → {Boolean}

+ + +
+
+ + +
+ Checks if a self signature of the user is revoked +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
certificate + + +module:packet/signature + + + +
primaryKey + + +module:packet/secret_key +| + +module:packet/public_key + + + + The primary key packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ True if the certificate is revoked +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

toPacketlist() → {module:packet/packetlist}

+ + +
+
+ + +
+ Transforms structured user data to packetlist +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +module:packet/packetlist + + +
+
+ + + + +
+ + + +
+

verify(primaryKey) → {module:enums.keyStatus}

+ + +
+
+ + +
+ Verify User. Checks for existence of self signatures, revocation signatures +and validity of self signature +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
primaryKey + + +module:packet/secret_key +| + +module:packet/public_key + + + + The primary key packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ status of user +
+ + + +
+
+ Type +
+
+ +module:enums.keyStatus + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-key.html b/doc/module-key.html new file mode 100644 index 00000000..fde13d78 --- /dev/null +++ b/doc/module-key.html @@ -0,0 +1,494 @@ + + + + + JSDoc: Module: key + + + + + + + + + + +
+ +

Module: key

+ + + + + +
+ +
+

+ key +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + +

Classes

+ +
+
Key
+
+ +
SubKey
+
+ +
User
+
+
+ + + + + + + +

Methods

+ +
+ +
+

<static> generate(keyType, numBits, userId, passphrase) → {module:key~Key}

+ + +
+
+ + +
+ Generates a new OpenPGP key. Currently only supports RSA keys. +Primary and subkey will be of same type. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keyType + + +Integer + + + + to indicate what type of key to make. + RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1
numBits + + +Integer + + + + number of bits for the key creation.
userId + + +String + + + + assumes already in form of "User Name "
passphrase + + +String + + + + The passphrase used to encrypt the resulting private key
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +module:key~Key + + +
+
+ + + + +
+ + + +
+

<static> readArmored(armoredText) → {Object}

+ + +
+
+ + +
+ Reads an OpenPGP armored text and returns one or multiple key objects +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
armoredText + + +String + + + + text to be parsed
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ result object with key and error arrays +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-keyid.html b/doc/module-keyid.html new file mode 100644 index 00000000..b9021d4d --- /dev/null +++ b/doc/module-keyid.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Module: keyid + + + + + + + + + + +
+ +

Module: keyid

+ + + + + +
+ +
+

+ keyid +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:42 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-message-Message.html b/doc/module-message-Message.html new file mode 100644 index 00000000..8dcfb4f7 --- /dev/null +++ b/doc/module-message-Message.html @@ -0,0 +1,1312 @@ + + + + + JSDoc: Class: Message + + + + + + + + + + +
+ +

Class: Message

+ + + + + +
+ +
+

+ message~ + + Message +

+ +
Class that represents an OpenPGP message. +Can be an encrypted message, signed message, compressed message or literal message
+ +
+ +
+
+ + + + +
+

new Message(packetlist)

+ + +
+
+ + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
packetlist + + +module:packet/packetlist + + + + The packets that form this message +See http://tools.ietf.org/html/rfc4880#section-11.3
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

armor() → {String}

+ + +
+
+ + +
+ Returns ASCII armored text of message +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ ASCII armor +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

decrypt(privateKey) → {Array.<module:message~Message>}

+ + +
+
+ + +
+ Decrypt the message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
privateKey + + +module:key~Key + + + + private key with decrypted secret data
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new message with decrypted content +
+ + + +
+
+ Type +
+
+ +Array.<module:message~Message> + + +
+
+ + + + +
+ + + +
+

encrypt(keys) → {Array.<module:message~Message>}

+ + +
+
+ + +
+ Encrypt the message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keys + + +Array.<module:key~Key> + + + + array of keys, used to encrypt the message
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new message with encrypted content +
+ + + +
+
+ Type +
+
+ +Array.<module:message~Message> + + +
+
+ + + + +
+ + + +
+

getEncryptionKeyIds() → {Array.<module:type/keyid>}

+ + +
+
+ + +
+ Returns the key IDs of the keys to which the session key is encrypted +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ array of keyid objects +
+ + + +
+
+ Type +
+
+ +Array.<module:type/keyid> + + +
+
+ + + + +
+ + + +
+

getLiteralData() → {String|null}

+ + +
+
+ + +
+ Get literal data that is the body of the message +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ literal body of the message as string +
+ + + +
+
+ Type +
+
+ +String +| + +null + + +
+
+ + + + +
+ + + +
+

getSigningKeyIds() → {Array.<module:type/keyid>}

+ + +
+
+ + +
+ Returns the key IDs of the keys that signed the message +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ array of keyid objects +
+ + + +
+
+ Type +
+
+ +Array.<module:type/keyid> + + +
+
+ + + + +
+ + + +
+

getText() → {String|null}

+ + +
+
+ + +
+ Get literal data as text +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ literal body of the message interpreted as text +
+ + + +
+
+ Type +
+
+ +String +| + +null + + +
+
+ + + + +
+ + + +
+

sign(privateKey) → {module:message~Message}

+ + +
+
+ + +
+ Sign the message (the literal data packet of the message) +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
privateKey + + +Array.<module:key~Key> + + + + private keys with decrypted secret key data for signing
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new message with signed content +
+ + + +
+
+ Type +
+
+ +module:message~Message + + +
+
+ + + + +
+ + + +
+

unwrapCompressed() → {module:message~Message}

+ + +
+
+ + +
+ Unwrap compressed message +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ message Content of compressed message +
+ + + +
+
+ Type +
+
+ +module:message~Message + + +
+
+ + + + +
+ + + +
+

verify(publicKeys) → {Array.<({keyid: module:type/keyid, valid: Boolean})>}

+ + +
+
+ + +
+ Verify message signatures +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
publicKeys + + +Array.<module:key~Key> + + + + public keys to verify signatures
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ list of signer's keyid and validity of signature +
+ + + +
+
+ Type +
+
+ +Array.<({keyid: module:type/keyid, valid: Boolean})> + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-message.html b/doc/module-message.html new file mode 100644 index 00000000..e44795a4 --- /dev/null +++ b/doc/module-message.html @@ -0,0 +1,562 @@ + + + + + JSDoc: Module: message + + + + + + + + + + +
+ +

Module: message

+ + + + + +
+ +
+

+ message +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + +

Classes

+ +
+
Message
+
+
+ + + + + + + +

Methods

+ +
+ +
+

<static> fromBinary(bytes) → {module:message~Message}

+ + +
+
+ + +
+ creates new message object from binary data +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bytes + + +String + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new message object +
+ + + +
+
+ Type +
+
+ +module:message~Message + + +
+
+ + + + +
+ + + +
+

<static> fromText(text) → {module:message~Message}

+ + +
+
+ + +
+ creates new message object from text +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new message object +
+ + + +
+
+ Type +
+
+ +module:message~Message + + +
+
+ + + + +
+ + + +
+

<static> readArmored(armoredText) → {module:message~Message}

+ + +
+
+ + +
+ reads an OpenPGP armored message and returns a message object +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
armoredText + + +String + + + + text to be parsed
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ new message object +
+ + + +
+
+ Type +
+
+ +module:message~Message + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-mpi.html b/doc/module-mpi.html new file mode 100644 index 00000000..42165914 --- /dev/null +++ b/doc/module-mpi.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Module: mpi + + + + + + + + + + +
+ +

Module: mpi

+ + + + + +
+ +
+

+ mpi +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-openpgp.html b/doc/module-openpgp.html new file mode 100644 index 00000000..6323cef8 --- /dev/null +++ b/doc/module-openpgp.html @@ -0,0 +1,1373 @@ + + + + + JSDoc: Module: openpgp + + + + + + + + + + +
+ +

Module: openpgp

+ + + + + +
+ +
+

+ openpgp +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

<static> decryptAndVerifyMessage(privateKey, publicKeys, message) → {Object}

+ + +
+
+ + +
+ Decrypts message and verifies signatures +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
privateKey + + +module:key~Key + + + + private key with decrypted secret key data
publicKeys + + +Array.<module:key~Key> + + + + public keys to verify signatures
message + + +module:message~Message + + + + the message object with signed and encrypted data
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ decrypted message as as native JavaScript string + with verified signatures or null if no literal data found +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

<static> decryptMessage(privateKey, message) → {String|null}

+ + +
+
+ + +
+ Decrypts message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
privateKey + + +module:key~Key + + + + private key with decrypted secret key data
message + + +module:message~Message + + + + the message object with the encrypted data
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ decrypted message as as native JavaScript string + or null if no literal data found +
+ + + +
+
+ Type +
+
+ +String +| + +null + + +
+
+ + + + +
+ + + +
+

<static> encryptMessage(keys, text) → {String}

+ + +
+
+ + +
+ Encrypts message text with keys +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keys + + +Array.<module:key~Key> + + + + array of keys, used to encrypt the message
text + + +String + + + + message as native JavaScript string
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ encrypted ASCII armored message +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> generateKeyPair(keyType, numBits, userId, passphrase) → {Object}

+ + +
+
+ + +
+ Generates a new OpenPGP key pair. Currently only supports RSA keys. +Primary and subkey will be of same type. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keyType + + +Integer + + + + to indicate what type of key to make. + RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1
numBits + + +Integer + + + + number of bits for the key creation. (should be 1024+, generally)
userId + + +String + + + + assumes already in form of "User Name "
passphrase + + +String + + + + The passphrase used to encrypt the resulting private key
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ {key: Array, privateKeyArmored: Array, publicKeyArmored: Array} +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

<static> signAndEncryptMessage(publicKeys, privateKey, text) → {String}

+ + +
+
+ + +
+ Signs message text and encrypts it +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
publicKeys + + +Array.<module:key~Key> + + + + array of keys, used to encrypt the message
privateKey + + +module:key~Key + + + + private key with decrypted secret key data for signing
text + + +String + + + + message as native JavaScript string
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ encrypted ASCII armored message +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> signClearMessage(privateKeys, text) → {String}

+ + +
+
+ + +
+ Signs a cleartext message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
privateKeys + + +Array.<module:key~Key> + + + + private key with decrypted secret key data to sign cleartext
text + + +String + + + + cleartext
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ ASCII armored message +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> verifyClearSignedMessage(publicKeys, message) → {Object}

+ + +
+
+ + +
+ Verifies signatures of cleartext signed message +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
publicKeys + + +Array.<module:key~Key> + + + + public keys to verify signatures
message + + +module:cleartext~CleartextMessage + + + + cleartext message object with signatures
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ cleartext with status of verified signatures +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-packet.html b/doc/module-packet.html new file mode 100644 index 00000000..951c331e --- /dev/null +++ b/doc/module-packet.html @@ -0,0 +1,1042 @@ + + + + + JSDoc: Module: packet + + + + + + + + + + +
+ +

Module: packet

+ + + + + +
+ +
+

+ packet +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

<static> compressed

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> literal

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> marker

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> one_pass_signature

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> public_key

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> public_key_encrypted_session_key

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> public_subkey

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> secret_key

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> secret_subkey

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> signature

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> sym_encrypted_integrity_protected

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> sym_encrypted_session_key

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> symmetrically_encrypted

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> trust

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> user_attribute

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> userid

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ +
+ + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-s2k.html b/doc/module-s2k.html new file mode 100644 index 00000000..bc6723c3 --- /dev/null +++ b/doc/module-s2k.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Module: s2k + + + + + + + + + + +
+ +

Module: s2k

+ + + + + +
+ +
+

+ s2k +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/module-util.html b/doc/module-util.html new file mode 100644 index 00000000..4b434820 --- /dev/null +++ b/doc/module-util.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Module: util + + + + + + + + + + +
+ +

Module: util

+ + + + + +
+ +
+

+ util +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:45 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/mpi.html b/doc/mpi.html new file mode 100644 index 00000000..87d75ab4 --- /dev/null +++ b/doc/mpi.html @@ -0,0 +1,495 @@ + + + + + JSDoc: Module: type/mpi + + + + + + + + + + +
+ +

Module: type/mpi

+ + + + + +
+ +
+

+ type/mpi +

+ +
+ +
+
+ + +
Implementation of type MPI (RFC4880 3.2)
+
+Multiprecision integers (also called MPIs) are unsigned integers used +to hold large integers such as the ones used in cryptographic +calculations. +An MPI consists of two pieces: a two-octet scalar that is the length +of the MPI in bits followed by a string of octets that contain the +actual integer.
+ + +
+

new (require("type/mpi"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

data

+ + +
+
+ +
+ An implementation dependent integer +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

read(input) → {Integer}

+ + +
+
+ + +
+ Parsing function for a mpi (RFC 4880 3.2). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Payload of mpi data
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Length of data read +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ Converts the mpi object to a string as specified in RFC4880 3.2 +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ mpi Byte representation +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:45 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/mpi.js.html b/doc/mpi.js.html new file mode 100644 index 00000000..757a7fe3 --- /dev/null +++ b/doc/mpi.js.html @@ -0,0 +1,150 @@ + + + + + JSDoc: Source: type/mpi.js + + + + + + + + + + +
+ +

Source: type/mpi.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two
+// octet scalar: MPI: [a,b,c,d,e,f]
+// - MPI size: (a << 8) | b 
+// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
+
+/**
+ * Implementation of type MPI (RFC4880 3.2)<br/>
+ * <br/>
+ * Multiprecision integers (also called MPIs) are unsigned integers used
+ * to hold large integers such as the ones used in cryptographic
+ * calculations.
+ * An MPI consists of two pieces: a two-octet scalar that is the length
+ * of the MPI in bits followed by a string of octets that contain the
+ * actual integer.
+ * @requires crypto/public_key/jsbn
+ * @requires util
+ * @module type/mpi
+ */
+
+var BigInteger = require('../crypto/public_key/jsbn.js'),
+  util = require('../util');
+
+/**
+ * @constructor
+ */
+module.exports = function mpi() {
+  /** An implementation dependent integer */
+  this.data = null;
+
+  /**
+   * Parsing function for a mpi (RFC 4880 3.2).
+   * @param {String} input Payload of mpi data
+   * @return {Integer} Length of data read
+   */
+  this.read = function (bytes) {
+    var bits = (bytes.charCodeAt(0) << 8) | bytes.charCodeAt(1);
+
+    // Additional rules:
+    //
+    //    The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
+    //
+    //    The length field of an MPI describes the length starting from its
+    //	  most significant non-zero bit.  Thus, the MPI [00 02 01] is not
+    //    formed correctly.  It should be [00 01 01].
+
+    // TODO: Verification of this size method! This size calculation as
+    // 		 specified above is not applicable in JavaScript
+    var bytelen = Math.ceil(bits / 8);
+
+    var raw = bytes.substr(2, bytelen);
+    this.fromBytes(raw);
+
+    return 2 + bytelen;
+  };
+
+  this.fromBytes = function (bytes) {
+    this.data = new BigInteger(util.hexstrdump(bytes), 16);
+  };
+
+  this.toBytes = function () {
+    return this.write().substr(2);
+  };
+
+  this.byteLength = function () {
+    return this.toBytes().length;
+  };
+
+  /**
+   * Converts the mpi object to a string as specified in RFC4880 3.2
+   * @return {String} mpi Byte representation
+   */
+  this.write = function () {
+    return this.data.toMPI();
+  };
+
+  this.toBigInteger = function () {
+    return this.data.clone();
+  };
+
+  this.fromBigInteger = function (bn) {
+    this.data = bn.clone();
+  };
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/one_pass_signature.html b/doc/one_pass_signature.html new file mode 100644 index 00000000..8171b98b --- /dev/null +++ b/doc/one_pass_signature.html @@ -0,0 +1,437 @@ + + + + + JSDoc: Module: packet/one_pass_signature + + + + + + + + + + +
+ +

Module: packet/one_pass_signature

+ + + + + +
+ +
+

+ packet/one_pass_signature +

+ +
+ +
+
+ + +
Implementation of the One-Pass Signature Packets (Tag 4)
+
+RFC4880 5.4: +The One-Pass Signature packet precedes the signed data and contains +enough information to allow the receiver to begin calculating any +hashes needed to verify the signature. It allows the Signature +packet to be placed at the end of the message, so that the signer +can compute the entire signed message in one pass.
+ + +
+

new (require("packet/one_pass_signature"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

read(bytes) → {module:packet/one_pass_signature}

+ + +
+
+ + +
+ parsing function for a one-pass signature packet (tag 4). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bytes + + +String + + + + payload of a tag 4 packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ object representation +
+ + + +
+
+ Type +
+
+ +module:packet/one_pass_signature + + +
+
+ + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ creates a string representation of a one-pass signature packet +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ a string representation of a one-pass signature packet +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/one_pass_signature.js.html b/doc/one_pass_signature.js.html new file mode 100644 index 00000000..df75b80d --- /dev/null +++ b/doc/one_pass_signature.js.html @@ -0,0 +1,145 @@ + + + + + JSDoc: Source: packet/one_pass_signature.js + + + + + + + + + + +
+ +

Source: packet/one_pass_signature.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the One-Pass Signature Packets (Tag 4)<br/>
+ * <br/>
+ * RFC4880 5.4:
+ * The One-Pass Signature packet precedes the signed data and contains
+ * enough information to allow the receiver to begin calculating any
+ * hashes needed to verify the signature.  It allows the Signature
+ * packet to be placed at the end of the message, so that the signer
+ * can compute the entire signed message in one pass.
+ * @requires enums
+ * @requires type/keyid
+ * @module packet/one_pass_signature
+*/
+
+var enums = require('../enums.js'),
+  type_keyid = require('../type/keyid.js');
+
+/**
+ * @constructor
+ */
+module.exports = function one_pass_signature() {
+  this.version = null; // A one-octet version number.  The current version is 3.
+  this.type = null; // A one-octet signature type.  Signature types are described in RFC4880 Section 5.2.1.
+  this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
+  this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1)
+  this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key.
+  this.flags = null; //  A one-octet number holding a flag showing whether the signature is nested.  A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data.
+
+  /**
+   * parsing function for a one-pass signature packet (tag 4).
+   * @param {String} bytes payload of a tag 4 packet
+   * @return {module:packet/one_pass_signature} object representation
+   */
+  this.read = function (bytes) {
+    var mypos = 0;
+    // A one-octet version number.  The current version is 3.
+    this.version = bytes.charCodeAt(mypos++);
+
+    // A one-octet signature type.  Signature types are described in
+    //   Section 5.2.1.
+    this.type = enums.read(enums.signature, bytes.charCodeAt(mypos++));
+
+    // A one-octet number describing the hash algorithm used.
+    this.hashAlgorithm = enums.read(enums.hash, bytes.charCodeAt(mypos++));
+
+    // A one-octet number describing the public-key algorithm used.
+    this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(mypos++));
+
+    // An eight-octet number holding the Key ID of the signing key.
+    this.signingKeyId = new type_keyid();
+    this.signingKeyId.read(bytes.substr(mypos));
+    mypos += 8;
+
+    // A one-octet number holding a flag showing whether the signature
+    //   is nested.  A zero value indicates that the next packet is
+    //   another One-Pass Signature packet that describes another
+    //   signature to be applied to the same message data.
+    this.flags = bytes.charCodeAt(mypos++);
+    return this;
+  }
+
+  /**
+   * creates a string representation of a one-pass signature packet
+   * @return {String} a string representation of a one-pass signature packet
+   */
+  this.write = function () {
+    var result = "";
+
+    result += String.fromCharCode(3);
+    result += String.fromCharCode(enums.write(enums.signature, this.type));
+    result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm));
+    result += String.fromCharCode(enums.write(enums.publicKey, this.publicKeyAlgorithm));
+    result += this.signingKeyId.write();
+    result += String.fromCharCode(this.flags);
+
+    return result;
+  }
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/openpgp.cfb.js.html b/doc/openpgp.cfb.js.html deleted file mode 100644 index 4168f6ad..00000000 --- a/doc/openpgp.cfb.js.html +++ /dev/null @@ -1,339 +0,0 @@ - - - - - JSDoc: Source: ciphers/openpgp.cfb.js - - - - - - - - - - -
- -

Source: ciphers/openpgp.cfb.js

- - - - - -
-
-
// Modified by Recurity Labs GmbH 
-
-// modified version of http://www.hanewin.net/encrypt/PGdecode.js:
-
-/* OpenPGP encryption using RSA/AES
- * Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de
- * version 2.0, check www.haneWIN.de for the latest version
-
- * This software is provided as-is, without express or implied warranty.  
- * Permission to use, copy, modify, distribute or sell this software, with or
- * without fee, for any purpose and by any individual or organization, is hereby
- * granted, provided that the above copyright notice and this paragraph appear 
- * in all copies. Distribution as a part of an application or binary must
- * include the above copyright notice in the documentation and/or other
- * materials provided with the application or distribution.
- */
-
-/**
- * An array of bytes, that is integers with values from 0 to 255
- * @typedef {(Array|Uint8Array)} openpgp_byte_array
- */
-
-/**
- * Block cipher function
- * @callback openpgp_cipher_block_fn
- * @param {openpgp_byte_array} block A block to perform operations on
- * @param {openpgp_byte_array} key to use in encryption/decryption
- * @return {openpgp_byte_array} Encrypted/decrypted block
- */
-
-
-// --------------------------------------
-/**
- * This function encrypts a given with the specified prefixrandom 
- * using the specified blockcipher to encrypt a message
- * @param {String} prefixrandom random bytes of block_size length provided 
- *  as a string to be used in prefixing the data
- * @param {openpgp_cipher_block_fn} blockcipherfn the algorithm encrypt function to encrypt
- *  data in one block_size encryption. 
- * @param {Integer} block_size the block size in bytes of the algorithm used
- * @param {String} plaintext data to be encrypted provided as a string
- * @param {openpgp_byte_array} key key to be used to encrypt the data. This will be passed to the 
- *  blockcipherfn
- * @param {Boolean} resync a boolean value specifying if a resync of the 
- *  IV should be used or not. The encrypteddatapacket uses the 
- *  "old" style with a resync. Encryption within an 
- *  encryptedintegrityprotecteddata packet is not resyncing the IV.
- * @return {String} a string with the encrypted data
- */
-function openpgp_cfb_encrypt(prefixrandom, blockcipherencryptfn, plaintext, block_size, key, resync) {
-	var FR = new Array(block_size);
-	var FRE = new Array(block_size);
-
-	prefixrandom = prefixrandom + prefixrandom.charAt(block_size-2) +prefixrandom.charAt(block_size-1);
-	util.print_debug("prefixrandom:"+util.hexstrdump(prefixrandom));
-	var ciphertext = "";
-	// 1.  The feedback register (FR) is set to the IV, which is all zeros.
-	for (var i = 0; i < block_size; i++) FR[i] = 0;
-	
-	// 2.  FR is encrypted to produce FRE (FR Encrypted).  This is the
-    //     encryption of an all-zero value.
-	FRE = blockcipherencryptfn(FR, key);
-	// 3.  FRE is xored with the first BS octets of random data prefixed to
-    //     the plaintext to produce C[1] through C[BS], the first BS octets
-    //     of ciphertext.
-	for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i));
-	
-	// 4.  FR is loaded with C[1] through C[BS].
-	for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
-	
-	// 5.  FR is encrypted to produce FRE, the encryption of the first BS
-    // 	   octets of ciphertext.
-	FRE = blockcipherencryptfn(FR, key);
-
-	// 6.  The left two octets of FRE get xored with the next two octets of
-	//     data that were prefixed to the plaintext.  This produces C[BS+1]
-	//     and C[BS+2], the next two octets of ciphertext.
-	ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size));
-	ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size+1));
-
-	if (resync) {
-		// 7.  (The resync step) FR is loaded with C3-C10.
-		for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i+2);
-	} else {
-		for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
-	}
-	// 8.  FR is encrypted to produce FRE.
-	FRE = blockcipherencryptfn(FR, key);
-	
-	if (resync) {
-		// 9.  FRE is xored with the first 8 octets of the given plaintext, now
-	    //	   that we have finished encrypting the 10 octets of prefixed data.
-	    // 	   This produces C11-C18, the next 8 octets of ciphertext.
-		for (var i = 0; i < block_size; i++)
-			ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
-		for(n=block_size+2; n < plaintext.length; n+=block_size) {
-			// 10. FR is loaded with C11-C18
-			for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n+i);
-		
-			// 11. FR is encrypted to produce FRE.
-			FRE = blockcipherencryptfn(FR, key);
-		
-			// 12. FRE is xored with the next 8 octets of plaintext, to produce the
-			// next 8 octets of ciphertext.  These are loaded into FR and the
-			// process is repeated until the plaintext is used up.
-			for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n-2)+i));
-		}
-	}
-	else {
-		plaintext = "  "+plaintext;
-		// 9.  FRE is xored with the first 8 octets of the given plaintext, now
-	    //	   that we have finished encrypting the 10 octets of prefixed data.
-	    // 	   This produces C11-C18, the next 8 octets of ciphertext.
-		for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
-		var tempCiphertext = ciphertext.substring(0,2*block_size).split('');
-		var tempCiphertextString = ciphertext.substring(block_size);
-		for(n=block_size; n<plaintext.length; n+=block_size) {
-			// 10. FR is loaded with C11-C18
-			for (var i = 0; i < block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i);
-			tempCiphertextString='';
-			
-			// 11. FR is encrypted to produce FRE.
-			FRE = blockcipherencryptfn(FR, key);
-			
-			// 12. FRE is xored with the next 8 octets of plaintext, to produce the
-			//     next 8 octets of ciphertext.  These are loaded into FR and the
-			//     process is repeated until the plaintext is used up.
-			for (var i = 0; i < block_size; i++){ tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i)));
-			tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i));
-			}
-		}
-		ciphertext = tempCiphertext.join('');
-		
-	}
-	return ciphertext;
-}
-
-/**
- * Decrypts the prefixed data for the Modification Detection Code (MDC) computation
- * @param {openpgp_block_cipher_fn} blockcipherencryptfn Cipher function to use
- * @param {Integer} block_size Blocksize of the algorithm
- * @param {openpgp_byte_array} key The key for encryption
- * @param {String} ciphertext The encrypted data
- * @return {String} plaintext Data of D(ciphertext) with blocksize length +2
- */
-function openpgp_cfb_mdc(blockcipherencryptfn, block_size, key, ciphertext) {
-	var iblock = new Array(block_size);
-	var ablock = new Array(block_size);
-	var i;
-
-	// initialisation vector
-	for(i=0; i < block_size; i++) iblock[i] = 0;
-
-	iblock = blockcipherencryptfn(iblock, key);
-	for(i = 0; i < block_size; i++)
-	{
-		ablock[i] = ciphertext.charCodeAt(i);
-		iblock[i] ^= ablock[i];
-	}
-
-	ablock = blockcipherencryptfn(ablock, key);
-
-	return util.bin2str(iblock)+
-		String.fromCharCode(ablock[0]^ciphertext.charCodeAt(block_size))+
-		String.fromCharCode(ablock[1]^ciphertext.charCodeAt(block_size+1));
-}
-/**
- * This function decrypts a given plaintext using the specified
- * blockcipher to decrypt a message
- * @param {openpgp_cipher_block_fn} blockcipherfn The algorithm _encrypt_ function to encrypt
- *  data in one block_size encryption.
- * @param {Integer} block_size the block size in bytes of the algorithm used
- * @param {String} plaintext ciphertext to be decrypted provided as a string
- * @param {openpgp_byte_array} key key to be used to decrypt the ciphertext. This will be passed to the 
- *  blockcipherfn
- * @param {Boolean} resync a boolean value specifying if a resync of the 
- *  IV should be used or not. The encrypteddatapacket uses the 
- *  "old" style with a resync. Decryption within an 
- *  encryptedintegrityprotecteddata packet is not resyncing the IV.
- * @return {String} a string with the plaintext data
- */
-
-function openpgp_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, resync)
-{
-	util.print_debug("resync:"+resync);
-	var iblock = new Array(block_size);
-	var ablock = new Array(block_size);
-	var i, n = '';
-	var text = [];
-
-	// initialisation vector
-	for(i=0; i < block_size; i++) iblock[i] = 0;
-
-	iblock = blockcipherencryptfn(iblock, key);
-	for(i = 0; i < block_size; i++)
-	{
-		ablock[i] = ciphertext.charCodeAt(i);
-		iblock[i] ^= ablock[i];
-	}
-
-	ablock = blockcipherencryptfn(ablock, key);
-
-	util.print_debug("openpgp_cfb_decrypt:\niblock:"+util.hexidump(iblock)+"\nablock:"+util.hexidump(ablock)+"\n");
-	util.print_debug((ablock[0]^ciphertext.charCodeAt(block_size)).toString(16)+(ablock[1]^ciphertext.charCodeAt(block_size+1)).toString(16));
-	
-	// test check octets
-	if(iblock[block_size-2]!=(ablock[0]^ciphertext.charCodeAt(block_size))
-	|| iblock[block_size-1]!=(ablock[1]^ciphertext.charCodeAt(block_size+1)))
-	{
-		util.print_eror("error duding decryption. Symmectric encrypted data not valid.");
-		return text.join('');
-	}
-	
-	/*  RFC4880: Tag 18 and Resync:
-	 *  [...] Unlike the Symmetrically Encrypted Data Packet, no
-   	 *  special CFB resynchronization is done after encrypting this prefix
-     *  data.  See "OpenPGP CFB Mode" below for more details.
-
-	 */
-	
-	if (resync) {
-	    for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i+2);
-		for(n=block_size+2; n<ciphertext.length; n+=block_size)
-		{
-			ablock = blockcipherencryptfn(iblock, key);
-
-			for(i = 0; i<block_size && i+n < ciphertext.length; i++)
-			{
-				iblock[i] = ciphertext.charCodeAt(n+i);
-				text.push(String.fromCharCode(ablock[i]^iblock[i])); 
-			}
-		}
-	} else {
-		for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i);
-		for(n=block_size; n<ciphertext.length; n+=block_size)
-		{
-			ablock = blockcipherencryptfn(iblock, key);
-			for(i = 0; i<block_size && i+n < ciphertext.length; i++)
-			{
-				iblock[i] = ciphertext.charCodeAt(n+i);
-				text.push(String.fromCharCode(ablock[i]^iblock[i])); 
-			}
-		}
-		
-	}
-	
-	return text.join('');
-}
-
-
-function normal_cfb_encrypt(blockcipherencryptfn, block_size, key, plaintext, iv) {
-	var blocki ="";
-	var blockc = "";
-	var pos = 0;
-	var cyphertext = [];
-	var tempBlock = [];
-	blockc = iv.substring(0,block_size);
-	while (plaintext.length > block_size*pos) {
-		var encblock = blockcipherencryptfn(blockc, key);
-		blocki = plaintext.substring((pos*block_size),(pos*block_size)+block_size);
-		for (var i=0; i < blocki.length; i++)
-		    tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i]));
-		blockc = tempBlock.join('');
-		tempBlock = [];
-		cyphertext.push(blockc);
-		pos++;
-	}
-	return cyphertext.join('');
-}
-
-function normal_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, iv) { 
-	var blockp ="";
-	var pos = 0;
-	var plaintext = [];
-	var offset = 0;
-	if (iv == null)
-		for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0);
-	else
-		blockp = iv.substring(0,block_size);
-	while (ciphertext.length > (block_size*pos)) {
-		var decblock = blockcipherencryptfn(blockp, key);
-		blockp = ciphertext.substring((pos*(block_size))+offset,(pos*(block_size))+(block_size)+offset);
-		for (var i=0; i < blockp.length; i++) {
-			plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i]));
-		}
-		pos++;
-	}
-	
-	return plaintext.join('');
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.config.js.html b/doc/openpgp.config.js.html deleted file mode 100644 index ab45e671..00000000 --- a/doc/openpgp.config.js.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - JSDoc: Source: config/openpgp.config.js - - - - - - - - - - -
- -

Source: config/openpgp.config.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- *
- * This object contains configuration values and implements
- * storing and retrieving configuration them from HTML5 local storage.
- *
- * This object can be accessed after calling openpgp.init()
- * using openpgp.config
- * Stored config parameters can be accessed using
- * openpgp.config.config
- * @class
- * @classdesc Implementation of the GPG4Browsers config object
- */
-function openpgp_config() {
-	/**
-	 * The variable with the actual configuration
-	 * @property {Integer} prefer_hash_algorithm
-	 * @property {Integer} encryption_cipher
-	 * @property {Integer} compression
-	 * @property {Boolean} show_version
-	 * @property {Boolean} show_comment
-	 * @property {Boolean} integrity_protect
-	 * @property {Integer} composition_behavior
-	 * @property {String} keyserver
-	 */
-	this.config = null;
-
-	/**
-	 * The default config object which is used if no
-	 * configuration was in place
-	 */
-	this.default_config = {
-			prefer_hash_algorithm: 2,
-			encryption_cipher: 9,
-			compression: 1,
-			show_version: true,
-			show_comment: true,
-			integrity_protect: true,
-			composition_behavior: 0,
-			keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371"
-	};
-
-	this.versionstring ="OpenPGP.js VERSION";
-	this.commentstring ="http://openpgpjs.org";
-	/**
-	 * Reads the config out of the HTML5 local storage
-	 * and initializes the object config.
-	 * if config is null the default config will be used
-	 */
-	function read() {
-		var cf = JSON.parse(window.localStorage.getItem("config"));
-		if (cf == null) {
-			this.config = this.default_config;
-			this.write();
-		}
-		else
-			this.config = cf;
-	}
-
-	/**
-	 * If enabled, debug messages will be printed
-	 */
-	this.debug = false;
-
-	/**
-	 * Writes the config to HTML5 local storage
-	 */
-	function write() {
-		window.localStorage.setItem("config",JSON.stringify(this.config));
-	}
-
-	this.read = read;
-	this.write = write;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.crypto.js.html b/doc/openpgp.crypto.js.html deleted file mode 100644 index 5b9f6d2a..00000000 --- a/doc/openpgp.crypto.js.html +++ /dev/null @@ -1,479 +0,0 @@ - - - - - JSDoc: Source: ciphers/openpgp.crypto.js - - - - - - - - - - -
- -

Source: ciphers/openpgp.crypto.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
-
-// The GPG4Browsers crypto interface
-
-/**
- * Encrypts data using the specified public key multiprecision integers 
- * and the specified algorithm.
- * @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
- * @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers
- * @param {openpgp_type_mpi} data Data to be encrypted as MPI
- * @return {(openpgp_type_mpi|openpgp_type_mpi[])} if RSA an openpgp_type_mpi; 
- * if elgamal encryption an array of two openpgp_type_mpi is returned; otherwise null
- */
-function openpgp_crypto_asymetricEncrypt(algo, publicMPIs, data) {
-	switch(algo) {
-	case 1: // RSA (Encrypt or Sign) [HAC]
-	case 2: // RSA Encrypt-Only [HAC]
-	case 3: // RSA Sign-Only [HAC]
-		var rsa = new RSA();
-		var n = publicMPIs[0].toBigInteger();
-		var e = publicMPIs[1].toBigInteger();
-		var m = data.toBigInteger();
-		return rsa.encrypt(m,e,n).toMPI();
-	case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
-		var elgamal = new Elgamal();
-		var p = publicMPIs[0].toBigInteger();
-		var g = publicMPIs[1].toBigInteger();
-		var y = publicMPIs[2].toBigInteger();
-		var m = data.toBigInteger();
-		return elgamal.encrypt(m,g,p,y);
-	default:
-		return null;
-	}
-}
-
-/**
- * Decrypts data using the specified public key multiprecision integers of the private key,
- * the specified secretMPIs of the private key and the specified algorithm.
- * @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
- * @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers 
- * of the public key part of the private key
- * @param {openpgp_type_mpi[]} secretMPIs Algorithm dependent multiprecision integers 
- * of the private key used
- * @param {openpgp_type_mpi} data Data to be encrypted as MPI
- * @return {BigInteger} returns a big integer containing the decrypted data; otherwise null
- */
-
-function openpgp_crypto_asymetricDecrypt(algo, publicMPIs, secretMPIs, dataMPIs) {
-	switch(algo) {
-	case 1: // RSA (Encrypt or Sign) [HAC]  
-	case 2: // RSA Encrypt-Only [HAC]
-	case 3: // RSA Sign-Only [HAC]
-		var rsa = new RSA();
-		var d = secretMPIs[0].toBigInteger();
-		var p = secretMPIs[1].toBigInteger();
-		var q = secretMPIs[2].toBigInteger();
-		var u = secretMPIs[3].toBigInteger();
-		var m = dataMPIs[0].toBigInteger();
-		return rsa.decrypt(m, d, p, q, u);
-	case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
-		var elgamal = new Elgamal();
-		var x = secretMPIs[0].toBigInteger();
-		var c1 = dataMPIs[0].toBigInteger();
-		var c2 = dataMPIs[1].toBigInteger();
-		var p = publicMPIs[0].toBigInteger();
-		return elgamal.decrypt(c1,c2,p,x);
-	default:
-		return null;
-	}
-	
-}
-
-/**
- * generate random byte prefix as string for the specified algorithm
- * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
- * @return {String} Random bytes with length equal to the block
- * size of the cipher
- */
-function openpgp_crypto_getPrefixRandom(algo) {
-	switch(algo) {
-	case 2:
-	case 3:
-	case 4:
-		return openpgp_crypto_getRandomBytes(8);
-	case 7:
-	case 8:
-	case 9:
-	case 10:
-		return openpgp_crypto_getRandomBytes(16);
-	default:
-		return null;
-	}
-}
-
-/**
- * retrieve the MDC prefixed bytes by decrypting them
- * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
- * @param {String} key Key as string. length is depending on the algorithm used
- * @param {String} data Encrypted data where the prefix is decrypted from
- * @return {String} Plain text data of the prefixed data
- */
-function openpgp_crypto_MDCSystemBytes(algo, key, data) {
-	util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nencrypteddata:",data);
-	switch(algo) {
-	case 0: // Plaintext or unencrypted data
-		return data;
-	case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
-		return openpgp_cfb_mdc(desede, 8, key, data, openpgp_cfb);
-	case 3: // CAST5 (128 bit key, as per [RFC2144])
-		return openpgp_cfb_mdc(cast5_encrypt, 8, key, data);
-	case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
-		return openpgp_cfb_mdc(BFencrypt, 8, key, data);
-	case 7: // AES with 128-bit key [AES]
-	case 8: // AES with 192-bit key
-	case 9: // AES with 256-bit key
-		return openpgp_cfb_mdc(AESencrypt, 16, keyExpansion(key), data);
-	case 10: 
-		return openpgp_cfb_mdc(TFencrypt, 16, key, data);
-	case 1: // IDEA [IDEA]
-		util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
-		return null;
-	default:
-	}
-	return null;
-}
-/**
- * Generating a session key for the specified symmetric algorithm
- * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
- * @return {String} Random bytes as a string to be used as a key
- */
-function openpgp_crypto_generateSessionKey(algo) {
-	switch (algo) {
-	case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
-	case 8: // AES with 192-bit key
-		return openpgp_crypto_getRandomBytes(24); 
-	case 3: // CAST5 (128 bit key, as per [RFC2144])
-	case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
-	case 7: // AES with 128-bit key [AES]
-		util.print_debug("length = 16:\n"+util.hexstrdump(openpgp_crypto_getRandomBytes(16)));
-		return openpgp_crypto_getRandomBytes(16);
-	case 9: // AES with 256-bit key
-	case 10:// Twofish with 256-bit key [TWOFISH]
-		return openpgp_crypto_getRandomBytes(32);
-	}
-	return null;
-}
-
-/**
- * 
- * @param {Integer} algo public Key algorithm
- * @param {Integer} hash_algo Hash algorithm
- * @param {openpgp_type_mpi[]} msg_MPIs Signature multiprecision integers
- * @param {openpgp_type_mpi[]} publickey_MPIs Public key multiprecision integers 
- * @param {String} data Data on where the signature was computed on.
- * @return {Boolean} true if signature (sig_data was equal to data over hash)
- */
-function openpgp_crypto_verifySignature(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
-	var calc_hash = openpgp_crypto_hashData(hash_algo, data);
-	switch(algo) {
-	case 1: // RSA (Encrypt or Sign) [HAC]  
-	case 2: // RSA Encrypt-Only [HAC]
-	case 3: // RSA Sign-Only [HAC]
-		var rsa = new RSA();
-		var n = publickey_MPIs[0].toBigInteger();
-		var e = publickey_MPIs[1].toBigInteger();
-		var x = msg_MPIs[0].toBigInteger();
-		var dopublic = rsa.verify(x,e,n);
-		var hash  = openpgp_encoding_emsa_pkcs1_decode(hash_algo,dopublic.toMPI().substring(2));
-		if (hash == -1) {
-			util.print_error("PKCS1 padding in message or key incorrect. Aborting...");
-			return false;
-		}
-		return hash == calc_hash;
-		
-	case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
-		util.print_error("signing with Elgamal is not defined in the OpenPGP standard.");
-		return null;
-	case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
-		var dsa = new DSA();
-		var s1 = msg_MPIs[0].toBigInteger();
-		var s2 = msg_MPIs[1].toBigInteger();
-		var p = publickey_MPIs[0].toBigInteger();
-		var q = publickey_MPIs[1].toBigInteger();
-		var g = publickey_MPIs[2].toBigInteger();
-		var y = publickey_MPIs[3].toBigInteger();
-		var m = data;
-		var dopublic = dsa.verify(hash_algo,s1,s2,m,p,q,g,y);
-		return dopublic.compareTo(s1) == 0;
-	default:
-		return null;
-	}
-	
-}
-   
-/**
- * Create a signature on data using the specified algorithm
- * @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4)
- * @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1)
- * @param {openpgp_type_mpi[]} publicMPIs Public key multiprecision integers 
- * of the private key 
- * @param {openpgp_type_mpi[]} secretMPIs Private key multiprecision 
- * integers which is used to sign the data
- * @param {String} data Data to be signed
- * @return {(String|openpgp_type_mpi)}
- */
-function openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, data) {
-	
-	switch(algo) {
-	case 1: // RSA (Encrypt or Sign) [HAC]  
-	case 2: // RSA Encrypt-Only [HAC]
-	case 3: // RSA Sign-Only [HAC]
-		var rsa = new RSA();
-		var d = secretMPIs[0].toBigInteger();
-		var n = publicMPIs[0].toBigInteger();
-		var m = openpgp_encoding_emsa_pkcs1_encode(hash_algo, data,publicMPIs[0].mpiByteLength);
-		util.print_debug("signing using RSA");
-		return rsa.sign(m, d, n).toMPI();
-	case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
-		var dsa = new DSA();
-		util.print_debug("DSA Sign: q size in Bytes:"+publicMPIs[1].getByteLength());
-		var p = publicMPIs[0].toBigInteger();
-		var q = publicMPIs[1].toBigInteger();
-		var g = publicMPIs[2].toBigInteger();
-		var y = publicMPIs[3].toBigInteger();
-		var x = secretMPIs[0].toBigInteger();
-		var m = data;
-		var result = dsa.sign(hash_algo,m, g, p, q, x);
-		util.print_debug("signing using DSA\n result:"+util.hexstrdump(result[0])+"|"+util.hexstrdump(result[1]));
-		return result[0]+result[1];
-	case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
-			util.print_debug("signing with Elgamal is not defined in the OpenPGP standard.");
-			return null;
-	default:
-		return null;
-	}	
-}
-
-/**
- * Create a hash on the specified data using the specified algorithm
- * @param {Integer} algo Hash algorithm type (see RFC4880 9.4)
- * @param {String} data Data to be hashed
- * @return {String} hash value
- */
-function openpgp_crypto_hashData(algo, data) {
-	var hash = null;
-	switch(algo) {
-	case 1: // - MD5 [HAC]
-		hash = MD5(data);
-		break;
-	case 2: // - SHA-1 [FIPS180]
-		hash = str_sha1(data);
-		break;
-	case 3: // - RIPE-MD/160 [HAC]
-		hash = RMDstring(data);
-		break;
-	case 8: // - SHA256 [FIPS180]
-		hash = str_sha256(data);
-		break;
-	case 9: // - SHA384 [FIPS180]
-		hash = str_sha384(data);
-		break;
-	case 10:// - SHA512 [FIPS180]
-		hash = str_sha512(data);
-		break;
-	case 11:// - SHA224 [FIPS180]
-		hash = str_sha224(data);
-	default:
-		break;
-	}
-	return hash;
-}
-
-/**
- * Returns the hash size in bytes of the specified hash algorithm type
- * @param {Integer} algo Hash algorithm type (See RFC4880 9.4)
- * @return {Integer} Size in bytes of the resulting hash
- */
-function openpgp_crypto_getHashByteLength(algo) {
-	var hash = null;
-	switch(algo) {
-	case 1: // - MD5 [HAC]
-		return 16;
-	case 2: // - SHA-1 [FIPS180]
-	case 3: // - RIPE-MD/160 [HAC]
-		return 20;
-	case 8: // - SHA256 [FIPS180]
-		return 32;
-	case 9: // - SHA384 [FIPS180]
-		return 48
-	case 10:// - SHA512 [FIPS180]
-		return 64;
-	case 11:// - SHA224 [FIPS180]
-		return 28;
-	}
-	return null;
-}
-
-/**
- * Retrieve secure random byte string of the specified length
- * @param {Integer} length Length in bytes to generate
- * @return {String} Random byte string
- */
-function openpgp_crypto_getRandomBytes(length) {
-	var result = '';
-	for (var i = 0; i < length; i++) {
-		result += String.fromCharCode(openpgp_crypto_getSecureRandomOctet());
-	}
-	return result;
-}
-
-/**
- * Return a pseudo-random number in the specified range
- * @param {Integer} from Min of the random number
- * @param {Integer} to Max of the random number (max 32bit)
- * @return {Integer} A pseudo random number
- */
-function openpgp_crypto_getPseudoRandom(from, to) {
-	return Math.round(Math.random()*(to-from))+from;
-}
-
-/**
- * Return a secure random number in the specified range
- * @param {Integer} from Min of the random number
- * @param {Integer} to Max of the random number (max 32bit)
- * @return {Integer} A secure random number
- */
-function openpgp_crypto_getSecureRandom(from, to) {
-	var buf = new Uint32Array(1);
-	window.crypto.getRandomValues(buf);
-	var bits = ((to-from)).toString(2).length;
-	while ((buf[0] & (Math.pow(2, bits) -1)) > (to-from))
-		window.crypto.getRandomValues(buf);
-	return from+(Math.abs(buf[0] & (Math.pow(2, bits) -1)));
-}
-
-function openpgp_crypto_getSecureRandomOctet() {
-	var buf = new Uint32Array(1);
-	window.crypto.getRandomValues(buf);
-	return buf[0] & 0xFF;
-}
-
-/**
- * Create a secure random big integer of bits length
- * @param {Integer} bits Bit length of the MPI to create
- * @return {BigInteger} Resulting big integer
- */
-function openpgp_crypto_getRandomBigInteger(bits) {
-	if (bits < 0)
-	   return null;
-	var numBytes = Math.floor((bits+7)/8);
-
-	var randomBits = openpgp_crypto_getRandomBytes(numBytes);
-	if (bits % 8 > 0) {
-		
-		randomBits = String.fromCharCode(
-						(Math.pow(2,bits % 8)-1) &
-						randomBits.charCodeAt(0)) +
-			randomBits.substring(1);
-	}
-	return new openpgp_type_mpi().create(randomBits).toBigInteger();
-}
-
-function openpgp_crypto_getRandomBigIntegerInRange(min, max) {
-	if (max.compareTo(min) <= 0)
-		return;
-	var range = max.subtract(min);
-	var r = openpgp_crypto_getRandomBigInteger(range.bitLength());
-	while (r > range) {
-		r = openpgp_crypto_getRandomBigInteger(range.bitLength());
-	}
-	return min.add(r);
-}
-
-
-//This is a test method to ensure that encryption/decryption with a given 1024bit RSAKey object functions as intended
-function openpgp_crypto_testRSA(key){
-	debugger;
-    var rsa = new RSA();
-	var mpi = new openpgp_type_mpi();
-	mpi.create(openpgp_encoding_eme_pkcs1_encode('ABABABAB', 128));
-	var msg = rsa.encrypt(mpi.toBigInteger(),key.ee,key.n);
-	var result = rsa.decrypt(msg, key.d, key.p, key.q, key.u);
-}
-
-/**
- * @typedef {Object} openpgp_keypair
- * @property {openpgp_packet_keymaterial} privateKey 
- * @property {openpgp_packet_keymaterial} publicKey
- */
-
-/**
- * Calls the necessary crypto functions to generate a keypair. 
- * Called directly by openpgp.js
- * @param {Integer} keyType Follows OpenPGP algorithm convention.
- * @param {Integer} numBits Number of bits to make the key to be generated
- * @return {openpgp_keypair}
- */
-function openpgp_crypto_generateKeyPair(keyType, numBits, passphrase, s2kHash, symmetricEncryptionAlgorithm){
-	var privKeyPacket;
-	var publicKeyPacket;
-	var d = new Date();
-	d = d.getTime()/1000;
-	var timePacket = String.fromCharCode(Math.floor(d/0x1000000%0x100)) + String.fromCharCode(Math.floor(d/0x10000%0x100)) + String.fromCharCode(Math.floor(d/0x100%0x100)) + String.fromCharCode(Math.floor(d%0x100));
-	switch(keyType){
-	case 1:
-	    var rsa = new RSA();
-	    var key = rsa.generate(numBits,"10001");
-	    privKeyPacket = new openpgp_packet_keymaterial().write_private_key(keyType, key, passphrase, s2kHash, symmetricEncryptionAlgorithm, timePacket);
-	    publicKeyPacket =  new openpgp_packet_keymaterial().write_public_key(keyType, key, timePacket);
-	    break;
-	default:
-		util.print_error("Unknown keytype "+keyType)
-	}
-	return {privateKey: privKeyPacket, publicKey: publicKeyPacket};
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.crypto.sym.js.html b/doc/openpgp.crypto.sym.js.html deleted file mode 100644 index fc99bbf1..00000000 --- a/doc/openpgp.crypto.sym.js.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - JSDoc: Source: ciphers/openpgp.crypto.sym.js - - - - - - - - - - -
- -

Source: ciphers/openpgp.crypto.sym.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
-
-// The GPG4Browsers symmetric crypto interface
-
-/**
- * Symmetrically encrypts data using prefixedrandom, a key with length 
- * depending on the algorithm in openpgp_cfb mode with or without resync
- * (MDC style)
- * @param {String} prefixrandom Secure random bytes as string in 
- * length equal to the block size of the algorithm used (use 
- * openpgp_crypto_getPrefixRandom(algo) to retrieve that string
- * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
- * @param {String} key Key as string. length is depending on the algorithm used
- * @param {String} data Data to encrypt
- * @param {Boolean} openpgp_cfb
- * @return {String} Encrypted data
- */
-function openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_cfb) {
-	switch(algo) {
-		case 0: // Plaintext or unencrypted data
-			return data; // blockcipherencryptfn, plaintext, block_size, key
-		case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
-			return openpgp_cfb_encrypt(prefixrandom, desede, data,8,key, openpgp_cfb).substring(0, data.length + 10);
-		case 3: // CAST5 (128 bit key, as per [RFC2144])
-			return openpgp_cfb_encrypt(prefixrandom, cast5_encrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10);
-		case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
-			return openpgp_cfb_encrypt(prefixrandom, BFencrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10);
-		case 7: // AES with 128-bit key [AES]
-		case 8: // AES with 192-bit key
-		case 9: // AES with 256-bit key
-			return openpgp_cfb_encrypt(prefixrandom, AESencrypt, data, 16, keyExpansion(key), openpgp_cfb).substring(0, data.length + 18);
-		case 10: // Twofish with 256-bit key [TWOFISH]
-			return openpgp_cfb_encrypt(prefixrandom, TFencrypt, data,16, key, openpgp_cfb).substring(0, data.length + 18);
-		case 1: // IDEA [IDEA]
-			util.print_error("IDEA Algorithm not implemented");
-			return null;
-		default:
-			return null;
-	}
-}
-
-/**
- * Symmetrically decrypts data using a key with length depending on the
- * algorithm in openpgp_cfb mode with or without resync (MDC style)
- * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
- * @param {String} key Key as string. length is depending on the algorithm used
- * @param {String} data Data to be decrypted
- * @param {Boolean} openpgp_cfb If true use the resync (for encrypteddata); 
- * otherwise use without the resync (for MDC encrypted data)
- * @return {String} Plaintext data
- */
-function openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) {
-	util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nalgo:"+algo+"\nencrypteddata:",data);
-	var n = 0;
-	if (!openpgp_cfb)
-		n = 2;
-	switch(algo) {
-	case 0: // Plaintext or unencrypted data
-		return data;
-	case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
-		return openpgp_cfb_decrypt(desede, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
-	case 3: // CAST5 (128 bit key, as per [RFC2144])
-		return openpgp_cfb_decrypt(cast5_encrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
-	case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
-		return openpgp_cfb_decrypt(BFencrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
-	case 7: // AES with 128-bit key [AES]
-	case 8: // AES with 192-bit key
-	case 9: // AES with 256-bit key
-		return openpgp_cfb_decrypt(AESencrypt, 16, keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18);
-	case 10: // Twofish with 256-bit key [TWOFISH]
-		var result = openpgp_cfb_decrypt(TFencrypt, 16, key, data, openpgp_cfb).substring(n, (data.length+n)-18);
-		return result;
-	case 1: // IDEA [IDEA]
-		util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
-		return null;
-	default:
-	}
-	return null;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.encoding.asciiarmor.js.html b/doc/openpgp.encoding.asciiarmor.js.html deleted file mode 100644 index 38240459..00000000 --- a/doc/openpgp.encoding.asciiarmor.js.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - - JSDoc: Source: encoding/openpgp.encoding.asciiarmor.js - - - - - - - - - - -
- -

Source: encoding/openpgp.encoding.asciiarmor.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * DeArmor an OpenPGP armored message; verify the checksum and return 
- * the encoded bytes
- * @param {String} text OpenPGP armored message
- * @returns {(String|Object)} Either the bytes of the decoded message 
- * or an object with attribute "text" containing the message text
- * and an attribute "openpgp" containing the bytes.
- */
-function openpgp_encoding_deArmor(text) {
-	var type = getPGPMessageType(text);
-	if (type != 2) {
-	var splittedtext = text.split('-----');
-	data = { openpgp: openpgp_encoding_base64_decode(splittedtext[2].split('\n\n')[1].split("\n=")[0].replace(/\n- /g,"\n")),
-			type: type};
-	if (verifyCheckSum(data.openpgp, splittedtext[2].split('\n\n')[1].split("\n=")[1].split('\n')[0]))
-		return data;
-	else
-		util.print_error("Ascii armor integrity check on message failed: '"+splittedtext[2].split('\n\n')[1].split("\n=")[1].split('\n')[0]+"' should be '"+getCheckSum(data))+"'";
-	} else {
-		var splittedtext = text.split('-----');
-		var result = { text: splittedtext[2].replace(/\n- /g,"\n").split("\n\n")[1],
-		               openpgp: openpgp_encoding_base64_decode(splittedtext[4].split("\n\n")[1].split("\n=")[0]),
-		               type: type};
-		if (verifyCheckSum(result.openpgp, splittedtext[4].split("\n\n")[1].split("\n=")[1]))
-				return result;
-		else
-			util.print_error("Ascii armor integrity check on message failed");
-	}
-}
-
-/**
- * Finds out which Ascii Armoring type is used. This is an internal function
- * @param {String} text [String] ascii armored text
- * @returns {Integer} 0 = MESSAGE PART n of m
- *         1 = MESSAGE PART n
- *         2 = SIGNED MESSAGE
- *         3 = PGP MESSAGE
- *         4 = PUBLIC KEY BLOCK
- *         5 = PRIVATE KEY BLOCK
- *         null = unknown
- */
-function getPGPMessageType(text) {
-	var splittedtext = text.split('-----');
-	// BEGIN PGP MESSAGE, PART X/Y
-	// Used for multi-part messages, where the armor is split amongst Y
-	// parts, and this is the Xth part out of Y.
-	if (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
-		return 0;
-	} else
-		// BEGIN PGP MESSAGE, PART X
-		// Used for multi-part messages, where this is the Xth part of an
-		// unspecified number of parts. Requires the MESSAGE-ID Armor
-		// Header to be used.
-	if (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
-		return 1;
-
-	} else
-		// BEGIN PGP SIGNATURE
-		// Used for detached signatures, OpenPGP/MIME signatures, and
-		// cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
-		// for detached signatures.
-	if (splittedtext[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
-		return 2;
-
-	} else
-  	    // BEGIN PGP MESSAGE
-	    // Used for signed, encrypted, or compressed files.
-	if (splittedtext[1].match(/BEGIN PGP MESSAGE/)) {
-		return 3;
-
-	} else
-		// BEGIN PGP PUBLIC KEY BLOCK
-		// Used for armoring public keys.
-	if (splittedtext[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
-		return 4;
-
-	} else
-		// BEGIN PGP PRIVATE KEY BLOCK
-		// Used for armoring private keys.
-	if (splittedtext[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) {
-		return 5;
-	}
-}
-
-/**
- * Add additional information to the armor version of an OpenPGP binary
- * packet block.
- * @author  Alex
- * @version 2011-12-16
- * @returns {String} The header information
- */
-function openpgp_encoding_armor_addheader() {
-    var result = "";
-	if (openpgp.config.config.show_version) {
-        result += "Version: "+openpgp.config.versionstring+'\r\n';
-    }
-	if (openpgp.config.config.show_comment) {
-        result += "Comment: "+openpgp.config.commentstring+'\r\n';
-    }
-    result += '\r\n';
-    return result;
-}
-
-/**
- * Armor an OpenPGP binary packet block
- * @param {Integer} messagetype type of the message
- * @param data
- * @param {Integer} partindex
- * @param {Integer} parttotal
- * @returns {String} Armored text
- */
-function openpgp_encoding_armor(messagetype, data, partindex, parttotal) {
-	var result = "";
-	switch(messagetype) {
-	case 0:
-		result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
-		result += openpgp_encoding_armor_addheader();
-		result += openpgp_encoding_base64_encode(data);
-		result += "\r\n="+getCheckSum(data)+"\r\n";
-		result += "-----END PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
-		break;
-	case 1:
-		result += "-----BEGIN PGP MESSAGE, PART "+partindex+"-----\r\n";
-		result += openpgp_encoding_armor_addheader();
-		result += openpgp_encoding_base64_encode(data);
-		result += "\r\n="+getCheckSum(data)+"\r\n";
-		result += "-----END PGP MESSAGE, PART "+partindex+"-----\r\n";
-		break;
-	case 2:
-		result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "+data.hash+"\r\n\r\n";
-		result += data.text.replace(/\n-/g,"\n- -");
-		result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
-		result += openpgp_encoding_armor_addheader();
-		result += openpgp_encoding_base64_encode(data.openpgp);
-		result += "\r\n="+getCheckSum(data.openpgp)+"\r\n";
-		result += "-----END PGP SIGNATURE-----\r\n";
-		break;
-	case 3:
-		result += "-----BEGIN PGP MESSAGE-----\r\n";
-		result += openpgp_encoding_armor_addheader();
-		result += openpgp_encoding_base64_encode(data);
-		result += "\r\n="+getCheckSum(data)+"\r\n";
-		result += "-----END PGP MESSAGE-----\r\n";
-		break;
-	case 4:
-		result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
-		result += openpgp_encoding_armor_addheader();
-		result += openpgp_encoding_base64_encode(data);
-		result += "\r\n="+getCheckSum(data)+"\r\n";
-		result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
-		break;
-	case 5:
-		result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
-		result += openpgp_encoding_armor_addheader();
-		result += openpgp_encoding_base64_encode(data);
-		result += "\r\n="+getCheckSum(data)+"\r\n";
-		result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
-		break;
-	}
-
-	return result;
-}
-
-/**
- * Calculates a checksum over the given data and returns it base64 encoded
- * @param {String} data Data to create a CRC-24 checksum for
- * @return {String} Base64 encoded checksum
- */
-function getCheckSum(data) {
-	var c = createcrc24(data);
-	var str = "" + String.fromCharCode(c >> 16)+
-				   String.fromCharCode((c >> 8) & 0xFF)+
-				   String.fromCharCode(c & 0xFF);
-	return openpgp_encoding_base64_encode(str);
-}
-
-/**
- * Calculates the checksum over the given data and compares it with the 
- * given base64 encoded checksum
- * @param {String} data Data to create a CRC-24 checksum for
- * @param {String} checksum Base64 encoded checksum
- * @return {Boolean} True if the given checksum is correct; otherwise false
- */
-function verifyCheckSum(data, checksum) {
-	var c = getCheckSum(data);
-	var d = checksum;
-	return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
-}
-/**
- * Internal function to calculate a CRC-24 checksum over a given string (data)
- * @param {String} data Data to create a CRC-24 checksum for
- * @return {Integer} The CRC-24 checksum as number
- */
-var crc_table = [
-0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0,
-0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340, 0x62330fbb,
-0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
-0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538];
-
-function createcrc24(input) {
-  var crc = 0xB704CE;
-  var index = 0;
-
-  while((input.length - index) > 16)  {
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+1)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+2)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+3)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+4)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+5)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+6)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+7)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+8)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+9)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+10)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+11)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+12)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+13)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+14)) & 0xff];
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+15)) & 0xff];
-   index += 16;
-  }
-
-  for(var j = index; j < input.length; j++) {
-   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff]
-  }
-  return crc & 0xffffff;
-}
-
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.encoding.js.html b/doc/openpgp.encoding.js.html deleted file mode 100644 index 639b1a5a..00000000 --- a/doc/openpgp.encoding.js.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - JSDoc: Source: encoding/openpgp.encoding.js - - - - - - - - - - -
- -

Source: encoding/openpgp.encoding.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * Wrapper function for the base64 codec. 
- * This function encodes a String (message) in base64 (radix-64)
- * @param {String} message The message to encode
- * @return {String} The base64 encoded data
- */
-function openpgp_encoding_base64_encode(message) {
-	return s2r(message);
-}
-
-
-/**
- * Wrapper function for the base64 codec.
- * This function decodes a String(message) in base64 (radix-64)
- * @param {String} message Base64 encoded data
- * @return {String} Raw data after decoding
- */
-function openpgp_encoding_base64_decode(message) {
-	return r2s(message);
-}
-
-/**
- * Wrapper function for jquery library.
- * This function escapes HTML characters within a string. This is used 
- * to prevent XSS.
- * @param {String} message Message to escape
- * @return {String} Html encoded string
- */
-function openpgp_encoding_html_encode(message) {
-	if (message == null)
-		return "";
-	return $('<div/>').text(message).html();
-}
-
-/**
- * create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1)
- * @param {String} message message to be padded
- * @param {Integer} length Length to the resulting message
- * @return {String} EME-PKCS1 padded message
- */
-function openpgp_encoding_eme_pkcs1_encode(message, length) {
-	if (message.length > length-11)
-		return -1;
-	var result = "";
-	result += String.fromCharCode(0);
-	result += String.fromCharCode(2);
-	for (var i = 0; i < length - message.length - 3; i++) {
-		result += String.fromCharCode(openpgp_crypto_getPseudoRandom(1,255));
-	}
-	result += String.fromCharCode(0);
-	result += message;
-	return result;
-}
-
-/**
- * decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2)
- * @param {String} message EME-PKCS1 padded message
- * @return {String} decoded message 
- */
-function openpgp_encoding_eme_pkcs1_decode(message, len) {
-	if (message.length < len)
-	    message = String.fromCharCode(0)+message;
-	if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2)
-		return -1;
-	var i = 2;
-	while (message.charCodeAt(i) != 0 && message.length > i)
-	    i++;
-	return message.substring(i+1, message.length);
-}
-/**
- * ASN1 object identifiers for hashes (See RFC4880 5.2.2)
- */
-hash_headers = new Array();
-hash_headers[1]  = [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10];
-hash_headers[3]  = [0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14];
-hash_headers[2]  = [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14];
-hash_headers[8]  = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20];
-hash_headers[9]  = [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30];
-hash_headers[10] = [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40];
-hash_headers[11] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1C];
-
-/**
- * create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3)
- * @param {Integer} algo Hash algorithm type used
- * @param {String} data Data to be hashed
- * @param {Integer} keylength Key size of the public mpi in bytes
- * @returns {String} Hashcode with pkcs1padding as string
- */
-function openpgp_encoding_emsa_pkcs1_encode(algo, data, keylength) {
-	var data2 = "";
-	data2 += String.fromCharCode(0x00);
-	data2 += String.fromCharCode(0x01);
-	for (var i = 0; i < (keylength - hash_headers[algo].length - 3 - openpgp_crypto_getHashByteLength(algo)); i++)
-		data2 += String.fromCharCode(0xff);
-	data2 += String.fromCharCode(0x00);
-	
-	for (var i = 0; i < hash_headers[algo].length; i++)
-		data2 += String.fromCharCode(hash_headers[algo][i]);
-	
-	data2 += openpgp_crypto_hashData(algo, data);
-	return new BigInteger(util.hexstrdump(data2),16);
-}
-
-/**
- * extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3) 
- * @param {String} data Hash in pkcs1 encoding
- * @returns {String} The hash as string
- */
-function openpgp_encoding_emsa_pkcs1_decode(algo, data) { 
-	var i = 0;
-	if (data.charCodeAt(0) == 0) i++;
-	else if (data.charCodeAt(0) != 1) return -1;
-	else i++;
-
-	while (data.charCodeAt(i) == 0xFF) i++;
-	if (data.charCodeAt(i++) != 0) return -1;
-	var j = 0;
-	for (j = 0; j < hash_headers[algo].length && j+i < data.length; j++) {
-		if (data.charCodeAt(j+i) != hash_headers[algo][j]) return -1;
-	}
-	i+= j;	
-	if (data.substring(i).length < openpgp_crypto_getHashByteLength(algo)) return -1;
-	return data.substring(i);
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.html b/doc/openpgp.html deleted file mode 100644 index 7d2e1e47..00000000 --- a/doc/openpgp.html +++ /dev/null @@ -1,1530 +0,0 @@ - - - - - JSDoc: Class: openpgp - - - - - - - - - - -
- -

Class: openpgp

- - - - - -
- -
-

- openpgp -

- -
Main Openpgp.js class. Use this to initiate and make all calls to this library.
- -
- -
-
- - - - -
-

new openpgp()

- - -
-
- - -
- GPG4Browsers Core interface. A single instance is hold -from the beginning. To use this library call "openpgp.init()" -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> generate_key_pair(keyType, numBits, userId, passphrase) → {Object}

- - -
-
- - -
- generates a new key pair for openpgp. Beta stage. Currently only -supports RSA keys, and no subkeys. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyType - - -Integer - - - - to indicate what type of key to make. -RSA is 1. Follows algorithms outlined in OpenPGP.
numBits - - -Integer - - - - number of bits for the key creation. (should -be 1024+, generally)
userId - - -String - - - - assumes already in form of "User Name -"
passphrase - - -String - - - - The passphrase used to encrypt the resulting private key
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- {privateKey: [openpgp_msg_privatekey], -privateKeyArmored: [string], publicKeyArmored: [string]} -
- - - -
-
- Type -
-
- -Object - - -
-
- - - - -
- - - -
-

<inner> init()

- - -
-
- - -
- initializes the library: -- reading the keyring from local storage -- reading the config from local storage -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

<inner> read_message(armoredText) → {openpgp_msg_message[]}

- - -
-
- - -
- reads message packets out of an OpenPGP armored text and -returns an array of message objects -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
armoredText - - -String - - - - text to be parsed
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- on error the function -returns null -
- - - -
-
- Type -
-
- -openpgp_msg_message[] - - -
-
- - - - -
- - - -
-

<inner> read_messages_dearmored(input) → {openpgp_msg_message[]}

- - -
-
- - -
- reads message packets out of an OpenPGP armored text and -returns an array of message objects. Can be called externally or internally. -External call will parse a de-armored messaged and return messages found. -Internal will be called to read packets wrapped in other packets (i.e. compressed) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - dearmored text of OpenPGP packets, to be parsed
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- on error the function -returns null -
- - - -
-
- Type -
-
- -openpgp_msg_message[] - - -
-
- - - - -
- - - -
-

<inner> read_privateKey(armoredText) → {openpgp_msg_privatekey[]}

- - -
-
- - -
- reads several privateKey objects from a ascii armored -representation an returns openpgp_msg_privatekey objects -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
armoredText - - -String - - - - OpenPGP armored text containing -the private key(s)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- on error the function -returns null -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey[] - - -
-
- - - - -
- - - -
-

<inner> read_publicKey(armoredText) → {openpgp_msg_publickey[]}

- - -
-
- - -
- reads several publicKey objects from a ascii armored -representation an returns openpgp_msg_publickey packets -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
armoredText - - -String - - - - OpenPGP armored text containing -the public key(s)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- on error the function -returns null -
- - - -
-
- Type -
-
- -openpgp_msg_publickey[] - - -
-
- - - - -
- - - -
-

<inner> write_encrypted_message(publickeys, messagetext) → {String}

- - -
-
- - -
- creates a binary string representation of an encrypted message. -The message will be encrypted with the public keys specified -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
publickeys - - -Object[] - - - - An array of {obj: [openpgp_msg_publickey]} --public keys to be used to encrypt the message
messagetext - - -String - - - - message text to encrypt
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a binary string representation of the message -which can be OpenPGP armored -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> write_signed_and_encrypted_message(privatekey, publickeys, messagetext) → {String}

- - -
-
- - -
- creates a binary string representation of an encrypted and signed message. -The message will be encrypted with the public keys specified and signed -with the specified private key. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
privatekey - - -Object - - - - {obj: [openpgp_msg_privatekey]} Private key -to be used to sign the message
publickeys - - -Object[] - - - - An arraf of {obj: [openpgp_msg_publickey]} -- public keys to be used to encrypt the message
messagetext - - -String - - - - message text to encrypt and sign
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a binary string representation of the message which -can be OpenPGP armored -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> write_signed_message(privatekey, messagetext) → {Object}

- - -
-
- - -
- creates a binary string representation a signed message. -The message will be signed with the specified private key. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
privatekey - - -Object - - - - {obj: [openpgp_msg_privatekey]} -- the private key to be used to sign the message
messagetext - - -String - - - - message text to sign
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- {Object: text [String]}, openpgp: {String} a binary - string representation of the message which can be OpenPGP - armored(openpgp) and a text representation of the message (text). -This can be directly used to OpenPGP armor the message -
- - - -
-
- Type -
-
- -Object - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.js.html b/doc/openpgp.js.html index 604aadf2..6a6462af 100644 --- a/doc/openpgp.js.html +++ b/doc/openpgp.js.html @@ -43,449 +43,152 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @fileoverview The openpgp base class should provide all of the functionality + * @fileoverview The openpgp base module should provide all of the functionality * to consume the openpgp.js library. All additional classes are documented * for extending and developing on top of the base library. */ /** - * GPG4Browsers Core interface. A single instance is hold - * from the beginning. To use this library call "openpgp.init()" - * @alias openpgp - * @class - * @classdesc Main Openpgp.js class. Use this to initiate and make all calls to this library. + * @requires cleartext + * @requires config + * @requires encoding/armor + * @requires enums + * @requires message + * @requires packet + * @module openpgp */ -function _openpgp () { - this.tostring = ""; - - /** - * initializes the library: - * - reading the keyring from local storage - * - reading the config from local storage - */ - function init() { - this.config = new openpgp_config(); - this.config.read(); - this.keyring = new openpgp_keyring(); - this.keyring.init(); - } - - /** - * reads several publicKey objects from a ascii armored - * representation an returns openpgp_msg_publickey packets - * @param {String} armoredText OpenPGP armored text containing - * the public key(s) - * @return {openpgp_msg_publickey[]} on error the function - * returns null - */ - function read_publicKey(armoredText) { - var mypos = 0; - var publicKeys = new Array(); - var publicKeyCount = 0; - var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp; - var l = input.length; - while (mypos != input.length) { - var first_packet = openpgp_packet.read_packet(input, mypos, l); - // public key parser - if (input[mypos].charCodeAt() == 0x99 || first_packet.tagType == 6) { - publicKeys[publicKeyCount] = new openpgp_msg_publickey(); - publicKeys[publicKeyCount].header = input.substring(mypos,mypos+3); - if (input[mypos].charCodeAt() == 0x99) { - // parse the length and read a tag6 packet - mypos++; - var l = (input[mypos++].charCodeAt() << 8) - | input[mypos++].charCodeAt(); - publicKeys[publicKeyCount].publicKeyPacket = new openpgp_packet_keymaterial(); - publicKeys[publicKeyCount].publicKeyPacket.header = publicKeys[publicKeyCount].header; - publicKeys[publicKeyCount].publicKeyPacket.read_tag6(input, mypos, l); - mypos += publicKeys[publicKeyCount].publicKeyPacket.packetLength; - mypos += publicKeys[publicKeyCount].read_nodes(publicKeys[publicKeyCount].publicKeyPacket, input, mypos, (input.length - mypos)); - } else { - publicKeys[publicKeyCount] = new openpgp_msg_publickey(); - publicKeys[publicKeyCount].publicKeyPacket = first_packet; - mypos += first_packet.headerLength+first_packet.packetLength; - mypos += publicKeys[publicKeyCount].read_nodes(first_packet, input, mypos, input.length -mypos); - } - } else { - util.print_error("no public key found!"); - return null; - } - publicKeys[publicKeyCount].data = input.substring(0,mypos); - publicKeyCount++; - } - return publicKeys; - } - - /** - * reads several privateKey objects from a ascii armored - * representation an returns openpgp_msg_privatekey objects - * @param {String} armoredText OpenPGP armored text containing - * the private key(s) - * @return {openpgp_msg_privatekey[]} on error the function - * returns null - */ - function read_privateKey(armoredText) { - var privateKeys = new Array(); - var privateKeyCount = 0; - var mypos = 0; - var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp; - var l = input.length; - while (mypos != input.length) { - var first_packet = openpgp_packet.read_packet(input, mypos, l); - if (first_packet.tagType == 5) { - privateKeys[privateKeys.length] = new openpgp_msg_privatekey(); - mypos += first_packet.headerLength+first_packet.packetLength; - mypos += privateKeys[privateKeyCount].read_nodes(first_packet, input, mypos, l); - // other blocks - } else { - util.print_error('no block packet found!'); - return null; - } - privateKeys[privateKeyCount].data = input.substring(0,mypos); - privateKeyCount++; - } - return privateKeys; - } - /** - * reads message packets out of an OpenPGP armored text and - * returns an array of message objects - * @param {String} armoredText text to be parsed - * @return {openpgp_msg_message[]} on error the function - * returns null - */ - function read_message(armoredText) { - var dearmored; - try{ - dearmored = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')); - } - catch(e){ - util.print_error('no message found!'); - return null; - } - return read_messages_dearmored(dearmored); - } - - /** - * reads message packets out of an OpenPGP armored text and - * returns an array of message objects. Can be called externally or internally. - * External call will parse a de-armored messaged and return messages found. - * Internal will be called to read packets wrapped in other packets (i.e. compressed) - * @param {String} input dearmored text of OpenPGP packets, to be parsed - * @return {openpgp_msg_message[]} on error the function - * returns null - */ - function read_messages_dearmored(input){ - var messageString = input.openpgp; - var signatureText = input.text; //text to verify signatures against. Modified by Tag11. - var messages = new Array(); - var messageCount = 0; - var mypos = 0; - var l = messageString.length; - while (mypos < messageString.length) { - var first_packet = openpgp_packet.read_packet(messageString, mypos, l); - if (!first_packet) { - break; - } - // public key parser (definition from the standard:) - // OpenPGP Message :- Encrypted Message | Signed Message | - // Compressed Message | Literal Message. - // Compressed Message :- Compressed Data Packet. - // - // Literal Message :- Literal Data Packet. - // - // ESK :- Public-Key Encrypted Session Key Packet | - // Symmetric-Key Encrypted Session Key Packet. - // - // ESK Sequence :- ESK | ESK Sequence, ESK. - // - // Encrypted Data :- Symmetrically Encrypted Data Packet | - // Symmetrically Encrypted Integrity Protected Data Packet - // - // Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data. - // - // One-Pass Signed Message :- One-Pass Signature Packet, - // OpenPGP Message, Corresponding Signature Packet. +var armor = require('./encoding/armor.js'), + packet = require('./packet'), + enums = require('./enums.js'), + config = require('./config'), + message = require('./message.js'), + cleartext = require('./cleartext.js'), + key = require('./key.js'); - // Signed Message :- Signature Packet, OpenPGP Message | - // One-Pass Signed Message. - if (first_packet.tagType == 1 || - (first_packet.tagType == 2 && first_packet.signatureType < 16) || - first_packet.tagType == 3 || - first_packet.tagType == 4 || - first_packet.tagType == 8 || - first_packet.tagType == 9 || - first_packet.tagType == 10 || - first_packet.tagType == 11 || - first_packet.tagType == 18 || - first_packet.tagType == 19) { - messages[messages.length] = new openpgp_msg_message(); - messages[messageCount].messagePacket = first_packet; - messages[messageCount].type = input.type; - // Encrypted Message - if (first_packet.tagType == 9 || - first_packet.tagType == 1 || - first_packet.tagType == 3 || - first_packet.tagType == 18) { - if (first_packet.tagType == 9) { - util.print_error("unexpected openpgp packet"); - break; - } else if (first_packet.tagType == 1) { - util.print_debug("session key found:\n "+first_packet.toString()); - var issessionkey = true; - messages[messageCount].sessionKeys = new Array(); - var sessionKeyCount = 0; - while (issessionkey) { - messages[messageCount].sessionKeys[sessionKeyCount] = first_packet; - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - first_packet = openpgp_packet.read_packet(messageString, mypos, l); - - if (first_packet.tagType != 1 && first_packet.tagType != 3) - issessionkey = false; - sessionKeyCount++; - } - if (first_packet.tagType == 18 || first_packet.tagType == 9) { - util.print_debug("encrypted data found:\n "+first_packet.toString()); - messages[messageCount].encryptedData = first_packet; - mypos += first_packet.packetLength+first_packet.headerLength; - l -= (first_packet.packetLength+first_packet.headerLength); - messageCount++; - - } else { - util.print_debug("something is wrong: "+first_packet.tagType); - } - - } else if (first_packet.tagType == 18) { - util.print_debug("symmetric encrypted data"); - break; - } - } else - if (first_packet.tagType == 2 && first_packet.signatureType < 3) { - // Signed Message - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - messages[messageCount].text = signatureText; - messages[messageCount].signature = first_packet; - messageCount++; - } else - // Signed Message - if (first_packet.tagType == 4) { - //TODO: Implement check - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } else - if (first_packet.tagType == 8) { - // Compressed Message - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - var decompressedText = first_packet.decompress(); - messages = messages.concat(openpgp.read_messages_dearmored({text: decompressedText, openpgp: decompressedText})); - } else - // Marker Packet (Obsolete Literal Packet) (Tag 10) - // "Such a packet MUST be ignored when received." see http://tools.ietf.org/html/rfc4880#section-5.8 - if (first_packet.tagType == 10) { - // reset messages - messages.length = 0; - // continue with next packet - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } else - if (first_packet.tagType == 11) { - // Literal Message -- work is already done in read_packet - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - signatureText = first_packet.data; - messages[messageCount].data = first_packet.data; - messageCount++; - } else - if (first_packet.tagType == 19) { - // Modification Detect Code - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } - } else { - util.print_error('no message found!'); - return null; - } - } - - return messages; - } - - /** - * creates a binary string representation of an encrypted and signed message. - * The message will be encrypted with the public keys specified and signed - * with the specified private key. - * @param {Object} privatekey {obj: [openpgp_msg_privatekey]} Private key - * to be used to sign the message - * @param {Object[]} publickeys An arraf of {obj: [openpgp_msg_publickey]} - * - public keys to be used to encrypt the message - * @param {String} messagetext message text to encrypt and sign - * @return {String} a binary string representation of the message which - * can be OpenPGP armored - */ - function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) { - var result = ""; - var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n")); - util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal); - for (var i = 0; i < publickeys.length; i++) { - var onepasssignature = new openpgp_packet_onepasssignature(); - var onepasssigstr = ""; - if (i == 0) - onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false); - else - onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false); - util.print_debug_hexstr_dump("onepasssigstr: |"+onepasssigstr+"|\n",onepasssigstr); - var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey); - util.print_debug_hexstr_dump("datasignature: |"+datasignature.openpgp+"|\n",datasignature.openpgp); - if (i == 0) { - result = onepasssigstr+literal+datasignature.openpgp; - } else { - result = onepasssigstr+result+datasignature.openpgp; - } - } - - util.print_debug_hexstr_dump("signed packet: |"+result+"|\n",result); - // signatures done.. now encryption - var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); - var result2 = ""; - - // creating session keys for each recipient - for (var i = 0; i < publickeys.length; i++) { - var pkey = publickeys[i].getEncryptionKey(); - if (pkey == null) { - util.print_error("no encryption key found! Key is for signing only."); - return null; - } - result2 += new openpgp_packet_encryptedsessionkey(). - write_pub_key_packet( - pkey.getKeyId(), - pkey.MPIs, - pkey.publicKeyAlgorithm, - openpgp.config.config.encryption_cipher, - sessionkey); - } - if (openpgp.config.config.integrity_protect) { - result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } else { - result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } - return openpgp_encoding_armor(3,result2,null,null); - } - /** - * creates a binary string representation of an encrypted message. - * The message will be encrypted with the public keys specified - * @param {Object[]} publickeys An array of {obj: [openpgp_msg_publickey]} - * -public keys to be used to encrypt the message - * @param {String} messagetext message text to encrypt - * @return {String} a binary string representation of the message - * which can be OpenPGP armored - */ - function write_encrypted_message(publickeys, messagetext) { - var result = ""; - var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n")); - util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal); - result = literal; - - // signatures done.. now encryption - var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); - var result2 = ""; - - // creating session keys for each recipient - for (var i = 0; i < publickeys.length; i++) { - var pkey = publickeys[i].getEncryptionKey(); - if (pkey == null) { - util.print_error("no encryption key found! Key is for signing only."); - return null; - } - result2 += new openpgp_packet_encryptedsessionkey(). - write_pub_key_packet( - pkey.getKeyId(), - pkey.MPIs, - pkey.publicKeyAlgorithm, - openpgp.config.config.encryption_cipher, - sessionkey); - } - if (openpgp.config.config.integrity_protect) { - result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } else { - result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } - return openpgp_encoding_armor(3,result2,null,null); - } - - /** - * creates a binary string representation a signed message. - * The message will be signed with the specified private key. - * @param {Object} privatekey {obj: [openpgp_msg_privatekey]} - * - the private key to be used to sign the message - * @param {String} messagetext message text to sign - * @return {Object} {Object: text [String]}, openpgp: {String} a binary - * string representation of the message which can be OpenPGP - * armored(openpgp) and a text representation of the message (text). - * This can be directly used to OpenPGP armor the message - */ - function write_signed_message(privatekey, messagetext) { - var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), privatekey); - var result = {text: messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), openpgp: sig.openpgp, hash: sig.hash}; - return openpgp_encoding_armor(2,result, null, null) - } - - /** - * generates a new key pair for openpgp. Beta stage. Currently only - * supports RSA keys, and no subkeys. - * @param {Integer} keyType to indicate what type of key to make. - * RSA is 1. Follows algorithms outlined in OpenPGP. - * @param {Integer} numBits number of bits for the key creation. (should - * be 1024+, generally) - * @param {String} userId assumes already in form of "User Name - * <username@email.com>" - * @param {String} passphrase The passphrase used to encrypt the resulting private key - * @return {Object} {privateKey: [openpgp_msg_privatekey], - * privateKeyArmored: [string], publicKeyArmored: [string]} - */ - function generate_key_pair(keyType, numBits, userId, passphrase){ - var userIdPacket = new openpgp_packet_userid(); - var userIdString = userIdPacket.write_packet(userId); - - var keyPair = openpgp_crypto_generateKeyPair(keyType,numBits, passphrase, openpgp.config.config.prefer_hash_algorithm, 3); - var privKeyString = keyPair.privateKey; - var privKeyPacket = new openpgp_packet_keymaterial().read_priv_key(privKeyString.string,3,privKeyString.string.length); - if(!privKeyPacket.decryptSecretMPIs(passphrase)) - util.print_error('Issue creating key. Unable to read resulting private key'); - var privKey = new openpgp_msg_privatekey(); - privKey.privateKeyPacket = privKeyPacket; - privKey.getPreferredSignatureHashAlgorithm = function(){return openpgp.config.config.prefer_hash_algorithm};//need to override this to solve catch 22 to generate signature. 8 is value for SHA256 - - var publicKeyString = privKey.privateKeyPacket.publicKey.data; - var hashData = String.fromCharCode(0x99)+ String.fromCharCode(((publicKeyString.length) >> 8) & 0xFF) - + String.fromCharCode((publicKeyString.length) & 0xFF) +publicKeyString+String.fromCharCode(0xB4) + - String.fromCharCode((userId.length) >> 24) +String.fromCharCode(((userId.length) >> 16) & 0xFF) - + String.fromCharCode(((userId.length) >> 8) & 0xFF) + String.fromCharCode((userId.length) & 0xFF) + userId - var signature = new openpgp_packet_signature(); - signature = signature.write_message_signature(16,hashData, privKey); - var publicArmored = openpgp_encoding_armor(4, keyPair.publicKey.string + userIdString + signature.openpgp ); - var privArmored = openpgp_encoding_armor(5,privKeyString.string+userIdString+signature.openpgp); - - return {privateKey : privKey, privateKeyArmored: privArmored, publicKeyArmored: publicArmored} - } - - this.generate_key_pair = generate_key_pair; - this.write_signed_message = write_signed_message; - this.write_signed_and_encrypted_message = write_signed_and_encrypted_message; - this.write_encrypted_message = write_encrypted_message; - this.read_message = read_message; - this.read_messages_dearmored = read_messages_dearmored; - this.read_publicKey = read_publicKey; - this.read_privateKey = read_privateKey; - this.init = init; +/** + * Encrypts message text with keys + * @param {Array<module:key~Key>} keys array of keys, used to encrypt the message + * @param {String} text message as native JavaScript string + * @return {String} encrypted ASCII armored message + * @static + */ +function encryptMessage(keys, text) { + var msg = message.fromText(text); + msg = msg.encrypt(keys); + var armored = armor.encode(enums.armor.message, msg.packets.write()); + return armored; } -var openpgp = new _openpgp(); +/** + * Signs message text and encrypts it + * @param {Array<module:key~Key>} publicKeys array of keys, used to encrypt the message + * @param {module:key~Key} privateKey private key with decrypted secret key data for signing + * @param {String} text message as native JavaScript string + * @return {String} encrypted ASCII armored message + * @static + */ +function signAndEncryptMessage(publicKeys, privateKey, text) { + var msg = message.fromText(text); + msg = msg.sign([privateKey]); + msg = msg.encrypt(publicKeys); + var armored = armor.encode(enums.armor.message, msg.packets.write()); + return armored; +} +/** + * Decrypts message + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {module:message~Message} message the message object with the encrypted data + * @return {(String|null)} decrypted message as as native JavaScript string + * or null if no literal data found + * @static + */ +function decryptMessage(privateKey, message) { + message = message.decrypt(privateKey); + return message.getText(); +} +/** + * Decrypts message and verifies signatures + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {Array<module:key~Key>} publicKeys public keys to verify signatures + * @param {module:message~Message} message the message object with signed and encrypted data + * @return {{text: String, signatures: Array<{keyid: module:type/keyid, valid: Boolean}>}} + * decrypted message as as native JavaScript string + * with verified signatures or null if no literal data found + * @static + */ +function decryptAndVerifyMessage(privateKey, publicKeys, message) { + var result = {}; + message = message.decrypt(privateKey); + result.text = message.getText(); + if (result.text) { + result.signatures = message.verify(publicKeys); + return result; + } + return null; +} + +/** + * Signs a cleartext message + * @param {Array<module:key~Key>} privateKeys private key with decrypted secret key data to sign cleartext + * @param {String} text cleartext + * @return {String} ASCII armored message + * @static + */ +function signClearMessage(privateKeys, text) { + var cleartextMessage = new cleartext.CleartextMessage(text); + cleartextMessage.sign(privateKeys); + return cleartextMessage.armor(); +} + +/** + * Verifies signatures of cleartext signed message + * @param {Array<module:key~Key>} publicKeys public keys to verify signatures + * @param {module:cleartext~CleartextMessage} message cleartext message object with signatures + * @return {{text: String, signatures: Array<{keyid: module:type/keyid, valid: Boolean}>}} + * cleartext with status of verified signatures + * @static + */ +function verifyClearSignedMessage(publicKeys, message) { + var result = {}; + if (!(message instanceof cleartext.CleartextMessage)) { + throw new Error('Parameter [message] needs to be of type CleartextMessage.'); + } + result.text = message.getText(); + result.signatures = message.verify(publicKeys); + return result; +} + +/** + * Generates a new OpenPGP key pair. Currently only supports RSA keys. + * Primary and subkey will be of same type. + * @param {Integer} keyType to indicate what type of key to make. + * RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1 + * @param {Integer} numBits number of bits for the key creation. (should be 1024+, generally) + * @param {String} userId assumes already in form of "User Name <username@email.com>" + * @param {String} passphrase The passphrase used to encrypt the resulting private key + * @return {Object} {key: Array<module:key~Key>, privateKeyArmored: Array<String>, publicKeyArmored: Array<String>} + * @static + */ +function generateKeyPair(keyType, numBits, userId, passphrase) { + var result = {}; + var newKey = key.generate(keyType, numBits, userId, passphrase); + result.key = newKey; + result.privateKeyArmored = newKey.armor(); + result.publicKeyArmored = newKey.toPublic().armor(); + return result; +} + +exports.encryptMessage = encryptMessage; +exports.signAndEncryptMessage = signAndEncryptMessage; +exports.decryptMessage = decryptMessage; +exports.decryptAndVerifyMessage = decryptAndVerifyMessage +exports.signClearMessage = signClearMessage; +exports.verifyClearSignedMessage = verifyClearSignedMessage; +exports.generateKeyPair = generateKeyPair; @@ -496,15 +199,16 @@ var openpgp = new _openpgp();
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) + Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST)
+ diff --git a/doc/openpgp.keyring.js.html b/doc/openpgp.keyring.js.html deleted file mode 100644 index 01887845..00000000 --- a/doc/openpgp.keyring.js.html +++ /dev/null @@ -1,313 +0,0 @@ - - - - - JSDoc: Source: openpgp.keyring.js - - - - - - - - - - -
- -

Source: openpgp.keyring.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
- */
-function openpgp_keyring() {
-		
-	/**
-	 * Initialization routine for the keyring. This method reads the 
-	 * keyring from HTML5 local storage and initializes this instance.
-	 * This method is called by openpgp.init().
-	 */
-	function init() {
-		var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys"));
-		var spublickeys = JSON.parse(window.localStorage.getItem("publickeys"));
-		if (sprivatekeys == null || sprivatekeys.length == 0) {
-			sprivatekeys = new Array();
-		}
-
-		if (spublickeys == null || spublickeys.length == 0) {
-			spublickeys = new Array();
-		}
-		this.publicKeys = new Array();
-		this.privateKeys = new Array();
-		var k = 0;
-		for (var i =0; i < sprivatekeys.length; i++) {
-			var r = openpgp.read_privateKey(sprivatekeys[i]);
-			this.privateKeys[k] = { armored: sprivatekeys[i], obj: r[0], keyId: r[0].getKeyId()};
-			k++;
-		}
-		k = 0;
-		for (var i =0; i < spublickeys.length; i++) {
-			var r = openpgp.read_publicKey(spublickeys[i]);
-			if (r[0] != null) {
-				this.publicKeys[k] = { armored: spublickeys[i], obj: r[0], keyId: r[0].getKeyId()};
-				k++;
-			}
-		}
-	}
-	this.init = init;
-
-	/**
-	 * Checks if at least one private key is in the keyring
-	 * @return {Boolean} True if there are private keys, else false.
-	 */
-	function hasPrivateKey() {
-		return this.privateKeys.length > 0;
-	}
-	this.hasPrivateKey = hasPrivateKey;
-
-	/**
-	 * Saves the current state of the keyring to HTML5 local storage.
-	 * The privateKeys array and publicKeys array gets Stringified using JSON
-	 */
-	function store() { 
-		var priv = new Array();
-		for (var i = 0; i < this.privateKeys.length; i++) {
-			priv[i] = this.privateKeys[i].armored;
-		}
-		var pub = new Array();
-		for (var i = 0; i < this.publicKeys.length; i++) {
-			pub[i] = this.publicKeys[i].armored;
-		}
-		window.localStorage.setItem("privatekeys",JSON.stringify(priv));
-		window.localStorage.setItem("publickeys",JSON.stringify(pub));
-	}
-	this.store = store;
-	/**
-	 * searches all public keys in the keyring matching the address or address part of the user ids
-	 * @param {String} email_address
-	 * @return {openpgp_msg_publickey[]} The public keys associated with provided email address.
-	 */
-	function getPublicKeyForAddress(email_address) {
-		var results = new Array();
-		var spl = email_address.split("<");
-		var email = "";
-		if (spl.length > 1) {
-			email = spl[1].split(">")[0];
-		} else {
-			email = email_address.trim();
-		}
-		email = email.toLowerCase();
-		if(!util.emailRegEx.test(email)){
-		    return results;
-		}
-		for (var i =0; i < this.publicKeys.length; i++) {
-			for (var j = 0; j < this.publicKeys[i].obj.userIds.length; j++) {
-				if (this.publicKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0)
-					results[results.length] = this.publicKeys[i];
-			}
-		}
-		return results;
-	}
-	this.getPublicKeyForAddress = getPublicKeyForAddress;
-
-	/**
-	 * Searches the keyring for a private key containing the specified email address
-	 * @param {String} email_address email address to search for
-	 * @return {openpgp_msg_privatekey[]} private keys found
-	 */
-	function getPrivateKeyForAddress(email_address) {
-		var results = new Array();
-		var spl = email_address.split("<");
-		var email = "";
-		if (spl.length > 1) {
-			email = spl[1].split(">")[0];
-		} else {
-			email = email_address.trim();
-		}
-		email = email.toLowerCase();
-		if(!util.emailRegEx.test(email)){
-		    return results;
-		}
-		for (var i =0; i < this.privateKeys.length; i++) {
-			for (var j = 0; j < this.privateKeys[i].obj.userIds.length; j++) {
-				if (this.privateKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0)
-					results[results.length] = this.privateKeys[i];
-			}
-		}
-		return results;
-	}
-
-	this.getPrivateKeyForAddress = getPrivateKeyForAddress;
-	/**
-	 * Searches the keyring for public keys having the specified key id
-	 * @param {String} keyId provided as string of hex number (lowercase)
-	 * @return {openpgp_msg_privatekey[]} public keys found
-	 */
-	function getPublicKeysForKeyId(keyId) {
-		var result = new Array();
-		for (var i=0; i < this.publicKeys.length; i++) {
-			var key = this.publicKeys[i];
-			if (keyId == key.obj.getKeyId())
-				result[result.length] = key;
-			else if (key.obj.subKeys != null) {
-				for (var j=0; j < key.obj.subKeys.length; j++) {
-					var subkey = key.obj.subKeys[j];
-					if (keyId == subkey.getKeyId()) {
-						result[result.length] = {
-								obj: key.obj.getSubKeyAsKey(j),
-								keyId: subkey.getKeyId()
-						}
-					}
-				}
-			}
-		}
-		return result;
-	}
-	this.getPublicKeysForKeyId = getPublicKeysForKeyId;
-	
-	/**
-	 * Searches the keyring for private keys having the specified key id
-	 * @param {String} keyId 8 bytes as string containing the key id to look for
-	 * @return {openpgp_msg_privatekey[]} private keys found
-	 */
-	function getPrivateKeyForKeyId(keyId) {
-		var result = new Array();
-		for (var i=0; i < this.privateKeys.length; i++) {
-			if (keyId == this.privateKeys[i].obj.getKeyId()) {
-				result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.privateKeyPacket};
-			}
-			if (this.privateKeys[i].obj.subKeys != null) {
-				var subkeyids = this.privateKeys[i].obj.getSubKeyIds();
-				for (var j=0; j < subkeyids.length; j++)
-					if (keyId == util.hexstrdump(subkeyids[j])) {
-						result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.subKeys[j]};
-					}
-			}
-		}
-		return result;
-	}
-	this.getPrivateKeyForKeyId = getPrivateKeyForKeyId;
-	
-	/**
-	 * Imports a public key from an exported ascii armored message 
-	 * @param {String} armored_text PUBLIC KEY BLOCK message to read the public key from
-	 */
-	function importPublicKey (armored_text) {
-		var result = openpgp.read_publicKey(armored_text);
-		for (var i = 0; i < result.length; i++) {
-			this.publicKeys[this.publicKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()};
-		}
-		return true;
-	}
-
-	/**
-	 * Imports a private key from an exported ascii armored message 
-	 * @param {String} armored_text PRIVATE KEY BLOCK message to read the private key from
-	 */
-	function importPrivateKey (armored_text, password) {
-		var result = openpgp.read_privateKey(armored_text);
-		if(!result[0].decryptSecretMPIs(password))
-		    return false;
-		for (var i = 0; i < result.length; i++) {
-			this.privateKeys[this.privateKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()};
-		}
-		return true;
-	}
-
-	this.importPublicKey = importPublicKey;
-	this.importPrivateKey = importPrivateKey;
-	
-	/**
-	 * returns the openpgp_msg_privatekey representation of the public key at public key ring index  
-	 * @param {Integer} index the index of the public key within the publicKeys array
-	 * @return {openpgp_msg_privatekey} the public key object
-	 */
-	function exportPublicKey(index) {
-		return this.publicKey[index];
-	}
-	this.exportPublicKey = exportPublicKey;
-		
-	
-	/**
-	 * Removes a public key from the public key keyring at the specified index 
-	 * @param {Integer} index the index of the public key within the publicKeys array
-	 * @return {openpgp_msg_privatekey} The public key object which has been removed
-	 */
-	function removePublicKey(index) {
-		var removed = this.publicKeys.splice(index,1);
-		this.store();
-		return removed;
-	}
-	this.removePublicKey = removePublicKey;
-
-	/**
-	 * returns the openpgp_msg_privatekey representation of the private key at private key ring index  
-	 * @param {Integer} index the index of the private key within the privateKeys array
-	 * @return {openpgp_msg_privatekey} the private key object
-	 */	
-	function exportPrivateKey(index) {
-		return this.privateKeys[index];
-	}
-	this.exportPrivateKey = exportPrivateKey;
-
-	/**
-	 * Removes a private key from the private key keyring at the specified index 
-	 * @param {Integer} index the index of the private key within the privateKeys array
-	 * @return {openpgp_msg_privatekey} The private key object which has been removed
-	 */
-	function removePrivateKey(index) {
-		var removed = this.privateKeys.splice(index,1);
-		this.store();
-		return removed;
-	}
-	this.removePrivateKey = removePrivateKey;
-
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.msg.message.js.html b/doc/openpgp.msg.message.js.html deleted file mode 100644 index 485d0f8c..00000000 --- a/doc/openpgp.msg.message.js.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - - JSDoc: Source: openpgp.msg.message.js - - - - - - - - - - -
- -

Source: openpgp.msg.message.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @protected
- * @class
- * @classdesc Top-level message object. Contains information from one or more packets
- */
-
-function openpgp_msg_message() {
-	
-	// -1 = no valid passphrase submitted
-	// -2 = no private key found
-	// -3 = decryption error
-	// text = valid decryption
-	this.text = "";
-	this.messagePacket = null;
-	this.type = null;
-	
-	/**
-	 * Decrypts a message and generates user interface message out of the found.
-	 * MDC will be verified as well as message signatures
-	 * @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key)
-	 * @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message
-	 * @return {String} plaintext of the message or null on error
-	 */
-	function decrypt(private_key, sessionkey) {
-        return this.decryptAndVerifySignature(private_key, sessionkey).text;
-	}
-
-	/**
-	 * Decrypts a message and generates user interface message out of the found.
-	 * MDC will be verified as well as message signatures
-	 * @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key)
-	 * @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message
-	 * @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
-	 * @return {String} plaintext of the message or null on error
-	 */
-	function decryptAndVerifySignature(private_key, sessionkey, pubkey) {
-		if (private_key == null || sessionkey == null || sessionkey == "")
-			return null;
-		var decrypted = sessionkey.decrypt(this, private_key.keymaterial);
-		if (decrypted == null)
-			return null;
-		var packet;
-		var position = 0;
-		var len = decrypted.length;
-		var validSignatures = new Array();
-		util.print_debug_hexstr_dump("openpgp.msg.messge decrypt:\n",decrypted);
-		
-		var messages = openpgp.read_messages_dearmored({text: decrypted, openpgp: decrypted});
-		for(var m in messages){
-			if(messages[m].data){
-				this.text = messages[m].data;
-			}
-			if(messages[m].signature){
-			    validSignatures.push(messages[m].verifySignature(pubkey));
-			}
-		}
-		return {text:this.text, validSignatures:validSignatures};
-	}
-	
-	/**
-	 * Verifies a message signature. This function can be called after read_message if the message was signed only.
-	 * @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
-	 * @return {boolean} true if the signature was correct; otherwise false
-	 */
-	function verifySignature(pubkey) {
-		var result = false;
-		if (this.signature.tagType == 2) {
-		    if(!pubkey || pubkey.length == 0){
-			    var pubkey;
-			    if (this.signature.version == 4) {
-				    pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.issuerKeyId);
-			    } else if (this.signature.version == 3) {
-				    pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.keyId);
-			    } else {
-				    util.print_error("unknown signature type on message!");
-				    return false;
-			    }
-			}
-			if (pubkey.length == 0)
-				util.print_warning("Unable to verify signature of issuer: "+util.hexstrdump(this.signature.issuerKeyId)+". Public key not found in keyring.");
-			else {
-				for (var i = 0 ; i < pubkey.length; i++) {
-					var tohash = this.text.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n");
-					if (this.signature.verify(tohash, pubkey[i])) {
-						util.print_info("Found Good Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[i].obj.getKeyId()).substring(8)+")");
-						result = true;
-					} else {
-						util.print_error("Signature verification failed: Bad Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8)+")");
-					}
-				}
-			}
-		}
-		return result;
-	}
-	
-	function toString() {
-		var result = "Session Keys:\n";
-		if (this.sessionKeys !=null)
-		for (var i = 0; i < this.sessionKeys.length; i++) {
-			result += this.sessionKeys[i].toString();
-		}
-		result += "\n\n EncryptedData:\n";
-		if(this.encryptedData != null)
-		result += this.encryptedData.toString();
-		
-		result += "\n\n Signature:\n";
-		if(this.signature != null)
-		result += this.signature.toString();
-		
-		result += "\n\n Text:\n"
-		if(this.signature != null)
-			result += this.text;
-		return result;
-	}
-	this.decrypt = decrypt;
-	this.decryptAndVerifySignature = decryptAndVerifySignature;
-	this.verifySignature = verifySignature;
-	this.toString = toString;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.msg.privatekey.js.html b/doc/openpgp.msg.privatekey.js.html deleted file mode 100644 index 9e206dc6..00000000 --- a/doc/openpgp.msg.privatekey.js.html +++ /dev/null @@ -1,240 +0,0 @@ - - - - - JSDoc: Source: openpgp.msg.privatekey.js - - - - - - - - - - -
- -

Source: openpgp.msg.privatekey.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Class that represents a decoded private key for internal openpgp.js use
- */
-
-function openpgp_msg_privatekey() {
-	this.subKeys = new Array();
-	this.privateKeyPacket = null;
-	this.userIds = new Array();
-	this.userAttributes = new Array();
-	this.revocationSignatures = new Array();
-	this.subKeys = new Array();
-
-	/**
-	 * 
-	 * @return last position
-	 */
-	function read_nodes(parent_node, input, position, len) {
-		this.privateKeyPacket = parent_node;
-		
-		var pos = position;
-		while (input.length > pos) {
-			var result = openpgp_packet.read_packet(input, pos, input.length - pos);
-			if (result == null) {
-				util.print_error("openpgp.msg.messge decrypt:\n"+'[pub/priv_key]parsing ends here @:' + pos + " l:" + len);
-				break;
-			} else {
-				switch (result.tagType) {
-				case 2: // public key revocation signature
-					if (result.signatureType == 32)
-						this.revocationSignatures[this.revocationSignatures.length] = result;
-					else if (result.signatureType > 15 && result.signatureType < 20) {
-						if (this.certificationsignatures == null)
-							this.certificationSignatures = new Array();
-						this.certificationSignatures[this.certificationSignatures.length] = result;
-					} else
-						util.print_error("openpgp.msg.messge decrypt:\n"+"unknown signature type directly on key "+result.signatureType+" @"+pos);
-					pos += result.packetLength + result.headerLength;
-					break;
-				case 7: // PrivateSubkey Packet
-					this.subKeys[this.subKeys.length] = result;
-					pos += result.packetLength + result.headerLength;
-					pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos);
-					break;
-				case 17: // User Attribute Packet
-					this.userAttributes[this.userAttributes.length] = result;
-					pos += result.packetLength + result.headerLength;
-					pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos);
-					break;
-				case 13: // User ID Packet
-					this.userIds[this.userIds.length] = result;
-					pos += result.packetLength + result.headerLength;
-					pos += result.read_nodes(this.privateKeyPacket, input, pos, input.length - pos);
-					break;
-				default:
-					this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength;
-					this.len = pos - position;
-					return this.len;
-				}
-			}
-		}
-		this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength;
-		this.len = pos - position;
-		
-		return this.len;
-	}
-	
-	function getKeyId() {
-		return this.privateKeyPacket.publicKey.getKeyId();
-	}
-	
-	
-	function getSubKeyIds() {
-		if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys.
-		var result = new Array();
-		for (var i = 0; i < this.subKeys.length; i++) {
-			result[i] = str_sha1(this.subKeys[i].publicKey.header+this.subKeys[i].publicKey.data).substring(12,20);
-		}
-		return result;
-	}
-	
-	
-	function getSigningKey() {
-		if ((this.privateKeyPacket.publicKey.publicKeyAlgorithm == 17 ||
-			 this.privateKeyPacket.publicKey.publicKeyAlgorithm != 2)
-			&& this.privateKeyPacket.publicKey.verifyKey() == 3)
-			return this.privateKeyPacket;
-		else if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys.
-			for (var j = 0; j < this.privateKeyPacket.subKeys.length; j++) {
-				if ((this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm == 17 ||
-					 this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm != 2) &&
-					 this.privateKeyPacket.subKeys[j].publicKey.verifyKey() == 3)
-					return this.privateKeyPacket.subKeys[j];
-			}
-		return null;
-	}
-	
-	function getPreferredSignatureHashAlgorithm() {
-		var pkey = this.getSigningKey();
-		if (pkey == null) {
-			util.print_error("private key is for encryption only! Cannot create a signature.")
-			return null;
-		}
-		if (pkey.publicKey.publicKeyAlgorithm == 17) {
-			var dsa = new DSA();
-			return dsa.select_hash_algorithm(pkey.publicKey.MPIs[1].toBigInteger()); // q
-		}
-		return openpgp.config.config.prefer_hash_algorithm;
-			
-	}
-
-	function decryptSecretMPIs(str_passphrase) {
-		return this.privateKeyPacket.decryptSecretMPIs(str_passphrase);
-	}
-	
-	function getFingerprint() {
-		return this.privateKeyPacket.publicKey.getFingerprint();
-	}
-
-	// TODO need to implement this
-	function revoke() {
-		
-	}
-
-	/**
-	 * extracts the public key part
-	 * @return {String} OpenPGP armored text containing the public key
-	 *                  returns null if no sufficient data to extract public key
-	 */
-	function extractPublicKey() {
-		// add public key
-		var key = this.privateKeyPacket.publicKey.header + this.privateKeyPacket.publicKey.data;
-		for (var i = 0; i < this.userIds.length; i++) {
-			// verify userids
-			if (this.userIds[i].certificationSignatures.length === 0) {
-				util.print_error("extractPublicKey - missing certification signatures");
-				return null;
-			}
-			var userIdPacket = new openpgp_packet_userid();
-			// add userids
-			key += userIdPacket.write_packet(this.userIds[i].text);
-			for (var j = 0; j < this.userIds[i].certificationSignatures.length; j++) {
-				var certSig = this.userIds[i].certificationSignatures[j];
-				// add signatures
-				key += openpgp_packet.write_packet_header(2, certSig.data.length) + certSig.data;
-			}
-		}
-		for (var k = 0; k < this.subKeys.length; k++) {
-			var pubSubKey = this.subKeys[k].publicKey;
-			// add public subkey package
-			key += openpgp_packet.write_old_packet_header(14, pubSubKey.data.length) + pubSubKey.data;
-			var subKeySig = this.subKeys[k].subKeySignature;
-			if (subKeySig !== null) {
-				// add subkey signature
-				key += openpgp_packet.write_packet_header(2, subKeySig.data.length) + subKeySig.data;
-			} else {
-				util.print_error("extractPublicKey - missing subkey signature");
-				return null;
-			}
-		}
-		var publicArmored = openpgp_encoding_armor(4, key);
-		return publicArmored;
-	}
-
-	this.extractPublicKey = extractPublicKey;
-	this.getSigningKey = getSigningKey;
-	this.getFingerprint = getFingerprint;
-	this.getPreferredSignatureHashAlgorithm = getPreferredSignatureHashAlgorithm;
-	this.read_nodes = read_nodes;
-	this.decryptSecretMPIs = decryptSecretMPIs;
-	this.getSubKeyIds = getSubKeyIds;
-	this.getKeyId = getKeyId;
-	
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.msg.publickey.js.html b/doc/openpgp.msg.publickey.js.html deleted file mode 100644 index 9a443b53..00000000 --- a/doc/openpgp.msg.publickey.js.html +++ /dev/null @@ -1,317 +0,0 @@ - - - - - JSDoc: Source: openpgp.msg.publickey.js - - - - - - - - - - -
- -

Source: openpgp.msg.publickey.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Decoded public key object for internal openpgp.js use
- */
-function openpgp_msg_publickey() {
-	this.data;
-	this.position;
-	this.len;
-	this.tostring = "OPENPGP PUBLIC KEY\n";
-	this.bindingSignature = null;
-	this.publicKeyPacket = null;
-	this.userIds = new Array();
-	this.userAttributes = new Array();
-	this.revocationSignatures = new Array();
-	this.subKeys = new Array();
-	this.arbitraryPacket = new Array();
-	this.directSignatures = new Array();
-	/**
-	 * 
-	 * @return last position
-	 */
-	function read_nodes(parent_node, input, position, len) {
-		this.publicKeyPacket = parent_node;
-		var exit = false;
-		var pos = position;
-		var l = len;
-		while (input.length != pos) {
-			var result = openpgp_packet.read_packet(input, pos, input.length - pos);
-			if (result == null) {
-				util.print_error("openpgp.msg.publickey read_nodes:\n"+'[pub_key]parsing ends here @:' + pos + " l:" + l);
-				break;
-			} else {
-				switch (result.tagType) {
-				case 2: // public key revocation signature
-					if (result.signatureType == 32)
-						this.revocationSignatures[this.revocationSignatures.length] = result;
-					else if (result.signatureType == 16 || result.signatureType == 17 || result.signatureType == 18  || result.signatureType == 19)
-						this.certificationSignature = result;
-					else if (result.signatureType == 25) {
-						this.bindingSignature = result;
-					} else if (result.signatureType == 31) {
-						this.directSignatures[this.directSignatures.length] = result;
-					} else
-						util.print_error("openpgp.msg.publickey read_nodes:\n"+"unknown signature type directly on key "+result.signatureType);
-					pos += result.packetLength + result.headerLength;
-					break;
-				case 14: // Public-Subkey Packet
-					this.subKeys[this.subKeys.length] = result;
-					pos += result.packetLength + result.headerLength;
-					pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
-					break;
-				case 17: // User Attribute Packet
-					this.userAttributes[this.userAttributes.length] = result;
-					pos += result.packetLength + result.headerLength;
-					pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
-					break;
-				case 13: // User ID Packet
-					this.userIds[this.userIds.length] = result;
-					pos += result.packetLength + result.headerLength;
-					pos += result.read_nodes(this.publicKeyPacket, input, pos, input.length - pos);
-					break;
-				default:
-					this.data = input;
-					this.position = position - this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength;
-					this.len = pos - position;
-					return this.len;
-				}
-			}
-		}
-		this.data = input;
-		this.position = position - (this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength);
-		this.len = pos - position;
-		return this.len;
-	}
-
-	function write() {
-
-	}
-
-	function getKeyId() {
-		return this.publicKeyPacket.getKeyId();
-	}
-	
-	function getFingerprint() {
-		return this.publicKeyPacket.getFingerprint();
-	}
-
-
-	
-	function validate() {
-		// check revocation keys
-		for (var i = 0; i < this.revocationSignatures.length; i++) {
-			var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
-			if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
-				return false;
-		}
-		
-		if (this.subKeys.length != 0) {
-			// search for a valid subkey
-			var found = false;
-			for (var i = 0; i < this.subKeys.length; i++)
-				if (this.subKeys[i].verifyKey() == 3) {
-					found = true;
-					break;
-				}
-			if (!found)
-				return false;
-		}
-		// search for one valid userid
-		found = false;
-		for (var i = 0; i < this.userIds.length; i++)
-			if (this.userIds[i].verify(this.publicKeyPacket) == 0) {
-				found = true;
-				break;
-			}
-		if (!found)
-			return false;
-		return true;
-	}
-	
-	/**
-	 * verifies all signatures
-	 * @return a 2 dimensional array. the first dimension corresponds to the userids available
-	 */
-	function verifyCertificationSignatures() {
-		var result = new Array();
-		for (var i = 0; i < this.userIds.length; i++) {
-			result[i] = this.userIds[i].verifyCertificationSignatures(this.publicKeyPacket);
-		}
-		return result;
-	}
-	this.verifyCertificationSignatures = verifyCertificationSignatures;
-	
-	/**
-	 * verifies:
-	 *  - revocation certificates directly on key
-	 *  - self signatures
-	 *  - subkey binding and revocation certificates
-	 *  
-	 *  This is useful for validating the key
-	 *  @returns {Boolean} true if the basic signatures are all valid
-	 */
-	function verifyBasicSignatures() {
-		for (var i = 0; i < this.revocationSignatures.length; i++) {
-			var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
-			if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
-				return false;
-		}
-		
-		if (this.subKeys.length != 0) {
-			// search for a valid subkey
-			var found = false;
-			for (var i = 0; i < this.subKeys.length; i++) {
-				if (this.subKeys[i] == null)
-					continue;
-				var result = this.subKeys[i].verifyKey();
-				if (result == 3) {
-					found = true;
-					break;
-				} 
-			}
-			if (!found)
-				return false;
-		}
-		var keyId = this.getKeyId();
-		for (var i = 0; i < this.userIds.length; i++) {
-			for (var j = 0; j < this.userIds[i].certificationRevocationSignatures.length; j++) {
-				if (this.userIds[i].certificationSignatures[j].getIssuer == keyId &&
-					this.userIds[i].certificationSignatures[j].verifyBasic(this.publicKeyPacket) != 4)
-					return false;
-			}
-		}
-		return true;
-	}
-	
-	function toString() {
-		var result = " OPENPGP Public Key\n    length: "+this.len+"\n";
-		result += "    Revocation Signatures:\n"
-		for (var i=0; i < this.revocationSignatures.length; i++) {
-			result += "    "+this.revocationSignatures[i].toString(); 
-		}
-		result += "    User Ids:\n";
-		for (var i=0; i < this.userIds.length; i++) {
-			result += "    "+this.userIds[i].toString(); 
-		}
-		result += "    User Attributes:\n";
-		for (var i=0; i < this.userAttributes.length; i++) {
-			result += "    "+this.userAttributes[i].toString(); 
-		}
-		result += "    Public Key SubKeys:\n";
-		for (var i=0; i < this.subKeys.length; i++) {
-			result += "    "+this.subKeys[i].toString(); 
-		}
-		return result;
-	}
-	
-	/**
-	 * finds an encryption key for this public key
-	 * @returns null if no encryption key has been found
-	 */
-	function getEncryptionKey() {
-		// V4: by convention subkeys are prefered for encryption service
-		// V3: keys MUST NOT have subkeys
-		for (var j = 0; j < this.subKeys.length; j++)
-				if (this.subKeys[j].publicKeyAlgorithm != 17 &&
-						this.subKeys[j].publicKeyAlgorithm != 3 &&
-						this.subKeys[j].verifyKey()) {
-					return this.subKeys[j];
-				}
-		// if no valid subkey for encryption, use primary key
-		if (this.publicKeyPacket.publicKeyAlgorithm != 17 && this.publicKeyPacket.publicKeyAlgorithm != 3
-			&& this.publicKeyPacket.verifyKey()) {
-			return this.publicKeyPacket;	
-		}
-		return null;
-	}
-	
-	function getSigningKey() {
-		if ((this.publicKeyPacket.publicKeyAlgorithm == 17 ||
-			 this.publicKeyPacket.publicKeyAlgorithm != 2))
-			return this.publicKeyPacket;
-		else if (this.publicKeyPacket.version == 4) // V3 keys MUST NOT have subkeys.
-			for (var j = 0; j < this.subKeys.length; j++) {
-				if ((this.subKeys[j].publicKeyAlgorithm == 17 ||
-					 this.subKeys[j].publicKeyAlgorithm != 2) &&
-					 this.subKeys[j].verifyKey())
-					return this.subKeys[j];
-			}
-		return null;
-	}
-
-        /* Returns the i-th subKey as a openpgp_msg_publickey object */
-	function getSubKeyAsKey(i) {
-		var ret = new openpgp_msg_publickey();
-		ret.userIds = this.userIds;
-		ret.userAttributes = this.userAttributes;
-		ret.publicKeyPacket = this.subKeys[i];
-		return ret;
-	}
-
-	this.getEncryptionKey = getEncryptionKey;
-	this.getSigningKey = getSigningKey;
-	this.read_nodes = read_nodes;
-	this.write = write;
-	this.toString = toString;
-	this.validate = validate;
-	this.getFingerprint = getFingerprint;
-	this.getKeyId = getKeyId;
-	this.verifyBasicSignatures = verifyBasicSignatures;
-	this.getSubKeyAsKey = getSubKeyAsKey;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.compressed.js.html b/doc/openpgp.packet.compressed.js.html deleted file mode 100644 index c04bb85b..00000000 --- a/doc/openpgp.packet.compressed.js.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.compressed.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.compressed.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the Compressed Data Packet (Tag 8)
- * 
- * RFC4880 5.6:
- * The Compressed Data packet contains compressed data.  Typically, this
- * packet is found as the contents of an encrypted packet, or following
- * a Signature or One-Pass Signature packet, and contains a literal data
- * packet.
- */   
-function openpgp_packet_compressed() {
-	this.tagType = 8;
-	this.decompressedData = null;
-	
-	/**
-	 * Parsing function for the packet.
-	 * @param {String} input Payload of a tag 8 packet
-	 * @param {Integer} position Position to start reading from the input string
-	 * @param {Integer} len Length of the packet or the remaining length of 
-	 * input at position
-	 * @return {openpgp_packet_compressed} Object representation
-	 */
-	function read_packet (input, position, len) {
-		this.packetLength = len;
-		var mypos = position;
-		// One octet that gives the algorithm used to compress the packet.
-		this.type = input.charCodeAt(mypos++);
-		// Compressed data, which makes up the remainder of the packet.
-		this.compressedData = input.substring(position+1, position+len);
-		return this;
-	}
-	/**
-	 * Decompression method for decompressing the compressed data
-	 * read by read_packet
-	 * @return {String} The decompressed data
-	 */
-	function decompress() {
-		if (this.decompressedData != null)
-			return this.decompressedData;
-
-		if (this.type == null)
-			return null;
-
-		switch (this.type) {
-		case 0: // - Uncompressed
-			this.decompressedData = this.compressedData;
-			break;
-		case 1: // - ZIP [RFC1951]
-			util.print_info('Decompressed packet [Type 1-ZIP]: ' + this.toString());
-			var compData = this.compressedData;
-			var radix = s2r(compData).replace(/\n/g,"");
-			// no header in this case, directly call deflate
-			var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix));
-			this.decompressedData = unescape(jxg_obj.deflate()[0][0]);
-			break;
-		case 2: // - ZLIB [RFC1950]
-			util.print_info('Decompressed packet [Type 2-ZLIB]: ' + this.toString());
-			var compressionMethod = this.compressedData.charCodeAt(0) % 0x10; //RFC 1950. Bits 0-3 Compression Method
-			//Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size.
-			//2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary (how is this defined). Basic checksum, and compression level.
-			if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951
-				// remove 4 bytes ADLER32 checksum from the end
-				var compData = this.compressedData.substring(0, this.compressedData.length - 4);
-				var radix = s2r(compData).replace(/\n/g,"");
-				//TODO check ADLER32 checksum
-				this.decompressedData = JXG.decompress(radix);
-				break;
-			} else {
-				util.print_error("Compression algorithm ZLIB only supports DEFLATE compression method.");
-			}
-			break;
-		case 3: //  - BZip2 [BZ2]
-			// TODO: need to implement this
-			util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
-			break;
-		default:
-			util.print_error("Compression algorithm unknown :"+this.type);
-			break;
-		}
-		util.print_debug("decompressed:"+util.hexstrdump(this.decompressedData));
-		return this.decompressedData; 
-	}
-
-	/**
-	 * Compress the packet data (member decompressedData)
-	 * @param {Integer} type Algorithm to be used // See RFC 4880 9.3
-	 * @param {String} data Data to be compressed
-	 * @return {String} The compressed data stored in attribute compressedData
-	 */
-	function compress(type, data) {
-		this.type = type;
-		this.decompressedData = data;
-		switch (this.type) {
-		case 0: // - Uncompressed
-			this.compressedData = this.decompressedData;
-			break;
-		case 1: // - ZIP [RFC1951]
-			util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");
-			break;
-		case 2: // - ZLIB [RFC1950]
-			// TODO: need to implement this
-			util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented.");
-			break;
-		case 3: //  - BZip2 [BZ2]
-			// TODO: need to implement this
-			util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
-			break;
-		default:
-			util.print_error("Compression algorithm unknown :"+this.type);
-			break;
-		}
-		this.packetLength = this.compressedData.length +1;
-		return this.compressedData; 
-	}
-	
-	/**
-	 * Creates a string representation of the packet
-	 * @param {Integer} algorithm Algorithm to be used // See RFC 4880 9.3
-	 * @param {String} data Data to be compressed
-	 * @return {String} String-representation of the packet
-	 */
-	function write_packet(algorithm, data) {
-		this.decompressedData = data;
-		if (algorithm == null) {
-			this.type = 1;
-		}
-		var result = String.fromCharCode(this.type)+this.compress(this.type);
-		return openpgp_packet.write_packet_header(8, result.length)+result;
-	}
-	
-	/**
-	 * Pretty printing the packet (useful for debug purposes)
-	 * @return {String}
-	 */
-	function toString() {
-		return '5.6.  Compressed Data Packet (Tag 8)\n'+
-		   '    length:  '+this.packetLength+'\n'+
-			   '    Compression Algorithm = '+this.type+'\n'+
-		       '    Compressed Data: Byte ['+util.hexstrdump(this.compressedData)+']\n';
-	}
-	
-	this.read_packet = read_packet;
-	this.toString = toString;
-	this.compress = compress;
-	this.decompress = decompress;
-	this.write_packet = write_packet;
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.encrypteddata.js.html b/doc/openpgp.packet.encrypteddata.js.html deleted file mode 100644 index e856fec6..00000000 --- a/doc/openpgp.packet.encrypteddata.js.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.encrypteddata.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.encrypteddata.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
- * 
- * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted
- * with a symmetric-key algorithm. When it has been decrypted, it contains other
- * packets (usually a literal data packet or compressed data packet, but in
- * theory other Symmetrically Encrypted Data packets or sequences of packets
- * that form whole OpenPGP messages).
- */
-
-function openpgp_packet_encrypteddata() {
-	this.tagType = 9;
-	this.packetLength = null;
-	this.encryptedData = null;
-	this.decryptedData = null;
-
-	/**
-	 * Parsing function for the packet.
-	 * 
-	 * @param {String} input Payload of a tag 9 packet
-	 * @param {Integer} position Position to start reading from the input string
-	 * @param {Integer} len Length of the packet or the remaining length of
-	 *            input at position
-	 * @return {openpgp_packet_encrypteddata} Object representation
-	 */
-	function read_packet(input, position, len) {
-		var mypos = position;
-		this.packetLength = len;
-		// - Encrypted data, the output of the selected symmetric-key cipher
-		// operating in OpenPGP's variant of Cipher Feedback (CFB) mode.
-		this.encryptedData = input.substring(position, position + len);
-		return this;
-	}
-
-	/**
-	 * Symmetrically decrypt the packet data
-	 * 
-	 * @param {Integer} symmetric_algorithm_type
-	 *             Symmetric key algorithm to use // See RFC4880 9.2
-	 * @param {String} key
-	 *             Key as string with the corresponding length to the
-	 *            algorithm
-	 * @return The decrypted data;
-	 */
-	function decrypt_sym(symmetric_algorithm_type, key) {
-		this.decryptedData = openpgp_crypto_symmetricDecrypt(
-				symmetric_algorithm_type, key, this.encryptedData, true);
-		util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+
-				"data: "+util.hexstrdump(this.decryptedData));
-		return this.decryptedData;
-	}
-
-	/**
-	 * Creates a string representation of the packet
-	 * 
-	 * @param {Integer} algo Symmetric key algorithm to use // See RFC4880 9.2
-	 * @param {String} key Key as string with the corresponding length to the
-	 *            algorithm
-	 * @param {String} data Data to be
-	 * @return {String} String-representation of the packet
-	 */
-	function write_packet(algo, key, data) {
-		var result = "";
-		result += openpgp_crypto_symmetricEncrypt(
-				openpgp_crypto_getPrefixRandom(algo), algo, key, data, true);
-		result = openpgp_packet.write_packet_header(9, result.length) + result;
-		return result;
-	}
-
-	function toString() {
-		return '5.7.  Symmetrically Encrypted Data Packet (Tag 9)\n'
-				+ '    length:  ' + this.packetLength + '\n'
-				+ '    Used symmetric algorithm: ' + this.algorithmType + '\n'
-				+ '    encrypted data: Bytes ['
-				+ util.hexstrdump(this.encryptedData) + ']\n';
-	}
-	this.decrypt_sym = decrypt_sym;
-	this.toString = toString;
-	this.read_packet = read_packet;
-	this.write_packet = write_packet;
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.encryptedintegrityprotecteddata.js.html b/doc/openpgp.packet.encryptedintegrityprotecteddata.js.html deleted file mode 100644 index fde850f2..00000000 --- a/doc/openpgp.packet.encryptedintegrityprotecteddata.js.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.encryptedintegrityprotecteddata.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.encryptedintegrityprotecteddata.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the Sym. Encrypted Integrity Protected Data 
- * Packet (Tag 18)
- * 
- * RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is
- * a variant of the Symmetrically Encrypted Data packet. It is a new feature
- * created for OpenPGP that addresses the problem of detecting a modification to
- * encrypted data. It is used in combination with a Modification Detection Code
- * packet.
- */
-
-function openpgp_packet_encryptedintegrityprotecteddata() {
-	this.tagType = 18;
-	this.version = null; // integer == 1
-	this.packetLength = null; // integer
-	this.encryptedData = null; // string
-	this.decrytpedData = null; // string
-	this.hash = null; // string
-	/**
-	 * Parsing function for the packet.
-	 * 
-	 * @param {String} input Payload of a tag 18 packet
-	 * @param {Integer} position
-	 *             position to start reading from the input string
-	 * @param {Integer} len Length of the packet or the remaining length of
-	 *            input at position
-	 * @return {openpgp_packet_encryptedintegrityprotecteddata} object
-	 *         representation
-	 */
-	function read_packet(input, position, len) {
-		this.packetLength = len;
-		// - A one-octet version number. The only currently defined value is
-		// 1.
-		this.version = input[position].charCodeAt();
-		if (this.version != 1) {
-			util
-					.print_error('openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: '
-							+ this.version
-							+ " , @ "
-							+ position
-							+ "hex:"
-							+ util.hexstrdump(input));
-			return null;
-		}
-		// - Encrypted data, the output of the selected symmetric-key cipher
-		//   operating in Cipher Feedback mode with shift amount equal to the
-		//   block size of the cipher (CFB-n where n is the block size).
-		this.encryptedData = input.substring(position + 1, position + 1 + len);
-		util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"
-				+ this.toString());
-		return this;
-	}
-
-	/**
-	 * Creates a string representation of a Sym. Encrypted Integrity Protected
-	 * Data Packet (tag 18) (see RFC4880 5.13)
-	 * 
-	 * @param {Integer} symmetric_algorithm
-	 *            The selected symmetric encryption algorithm to be used
-	 * @param {String} key The key of cipher blocksize length to be used
-	 * @param {String} data
-	 *            Plaintext data to be encrypted within the packet
-	 * @return {String} A string representation of the packet
-	 */
-	function write_packet(symmetric_algorithm, key, data) {
-
-		var prefixrandom = openpgp_crypto_getPrefixRandom(symmetric_algorithm);
-		var prefix = prefixrandom
-				+ prefixrandom.charAt(prefixrandom.length - 2)
-				+ prefixrandom.charAt(prefixrandom.length - 1);
-		var tohash = data;
-		tohash += String.fromCharCode(0xD3);
-		tohash += String.fromCharCode(0x14);
-		util.print_debug_hexstr_dump("data to be hashed:"
-				, prefix + tohash);
-		tohash += str_sha1(prefix + tohash);
-		util.print_debug_hexstr_dump("hash:"
-				, tohash.substring(tohash.length - 20,
-						tohash.length));
-		var result = openpgp_crypto_symmetricEncrypt(prefixrandom,
-				symmetric_algorithm, key, tohash, false).substring(0,
-				prefix.length + tohash.length);
-		var header = openpgp_packet.write_packet_header(18, result.length + 1)
-				+ String.fromCharCode(1);
-		this.encryptedData = result;
-		return header + result;
-	}
-
-	/**
-	 * Decrypts the encrypted data contained in this object read_packet must
-	 * have been called before
-	 * 
-	 * @param {Integer} symmetric_algorithm_type
-	 *            The selected symmetric encryption algorithm to be used
-	 * @param {String} key The key of cipher blocksize length to be used
-	 * @return {String} The decrypted data of this packet
-	 */
-	function decrypt(symmetric_algorithm_type, key) {
-		this.decryptedData = openpgp_crypto_symmetricDecrypt(
-				symmetric_algorithm_type, key, this.encryptedData, false);
-		// there must be a modification detection code packet as the
-		// last packet and everything gets hashed except the hash itself
-		this.hash = str_sha1(openpgp_crypto_MDCSystemBytes(
-				symmetric_algorithm_type, key, this.encryptedData)
-				+ this.decryptedData.substring(0,
-						this.decryptedData.length - 20));
-		util.print_debug_hexstr_dump("calc hash = ", this.hash);
-		if (this.hash == this.decryptedData.substring(
-				this.decryptedData.length - 20, this.decryptedData.length))
-			return this.decryptedData;
-		else
-			util
-					.print_error("Decryption stopped: discovered a modification of encrypted data.");
-		return null;
-	}
-
-	function toString() {
-	    var data = '';
-	    if(openpgp.config.debug)
-	        data = '    data: Bytes ['
-				+ util.hexstrdump(this.encryptedData) + ']';
-	    
-		return '5.13.  Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n'
-				+ '    length:  '
-				+ this.packetLength
-				+ '\n'
-				+ '    version: '
-				+ this.version
-				+ '\n'
-				+ data;
-	}
-
-	this.write_packet = write_packet;
-	this.read_packet = read_packet;
-	this.toString = toString;
-	this.decrypt = decrypt;
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.encryptedsessionkey.js.html b/doc/openpgp.packet.encryptedsessionkey.js.html deleted file mode 100644 index ccca42d7..00000000 --- a/doc/openpgp.packet.encryptedsessionkey.js.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.encryptedsessionkey.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.encryptedsessionkey.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Public-Key Encrypted Session Key Packets (Tag 1)
- * 
- * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
- * used to encrypt a message. Zero or more Public-Key Encrypted Session Key
- * packets and/or Symmetric-Key Encrypted Session Key packets may precede a
- * Symmetrically Encrypted Data Packet, which holds an encrypted message. The
- * message is encrypted with the session key, and the session key is itself
- * encrypted and stored in the Encrypted Session Key packet(s). The
- * Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
- * Session Key packet for each OpenPGP key to which the message is encrypted.
- * The recipient of the message finds a session key that is encrypted to their
- * public key, decrypts the session key, and then uses the session key to
- * decrypt the message.
- */
-function openpgp_packet_encryptedsessionkey() {
-
-	/**
-	 * Parsing function for a publickey encrypted session key packet (tag 1).
-	 * 
-	 * @param {String} input Payload of a tag 1 packet
-	 * @param {Integer} position Position to start reading from the input string
-	 * @param {Integer} len Length of the packet or the remaining length of
-	 *            input at position
-	 * @return {openpgp_packet_encrypteddata} Object representation
-	 */
-	function read_pub_key_packet(input, position, len) {
-		this.tagType = 1;
-		this.packetLength = len;
-		var mypos = position;
-		if (len < 10) {
-			util
-					.print_error("openpgp.packet.encryptedsessionkey.js\n" + 'invalid length');
-			return null;
-		}
-
-		this.version = input[mypos++].charCodeAt();
-		this.keyId = new openpgp_type_keyid();
-		this.keyId.read_packet(input, mypos);
-		mypos += 8;
-		this.publicKeyAlgorithmUsed = input[mypos++].charCodeAt();
-
-		switch (this.publicKeyAlgorithmUsed) {
-		case 1:
-		case 2: // RSA
-			this.MPIs = new Array();
-			this.MPIs[0] = new openpgp_type_mpi();
-			this.MPIs[0].read(input, mypos, mypos - position);
-			break;
-		case 16: // Elgamal
-			this.MPIs = new Array();
-			this.MPIs[0] = new openpgp_type_mpi();
-			this.MPIs[0].read(input, mypos, mypos - position);
-			mypos += this.MPIs[0].packetLength;
-			this.MPIs[1] = new openpgp_type_mpi();
-			this.MPIs[1].read(input, mypos, mypos - position);
-			break;
-		default:
-			util.print_error("openpgp.packet.encryptedsessionkey.js\n"
-					+ "unknown public key packet algorithm type "
-					+ this.publicKeyAlgorithmType);
-			break;
-		}
-		return this;
-	}
-
-	/**
-	 * Create a string representation of a tag 1 packet
-	 * 
-	 * @param {String} publicKeyId
-	 *             The public key id corresponding to publicMPIs key as string
-	 * @param {openpgp_type_mpi[]} publicMPIs
-	 *            Multiprecision integer objects describing the public key
-	 * @param {Integer} pubalgo
-	 *            The corresponding public key algorithm // See RFC4880 9.1
-	 * @param {Integer} symmalgo
-	 *            The symmetric cipher algorithm used to encrypt the data 
-	 *            within an encrypteddatapacket or encryptedintegrity-
-	 *            protecteddatapacket 
-	 *            following this packet //See RFC4880 9.2
-	 * @param {String} sessionkey
-	 *            A string of randombytes representing the session key
-	 * @return {String} The string representation
-	 */
-	function write_pub_key_packet(publicKeyId, publicMPIs, pubalgo, symmalgo,
-			sessionkey) {
-		var result = String.fromCharCode(3);
-		var data = String.fromCharCode(symmalgo);
-		data += sessionkey;
-		var checksum = util.calc_checksum(sessionkey);
-		data += String.fromCharCode((checksum >> 8) & 0xFF);
-		data += String.fromCharCode((checksum) & 0xFF);
-		result += publicKeyId;
-		result += String.fromCharCode(pubalgo);
-		var mpi = new openpgp_type_mpi();
-		var mpiresult = openpgp_crypto_asymetricEncrypt(pubalgo, publicMPIs,
-				mpi.create(openpgp_encoding_eme_pkcs1_encode(data,
-						publicMPIs[0].mpiByteLength)));
-		for ( var i = 0; i < mpiresult.length; i++) {
-			result += mpiresult[i];
-		}
-		result = openpgp_packet.write_packet_header(1, result.length) + result;
-		return result;
-	}
-
-	/**
-	 * Parsing function for a symmetric encrypted session key packet (tag 3).
-	 * 
-	 * @param {String} input Payload of a tag 1 packet
-	 * @param {Integer} position Position to start reading from the input string
-	 * @param {Integer} len
-	 *            Length of the packet or the remaining length of
-	 *            input at position
-	 * @return {openpgp_packet_encrypteddata} Object representation
-	 */
-	function read_symmetric_key_packet(input, position, len) {
-		this.tagType = 3;
-		var mypos = position;
-		// A one-octet version number. The only currently defined version is 4.
-		this.version = input[mypos++];
-
-		// A one-octet number describing the symmetric algorithm used.
-		this.symmetricKeyAlgorithmUsed = input[mypos++];
-		// A string-to-key (S2K) specifier, length as defined above.
-		this.s2k = new openpgp_type_s2k();
-		this.s2k.read(input, mypos);
-
-		// Optionally, the encrypted session key itself, which is decrypted
-		// with the string-to-key object.
-		if ((s2k.s2kLength + mypos) < len) {
-			this.encryptedSessionKey = new Array();
-			for ( var i = (mypos - position); i < len; i++) {
-				this.encryptedSessionKey[i] = input[mypos++];
-			}
-		}
-		return this;
-	}
-	/**
-	 * Decrypts the session key (only for public key encrypted session key
-	 * packets (tag 1)
-	 * 
-	 * @param {openpgp_msg_message} msg
-	 *            The message object (with member encryptedData
-	 * @param {openpgp_msg_privatekey} key
-	 *            Private key with secMPIs unlocked
-	 * @return {String} The unencrypted session key
-	 */
-	function decrypt(msg, key) {
-		if (this.tagType == 1) {
-			var result = openpgp_crypto_asymetricDecrypt(
-					this.publicKeyAlgorithmUsed, key.publicKey.MPIs,
-					key.secMPIs, this.MPIs).toMPI();
-			var checksum = ((result.charCodeAt(result.length - 2) << 8) + result
-					.charCodeAt(result.length - 1));
-			var decoded = openpgp_encoding_eme_pkcs1_decode(result.substring(2, result.length - 2), key.publicKey.MPIs[0].getByteLength());
-			var sesskey = decoded.substring(1);
-			var algo = decoded.charCodeAt(0);
-			if (msg.encryptedData.tagType == 18)
-				return msg.encryptedData.decrypt(algo, sesskey);
-			else
-				return msg.encryptedData.decrypt_sym(algo, sesskey);
-		} else if (this.tagType == 3) {
-			util
-					.print_error("Symmetric encrypted sessionkey is not supported!");
-			return null;
-		}
-	}
-
-	/**
-	 * Creates a string representation of this object (useful for debug
-	 * purposes)
-	 * 
-	 * @return {String} The string containing a openpgp description
-	 */
-	function toString() {
-		if (this.tagType == 1) {
-			var result = '5.1.  Public-Key Encrypted Session Key Packets (Tag 1)\n'
-					+ '    KeyId:  '
-					+ this.keyId.toString()
-					+ '\n'
-					+ '    length: '
-					+ this.packetLength
-					+ '\n'
-					+ '    version:'
-					+ this.version
-					+ '\n'
-					+ '    pubAlgUs:'
-					+ this.publicKeyAlgorithmUsed + '\n';
-			for ( var i = 0; i < this.MPIs.length; i++) {
-				result += this.MPIs[i].toString();
-			}
-			return result;
-		} else
-			return '5.3 Symmetric-Key Encrypted Session Key Packets (Tag 3)\n'
-					+ '    KeyId:  ' + this.keyId.toString() + '\n'
-					+ '    length: ' + this.packetLength + '\n'
-					+ '    version:' + this.version + '\n' + '    symKeyA:'
-					+ this.symmetricKeyAlgorithmUsed + '\n' + '    s2k:    '
-					+ this.s2k + '\n';
-	}
-
-	this.read_pub_key_packet = read_pub_key_packet;
-	this.read_symmetric_key_packet = read_symmetric_key_packet;
-	this.write_pub_key_packet = write_pub_key_packet;
-	this.toString = toString;
-	this.decrypt = decrypt;
-};
-
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.js.html b/doc/openpgp.packet.js.html deleted file mode 100644 index 5ee604af..00000000 --- a/doc/openpgp.packet.js.html +++ /dev/null @@ -1,456 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Parent openpgp packet class. Operations focus on determining 
- * packet types and packet header.
- */
-function _openpgp_packet() {
-	/**
-	 * Encodes a given integer of length to the openpgp length specifier to a
-	 * string
-	 * 
-	 * @param {Integer} length The length to encode
-	 * @return {String} String with openpgp length representation
-	 */
-	function encode_length(length) {
-		result = "";
-		if (length < 192) {
-			result += String.fromCharCode(length);
-		} else if (length > 191 && length < 8384) {
-			/*
-			 * let a = (total data packet length) - 192 let bc = two octet
-			 * representation of a let d = b + 192
-			 */
-			result += String.fromCharCode(((length - 192) >> 8) + 192);
-			result += String.fromCharCode((length - 192) & 0xFF);
-		} else {
-			result += String.fromCharCode(255);
-			result += String.fromCharCode((length >> 24) & 0xFF);
-			result += String.fromCharCode((length >> 16) & 0xFF);
-			result += String.fromCharCode((length >> 8) & 0xFF);
-			result += String.fromCharCode(length & 0xFF);
-		}
-		return result;
-	}
-	this.encode_length = encode_length;
-
-	/**
-	 * Writes a packet header version 4 with the given tag_type and length to a
-	 * string
-	 * 
-	 * @param {Integer} tag_type Tag type
-	 * @param {Integer} length Length of the payload
-	 * @return {String} String of the header
-	 */
-	function write_packet_header(tag_type, length) {
-		/* we're only generating v4 packet headers here */
-		var result = "";
-		result += String.fromCharCode(0xC0 | tag_type);
-		result += encode_length(length);
-		return result;
-	}
-
-	/**
-	 * Writes a packet header Version 3 with the given tag_type and length to a
-	 * string
-	 * 
-	 * @param {Integer} tag_type Tag type
-	 * @param {Integer} length Length of the payload
-	 * @return {String} String of the header
-	 */
-	function write_old_packet_header(tag_type, length) {
-		var result = "";
-		if (length < 256) {
-			result += String.fromCharCode(0x80 | (tag_type << 2));
-			result += String.fromCharCode(length);
-		} else if (length < 65536) {
-			result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
-			result += String.fromCharCode(length >> 8);
-			result += String.fromCharCode(length & 0xFF);
-		} else {
-			result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
-			result += String.fromCharCode((length >> 24) & 0xFF);
-			result += String.fromCharCode((length >> 16) & 0xFF);
-			result += String.fromCharCode((length >> 8) & 0xFF);
-			result += String.fromCharCode(length & 0xFF);
-		}
-		return result;
-	}
-	this.write_old_packet_header = write_old_packet_header;
-	this.write_packet_header = write_packet_header;
-	/**
-	 * Generic static Packet Parser function
-	 * 
-	 * @param {String} input Input stream as string
-	 * @param {integer} position Position to start parsing
-	 * @param {integer} len Length of the input from position on
-	 * @return {Object} Returns a parsed openpgp_packet
-	 */
-	function read_packet(input, position, len) {
-		// some sanity checks
-		if (input == null || input.length <= position
-				|| input.substring(position).length < 2
-				|| (input[position].charCodeAt() & 0x80) == 0) {
-			util
-					.print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format.");
-			return null;
-		}
-		var mypos = position;
-		var tag = -1;
-		var format = -1;
-
-		format = 0; // 0 = old format; 1 = new format
-		if ((input[mypos].charCodeAt() & 0x40) != 0) {
-			format = 1;
-		}
-
-		var packet_length_type;
-		if (format) {
-			// new format header
-			tag = input[mypos].charCodeAt() & 0x3F; // bit 5-0
-		} else {
-			// old format header
-			tag = (input[mypos].charCodeAt() & 0x3F) >> 2; // bit 5-2
-			packet_length_type = input[mypos].charCodeAt() & 0x03; // bit 1-0
-		}
-
-		// header octet parsing done
-		mypos++;
-
-		// parsed length from length field
-		var bodydata = null;
-
-		// used for partial body lengths
-		var real_packet_length = -1;
-		if (!format) {
-			// 4.2.1. Old Format Packet Lengths
-			switch (packet_length_type) {
-			case 0: // The packet has a one-octet length. The header is 2 octets
-				// long.
-				packet_length = input[mypos++].charCodeAt();
-				break;
-			case 1: // The packet has a two-octet length. The header is 3 octets
-				// long.
-				packet_length = (input[mypos++].charCodeAt() << 8)
-						| input[mypos++].charCodeAt();
-				break;
-			case 2: // The packet has a four-octet length. The header is 5
-				// octets long.
-				packet_length = (input[mypos++].charCodeAt() << 24)
-						| (input[mypos++].charCodeAt() << 16)
-						| (input[mypos++].charCodeAt() << 8)
-						| input[mypos++].charCodeAt();
-				break;
-			default:
-				// 3 - The packet is of indeterminate length. The header is 1
-				// octet long, and the implementation must determine how long
-				// the packet is. If the packet is in a file, this means that
-				// the packet extends until the end of the file. In general, 
-				// an implementation SHOULD NOT use indeterminate-length 
-				// packets except where the end of the data will be clear 
-				// from the context, and even then it is better to use a 
-				// definite length, or a new format header. The new format 
-				// headers described below have a mechanism for precisely
-				// encoding data of indeterminate length.
-				packet_length = len;
-				break;
-			}
-
-		} else // 4.2.2. New Format Packet Lengths
-		{
-
-			// 4.2.2.1. One-Octet Lengths
-			if (input[mypos].charCodeAt() < 192) {
-				packet_length = input[mypos++].charCodeAt();
-				util.print_debug("1 byte length:" + packet_length);
-				// 4.2.2.2. Two-Octet Lengths
-			} else if (input[mypos].charCodeAt() >= 192
-					&& input[mypos].charCodeAt() < 224) {
-				packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
-						+ (input[mypos++].charCodeAt()) + 192;
-				util.print_debug("2 byte length:" + packet_length);
-				// 4.2.2.4. Partial Body Lengths
-			} else if (input[mypos].charCodeAt() > 223
-					&& input[mypos].charCodeAt() < 255) {
-				packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
-				util.print_debug("4 byte length:" + packet_length);
-				// EEEK, we're reading the full data here...
-				var mypos2 = mypos + packet_length;
-				bodydata = input.substring(mypos, mypos + packet_length);
-				while (true) {
-					if (input[mypos2].charCodeAt() < 192) {
-						var tmplen = input[mypos2++].charCodeAt();
-						packet_length += tmplen;
-						bodydata += input.substring(mypos2, mypos2 + tmplen);
-						mypos2 += tmplen;
-						break;
-					} else if (input[mypos2].charCodeAt() >= 192
-							&& input[mypos2].charCodeAt() < 224) {
-						var tmplen = ((input[mypos2++].charCodeAt() - 192) << 8)
-								+ (input[mypos2++].charCodeAt()) + 192;
-						packet_length += tmplen;
-						bodydata += input.substring(mypos2, mypos2 + tmplen);
-						mypos2 += tmplen;
-						break;
-					} else if (input[mypos2].charCodeAt() > 223
-							&& input[mypos2].charCodeAt() < 255) {
-						var tmplen = 1 << (input[mypos2++].charCodeAt() & 0x1F);
-						packet_length += tmplen;
-						bodydata += input.substring(mypos2, mypos2 + tmplen);
-						mypos2 += tmplen;
-					} else {
-						mypos2++;
-						var tmplen = (input[mypos2++].charCodeAt() << 24)
-								| (input[mypos2++].charCodeAt() << 16)
-								| (input[mypos2++].charCodeAt() << 8)
-								| input[mypos2++].charCodeAt();
-						bodydata += input.substring(mypos2, mypos2 + tmplen);
-						packet_length += tmplen;
-						mypos2 += tmplen;
-						break;
-					}
-				}
-				real_packet_length = mypos2;
-				// 4.2.2.3. Five-Octet Lengths
-			} else {
-				mypos++;
-				packet_length = (input[mypos++].charCodeAt() << 24)
-						| (input[mypos++].charCodeAt() << 16)
-						| (input[mypos++].charCodeAt() << 8)
-						| input[mypos++].charCodeAt();
-			}
-		}
-
-		// if there was'nt a partial body length: use the specified
-		// packet_length
-		if (real_packet_length == -1) {
-			real_packet_length = packet_length;
-		}
-
-		if (bodydata == null) {
-			bodydata = input.substring(mypos, mypos + real_packet_length);
-		}
-
-		// alert('tag type: '+this.tag+' length: '+packet_length);
-		var version = 1; // (old format; 2= new format)
-		// if (input[mypos++].charCodeAt() > 15)
-		// version = 2;
-
-		switch (tag) {
-		case 0: // Reserved - a packet tag MUST NOT have this value
-			break;
-		case 1: // Public-Key Encrypted Session Key Packet
-			var result = new openpgp_packet_encryptedsessionkey();
-			if (result.read_pub_key_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 2: // Signature Packet
-			var result = new openpgp_packet_signature();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 3: // Symmetric-Key Encrypted Session Key Packet
-			var result = new openpgp_packet_encryptedsessionkey();
-			if (result.read_symmetric_key_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 4: // One-Pass Signature Packet
-			var result = new openpgp_packet_onepasssignature();
-			if (result.read_packet(bodydata, 0, packet_length)) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 5: // Secret-Key Packet
-			var result = new openpgp_packet_keymaterial();
-			result.header = input.substring(position, mypos);
-			if (result.read_tag5(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 6: // Public-Key Packet
-			var result = new openpgp_packet_keymaterial();
-			result.header = input.substring(position, mypos);
-			if (result.read_tag6(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 7: // Secret-Subkey Packet
-			var result = new openpgp_packet_keymaterial();
-			if (result.read_tag7(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 8: // Compressed Data Packet
-			var result = new openpgp_packet_compressed();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 9: // Symmetrically Encrypted Data Packet
-			var result = new openpgp_packet_encrypteddata();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 10: // Marker Packet = PGP (0x50, 0x47, 0x50)
-			var result = new openpgp_packet_marker();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 11: // Literal Data Packet
-			var result = new openpgp_packet_literaldata();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.header = input.substring(position, mypos);
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 12: // Trust Packet
-			// TODO: to be implemented
-			break;
-		case 13: // User ID Packet
-			var result = new openpgp_packet_userid();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 14: // Public-Subkey Packet
-			var result = new openpgp_packet_keymaterial();
-			result.header = input.substring(position, mypos);
-			if (result.read_tag14(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 17: // User Attribute Packet
-			var result = new openpgp_packet_userattribute();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 18: // Sym. Encrypted and Integrity Protected Data Packet
-			var result = new openpgp_packet_encryptedintegrityprotecteddata();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		case 19: // Modification Detection Code Packet
-			var result = new openpgp_packet_modificationdetectioncode();
-			if (result.read_packet(bodydata, 0, packet_length) != null) {
-				result.headerLength = mypos - position;
-				result.packetLength = real_packet_length;
-				return result;
-			}
-			break;
-		default:
-			util.print_error("openpgp.packet.js\n"
-					+ "[ERROR] openpgp_packet: failed to parse packet @:"
-					+ mypos + "\nchar:'"
-					+ util.hexstrdump(input.substring(mypos)) + "'\ninput:"
-					+ util.hexstrdump(input));
-			return null;
-			break;
-		}
-	}
-
-	this.read_packet = read_packet;
-}
-
-var openpgp_packet = new _openpgp_packet();
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.keymaterial.js.html b/doc/openpgp.packet.keymaterial.js.html deleted file mode 100644 index 8bc37c1d..00000000 --- a/doc/openpgp.packet.keymaterial.js.html +++ /dev/null @@ -1,868 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.keymaterial.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.keymaterial.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
- *   
- * RFC4480 5.5:
- * A key material packet contains all the information about a public or
- * private key.  There are four variants of this packet type, and two
- * major versions.  Consequently, this section is complex.
- */
-function openpgp_packet_keymaterial() {
-	// members:
-	this.publicKeyAlgorithm = null;
-	this.tagType = null;
-	this.creationTime = null;
-	this.version = null;
-	this.expiration  = null;// V3
-	this.MPIs = null;
-	this.secMPIs = null;
-	this.publicKey = null;
-	this.symmetricEncryptionAlgorithm = null;
-	this.s2kUsageConventions = null;
-	this.IVLength  = null;
-    this.encryptedMPIData = null;
-    this.hasUnencryptedSecretKeyData = null;
-    this.checksum = null;
-    this.parentNode = null;
-	this.subKeySignature = null;
-	this.subKeyRevocationSignature = null;
-
-	// 5.5.1. Key Packet Variants
-	
-	// 5.5.1.3. Secret-Key Packet (Tag 5)
-	/**
-	 * This function reads the payload of a secret key packet (Tag 5)
-	 * and initializes the openpgp_packet_keymaterial
-	 * @param {String} input Input string to read the packet from
-	 * @param {Integer} position Start position for the parser
-	 * @param {Intefer} len Length of the packet or remaining length of input
-	 * @return {openpgp_packet_keymaterial}
-	 */
-	function read_tag5(input, position, len) {
-		this.tagType = 5;
-		this.read_priv_key(input, position, len);
-		return this;
-	}
-
-	// 5.5.1.1. Public-Key Packet (Tag 6)
-	/**
-	 * This function reads the payload of a public key packet (Tag 6)
-	 * and initializes the openpgp_packet_keymaterial
-	 * @param {String} input Input string to read the packet from
-	 * @param {Integer} position Start position for the parser
-	 * @param {Integer} len Length of the packet or remaining length of input
-	 * @return {openpgp_packet_keymaterial}
-	 */
-	function read_tag6(input, position, len) {
-		// A Public-Key packet starts a series of packets that forms an OpenPGP
-		// key (sometimes called an OpenPGP certificate).
-		this.tagType = 6;
-		this.packetLength = len;
-		this.read_pub_key(input, position,len);
-		
-		return this;
-	}
-
-	// 5.5.1.4. Secret-Subkey Packet (Tag 7)
-	/**
-	 * This function reads the payload of a secret key sub packet (Tag 7)
-	 * and initializes the openpgp_packet_keymaterial
-	 * @param {String} input Input string to read the packet from
-	 * @param {Integer} position Start position for the parser
-	 * @param {Integer} len Length of the packet or remaining length of input
-	 * @return {openpgp_packet_keymaterial}
-	 */
-	function read_tag7(input, position, len) {
-		this.tagType = 7;
-		this.packetLength = len;
-		return this.read_priv_key(input, position, len);
-	}
-
-	// 5.5.1.2. Public-Subkey Packet (Tag 14)
-	/**
-	 * This function reads the payload of a public key sub packet (Tag 14)
-	 * and initializes the openpgp_packet_keymaterial
-	 * @param {String} input Input string to read the packet from
-	 * @param {Integer} position Start position for the parser
-	 * @param {Integer} len Length of the packet or remaining length of input
-	 * @return {openpgp_packet_keymaterial}
-	 */
-	function read_tag14(input, position, len) {
-		this.subKeySignature = null;
-		this.subKeyRevocationSignature = new Array();
-		this.tagType = 14;
-		this.packetLength = len;
-		this.read_pub_key(input, position,len);
-		return this;
-	}
-	
-	/**
-	 * Internal Parser for public keys as specified in RFC 4880 section 
-	 * 5.5.2 Public-Key Packet Formats
-	 * called by read_tag<num>
-	 * @param {String} input Input string to read the packet from
-	 * @param {Integer} position Start position for the parser
-	 * @param {Integer} len Length of the packet or remaining length of input
-	 * @return {Object} This object with attributes set by the parser
-	 */  
-	function read_pub_key(input, position, len) {
-		var mypos = position;
-		// A one-octet version number (3 or 4).
-		this.version = input[mypos++].charCodeAt();
-		if (this.version == 3) {
-			// A four-octet number denoting the time that the key was created.
-			this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) |
-				(input[mypos++].charCodeAt() << 16) |
-				(input[mypos++].charCodeAt() <<  8) |
-				(input[mypos++].charCodeAt()))*1000);
-			
-		    // - A two-octet number denoting the time in days that this key is
-		    //   valid.  If this number is zero, then it does not expire.
-			this.expiration = (input[mypos++].charCodeAt() << 8) & input[mypos++].charCodeAt();
-	
-		    // - A one-octet number denoting the public-key algorithm of this key.
-			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
-			var mpicount = 0;
-		    // - A series of multiprecision integers comprising the key material:
-			//   Algorithm-Specific Fields for RSA public keys:
-		    //       - a multiprecision integer (MPI) of RSA public modulus n;
-		    //       - an MPI of RSA public encryption exponent e.
-			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
-				mpicount = 2;
-			//   Algorithm-Specific Fields for Elgamal public keys:
-			//     - MPI of Elgamal prime p;
-			//     - MPI of Elgamal group generator g;
-			//     - MPI of Elgamal public key value y (= g**x mod p where x  is secret).
-
-			else if (this.publicKeyAlgorithm == 16)
-				mpicount = 3;
-			//   Algorithm-Specific Fields for DSA public keys:
-			//       - MPI of DSA prime p;
-			//       - MPI of DSA group order q (q is a prime divisor of p-1);
-			//       - MPI of DSA group generator g;
-			//       - MPI of DSA public-key value y (= g**x mod p where x  is secret).
-			else if (this.publicKeyAlgorithm == 17)
-				mpicount = 4;
-
-			this.MPIs = new Array();
-			for (var i = 0; i < mpicount; i++) {
-				this.MPIs[i] = new openpgp_type_mpi();
-				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && 
-						!this.packetLength < (mypos-position)) {
-					mypos += this.MPIs[i].packetLength;
-				} else {
-					util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
-				}
-			}
-			this.packetLength = mypos-position;
-		} else if (this.version == 4) {
-			// - A four-octet number denoting the time that the key was created.
-			this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) |
-			(input[mypos++].charCodeAt() << 16) |
-			(input[mypos++].charCodeAt() <<  8) |
-			(input[mypos++].charCodeAt()))*1000);
-			
-			// - A one-octet number denoting the public-key algorithm of this key.
-			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
-			var mpicount = 0;
-		    // - A series of multiprecision integers comprising the key material:
-			//   Algorithm-Specific Fields for RSA public keys:
-		    //       - a multiprecision integer (MPI) of RSA public modulus n;
-		    //       - an MPI of RSA public encryption exponent e.
-			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
-					mpicount = 2;
-			//   Algorithm-Specific Fields for Elgamal public keys:
-			//     - MPI of Elgamal prime p;
-			//     - MPI of Elgamal group generator g;
-			//     - MPI of Elgamal public key value y (= g**x mod p where x  is secret).
-			else if (this.publicKeyAlgorithm == 16)
-				mpicount = 3;
-
-			//   Algorithm-Specific Fields for DSA public keys:
-			//       - MPI of DSA prime p;
-			//       - MPI of DSA group order q (q is a prime divisor of p-1);
-			//       - MPI of DSA group generator g;
-			//       - MPI of DSA public-key value y (= g**x mod p where x  is secret).
-			else if (this.publicKeyAlgorithm == 17)
-				mpicount = 4;
-
-			this.MPIs = new Array();
-			var i = 0;
-			for (var i = 0; i < mpicount; i++) {
-				this.MPIs[i] = new openpgp_type_mpi();
-				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
-						!this.packetLength < (mypos-position)) {
-					mypos += this.MPIs[i].packetLength;
-				} else {
-					util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
-				}
-			}
-			this.packetLength = mypos-position;
-		} else {
-			return null;
-		}
-		this.data = input.substring(position, mypos);
-		this.packetdata = input.substring(position, mypos);
-		return this;
-	}
-	
-	// 5.5.3.  Secret-Key Packet Formats
-	
-	/**
-	 * Internal parser for private keys as specified in RFC 4880 section 5.5.3
-	 * @param {String} input Input string to read the packet from
-	 * @param {Integer} position Start position for the parser
-	 * @param {Integer} len Length of the packet or remaining length of input
-	 * @return {Object} This object with attributes set by the parser
-	 */
-	function read_priv_key(input,position, len) {
-	    // - A Public-Key or Public-Subkey packet, as described above.
-	    this.publicKey = new openpgp_packet_keymaterial();
-		if (this.publicKey.read_pub_key(input,position, len) == null) {
-			util.print_error("openpgp.packet.keymaterial.js\n"+"Failed reading public key portion of a private key: "+input[position].charCodeAt()+" "+position+" "+len+"\n Aborting here...");
-			return null;
-		}
-		this.publicKey.header = openpgp_packet.write_old_packet_header(6,this.publicKey.packetLength);
-		// this.publicKey.header = String.fromCharCode(0x99) + String.fromCharCode(this.publicKey.packetLength >> 8 & 0xFF)+String.fromCharCode(this.publicKey.packetLength & 0xFF);
-		var mypos = position + this.publicKey.data.length;
-		this.packetLength = len;
-		
-	    // - One octet indicating string-to-key usage conventions.  Zero
-	    //   indicates that the secret-key data is not encrypted.  255 or 254
-	    //   indicates that a string-to-key specifier is being given.  Any
-	    //   other value is a symmetric-key encryption algorithm identifier.
-	    this.s2kUsageConventions = input[mypos++].charCodeAt();
-	    
-	    if (this.s2kUsageConventions == 0)
-	    	this.hasUnencryptedSecretKeyData = true;
-	   
-	    // - [Optional] If string-to-key usage octet was 255 or 254, a one-
-	    //   octet symmetric encryption algorithm.
-	    if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
-	    	this.symmetricEncryptionAlgorithm = input[mypos++].charCodeAt();
-	    }
-	     
-	    // - [Optional] If string-to-key usage octet was 255 or 254, a
-	    //   string-to-key specifier.  The length of the string-to-key
-	    //   specifier is implied by its type, as described above.
-	    if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
-	    	this.s2k = new openpgp_type_s2k();
-	    	this.s2k.read(input, mypos);
-	    	mypos +=this.s2k.s2kLength;
-	    }
-	    
-	    // - [Optional] If secret data is encrypted (string-to-key usage octet
-	    //   not zero), an Initial Vector (IV) of the same length as the
-	    //   cipher's block size.
-	    this.symkeylength = 0;
-	    if (this.s2kUsageConventions != 0 && this.s2kUsageConventions != 255 &&
-	    		this.s2kUsageConventions != 254) {
-	    	this.symmetricEncryptionAlgorithm = this.s2kUsageConventions;
-	    }
-	    if (this.s2kUsageConventions != 0 && this.s2k.type != 1001) {
-	    	this.hasIV = true;
-	    	switch (this.symmetricEncryptionAlgorithm) {
-		    case  1: // - IDEA [IDEA]
-		    	util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encrytryption algorithim: IDEA is not implemented");
-		    	return null;
-	    	case  2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
-	    	case  3: // - CAST5 (128 bit key, as per [RFC2144])
-	    		this.IVLength = 8;
-		    	break;
-		    case  4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
-		    case  7: // - AES with 128-bit key [AES]
-	    	case  8: // - AES with 192-bit key
-	    	case  9: // - AES with 256-bit key
-	    		this.IVLength = 16;
-		    	break;
-	    	case 10: // - Twofish with 256-bit key [TWOFISH]
-	    		this.IVLength = 32;	    		
-		    	break;
-	    	case  5: // - Reserved
-	    	case  6: // - Reserved
-	    	default:
-	    		util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
-	    		return null;
-	    	}
-	    	mypos++; 
-	    	this.IV = input.substring(mypos, mypos+this.IVLength);
-	    	mypos += this.IVLength;
-	    }
-	    // - Plain or encrypted multiprecision integers comprising the secret
-	    //   key data.  These algorithm-specific fields are as described
-	    //   below.
-
-      // s2k type 1001 corresponds to GPG specific extension without primary key secrets
-      // http://www.gnupg.org/faq/GnuPG-FAQ.html#how-can-i-use-gnupg-in-an-automated-environment
-	    if (this.s2kUsageConventions != 0 && this.s2k.type == 1001) {
-	    	this.secMPIs = null;
-	    	this.encryptedMPIData = null;
-	    } else if (!this.hasUnencryptedSecretKeyData) {
-	    	this.encryptedMPIData = input.substring(mypos, len);
-	    	mypos += this.encryptedMPIData.length;
-	    } else {
-	    	if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
-	    		//   Algorithm-Specific Fields for RSA secret keys:
-	    		//   - multiprecision integer (MPI) of RSA secret exponent d.
-	    		//   - MPI of RSA secret prime value p.
-	    		//   - MPI of RSA secret prime value q (p < q).
-	    		//   - MPI of u, the multiplicative inverse of p, mod q.
-	    		this.secMPIs = new Array();
-	    		this.secMPIs[0] = new openpgp_type_mpi();
-	    		this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
-	    		mypos += this.secMPIs[0].packetLength;
-	    		this.secMPIs[1] = new openpgp_type_mpi();
-	    		this.secMPIs[1].read(input, mypos, len-2- (mypos - position));
-	    		mypos += this.secMPIs[1].packetLength;
-	    		this.secMPIs[2] = new openpgp_type_mpi();
-	    		this.secMPIs[2].read(input, mypos, len-2- (mypos - position));
-	    		mypos += this.secMPIs[2].packetLength;
-	    		this.secMPIs[3] = new openpgp_type_mpi();
-	    		this.secMPIs[3].read(input, mypos, len-2- (mypos - position));
-	    		mypos += this.secMPIs[3].packetLength;
-	    	} else if (this.publicKey.publicKeyAlgorithm == 16) {
-	    		// Algorithm-Specific Fields for Elgamal secret keys:
-	    		//   - MPI of Elgamal secret exponent x.
-	    		this.secMPIs = new Array();
-	    		this.secMPIs[0] = new openpgp_type_mpi();
-	    		this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
-	    		mypos += this.secMPIs[0].packetLength;
-	    	} else if (this.publicKey.publicKeyAlgorithm == 17) {
-	    		// Algorithm-Specific Fields for DSA secret keys:
-	    		//   - MPI of DSA secret exponent x.
-	    		this.secMPIs = new Array();
-	    		this.secMPIs[0] = new openpgp_type_mpi();
-	    		this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
-	    		mypos += this.secMPIs[0].packetLength;
-	    	}
-	    	// checksum because s2k usage convention is 0
-	        this.checksum = new Array(); 
-		    this.checksum[0] = input[mypos++].charCodeAt();
-		    this.checksum[1] = input[mypos++].charCodeAt();
-	    }
-	    return this;
-	}
-	
-
-	/**
-	 * Decrypts the private key MPIs which are needed to use the key.
-	 * openpgp_packet_keymaterial.hasUnencryptedSecretKeyData should be 
-	 * false otherwise
-	 * a call to this function is not needed
-	 * 
-	 * @param {String} str_passphrase The passphrase for this private key 
-	 * as string
-	 * @return {Boolean} True if the passphrase was correct; false if not
-	 */
-	function decryptSecretMPIs(str_passphrase) {
-		if (this.hasUnencryptedSecretKeyData)
-			return this.secMPIs;
-		// creating a key out of the passphrase
-		var key = this.s2k.produce_key(str_passphrase);
-		var cleartextMPIs = "";
-    	switch (this.symmetricEncryptionAlgorithm) {
-	    case  1: // - IDEA [IDEA]
-	    	util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encryption algorithim: IDEA is not implemented");
-	    	return false;
-    	case  2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
-    		cleartextMPIs = normal_cfb_decrypt(function(block, key) {
-    			return des(key, block,1,null,0);
-    		}, this.IVLength, key, this.encryptedMPIData, this.IV);
-    		break;
-    	case  3: // - CAST5 (128 bit key, as per [RFC2144])
-    		cleartextMPIs = normal_cfb_decrypt(function(block, key) {
-        		var cast5 = new openpgp_symenc_cast5();
-        		cast5.setKey(key);
-        		return cast5.encrypt(util.str2bin(block)); 
-    		}, this.IVLength, util.str2bin(key.substring(0,16)), this.encryptedMPIData, this.IV);
-    		break;
-	    case  4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
-	    	cleartextMPIs = normal_cfb_decrypt(function(block, key) {
-    			var blowfish = new Blowfish(key);
-        		return blowfish.encrypt(block); 
-    		}, this.IVLength, key, this.encryptedMPIData, this.IV);
-    		break;
-	    case  7: // - AES with 128-bit key [AES]
-    	case  8: // - AES with 192-bit key
-    	case  9: // - AES with 256-bit key
-    	    var numBytes = 16;
-            //This is a weird way to achieve this. If's within a switch is probably not ideal.
-    	    if(this.symmetricEncryptionAlgorithm == 8){
-    	        numBytes = 24;
-    	        key = this.s2k.produce_key(str_passphrase,numBytes);
-    	    }
-    	    if(this.symmetricEncryptionAlgorithm == 9){
-    	        numBytes = 32;
-    	        key = this.s2k.produce_key(str_passphrase,numBytes);
-    	    }
-    		cleartextMPIs = normal_cfb_decrypt(function(block,key){
-    		    return AESencrypt(util.str2bin(block),key);
-    		},
-    				this.IVLength, keyExpansion(key.substring(0,numBytes)), this.encryptedMPIData, this.IV);
-	    	break;
-    	case 10: // - Twofish with 256-bit key [TWOFISH]
-    		util.print_error("openpgp.packet.keymaterial.js\n"+"Key material is encrypted with twofish: not implemented");   		
-	    	return false;
-    	case  5: // - Reserved
-    	case  6: // - Reserved
-    	default:
-    		util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
-    		return false;
-    	}
-    	
-    	if (cleartextMPIs == null) {
-    		util.print_error("openpgp.packet.keymaterial.js\n"+"cleartextMPIs was null");
-    		return false;
-    	}
-    	
-    	var cleartextMPIslength = cleartextMPIs.length;
-
-    	if (this.s2kUsageConventions == 254 &&
-    			str_sha1(cleartextMPIs.substring(0,cleartextMPIs.length - 20)) == 
-    				cleartextMPIs.substring(cleartextMPIs.length - 20)) {
-    		cleartextMPIslength -= 20;
-    	} else if (this.s2kUsageConventions != 254 && util.calc_checksum(cleartextMPIs.substring(0,cleartextMPIs.length - 2)) == 
-    			(cleartextMPIs.charCodeAt(cleartextMPIs.length -2) << 8 | cleartextMPIs.charCodeAt(cleartextMPIs.length -1))) {
-    		cleartextMPIslength -= 2;
-    	} else {
-    		return false;
-    	}
-
-    	if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
-    		//   Algorithm-Specific Fields for RSA secret keys:
-    		//   - multiprecision integer (MPI) of RSA secret exponent d.
-    		//   - MPI of RSA secret prime value p.
-    		//   - MPI of RSA secret prime value q (p < q).
-    		//   - MPI of u, the multiplicative inverse of p, mod q.
-    		var mypos = 0;
-    		this.secMPIs = new Array();
-    		this.secMPIs[0] = new openpgp_type_mpi();
-    		this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
-    		mypos += this.secMPIs[0].packetLength;
-    		this.secMPIs[1] = new openpgp_type_mpi();
-    		this.secMPIs[1].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
-    		mypos += this.secMPIs[1].packetLength;
-    		this.secMPIs[2] = new openpgp_type_mpi();
-    		this.secMPIs[2].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
-    		mypos += this.secMPIs[2].packetLength;
-    		this.secMPIs[3] = new openpgp_type_mpi();
-    		this.secMPIs[3].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
-    		mypos += this.secMPIs[3].packetLength;
-    	} else if (this.publicKey.publicKeyAlgorithm == 16) {
-    		// Algorithm-Specific Fields for Elgamal secret keys:
-    		//   - MPI of Elgamal secret exponent x.
-    		this.secMPIs = new Array();
-    		this.secMPIs[0] = new openpgp_type_mpi();
-    		this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIs);
-    	} else if (this.publicKey.publicKeyAlgorithm == 17) {
-    		// Algorithm-Specific Fields for DSA secret keys:
-    		//   - MPI of DSA secret exponent x.
-    		this.secMPIs = new Array();
-    		this.secMPIs[0] = new openpgp_type_mpi();
-    		this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
-    	}
-    	return true;
-	}
-	
-	/**
-	 * Generates Debug output
-	 * @return String which gives some information about the keymaterial
-	 */
-	function toString() {
-		var result = "";
-		switch (this.tagType) {
-		case 6:
-			 result += '5.5.1.1. Public-Key Packet (Tag 6)\n'+
-			   '    length:             '+this.packetLength+'\n'+
-			   '    version:            '+this.version+'\n'+
-			   '    creation time:      '+this.creationTime+'\n'+
-			   '    expiration time:    '+this.expiration+'\n'+
-			   '    publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
-			break;
-		case 14:
-			result += '5.5.1.2. Public-Subkey Packet (Tag 14)\n'+
-			   '    length:             '+this.packetLength+'\n'+
-			   '    version:            '+this.version+'\n'+
-			   '    creation time:      '+this.creationTime+'\n'+
-			   '    expiration time:    '+this.expiration+'\n'+
-			   '    publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
-			break;
-		case 5:
-			result +='5.5.1.3. Secret-Key Packet (Tag 5)\n'+
-			   '    length:             '+this.packetLength+'\n'+
-			   '    version:            '+this.publicKey.version+'\n'+
-			   '    creation time:      '+this.publicKey.creationTime+'\n'+
-			   '    expiration time:    '+this.publicKey.expiration+'\n'+
-			   '    publicKeyAlgorithm: '+this.publicKey.publicKeyAlgorithm+'\n';
-			break;
-		case 7:
-			result += '5.5.1.4. Secret-Subkey Packet (Tag 7)\n'+
-			   '    length:             '+this.packetLength+'\n'+
-			   '    version[1]:         '+(this.version == 4)+'\n'+
-			   '    creationtime[4]:    '+this.creationTime+'\n'+
-			   '    expiration[2]:      '+this.expiration+'\n'+
-			   '    publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
-			break;
-		default:
-			result += 'unknown key material packet\n';
-		}
-		if (this.MPIs != null) {
-			result += "Public Key MPIs:\n";
-			for (var i = 0; i < this.MPIs.length; i++) {
-      	  	result += this.MPIs[i].toString();
-        	}
-		}
-		if (this.publicKey != null && this.publicKey.MPIs != null) {
-			result += "Public Key MPIs:\n";
-			for (var i = 0; i < this.publicKey.MPIs.length; i++) {
-	      	  	result += this.publicKey.MPIs[i].toString();
-        	}
-		}
-		if (this.secMPIs != null) {
-			result += "Secret Key MPIs:\n";
-			for (var i = 0; i < this.secMPIs.length; i++) {
-		      	  result += this.secMPIs[i].toString();
-		        }
-		}
-		
-		if (this.subKeySignature != null)
-			result += "subKey Signature:\n"+this.subKeySignature.toString();
-		
-		if (this.subKeyRevocationSignature != null )
-			result += "subKey Revocation Signature:\n"+this.subKeyRevocationSignature.toString();
-        return result;
-	}
-	
-	/**
-	 * Continue parsing packets belonging to the key material such as signatures
-	 * @param {Object} parent_node The parent object
-	 * @param {String} input Input string to read the packet(s) from
-	 * @param {Integer} position Start position for the parser
-	 * @param {Integer} len Length of the packet(s) or remaining length of input
-	 * @return {Integer} Length of nodes read
-	 */
-	function read_nodes(parent_node, input, position, len) {
-		this.parentNode = parent_node;
-		if (this.tagType == 14) { // public sub-key packet
-			var pos = position;
-			var result = null;
-			while (input.length != pos) {
-				var l = input.length - pos;
-				result = openpgp_packet.read_packet(input, pos, l);
-				if (result == null) {
-					util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_pub]parsing ends here @:' + pos + " l:" + l);
-					break;
-				} else {
-					
-					switch (result.tagType) {
-					case 2: // Signature Packet certification signature
-						if (result.signatureType == 24)  { // subkey binding signature
-							this.subKeySignature = result;
-							pos += result.packetLength + result.headerLength;
-							break;
-						} else if (result.signatureType == 40) { // subkey revocation signature
-							this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result;
-							pos += result.packetLength + result.headerLength;
-							break;
-						} else {
-							util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+result.toString());
-						}
-						
-					default:
-						this.data = input;
-						this.position = position - this.parentNode.packetLength;
-						this.len = pos - position;
-						return this.len;
-						break;
-					}
-				}
-			}
-			this.data = input;
-			this.position = position - this.parentNode.packetLength;
-			this.len = pos - position;
-			return this.len;
-		} else if (this.tagType == 7) { // private sub-key packet
-			var pos = position;
-			while (input.length != pos) {
-				var result = openpgp_packet.read_packet(input, pos, len - (pos - position));
-				if (result == null) {
-					util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_priv] parsing ends here @:' + pos);
-					break;
-				} else {
-					switch (result.tagType) {
-					case 2: // Signature Packet certification signature
-						if (result.signatureType == 24) // subkey embedded signature
-							this.subKeySignature = result; 
-						else if (result.signatureType == 40) // subkey revocation signature
-							this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result;
-						pos += result.packetLength + result.headerLength;
-						break;
-					default:
-						this.data = input;
-						this.position = position - this.parentNode.packetLength;
-						this.len = pos - position;
-						return this.len;
-					}
-				}
-			}
-			this.data = input;
-			this.position = position - this.parentNode.packetLength;
-			this.len = pos - position;
-			return this.len;
-		} else {
-			util.print_error("openpgp.packet.keymaterial.js\n"+"unknown parent node for a key material packet "+parent_node.tagType);
-		}
-	}
-
-	/**
-	 * Checks the validity for usage of this (sub)key
-	 * @return {Integer} 0 = bad key, 1 = expired, 2 = revoked, 3 = valid
-	 */
-	function verifyKey() {
-		if (this.tagType == 14) {
-			if (this.subKeySignature == null) {
-				return 0;
-			}
-			if (this.subKeySignature.version == 4 &&
-				this.subKeySignature.keyNeverExpires != null &&
-				!this.subKeySignature.keyNeverExpires &&
-				new Date((this.subKeySignature.keyExpirationTime*1000)+ this.creationTime.getTime()) < new Date()) {
-				    return 1;
-				}
-			var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+
-			String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata;
-			if (!this.subKeySignature.verify(hashdata,this.parentNode)) {
-				return 0;
-			}
-			for (var i = 0; i < this.subKeyRevocationSignature.length; i++) {
-			    if (this.getKeyId() == this.subKeyRevocationSignature[i].keyId){
-			        return 2;
-			    }
-			}
-		}
-		return 3;
-	}
-
-	/**
-	 * Calculates the key id of they key 
-	 * @return {String} A 8 byte key id
-	 */
-	function getKeyId() {
-		if (this.version == 4) {
-			var f = this.getFingerprint();
-			return f.substring(12,20);
-		} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
-			var key_id = this.MPIs[0].substring((this.MPIs[0].mpiByteLength-8));
-			util.print_debug("openpgp.msg.publickey read_nodes:\n"+"V3 key ID: "+key_id);
-			return key_id;
-		}
-	}
-	
-	/**
-	 * Calculates the fingerprint of the key
-	 * @return {String} A string containing the fingerprint
-	 */
-	function getFingerprint() {
-		if (this.version == 4) {
-			tohash = String.fromCharCode(0x99)+ String.fromCharCode(((this.packetdata.length) >> 8) & 0xFF) 
-				+ String.fromCharCode((this.packetdata.length) & 0xFF)+this.packetdata;
-			util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm);
-			return str_sha1(tohash, tohash.length);
-		} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
-			return MD5(this.MPIs[0].MPI);
-		}
-	}
-	
-	/*
-     * Creates an OpenPGP key packet for the given key. much 
-	 * TODO in regards to s2k, subkeys.
-     * @param {Integer} keyType Follows the OpenPGP algorithm standard, 
-	 * IE 1 corresponds to RSA.
-     * @param {RSA.keyObject} key
-     * @param password
-     * @param s2kHash
-     * @param symmetricEncryptionAlgorithm
-     * @param timePacket
-     * @return {Object} {body: [string]OpenPGP packet body contents, 
-		header: [string] OpenPGP packet header, string: [string] header+body}
-     */
-    function write_private_key(keyType, key, password, s2kHash, symmetricEncryptionAlgorithm, timePacket){
-        this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
-		var tag = 5;
-		var body = String.fromCharCode(4);
-		body += timePacket;
-		switch(keyType){
-		case 1:
-		    body += String.fromCharCode(keyType);//public key algo
-		    body += key.n.toMPI();
-		    body += key.ee.toMPI();
-		    var algorithmStart = body.length;
-		    //below shows ske/s2k
-		    if(password){
-		        body += String.fromCharCode(254); //octet of 254 indicates s2k with SHA1
-		        //if s2k == 255,254 then 1 octet symmetric encryption algo
-		        body += String.fromCharCode(this.symmetricEncryptionAlgorithm);
-		        //if s2k == 255,254 then s2k specifier
-		        body += String.fromCharCode(3); //s2k salt+iter
-		        body += String.fromCharCode(s2kHash);
-		        //8 octet salt value
-		        //1 octet count
-		        var cleartextMPIs = key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI();
-		        var sha1Hash = str_sha1(cleartextMPIs);
-   		        util.print_debug_hexstr_dump('write_private_key sha1: ',sha1Hash);
-		        var salt = openpgp_crypto_getRandomBytes(8);
-		        util.print_debug_hexstr_dump('write_private_key Salt: ',salt);
-		        body += salt;
-		        var c = 96; //c of 96 translates to count of 65536
-		        body += String.fromCharCode(c);
-		        util.print_debug('write_private_key c: '+ c);
-		        var s2k = new openpgp_type_s2k();
-		        var hashKey = s2k.write(3, s2kHash, password, salt, c);
-		        //if s2k, IV of same length as cipher's block
-		        switch(this.symmetricEncryptionAlgorithm){
-		        case 3:
-		            this.IVLength = 8;
-		            this.IV = openpgp_crypto_getRandomBytes(this.IVLength);
-            		ciphertextMPIs = normal_cfb_encrypt(function(block, key) {
-                		var cast5 = new openpgp_symenc_cast5();
-                		cast5.setKey(key);
-                		return cast5.encrypt(util.str2bin(block)); 
-            		}, this.IVLength, util.str2bin(hashKey.substring(0,16)), cleartextMPIs + sha1Hash, this.IV);
-            		body += this.IV + ciphertextMPIs;
-		            break;
-		        case 7:
-		        case 8:
-		        case 9:
-		            this.IVLength = 16;
-		            this.IV = openpgp_crypto_getRandomBytes(this.IVLength);
-		            ciphertextMPIs = normal_cfb_encrypt(AESencrypt,
-            				this.IVLength, hashKey, cleartextMPIs + sha1Hash, this.IV);
-            		body += this.IV + ciphertextMPIs;
-	            	break;
-		        }
-		    }
-		    else{
-		        body += String.fromCharCode(0);//1 octet -- s2k, 0 for no s2k
-		        body += key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI();
-		        var checksum = util.calc_checksum(key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI());
-        		body += String.fromCharCode(checksum/0x100) + String.fromCharCode(checksum%0x100);//DEPRECATED:s2k == 0, 255: 2 octet checksum, sum all octets%65536
-        		util.print_debug_hexstr_dump('write_private_key basic checksum: '+ checksum);
-		    }
-		    break;
-		default :
-			body = "";
-			util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType);
-        }
-		var header = openpgp_packet.write_packet_header(tag,body.length);
-		return {string: header+body , header: header, body: body};
-    }
-	
-	/*
-     * Same as write_private_key, but has less information because of 
-	 * public key.
-     * @param {Integer} keyType Follows the OpenPGP algorithm standard, 
-	 * IE 1 corresponds to RSA.
-     * @param {RSA.keyObject} key
-     * @param timePacket
-     * @return {Object} {body: [string]OpenPGP packet body contents, 
-	 * header: [string] OpenPGP packet header, string: [string] header+body}
-     */
-    function write_public_key(keyType, key, timePacket){
-        var tag = 6;
-        var body = String.fromCharCode(4);
-        body += timePacket;
-		switch(keyType){
-		case 1:
-		    body += String.fromCharCode(1);//public key algo
-		    body += key.n.toMPI();
-		    body += key.ee.toMPI();
-		    break;
-	    default:
-	    	util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType);
-	    }
-        var header = openpgp_packet.write_packet_header(tag,body.length);
-        return {string: header+body , header: header, body: body};
-        }
-
-	
-	this.read_tag5 = read_tag5;
-	this.read_tag6 = read_tag6;
-	this.read_tag7 = read_tag7;
-	this.read_tag14 = read_tag14;
-	this.toString = toString;
-	this.read_pub_key = read_pub_key;
-	this.read_priv_key = read_priv_key;
-	this.decryptSecretMPIs = decryptSecretMPIs;
-	this.read_nodes = read_nodes;
-	this.verifyKey = verifyKey;
-	this.getKeyId = getKeyId;
-	this.getFingerprint = getFingerprint;
-	this.write_private_key = write_private_key;
-	this.write_public_key = write_public_key;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.literaldata.js.html b/doc/openpgp.packet.literaldata.js.html deleted file mode 100644 index 1605c031..00000000 --- a/doc/openpgp.packet.literaldata.js.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.literaldata.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.literaldata.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the Literal Data Packet (Tag 11)
- * 
- * RFC4880 5.9: A Literal Data packet contains the body of a message; data that
- * is not to be further interpreted.
- */
-function openpgp_packet_literaldata() {
-	this.tagType = 11;
-
-	
-	/**
-	 * Set the packet data to a javascript native string or a squence of 
-	 * bytes. Conversion to a proper utf8 encoding takes place when the 
-	 * packet is written.
-	 * @param {String} str Any native javascript string
-	 * @param {openpgp_packet_literaldata.formats} format 
-	 */
-	this.set_data = function(str, format) {
-		this.format = format;
-		this.data = str;
-	}
-
-	/**
-	 * Set the packet data to value represented by the provided string
-	 * of bytes together with the appropriate conversion format.
-	 * @param {String} bytes The string of bytes
-	 * @param {openpgp_packet_literaldata.formats} format
-	 */
-	this.set_data_bytes = function(bytes, format) {
-		this.format = format;
-
-		if(format == openpgp_packet_literaldata.formats.utf8)
-			bytes = util.decode_utf8(bytes);
-
-		this.data = bytes;
-	}
-
-	/**
-	 * Get the byte sequence representing the literal packet data
-	 * @returns {String} A sequence of bytes
-	 */
-	this.get_data_bytes = function() {
-		if(this.format == openpgp_packet_literaldata.formats.utf8)
-			return util.encode_utf8(this.data);
-		else
-			return this.data;
-	}
-	
-	
-
-	/**
-	 * Parsing function for a literal data packet (tag 11).
-	 * 
-	 * @param {String} input Payload of a tag 11 packet
-	 * @param {Integer} position
-	 *            Position to start reading from the input string
-	 * @param {Integer} len
-	 *            Length of the packet or the remaining length of
-	 *            input at position
-	 * @return {openpgp_packet_encrypteddata} object representation
-	 */
-	this.read_packet = function(input, position, len) {
-		this.packetLength = len;
-		// - A one-octet field that describes how the data is formatted.
-
-		var format = input[position];
-
-		this.filename = util.decode_utf8(input.substr(position + 2, input
-				.charCodeAt(position + 1)));
-
-		this.date = new Date(parseInt(input.substr(position + 2
-				+ input.charCodeAt(position + 1), 4)) * 1000);
-
-		var bytes = input.substring(position + 6
-				+ input.charCodeAt(position + 1));
-	
-		this.set_data_bytes(bytes, format);
-		return this;
-	}
-
-	/**
-	 * Creates a string representation of the packet
-	 * 
-	 * @param {String} data The data to be inserted as body
-	 * @return {String} string-representation of the packet
-	 */
-	this.write_packet = function(data) {
-		this.set_data(data, openpgp_packet_literaldata.formats.utf8);
-		this.filename = util.encode_utf8("msg.txt");
-		this.date = new Date();
-
-		data = this.get_data_bytes();
-
-		var result = openpgp_packet.write_packet_header(11, data.length + 6
-				+ this.filename.length);
-		result += this.format;
-		result += String.fromCharCode(this.filename.length);
-		result += this.filename;
-		result += String
-				.fromCharCode((Math.round(this.date.getTime() / 1000) >> 24) & 0xFF);
-		result += String
-				.fromCharCode((Math.round(this.date.getTime() / 1000) >> 16) & 0xFF);
-		result += String
-				.fromCharCode((Math.round(this.date.getTime() / 1000) >> 8) & 0xFF);
-		result += String
-				.fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF);
-		result += data;
-		return result;
-	}
-
-	/**
-	 * Generates debug output (pretty print)
-	 * 
-	 * @return {String} String which gives some information about the keymaterial
-	 */
-	this.toString = function() {
-		return '5.9.  Literal Data Packet (Tag 11)\n' + '    length: '
-				+ this.packetLength + '\n' + '    format: ' + this.format
-				+ '\n' + '    filename:' + this.filename + '\n'
-				+ '    date:   ' + this.date + '\n' + '    data:  |'
-				+ this.data + '|\n' + '    rdata: |' + this.real_data + '|\n';
-	}
-}
-
-/**
- * Data types in the literal packet
- * @readonly
- * @enum {String}
- */
-openpgp_packet_literaldata.formats = {
-	/** Binary data */
-	binary: 'b',
-	/** Text data */
-	text: 't',
-	/** Utf8 data */
-	utf8: 'u'
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.marker.js.html b/doc/openpgp.packet.marker.js.html deleted file mode 100644 index 42792782..00000000 --- a/doc/openpgp.packet.marker.js.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.marker.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.marker.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the strange "Marker packet" (Tag 10)
- * 
- * RFC4880 5.8: An experimental version of PGP used this packet as the Literal
- * packet, but no released version of PGP generated Literal packets with this
- * tag. With PGP 5.x, this packet has been reassigned and is reserved for use as
- * the Marker packet.
- * 
- * Such a packet MUST be ignored when received.
- */
-function openpgp_packet_marker() {
-	this.tagType = 10;
-	/**
-	 * Parsing function for a literal data packet (tag 10).
-	 * 
-	 * @param {String} input Payload of a tag 10 packet
-	 * @param {Integer} position
-	 *            Position to start reading from the input string
-	 * @param {Integer} len
-	 *            Length of the packet or the remaining length of
-	 *            input at position
-	 * @return {openpgp_packet_encrypteddata} Object representation
-	 */
-	function read_packet(input, position, len) {
-		this.packetLength = 3;
-		if (input[position].charCodeAt() == 0x50 && // P
-				input[position + 1].charCodeAt() == 0x47 && // G
-				input[position + 2].charCodeAt() == 0x50) // P
-			return this;
-		// marker packet does not contain "PGP"
-		return null;
-	}
-
-	/**
-	 * Generates Debug output
-	 * 
-	 * @return {String} String which gives some information about the 
-	 * keymaterial
-	 */
-	function toString() {
-		return "5.8.  Marker Packet (Obsolete Literal Packet) (Tag 10)\n"
-				+ "     packet reads: \"PGP\"\n";
-	}
-
-	this.read_packet = read_packet;
-	this.toString = toString;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.modificationdetectioncode.js.html b/doc/openpgp.packet.modificationdetectioncode.js.html deleted file mode 100644 index dbf74c06..00000000 --- a/doc/openpgp.packet.modificationdetectioncode.js.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.modificationdetectioncode.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.modificationdetectioncode.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the Modification Detection Code Packet (Tag 19)
- * 
- * RFC4880 5.14: The Modification Detection Code packet contains a SHA-1 hash of
- * plaintext data, which is used to detect message modification. It is only used
- * with a Symmetrically Encrypted Integrity Protected Data packet. The
- * Modification Detection Code packet MUST be the last packet in the plaintext
- * data that is encrypted in the Symmetrically Encrypted Integrity Protected
- * Data packet, and MUST appear in no other place.
- */
-
-function openpgp_packet_modificationdetectioncode() {
-	this.tagType = 19;
-	this.hash = null;
-	/**
-	 * parsing function for a modification detection code packet (tag 19).
-	 * 
-	 * @param {String} input payload of a tag 19 packet
-	 * @param {Integer} position
-	 *            position to start reading from the input string
-	 * @param {Integer} len
-	 *            length of the packet or the remaining length of
-	 *            input at position
-	 * @return {openpgp_packet_encrypteddata} object representation
-	 */
-	function read_packet(input, position, len) {
-		this.packetLength = len;
-
-		if (len != 20) {
-			util
-					.print_error("openpgp.packet.modificationdetectioncode.js\n"
-							+ 'invalid length for a modification detection code packet!'
-							+ len);
-			return null;
-		}
-		// - A 20-octet SHA-1 hash of the preceding plaintext data of the
-		// Symmetrically Encrypted Integrity Protected Data packet,
-		// including prefix data, the tag octet, and length octet of the
-		// Modification Detection Code packet.
-		this.hash = input.substring(position, position + 20);
-		return this;
-	}
-
-	/*
-	 * this packet is created within the encryptedintegrityprotected packet
-	 * function write_packet(data) { }
-	 */
-
-	/**
-	 * generates debug output (pretty print)
-	 * 
-	 * @return {String} String which gives some information about the 
-	 * modification detection code
-	 */
-	function toString() {
-		return '5.14 Modification detection code packet\n' + '    bytes ('
-				+ this.hash.length + '): [' + util.hexstrdump(this.hash) + ']';
-	}
-	this.read_packet = read_packet;
-	this.toString = toString;
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.onepasssignature.js.html b/doc/openpgp.packet.onepasssignature.js.html deleted file mode 100644 index 6bf60d8a..00000000 --- a/doc/openpgp.packet.onepasssignature.js.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.onepasssignature.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.onepasssignature.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the One-Pass Signature Packets (Tag 4)
- * 
- * RFC4880 5.4:
- * The One-Pass Signature packet precedes the signed data and contains
- * enough information to allow the receiver to begin calculating any
- * hashes needed to verify the signature.  It allows the Signature
- * packet to be placed at the end of the message, so that the signer
- * can compute the entire signed message in one pass.
- */
-function openpgp_packet_onepasssignature() {
-	this.tagType = 4;
-	this.version = null; // A one-octet version number.  The current version is 3.
-	this.type = null; 	 // A one-octet signature type.  Signature types are described in RFC4880 Section 5.2.1.
-	this.hashAlgorithm = null; 	   // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
-	this.publicKeyAlgorithm = null;	     // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1)
-	this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key.
-	this.flags = null; 	//  A one-octet number holding a flag showing whether the signature is nested.  A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data.
-
-	/**
-	 * parsing function for a one-pass signature packet (tag 4).
-	 * @param {String} input payload of a tag 4 packet
-	 * @param {Integer} position position to start reading from the input string
-	 * @param {Integer} len length of the packet or the remaining length of input at position
-	 * @return {openpgp_packet_encrypteddata} object representation
-	 */
-	function read_packet(input, position, len) {
-		this.packetLength = len;
-		var mypos = position;
-		// A one-octet version number.  The current version is 3.
-		this.version = input.charCodeAt(mypos++);
-
-	     // A one-octet signature type.  Signature types are described in
-	     //   Section 5.2.1.
-		this.type = input.charCodeAt(mypos++);
-
-	     // A one-octet number describing the hash algorithm used.
-		this.hashAlgorithm = input.charCodeAt(mypos++);
-
-	     // A one-octet number describing the public-key algorithm used.
-		this.publicKeyAlgorithm = input.charCodeAt(mypos++);
-	     // An eight-octet number holding the Key ID of the signing key.
-		this.signingKeyId = new openpgp_type_keyid();
-		this.signingKeyId.read_packet(input,mypos);
-		mypos += 8;
-		
-	     // A one-octet number holding a flag showing whether the signature
-	     //   is nested.  A zero value indicates that the next packet is
-	     //   another One-Pass Signature packet that describes another
-	     //   signature to be applied to the same message data.
-		this.flags = input.charCodeAt(mypos++);
-		return this;
-	}
-
-	/**
-	 * creates a string representation of a one-pass signature packet
-	 * @param {Integer} type Signature types as described in RFC4880 Section 5.2.1.
-	 * @param {Integer} hashalgorithm the hash algorithm used within the signature
-	 * @param {openpgp_msg_privatekey} privatekey the private key used to generate the signature
-	 * @param {Integer} length length of data to be signed
-	 * @param {boolean} nested boolean showing whether the signature is nested. 
-	 *  "true" indicates that the next packet is another One-Pass Signature packet
-	 *   that describes another signature to be applied to the same message data. 
-	 * @return {String} a string representation of a one-pass signature packet
-	 */
-	function write_packet(type, hashalgorithm, privatekey,length, nested) {
-		var result =""; 
-		
-		result += openpgp_packet.write_packet_header(4,13);
-		result += String.fromCharCode(3);
-		result += String.fromCharCode(type);
-		result += String.fromCharCode(hashalgorithm);
-		result += String.fromCharCode(privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm);
-		result += privatekey.getKeyId();
-		if (nested)
-			result += String.fromCharCode(0);
-		else
-			result += String.fromCharCode(1);
-		
-		return result;
-	}
-	
-	/**
-	 * generates debug output (pretty print)
-	 * @return {String} String which gives some information about the one-pass signature packet
-	 */
-	function toString() {
-		return '5.4.  One-Pass Signature Packets (Tag 4)\n'+
-			   '    length: '+this.packetLength+'\n'+
-			   '    type:   '+this.type+'\n'+
-			   '    keyID:  '+this.signingKeyId.toString()+'\n'+
-			   '    hashA:  '+this.hashAlgorithm+'\n'+
-			   '    pubKeyA:'+this.publicKeyAlgorithm+'\n'+
-			   '    flags:  '+this.flags+'\n'+
-			   '    version:'+this.version+'\n';
-	}
-	
-	this.read_packet = read_packet;
-	this.toString = toString;
-	this.write_packet = write_packet;
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.signature.js.html b/doc/openpgp.packet.signature.js.html deleted file mode 100644 index 4f739881..00000000 --- a/doc/openpgp.packet.signature.js.html +++ /dev/null @@ -1,778 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.signature.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.signature.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the Signature Packet (Tag 2)
- * 
- * RFC4480 5.2:
- * A Signature packet describes a binding between some public key and
- * some data.  The most common signatures are a signature of a file or a
- * block of text, and a signature that is a certification of a User ID.
- */
-function openpgp_packet_signature() {
-	this.tagType = 2;
-	this.signatureType = null;
-	this.creationTime = null;
-	this.keyId = null;
-	this.signatureData = null;
-	this.signatureExpirationTime = null;
-	this.signatureNeverExpires = null;
-	this.signedHashValue = null;
-	this.MPIs = null;
-	this.publicKeyAlgorithm = null; 
-	this.hashAlgorithm = null;
-	this.exportable = null;
-	this.trustLevel = null;
-	this.trustAmount = null;
-	this.regular_expression = null;
-	this.revocable = null;
-	this.keyExpirationTime = null;
-	this.keyNeverExpires = null;
-	this.preferredSymmetricAlgorithms = null;
-	this.revocationKeyClass = null;
-	this.revocationKeyAlgorithm = null;
-	this.revocationKeyFingerprint = null;
-	this.issuerKeyId = null;
-	this.notationFlags = null; 
-	this.notationName = null;
-	this.notationValue = null;
-	this.preferredHashAlgorithms = null;
-	this.preferredCompressionAlgorithms = null;
-	this.keyServerPreferences = null;
-	this.preferredKeyServer = null;
-	this.isPrimaryUserID = null;
-	this.policyURI = null;
-	this.keyFlags = null;
-	this.signersUserId = null;
-	this.reasonForRevocationFlag = null;
-	this.reasonForRevocationString = null;
-	this.signatureTargetPublicKeyAlgorithm = null;
-	this.signatureTargetHashAlgorithm = null;
-	this.signatureTargetHash = null;
-	this.embeddedSignature = null;
-	this.verified = false;
-	
-
-	/**
-	 * parsing function for a signature packet (tag 2).
-	 * @param {String} input payload of a tag 2 packet
-	 * @param {Integer} position position to start reading from the input string
-	 * @param {Integer} len length of the packet or the remaining length of input at position
-	 * @return {openpgp_packet_encrypteddata} object representation
-	 */
-	function read_packet(input, position, len) {
-		this.data = input.substring	(position, position+len);
-		if (len < 0) {
-			util.print_debug("openpgp.packet.signature.js\n"+"openpgp_packet_signature read_packet length < 0 @:"+position);
-			return null;
-		}
-		var mypos = position;
-		this.packetLength = len;
-		// alert('starting parsing signature: '+position+' '+this.packetLength);
-		this.version = input[mypos++].charCodeAt();
-		// switch on version (3 and 4)
-		switch (this.version) {
-		case 3:
-			// One-octet length of following hashed material. MUST be 5.
-			if (input[mypos++].charCodeAt() != 5)
-				util.print_debug("openpgp.packet.signature.js\n"+'invalid One-octet length of following hashed material.  MUST be 5. @:'+(mypos-1));
-			var sigpos = mypos;
-			// One-octet signature type.
-			this.signatureType = input[mypos++].charCodeAt();
-
-			// Four-octet creation time.
-			this.creationTime = new Date(((input[mypos++].charCodeAt()) << 24 |
-					(input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8) |
-					input[mypos++].charCodeAt())* 1000);
-			
-			// storing data appended to data which gets verified
-			this.signatureData = input.substring(position, mypos);
-			
-			// Eight-octet Key ID of signer.
-			this.keyId = input.substring(mypos, mypos +8);
-			mypos += 8;
-
-			// One-octet public-key algorithm.
-			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
-
-			// One-octet hash algorithm.
-			this.hashAlgorithm = input[mypos++].charCodeAt();
-
-			// Two-octet field holding left 16 bits of signed hash value.
-			this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
-			var mpicount = 0;
-			// Algorithm-Specific Fields for RSA signatures:
-			// 	    - multiprecision integer (MPI) of RSA signature value m**d mod n.
-			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
-				mpicount = 1;
-			//    Algorithm-Specific Fields for DSA signatures:
-			//      - MPI of DSA value r.
-			//      - MPI of DSA value s.
-			else if (this.publicKeyAlgorithm == 17)
-				mpicount = 2;
-			
-			this.MPIs = new Array();
-			for (var i = 0; i < mpicount; i++) {
-				this.MPIs[i] = new openpgp_type_mpi();
-				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && 
-						!this.packetLength < (mypos-position)) {
-					mypos += this.MPIs[i].packetLength;
-				} else {
-			 		util.print_error('signature contains invalid MPI @:'+mypos);
-				}
-			}
-		break;
-		case 4:
-			this.signatureType = input[mypos++].charCodeAt();
-			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
-			this.hashAlgorithm = input[mypos++].charCodeAt();
-
-			// Two-octet scalar octet count for following hashed subpacket
-			// data.
-			var hashed_subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
-
-			// Hashed subpacket data set (zero or more subpackets)
-			var subpacket_length = 0;
-			while (hashed_subpacket_count != subpacket_length) {
-				if (hashed_subpacket_count < subpacket_length) {
-					util.print_debug("openpgp.packet.signature.js\n"+"hashed missed something: "+mypos+" c:"+hashed_subpacket_count+" l:"+subpacket_length);
-				}
-
-				subpacket_length += this._raw_read_signature_sub_packet(input,
-						mypos + subpacket_length, hashed_subpacket_count
-								- subpacket_length);
-			}
-			
-			mypos += hashed_subpacket_count;
-			this.signatureData = input.substring(position, mypos);
-
-			// alert("signatureData: "+util.hexstrdump(this.signatureData));
-			
-			// Two-octet scalar octet count for the following unhashed subpacket
-			var subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
-				
-			// Unhashed subpacket data set (zero or more subpackets).
-			subpacket_length = 0;
-			while (subpacket_count != subpacket_length) {
-				if (subpacket_count < subpacket_length) {
-					util.print_debug("openpgp.packet.signature.js\n"+"missed something: "+subpacket_length+" c:"+subpacket_count+" "+" l:"+subpacket_length);
-				}
-				subpacket_length += this._raw_read_signature_sub_packet(input,
-						mypos + subpacket_length, subpacket_count
-								- subpacket_length);
-
-			}
-			mypos += subpacket_count;
-			// Two-octet field holding the left 16 bits of the signed hash
-			// value.
-			this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
-			// One or more multiprecision integers comprising the signature.
-			// This portion is algorithm specific, as described above.
-			var mpicount = 0;
-			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
-				mpicount = 1;
-			else if (this.publicKeyAlgorithm == 17)
-				mpicount = 2;
-			
-			this.MPIs = new Array();
-			for (var i = 0; i < mpicount; i++) {
-				this.MPIs[i] = new openpgp_type_mpi();
-				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && 
-						!this.packetLength < (mypos-position)) {
-					mypos += this.MPIs[i].packetLength;
-				} else {
-			 		util.print_error('signature contains invalid MPI @:'+mypos);
-				}
-			}
-			break;
-		default:
-			util.print_error("openpgp.packet.signature.js\n"+'unknown signature packet version'+this.version);
-			break;
-		}
-		// util.print_message("openpgp.packet.signature.js\n"+"end signature: l: "+this.packetLength+"m: "+mypos+" m-p: "+(mypos-position));
-		return this;
-	}
-	/**
-	 * creates a string representation of a message signature packet (tag 2).
-	 * This can be only used on text data
-	 * @param {Integer} signature_type should be 1 (one) 
-	 * @param {String} data data to be signed
-	 * @param {openpgp_msg_privatekey} privatekey private key used to sign the message. (secMPIs MUST be unlocked)
-	 * @return {String} string representation of a signature packet
-	 */
-	function write_message_signature(signature_type, data, privatekey) {
-		var publickey = privatekey.privateKeyPacket.publicKey;
-		var hash_algo = privatekey.getPreferredSignatureHashAlgorithm();
-		var result = String.fromCharCode(4); 
-		result += String.fromCharCode(signature_type);
-		result += String.fromCharCode(publickey.publicKeyAlgorithm);
-		result += String.fromCharCode(hash_algo);
-		var d = Math.round(new Date().getTime() / 1000);
-		var datesubpacket = write_sub_signature_packet(2,""+
-				String.fromCharCode((d >> 24) & 0xFF) + 
-				String.fromCharCode((d >> 16) & 0xFF) +
-				String.fromCharCode((d >> 8) & 0xFF) + 
-				String.fromCharCode(d & 0xFF));
-		var issuersubpacket = write_sub_signature_packet(16, privatekey.getKeyId());
-		result += String.fromCharCode(((datesubpacket.length + issuersubpacket.length) >> 8) & 0xFF);
-		result += String.fromCharCode ((datesubpacket.length + issuersubpacket.length) & 0xFF);
-		result += datesubpacket;
-		result += issuersubpacket;
-		var trailer = '';
-		
-		trailer += String.fromCharCode(4);
-		trailer += String.fromCharCode(0xFF);
-		trailer += String.fromCharCode((result.length) >> 24);
-		trailer += String.fromCharCode(((result.length) >> 16) & 0xFF);
-		trailer += String.fromCharCode(((result.length) >> 8) & 0xFF);
-		trailer += String.fromCharCode((result.length) & 0xFF);
-		var result2 = String.fromCharCode(0);
-		result2 += String.fromCharCode(0);
-		var hash = openpgp_crypto_hashData(hash_algo, data+result+trailer);
-		util.print_debug("DSA Signature is calculated with:|"+data+result+trailer+"|\n"+util.hexstrdump(data+result+trailer)+"\n hash:"+util.hexstrdump(hash));
-		result2 += hash.charAt(0);
-		result2 += hash.charAt(1);
-		result2 += openpgp_crypto_signData(hash_algo,privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm,
-				publickey.MPIs,
-				privatekey.privateKeyPacket.secMPIs,
-				data+result+trailer);
-		return {openpgp: (openpgp_packet.write_packet_header(2, (result+result2).length)+result + result2), 
-				hash: util.get_hashAlgorithmString(hash_algo)};
-	}
-	/**
-	 * creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
-	 * @param {Integer} type subpacket signature type. Signature types as described in RFC4880 Section 5.2.3.2
-	 * @param {String} data data to be included
-	 * @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1)
-	 */
-	function write_sub_signature_packet(type, data) {
-		var result = "";
-		result += openpgp_packet.encode_length(data.length+1);
-		result += String.fromCharCode(type);
-		result += data;
-		return result;
-	}
-	
-	// V4 signature sub packets
-	
-	this._raw_read_signature_sub_packet = function(input, position, len) {
-		if (len < 0)
-			util.print_debug("openpgp.packet.signature.js\n"+"_raw_read_signature_sub_packet length < 0 @:"+position);
-		var mypos = position;
-		var subplen = 0;
-		// alert('starting signature subpackage read at position:'+position+' length:'+len);
-		if (input[mypos].charCodeAt() < 192) {
-			subplen = input[mypos++].charCodeAt();
-		} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
-			subplen = ((input[mypos++].charCodeAt() - 192) << 8) + (input[mypos++].charCodeAt()) + 192;
-		} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
-			subplen = 1 << (input[mypos++].charCodeAt() & 0x1F);
-		} else if (input[mypos].charCodeAt() < 255) {
-			mypos++;
-			subplen = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
-					|  (input[mypos++].charCodeAt() << 8) |  input[mypos++].charCodeAt();
-		}
-		
-		var type = input[mypos++].charCodeAt() & 0x7F;
-		// alert('signature subpacket type '+type+" with length: "+subplen);
-		// subpacket type
-		switch (type) {
-		case 2: // Signature Creation Time
-			this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
-					| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt())*1000);
-			break;
-		case 3: // Signature Expiration Time
-			this.signatureExpirationTime =  (input[mypos++].charCodeAt() << 24)
-					| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
-					| input[mypos++].charCodeAt();
-			this.signatureNeverExpires = (this.signature_expiration_time == 0);
-			
-			break;
-		case 4: // Exportable Certification
-			this.exportable = input[mypos++].charCodeAt() == 1;
-			break;
-		case 5: // Trust Signature
-			this.trustLevel = input[mypos++].charCodeAt();
-			this.trustAmount = input[mypos++].charCodeAt();
-			break;
-		case 6: // Regular Expression
-			this.regular_expression = new String();
-			for (var i = 0; i < subplen - 1; i++)
-				this.regular_expression += (input[mypos++]);
-			break;
-		case 7: // Revocable
-			this.revocable = input[mypos++].charCodeAt() == 1;
-			break;
-		case 9: // Key Expiration Time
-			this.keyExpirationTime = (input[mypos++].charCodeAt() << 24)
-					| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
-					| input[mypos++].charCodeAt();
-			this.keyNeverExpires = (this.keyExpirationTime == 0);
-			break;
-		case 11: // Preferred Symmetric Algorithms
-			this.preferredSymmetricAlgorithms = new Array();
-			for (var i = 0; i < subplen-1; i++) {
-				this.preferredSymmetricAlgorithms = input[mypos++].charCodeAt();
-			}
-			break;
-		case 12: // Revocation Key
-			// (1 octet of class, 1 octet of public-key algorithm ID, 20
-			// octets of
-			// fingerprint)
-			this.revocationKeyClass = input[mypos++].charCodeAt();
-			this.revocationKeyAlgorithm = input[mypos++].charCodeAt();
-			this.revocationKeyFingerprint = new Array();
-			for ( var i = 0; i < 20; i++) {
-				this.revocationKeyFingerprint = input[mypos++].charCodeAt();
-			}
-			break;
-		case 16: // Issuer
-			this.issuerKeyId = input.substring(mypos,mypos+8);
-			mypos += 8;
-			break;
-		case 20: // Notation Data
-			this.notationFlags = (input[mypos++].charCodeAt() << 24) | 
-								 (input[mypos++].charCodeAt() << 16) |
-								 (input[mypos++].charCodeAt() <<  8) | 
-								 (input[mypos++].charCodeAt());
-			var nameLength = (input[mypos++].charCodeAt() <<  8) | (input[mypos++].charCodeAt());
-			var valueLength = (input[mypos++].charCodeAt() <<  8) | (input[mypos++].charCodeAt());
-			this.notationName = "";
-			for (var i = 0; i < nameLength; i++) {
-				this.notationName += input[mypos++];
-			}
-			this.notationValue = "";
-			for (var i = 0; i < valueLength; i++) {
-				this.notationValue += input[mypos++];
-			}
-			break;
-		case 21: // Preferred Hash Algorithms
-			this.preferredHashAlgorithms = new Array();
-			for (var i = 0; i < subplen-1; i++) {
-				this.preferredHashAlgorithms = input[mypos++].charCodeAt();
-			}
-			break;
-		case 22: // Preferred Compression Algorithms
-			this.preferredCompressionAlgorithms = new Array();
-			for ( var i = 0; i < subplen-1; i++) {
-				this.preferredCompressionAlgorithms = input[mypos++].charCodeAt();
-			}
-			break;
-		case 23: // Key Server Preferences
-			this.keyServerPreferences = new Array();
-			for ( var i = 0; i < subplen-1; i++) {
-				this.keyServerPreferences = input[mypos++].charCodeAt();
-			}
-			break;
-		case 24: // Preferred Key Server
-			this.preferredKeyServer = new String();
-			for ( var i = 0; i < subplen-1; i++) {
-				this.preferredKeyServer += input[mypos++];
-			}
-			break;
-		case 25: // Primary User ID
-			this.isPrimaryUserID = input[mypos++] != 0;
-			break;
-		case 26: // Policy URI
-			this.policyURI = new String();
-			for ( var i = 0; i < subplen-1; i++) {
-				this.policyURI += input[mypos++];
-			}
-			break;
-		case 27: // Key Flags
-			this.keyFlags = new Array();
-			for ( var i = 0; i < subplen-1; i++) {
-				this.keyFlags = input[mypos++].charCodeAt();
-			}
-			break;
-		case 28: // Signer's User ID
-			this.signersUserId = new String();
-			for ( var i = 0; i < subplen-1; i++) {
-				this.signersUserId += input[mypos++];
-			}
-			break;
-		case 29: // Reason for Revocation
-			this.reasonForRevocationFlag = input[mypos++].charCodeAt();
-			this.reasonForRevocationString = new String();
-			for ( var i = 0; i < subplen -2; i++) {
-				this.reasonForRevocationString += input[mypos++];
-			}
-			break;
-		case 30: // Features
-			// TODO: to be implemented
-			return subplen+1;
-		case 31: // Signature Target
-			// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
-			this.signatureTargetPublicKeyAlgorithm = input[mypos++].charCodeAt();
-			this.signatureTargetHashAlgorithm = input[mypos++].charCodeAt();
-			var signatureTargetHashAlgorithmLength = 0;
-			switch(this.signatureTargetHashAlgorithm) {
-			case  1: // - MD5 [HAC]                             "MD5"
-			case  2: // - SHA-1 [FIPS180]                       "SHA1"
-				signatureTargetHashAlgorithmLength = 20;
-				break;
-			case  3: // - RIPE-MD/160 [HAC]                     "RIPEMD160"
-			case  8: // - SHA256 [FIPS180]                      "SHA256"
-			case  9: // - SHA384 [FIPS180]                      "SHA384"
-			case 10: // - SHA512 [FIPS180]                      "SHA512"
-			case 11: // - SHA224 [FIPS180]                      "SHA224"
-				break;
-			// 100 to 110 - Private/Experimental algorithm
-	    	default:
-	    		util.print_error("openpgp.packet.signature.js\n"+"unknown signature target hash algorithm:"+this.signatureTargetHashAlgorithm);
-	    		return null;
-			}
-			this.signatureTargetHash = new Array();
-			for (var i = 0; i < signatureTargetHashAlgorithmLength; i++) {
-				this.signatureTargetHash[i] = input[mypos++]; 
-			}
-		case 32: // Embedded Signature
-			this.embeddedSignature = new openpgp_packet_signature();
-			this.embeddedSignature.read_packet(input, mypos, len -(mypos-position));
-			return ((mypos+ this.embeddedSignature.packetLength) - position);
-			break;
-		case 100: // Private or experimental
-		case 101: // Private or experimental
-		case 102: // Private or experimental
-		case 103: // Private or experimental
-		case 104: // Private or experimental
-		case 105: // Private or experimental
-		case 106: // Private or experimental
-		case 107: // Private or experimental
-		case 108: // Private or experimental
-		case 109: // Private or experimental
-		case 110: // Private or experimental
-			util.print_error("openpgp.packet.signature.js\n"+'private or experimental signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
-			return subplen+1;
-			break;	
-		case 0: // Reserved
-		case 1: // Reserved
-		case 8: // Reserved
-		case 10: // Placeholder for backward compatibility
-		case 13: // Reserved
-		case 14: // Reserved
-		case 15: // Reserved
-		case 17: // Reserved
-		case 18: // Reserved
-		case 19: // Reserved
-		default:
-			util.print_error("openpgp.packet.signature.js\n"+'unknown signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
-			return subplen+1;
-			break;
-		}
-		return mypos -position;
-	};
-	/**
-	 * verifys the signature packet. Note: not signature types are implemented
-	 * @param {String} data data which on the signature applies
-	 * @param {openpgp_msg_privatekey} key the public key to verify the signature
-	 * @return {boolean} True if message is verified, else false.
-	 */
-	function verify(data, key) {
-		// calculating the trailer
-		var trailer = '';
-		trailer += String.fromCharCode(this.version);
-		trailer += String.fromCharCode(0xFF);
-		trailer += String.fromCharCode(this.signatureData.length >> 24);
-		trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
-		trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
-		trailer += String.fromCharCode(this.signatureData.length & 0xFF);
-		switch(this.signatureType) {
-		case 0: // 0x00: Signature of a binary document.
-			if (this.version == 4) {
-				this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
-					this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
-			}
-			break;
-
-		case 1: // 0x01: Signature of a canonical text document.
-			if (this.version == 4) {
-				this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
-					this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
-				return this.verified;
-			}
-			break;
-				
-		case 2: // 0x02: Standalone signature.
-			// This signature is a signature of only its own subpacket contents.
-			// It is calculated identically to a signature over a zero-length
-			// binary document.  Note that it doesn't make sense to have a V3
-			// standalone signature.
-			if (this.version == 3) {
-				this.verified = false;
-				break;
-				}
-			
-			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
-					this.MPIs, key.obj.publicKeyPacket.MPIs, this.signatureData+trailer);
-			break;
-		case 16:			
-			// 0x10: Generic certification of a User ID and Public-Key packet.
-			// The issuer of this certification does not make any particular
-			// assertion as to how well the certifier has checked that the owner
-			// of the key is in fact the person described by the User ID.
-		case 17:
-			// 0x11: Persona certification of a User ID and Public-Key packet.
-			// The issuer of this certification has not done any verification of
-			// the claim that the owner of this key is the User ID specified.
-		case 18:
-			// 0x12: Casual certification of a User ID and Public-Key packet.
-			// The issuer of this certification has done some casual
-			// verification of the claim of identity.
-		case 19:
-			// 0x13: Positive certification of a User ID and Public-Key packet.
-			// The issuer of this certification has done substantial
-			// verification of the claim of identity.
-			// 
-			// Most OpenPGP implementations make their "key signatures" as 0x10
-			// certifications.  Some implementations can issue 0x11-0x13
-			// certifications, but few differentiate between the types.
-		case 48:
-			// 0x30: Certification revocation signature
-			// This signature revokes an earlier User ID certification signature
-			// (signature class 0x10 through 0x13) or direct-key signature
-			// (0x1F).  It should be issued by the same key that issued the
-			// revoked signature or an authorized revocation key.  The signature
-			// is computed over the same data as the certificate that it
-			// revokes, and should have a later creation date than that
-			// certificate.
-
-			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
-					this.MPIs, key.MPIs, data+this.signatureData+trailer);
-			break;
-						
-		case 24:
-			// 0x18: Subkey Binding Signature
-			// This signature is a statement by the top-level signing key that
-			// indicates that it owns the subkey.  This signature is calculated
-			// directly on the primary key and subkey, and not on any User ID or
-			// other packets.  A signature that binds a signing subkey MUST have
-			// an Embedded Signature subpacket in this binding signature that
-			// contains a 0x19 signature made by the signing subkey on the
-			// primary key and subkey.
-			if (this.version == 3) {
-				this.verified = false;
-				break;
-			}
-			
-			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
-					this.MPIs, key.MPIs, data+this.signatureData+trailer);
-			break;
-		case 25:
-			// 0x19: Primary Key Binding Signature
-			// This signature is a statement by a signing subkey, indicating
-			// that it is owned by the primary key and subkey.  This signature
-			// is calculated the same way as a 0x18 signature: directly on the
-			// primary key and subkey, and not on any User ID or other packets.
-			
-			// When a signature is made over a key, the hash data starts with the
-			// octet 0x99, followed by a two-octet length of the key, and then body
-			// of the key packet.  (Note that this is an old-style packet header for
-			// a key packet with two-octet length.)  A subkey binding signature
-			// (type 0x18) or primary key binding signature (type 0x19) then hashes
-			// the subkey using the same format as the main key (also using 0x99 as
-			// the first octet).
-		case 31:
-			// 0x1F: Signature directly on a key
-			// This signature is calculated directly on a key.  It binds the
-			// information in the Signature subpackets to the key, and is
-			// appropriate to be used for subpackets that provide information
-			// about the key, such as the Revocation Key subpacket.  It is also
-			// appropriate for statements that non-self certifiers want to make
-			// about the key itself, rather than the binding between a key and a
-			// name.
-		case 32:
-			// 0x20: Key revocation signature
-			// The signature is calculated directly on the key being revoked.  A
-			// revoked key is not to be used.  Only revocation signatures by the
-			// key being revoked, or by an authorized revocation key, should be
-			// considered valid revocation signatures.
-		case 40:
-			// 0x28: Subkey revocation signature
-			// The signature is calculated directly on the subkey being revoked.
-			// A revoked subkey is not to be used.  Only revocation signatures
-			// by the top-level signature key that is bound to this subkey, or
-			// by an authorized revocation key, should be considered valid
-			// revocation signatures.
-			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
-					this.MPIs, key.MPIs, data+this.signatureData+trailer);
-			break;
-			
-			// Key revocation signatures (types 0x20 and 0x28)
-			// hash only the key being revoked.
-		case 64:
-			// 0x40: Timestamp signature.
-			// This signature is only meaningful for the timestamp contained in
-			// it.
-		case 80:
-			//    0x50: Third-Party Confirmation signature.
-			// This signature is a signature over some other OpenPGP Signature
-			// packet(s).  It is analogous to a notary seal on the signed data.
-			// A third-party signature SHOULD include Signature Target
-			// subpacket(s) to give easy identification.  Note that we really do
-			// mean SHOULD.  There are plausible uses for this (such as a blind
-			// party that only sees the signature, not the key or source
-			// document) that cannot include a target subpacket.
-		default:
-			util.print_error("openpgp.packet.signature.js\n"+"signature verification for type"+ this.signatureType+" not implemented");
-			break;
-		}
-		return this.verified;
-	}
-	/**
-	 * generates debug output (pretty print)
-	 * @return {String} String which gives some information about the signature packet
-	 */
-
-	function toString () {
-		if (this.version == 3) {
-			var result = '5.2. Signature Packet (Tag 2)\n'+
-	          "Packet Length:                     :"+this.packetLength+'\n'+
-	          "Packet version:                    :"+this.version+'\n'+
-	          "One-octet signature type           :"+this.signatureType+'\n'+
-	          "Four-octet creation time.          :"+this.creationTime+'\n'+
-	         "Eight-octet Key ID of signer.       :"+util.hexidump(this.keyId)+'\n'+
-	          "One-octet public-key algorithm.    :"+this.publicKeyAlgorithm+'\n'+
-	          "One-octet hash algorithm.          :"+this.hashAlgorithm+'\n'+
-	          "Two-octet field holding left\n" +
-	          " 16 bits of signed hash value.     :"+this.signedHashValue+'\n';
-		} else {
-          var result = '5.2. Signature Packet (Tag 2)\n'+
-          "Packet Length:                     :"+this.packetLength+'\n'+
-          "Packet version:                    :"+this.version+'\n'+
-          "One-octet signature type           :"+this.signatureType+'\n'+
-          "One-octet public-key algorithm.    :"+this.publicKeyAlgorithm+'\n'+
-          "One-octet hash algorithm.          :"+this.hashAlgorithm+'\n'+
-          "Two-octet field holding left\n" +
-          " 16 bits of signed hash value.     :"+this.signedHashValue+'\n'+
-          "Signature Creation Time            :"+this.creationTime+'\n'+
-          "Signature Expiration Time          :"+this.signatureExpirationTime+'\n'+
-          "Signature Never Expires            :"+this.signatureNeverExpires+'\n'+
-          "Exportable Certification           :"+this.exportable+'\n'+
-          "Trust Signature level:             :"+this.trustLevel+' amount'+this.trustAmount+'\n'+
-          "Regular Expression                 :"+this.regular_expression+'\n'+
-          "Revocable                          :"+this.revocable+'\n'+
-          "Key Expiration Time                :"+this.keyExpirationTime+" "+this.keyNeverExpires+'\n'+
-          "Preferred Symmetric Algorithms     :"+this.preferredSymmetricAlgorithms+'\n'+
-          "Revocation Key"+'\n'+
-          "   ( 1 octet of class,             :"+this.revocationKeyClass +'\n'+
-          "     1 octet of public-key ID,     :" +this.revocationKeyAlgorithm+'\n'+
-          "    20 octets of fingerprint)      :"+this.revocationKeyFingerprint+'\n'+
-          "Issuer                             :"+util.hexstrdump(this.issuerKeyId)+'\n'+
-          "Preferred Hash Algorithms          :"+this.preferredHashAlgorithms+'\n'+
-          "Preferred Compression Alg.         :"+this.preferredCompressionAlgorithms+'\n'+
-          "Key Server Preferences             :"+this.keyServerPreferences+'\n'+
-          "Preferred Key Server               :"+this.preferredKeyServer+'\n'+
-          "Primary User ID                    :"+this.isPrimaryUserID+'\n'+
-          "Policy URI                         :"+this.policyURI+'\n'+
-          "Key Flags                          :"+this.keyFlags+'\n'+
-          "Signer's User ID                   :"+this.signersUserId+'\n'+
-          "Notation                           :"+this.notationName+" = "+this.notationValue+"\n"+
-          "Reason for Revocation\n"+
-          "      Flag                         :"+this.reasonForRevocationFlag+'\n'+
-          "      Reason                       :"+this.reasonForRevocationString+'\nMPI:\n';
-		}
-          for (var i = 0; i < this.MPIs.length; i++) {
-        	  result += this.MPIs[i].toString();
-          }
-          return result;
-     }
-
-	/**
-	 * gets the issuer key id of this signature
-	 * @return {String} issuer key id as string (8bytes)
-	 */
-	function getIssuer() {
-		 if (this.version == 4)
-			 return this.issuerKeyId;
-		 if (this.verions == 4)
-			 return this.keyId;
-		 return null;
-	}
-
-	/**
-	 * Tries to get the corresponding public key out of the public keyring for the issuer created this signature
-	 * @return {Object} {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise
-	 */
-	function getIssuerKey() {
-		 var result = null;
-		 if (this.version == 4) {
-			 result = openpgp.keyring.getPublicKeysForKeyId(this.issuerKeyId);
-		 } else if (this.version == 3) {
-			 result = openpgp.keyring.getPublicKeysForKeyId(this.keyId);
-		 } else return null;
-		 if (result.length == 0)
-			 return null;
-		 return result[0];
-	}
-	this.getIssuerKey = getIssuerKey;
-	this.getIssuer = getIssuer;	 
-	this.write_message_signature = write_message_signature;
-	this.verify = verify;
-    this.read_packet = read_packet;
-    this.toString = toString;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.userattribute.js.html b/doc/openpgp.packet.userattribute.js.html deleted file mode 100644 index b89c712c..00000000 --- a/doc/openpgp.packet.userattribute.js.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.userattribute.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.userattribute.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/** 
- * @class
- * @classdesc Implementation of the User Attribute Packet (Tag 17)
- *  The User Attribute packet is a variation of the User ID packet.  It
- *  is capable of storing more types of data than the User ID packet,
- *  which is limited to text.  Like the User ID packet, a User Attribute
- *  packet may be certified by the key owner ("self-signed") or any other
- *  key owner who cares to certify it.  Except as noted, a User Attribute
- *  packet may be used anywhere that a User ID packet may be used.
- *
- *  While User Attribute packets are not a required part of the OpenPGP
- *  standard, implementations SHOULD provide at least enough
- *  compatibility to properly handle a certification signature on the
- *  User Attribute packet.  A simple way to do this is by treating the
- *  User Attribute packet as a User ID packet with opaque contents, but
- *  an implementation may use any method desired.
- */
-function openpgp_packet_userattribute() {
-	this.tagType = 17;
-	this.certificationSignatures = new Array();
-	this.certificationRevocationSignatures = new Array();
-	this.revocationSignatures = new Array();
-	this.parentNode = null;
-
-	/**
-	 * parsing function for a user attribute packet (tag 17).
-	 * @param {String} input payload of a tag 17 packet
-	 * @param {Integer} position position to start reading from the input string
-	 * @param {Integer} len length of the packet or the remaining length of input at position
-	 * @return {openpgp_packet_encrypteddata} object representation
-	 */
-	function read_packet (input, position, len) {
-		var total_len = 0;
-		this.packetLength = len;
-		this.userattributes = new Array();
-		var count = 0;
-		var mypos = position;
-		while (len != total_len) {
-			var current_len = 0;
-			// 4.2.2.1. One-Octet Lengths
-			if (input[mypos].charCodeAt() < 192) {
-				packet_length = input[mypos++].charCodeAt();
-				current_len = 1;
-			// 4.2.2.2. Two-Octet Lengths
-			} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
-				packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
-					+ (input[mypos++].charCodeAt()) + 192;
-				current_len = 2;
-			// 4.2.2.4. Partial Body Lengths
-			} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
-				packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
-				current_len = 1;
-			// 4.2.2.3. Five-Octet Lengths
-			} else {
-				current_len = 5;
-				mypos++;
-				packet_length = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
-					| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
-			}
-			
-			var subpackettype = input[mypos++].charCodeAt();
-			packet_length--;
-			current_len++;
-			this.userattributes[count] = new Array();
-			this.userattributes[count] = input.substring(mypos, mypos + packet_length);
-			mypos += packet_length;
-			total_len += current_len+packet_length;
-		}
-		this.packetLength = mypos - position;
-		return this;
-	}
-	
-	/**
-	 * generates debug output (pretty print)
-	 * @return {String} String which gives some information about the user attribute packet
-	 */
-	function toString() {
-		var result = '5.12.  User Attribute Packet (Tag 17)\n'+
-		             '    AttributePackets: (count = '+this.userattributes.length+')\n';
-		for (var i = 0; i < this.userattributes.length; i++) {
-			result += '    ('+this.userattributes[i].length+') bytes: ['+util.hexidump(this.userattributes[i])+']\n'; 
-		}
-		return result;
-	}
-	
-	/**
-	 * Continue parsing packets belonging to the user attribute packet such as signatures
-	 * @param {Object} parent_node the parent object
-	 * @param {String} input input string to read the packet(s) from
-	 * @param {Integer} position start position for the parser
-	 * @param {Integer} len length of the packet(s) or remaining length of input
-	 * @return {Integer} length of nodes read
-	 */
-	function read_nodes(parent_node, input, position, len) {
-		
-		this.parentNode = parent_node;
-		var exit = false;
-		var pos = position;
-		var l = len;
-		while (input.length != pos) {
-			var result = openpgp_packet.read_packet(input, pos, l);
-			if (result == null) {
-				util.print_error("openpgp.packet.userattribute.js\n"+'[user_attr] parsing ends here @:' + pos + " l:" + l);
-				break;
-			} else {
-				switch (result.tagType) {
-				case 2: // Signature Packet
-					if (result.signatureType > 15
-							&& result.signatureType < 20) // certification
-						// //
-						// signature
-						this.certificationSignatures[this.certificationSignatures.length] = result;
-					else if (result.signatureType == 32) // certification revocation signature
-						this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
-					pos += result.packetLength + result.headerLength;
-					l = len - (pos - position);
-					break;
-				default:
-					this.data = input;
-					this.position = position - parent_node.packetLength;
-					this.len = pos - position;
-					return this.len;
-					break;
-				}
-			}
-		}
-		this.data = input;
-		this.position = position - parent_node.packetLength;
-		this.len = pos - position;
-		return this.len;
-
-	}
-	
-	this.read_packet = read_packet;
-	this.read_nodes = read_nodes;
-	this.toString = toString;
-	
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.packet.userid.js.html b/doc/openpgp.packet.userid.js.html deleted file mode 100644 index 79d56e55..00000000 --- a/doc/openpgp.packet.userid.js.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - JSDoc: Source: packet/openpgp.packet.userid.js - - - - - - - - - - -
- -

Source: packet/openpgp.packet.userid.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the User ID Packet (Tag 13)
- * A User ID packet consists of UTF-8 text that is intended to represent
- * the name and email address of the key holder.  By convention, it
- * includes an RFC 2822 [RFC2822] mail name-addr, but there are no
- * restrictions on its content.  The packet length in the header
- * specifies the length of the User ID. 
- */
-
-function openpgp_packet_userid() {
-	this.text = ''
-	this.tagType = 13;
-	this.certificationSignatures = new Array();
-	this.certificationRevocationSignatures = new Array();
-	this.revocationSignatures = new Array();
-	this.parentNode = null;
-	
-	/**
-	 * Set the packet text field to a native javascript string
-	 * Conversion to a proper utf8 encoding takes place when the 
-	 * packet is written.
-	 * @param {String} str Any native javascript string
-	 */
-	this.set_text = function(str) {
-		this.text = str;
-	}
-
-	/**
-	 * Set the packet text to value represented by the provided string
-	 * of bytes.
-	 * @param {String} bytes A string of bytes
-	 */
-	this.set_text_bytes = function(bytes) {
-		this.text = util.decode_utf8(bytes);
-	}
-
-	/**
-	 * Get the byte sequence representing the text of this packet.
-	 * @returns {String} A sequence of bytes
-	 */
-	this.get_text_bytes = function() {
-		return util.encode_utf8(this.text);
-	}
-	
-
-	/**
-	 * Parsing function for a user id packet (tag 13).
-	 * @param {String} input payload of a tag 13 packet
-	 * @param {Integer} position position to start reading from the input string
-	 * @param {Integer} len length of the packet or the remaining length of input at position
-	 * @return {openpgp_packet_encrypteddata} object representation
-	 */
-	this.read_packet = function(input, position, len) {
-		this.packetLength = len;
-
-		var bytes = '';
-		for ( var i = 0; i < len; i++) {
-			bytes += input[position + i];
-		}
-
-		this.set_text_bytes(bytes);
-		return this;
-	}
-
-	/**
-	 * Creates a string representation of the user id packet
-	 * @param {String} user_id the user id as string ("John Doe <john.doe@mail.us")
-	 * @return {String} string representation
-	 */
-	this.write_packet = function(user_id) {
-		this.set_text(user_id);
-		var bytes = this.get_text_bytes();
-
-		var result = openpgp_packet.write_packet_header(13, bytes.length);
-		result += bytes;
-		return result;
-	}
-
-	/**
-	 * Continue parsing packets belonging to the userid packet such as signatures
-	 * @param {Object} parent_node the parent object
-	 * @param {String} input input string to read the packet(s) from
-	 * @param {Integer} position start position for the parser
-	 * @param {Integer} len length of the packet(s) or remaining length of input
-	 * @return {Integer} length of nodes read
-	 */
-	this.read_nodes = function(parent_node, input, position, len) {
-		if (parent_node.tagType == 6) { // public key
-			this.parentNode = parent_node;
-			var pos = position;
-			var l = len;
-			while (input.length != pos) {
-				var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
-				if (result == null) {
-					util.print_error('[user_id] parsing ends here @:' + pos + " l:" + l);
-					break;
-				} else {
-					
-					pos += result.packetLength + result.headerLength;
-					l = input.length - pos;
-					switch (result.tagType) {
-					case 2: // Signature Packet
-						if (result.signatureType > 15
-								&& result.signatureType < 20) { // certification
-							// //
-							// signature
-							this.certificationSignatures[this.certificationSignatures.length] = result;
-							break;
-						} else if (result.signatureType == 48) {// certification revocation signature
-							this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
-							break;
-						} else if (result.signatureType == 24) { // omg. standalone signature 
-							this.certificationSignatures[this.certificationSignatures.length] = result;
-							break;
-						} else {
-							util.print_debug("unknown sig t: "+result.signatureType+"@"+(pos - (result.packetLength + result.headerLength)));
-						}
-					default:
-						this.data = input;
-						this.position = position - parent_node.packetLength;
-						this.len = pos - position -(result.headerLength + result.packetLength);
-						return this.len;
-					}
-				}
-			}
-			this.data = input;
-			this.position = position - parent_node.packetLength;
-			this.len = pos - position -(result.headerLength + result.packetLength);
-			return this.len;
-		} else if (parent_node.tagType == 5) { // secret Key
-			this.parentNode = parent_node;
-			var exit = false;
-			var pos = position;
-			while (input.length != pos) {
-				var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
-				if (result == null) {
-					util.print_error('parsing ends here @:' + pos + " l:" + l);
-					break;
-				} else {
-					pos += result.packetLength + result.headerLength;
-					l = input.length - pos;
-					switch (result.tagType) {
-					case 2: // Signature Packet certification signature
-						if (result.signatureType > 15
-								&& result.signatureType < 20)
-							this.certificationSignatures[this.certificationSignatures.length] = result;
-						// certification revocation signature
-						else if (result.signatureType == 48)
-							this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
-					default:
-						this.data = input;
-						this.position = position - parent_node.packetLength;
-						this.len = pos - position -(result.headerLength + result.packetLength);
-						return this.len;
-					}
-				}
-			}
-		} else {
-			util.print_error("unknown parent node for a userId packet "+parent_node.tagType);
-		}
-	}
-	
-	/**
-	 * generates debug output (pretty print)
-	 * @return {String} String which gives some information about the user id packet
-	 */
-	this.toString = function() {
-		var result = '     5.11.  User ID Packet (Tag 13)\n' + '    text ('
-				+ this.text.length + '): "' + this.text.replace("<", "<")
-				+ '"\n';
-		result +="certification signatures:\n";
-		for (var i = 0; i < this.certificationSignatures.length; i++) {
-			result += "        "+this.certificationSignatures[i].toString();
-		}
-		result +="certification revocation signatures:\n";
-		for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
-			result += "        "+this.certificationRevocationSignatures[i].toString();
-		}
-		return result;
-	}
-
-	/**
-	 * lookup function to find certification revocation signatures
-	 * @param {String} keyId string containing the key id of the issuer of this signature
-	 * @return a CertificationRevocationSignature if found; otherwise null
-	 */
-	this.hasCertificationRevocationSignature = function(keyId) {
-		for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
-			if ((this.certificationRevocationSignatures[i].version == 3 &&
-				 this.certificationRevocationSignatures[i].keyId == keyId) ||
-				(this.certificationRevocationSignatures[i].version == 4 &&
-				 this.certificationRevocationSignatures[i].issuerKeyId == keyId))
-				return this.certificationRevocationSignatures[i];
-		}
-		return null;
-	}
-
-	/**
-	 * Verifies all certification signatures. This method does not consider possible revocation signatures.
-	 * @param {Object} publicKeyPacket the top level key material
-	 * @return {Integer[]} An array of integers corresponding to the array of certification signatures. The meaning of each integer is the following:
-	 * 0 = bad signature
-	 * 1 = signature expired
-	 * 2 = issuer key not available
-	 * 3 = revoked
-	 * 4 = signature valid
-	 * 5 = signature by key owner expired
-	 * 6 = signature by key owner revoked
-	 */
-	this.verifyCertificationSignatures = function(publicKeyPacket) {
-		var bytes = this.get_text_bytes();
-		result = new Array();
-		for (var i = 0 ; i < this.certificationSignatures.length; i++) {
-			// A certification signature (type 0x10 through 0x13) hashes the User
-			// ID being bound to the key into the hash context after the above
-			// data.  A V3 certification hashes the contents of the User ID or
-			// attribute packet packet, without any header.  A V4 certification
-			// hashes the constant 0xB4 for User ID certifications or the constant
-			// 0xD1 for User Attribute certifications, followed by a four-octet
-			// number giving the length of the User ID or User Attribute data, and
-			// then the User ID or User Attribute data.
-
-			if (this.certificationSignatures[i].version == 4) {
-				if (this.certificationSignatures[i].signatureExpirationTime != null &&
-						this.certificationSignatures[i].signatureExpirationTime != null &&
-						this.certificationSignatures[i].signatureExpirationTime != 0 &&
-						!this.certificationSignatures[i].signatureNeverExpires &&
-						new Date(this.certificationSignatures[i].creationTime.getTime() +(this.certificationSignatures[i].signatureExpirationTime*1000)) < new Date()) {
-					if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
-						result[i] = 5;
-					else
-						result[i] = 1;
-					continue;
-				}
-				if (this.certificationSignatures[i].issuerKeyId == null) {
-					result[i] = 0;
-					continue;
-				}
-				var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].issuerKeyId);
-				if (issuerPublicKey == null || issuerPublicKey.length == 0) {
-					result[i] = 2;
-					continue;
-				}
-				// TODO: try to verify all returned issuer public keys (key ids are not unique!)
-				var issuerPublicKey = issuerPublicKey[0];
-				var signingKey = issuerPublicKey.obj.getSigningKey();
-				if (signingKey == null) {
-					result[i] = 0;
-					continue;
-				}
-				var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].issuerKeyId);
-				if (revocation != null && revocation.creationTime > 
-					this.certificationSignatures[i].creationTime) {
-
-					var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
-					publicKeyPacket.data+String.fromCharCode(0xB4)+
-					String.fromCharCode((bytes.length >> 24) & 0xFF)+
-					String.fromCharCode((bytes.length >> 16) & 0xFF)+
-					String.fromCharCode((bytes.length >>  8) & 0xFF)+
-					String.fromCharCode((bytes.length) & 0xFF)+
-					bytes;
-					if (revocation.verify(signaturedata, signingKey)) {
-						if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
-							result[i] = 6;
-						else
-							result[i] = 3;
-						continue;
-					}
-				}
-
-				var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
-						publicKeyPacket.data+String.fromCharCode(0xB4)+
-						String.fromCharCode((bytes.length >> 24) & 0xFF)+
-						String.fromCharCode((bytes.length >> 16) & 0xFF)+
-						String.fromCharCode((bytes.length >>  8) & 0xFF)+
-						String.fromCharCode((bytes.length) & 0xFF)+
-						bytes;
-				if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
-					result[i] = 4;
-				} else
-				result[i] = 0;
-			} else if (this.certificationSignatures[i].version == 3) {
-				if (this.certificationSignatures[i].keyId == null) {
-					result[i] = 0;
-					continue;
-				}
-				var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].keyId);
-				if (issuerPublicKey == null || issuerPublicKey.length == 0) {
-					result[i] = 2;
-					continue;
-				}
-				issuerPublicKey = issuerPublicKey[0];
-				var signingKey = publicKey.obj.getSigningKey();
-				if (signingKey == null) {
-					result[i] = 0;
-					continue;
-				}
-				var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].keyId);
-				if (revocation != null && revocation.creationTime > 
-					this.certificationSignatures[i].creationTime) {
-					var signaturedata = String.fromCharCode(0x99)+ this.publicKeyPacket.header.substring(1)+
-					this.publicKeyPacket.data+bytes;
-					if (revocation.verify(signaturedata, signingKey)) {
-						if (revocation.keyId == publicKeyPacket.getKeyId())
-							result[i] = 6;
-						else
-							result[i] = 3;
-						continue;
-					}
-				}
-				var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
-					publicKeyPacket.data + bytes;
-				if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
-					result[i] = 4;
-				} else 
-				result[i] = 0;
-			} else {
-				result[i] = 0;
-			}
-		}
-		return result;
-	}
-
-	/**
-	 * verifies the signatures of the user id
-	 * @return 0 if the userid is valid; 1 = userid expired; 2 = userid revoked
-	 */
-	this.verify = function(publicKeyPacket) {
-		var result = this.verifyCertificationSignatures(publicKeyPacket);
-		if (result.indexOf(6) != -1)
-			return 2;
-		if (result.indexOf(5) != -1)
-			return 1;
-		return 0;
-	}
-
-	// TODO: implementation missing
-	this.addCertification = function(publicKeyPacket, privateKeyPacket) {
-		
-	}
-
-	// TODO: implementation missing
-	this.revokeCertification = function(publicKeyPacket, privateKeyPacket) {
-		
-	}
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.type.keyid.js.html b/doc/openpgp.type.keyid.js.html deleted file mode 100644 index 318f9958..00000000 --- a/doc/openpgp.type.keyid.js.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - JSDoc: Source: type/openpgp.type.keyid.js - - - - - - - - - - -
- -

Source: type/openpgp.type.keyid.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of type key id (RFC4880 3.3)
- *  A Key ID is an eight-octet scalar that identifies a key.
-   Implementations SHOULD NOT assume that Key IDs are unique.  The
-   section "Enhanced Key Formats" below describes how Key IDs are
-   formed.
- */
-function openpgp_type_keyid() {
-	/**
-	 * Parsing method for a key id
-	 * @param {String} input Input to read the key id from 
-	 * @param {integer} position Position where to start reading the key 
-	 * id from input
-	 * @return {openpgp_type_keyid} This object
-	 */
-	function read_packet(input, position) {
-		this.bytes = input.substring(position, position+8);
-		return this;
-	}
-	
-	/**
-	 * Generates debug output (pretty print)
-	 * @return {String} Key Id as hexadecimal string
-	 */
-	function toString() {
-		return util.hexstrdump(this.bytes);
-	}
-	
-	this.read_packet = read_packet;
-	this.toString = toString;
-};
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.type.mpi.js.html b/doc/openpgp.type.mpi.js.html deleted file mode 100644 index 5f5a3b5e..00000000 --- a/doc/openpgp.type.mpi.js.html +++ /dev/null @@ -1,184 +0,0 @@ - - - - - JSDoc: Source: type/openpgp.type.mpi.js - - - - - - - - - - -
- -

Source: type/openpgp.type.mpi.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two
-// octet scalar: MPI: [a,b,c,d,e,f]
-// - MPI size: (a << 8) | b 
-// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
-
-/**
- * @class
- * @classdescImplementation of type MPI (RFC4880 3.2)
- * Multiprecision integers (also called MPIs) are unsigned integers used
- * to hold large integers such as the ones used in cryptographic
- * calculations.
- * An MPI consists of two pieces: a two-octet scalar that is the length
- * of the MPI in bits followed by a string of octets that contain the
- * actual integer.
- */
-function openpgp_type_mpi() {
-	this.MPI = null;
-	this.mpiBitLength = null;
-	this.mpiByteLength = null;
-	this.data = null;
-	/**
-	 * Parsing function for a mpi (RFC 4880 3.2).
-	 * @param {String} input Payload of mpi data
-	 * @param {Integer} position Position to start reading from the input 
-	 * string
-	 * @param {Integer} len Length of the packet or the remaining length of 
-	 * input at position
-	 * @return {openpgp_type_mpi} Object representation
-	 */
-	function read(input, position, len) {
-		var mypos = position;
-		
-		this.mpiBitLength = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
-		
-		// Additional rules:
-		//
-		//    The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
-		//
-		//    The length field of an MPI describes the length starting from its
-		//	  most significant non-zero bit.  Thus, the MPI [00 02 01] is not
-		//    formed correctly.  It should be [00 01 01].
-
-		// TODO: Verification of this size method! This size calculation as
-		// 		 specified above is not applicable in JavaScript
-		this.mpiByteLength = (this.mpiBitLength - (this.mpiBitLength % 8)) / 8;
-		if (this.mpiBitLength % 8 != 0)
-			this.mpiByteLength++;
-		
-		this.MPI = input.substring(mypos,mypos+this.mpiByteLength);
-		this.data = input.substring(position, position+2+this.mpiByteLength);
-		this.packetLength = this.mpiByteLength +2;
-		return this;
-	}
-	
-	/**
-	 * Generates debug output (pretty print)
-	 * @return {String} String which gives some information about the mpi
-	 */
-	function toString() {
-		var r = "    MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x";
-		r+=util.hexstrdump(this.MPI);
-		return r+'\n';
-	}
-	
-	/**
-	 * Converts the mpi to an BigInteger object
-	 * @return {BigInteger}
-	 */
-	function getBigInteger() {
-		return new BigInteger(util.hexstrdump(this.MPI),16); 
-	}
-
-	
-	function getBits(num) {
-		for (var i = 0; i < 9; i++)
-		if (num >> i == 0)
-		return i;
-	}
-	
-	/**
-	 * Gets the length of the mpi in bytes
-	 * @return {Integer} Mpi byte length
-	 */
-	function getByteLength() {
-		return this.mpiByteLength;
-	}
-	
-	/**
-	 * Creates an mpi from the specified string
-	 * @param {String} data Data to read the mpi from
-	 * @return {openpgp_type_mpi} 
-	 */
-	function create(data) {
-		this.MPI = data;
-		this.mpiBitLength = (data.length -1) *8 + getBits(data.charCodeAt(0));
-		this.mpiByteLength = data.length;
-		return this;
-	}
-	
-	/**
-	 * Converts the mpi object to a string as specified in RFC4880 3.2
-	 * @return {String} mpi Byte representation
-	 */
-	function toBin() {
-		var result = String.fromCharCode((this.mpiBitLength >> 8) & 0xFF);
-		result += String.fromCharCode(this.mpiBitLength & 0xFF);
-		result += this.MPI;
-		return result;
-	}
-	
-	this.read = read;
-	this.toBigInteger = getBigInteger;
-	this.toString = toString;
-	this.create = create;
-	this.toBin = toBin;
-	this.getByteLength = getByteLength;
-}
-
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp.type.s2k.js.html b/doc/openpgp.type.s2k.js.html deleted file mode 100644 index f9bceead..00000000 --- a/doc/openpgp.type.s2k.js.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - JSDoc: Source: type/openpgp.type.s2k.js - - - - - - - - - - -
- -

Source: type/openpgp.type.s2k.js

- - - - - -
-
-
// GPG4Browsers - An OpenPGP implementation in javascript
-// Copyright (C) 2011 Recurity Labs GmbH
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-/**
- * @class
- * @classdesc Implementation of the String-to-key specifier (RFC4880 3.7)
- * String-to-key (S2K) specifiers are used to convert passphrase strings
-   into symmetric-key encryption/decryption keys.  They are used in two
-   places, currently: to encrypt the secret part of private keys in the
-   private keyring, and to convert passphrases to encryption keys for
-   symmetrically encrypted messages.
- */
-function openpgp_type_s2k() {
-	/**
-	 * Parsing function for a string-to-key specifier (RFC 4880 3.7).
-	 * @param {String} input Payload of string-to-key specifier
-	 * @param {Integer} position Position to start reading from the input string
-	 * @return {openpgp_type_s2k} Object representation
-	 */
-	function read(input, position) {
-		var mypos = position;
-		this.type = input[mypos++].charCodeAt();
-		switch (this.type) {
-		case 0: // Simple S2K
-			// Octet 1: hash algorithm
-			this.hashAlgorithm = input[mypos++].charCodeAt();
-			this.s2kLength = 1;
-			break;
-
-		case 1: // Salted S2K
-			// Octet 1: hash algorithm
-			this.hashAlgorithm = input[mypos++].charCodeAt();
-
-			// Octets 2-9: 8-octet salt value
-			this.saltValue = input.substring(mypos, mypos+8);
-			mypos += 8;
-			this.s2kLength = 9;
-			break;
-
-		case 3: // Iterated and Salted S2K
-			// Octet 1: hash algorithm
-			this.hashAlgorithm = input[mypos++].charCodeAt();
-
-			// Octets 2-9: 8-octet salt value
-			this.saltValue = input.substring(mypos, mypos+8);
-			mypos += 8;
-
-			// Octet 10: count, a one-octet, coded value
-			this.EXPBIAS = 6;
-			var c = input[mypos++].charCodeAt();
-			this.count = (16 + (c & 15)) << ((c >> 4) + this.EXPBIAS);
-			this.s2kLength = 10;
-			break;
-
-		case 101:
-			if(input.substring(mypos+1, mypos+4) == "GNU") {
-				this.hashAlgorithm = input[mypos++].charCodeAt();
-				mypos += 3; // GNU
-				var gnuExtType = 1000 + input[mypos++].charCodeAt();
-				if(gnuExtType == 1001) {
-					this.type = gnuExtType;
-					this.s2kLength = 5;
-					// GnuPG extension mode 1001 -- don't write secret key at all
-				} else {
-					util.print_error("unknown s2k gnu protection mode! "+this.type);
-				}
-			} else {
-				util.print_error("unknown s2k type! "+this.type);
-			}
-			break;
-
-		case 2: // Reserved value
-		default:
-			util.print_error("unknown s2k type! "+this.type);
-			break;
-		}
-		return this;
-	}
-	
-	
-	/**
-	 * writes an s2k hash based on the inputs.
-	 * @return {String} Produced key of hashAlgorithm hash length
-	 */
-	function write(type, hash, passphrase, salt, c){
-	    this.type = type;
-	    if(this.type == 3){this.saltValue = salt;
-	        this.hashAlgorithm = hash;
-	        this.count = (16 + (c & 15)) << ((c >> 4) + 6);
-	        this.s2kLength = 10;
-	    }
-	    return this.produce_key(passphrase);
-	}
-
-	/**
-	 * Produces a key using the specified passphrase and the defined 
-	 * hashAlgorithm 
-	 * @param {String} passphrase Passphrase containing user input
-	 * @return {String} Produced key with a length corresponding to 
-	 * hashAlgorithm hash length
-	 */
-	function produce_key(passphrase, numBytes) {
-		passphrase = util.encode_utf8(passphrase);
-		if (this.type == 0) {
-			return openpgp_crypto_hashData(this.hashAlgorithm,passphrase);
-		} else if (this.type == 1) {
-			return openpgp_crypto_hashData(this.hashAlgorithm,this.saltValue+passphrase);
-		} else if (this.type == 3) {
-			var isp = [];
-			isp[0] = this.saltValue+passphrase;
-			while (isp.length*(this.saltValue+passphrase).length < this.count)
-				isp.push(this.saltValue+passphrase);
-			isp = isp.join('');			
-			if (isp.length > this.count)
-				isp = isp.substr(0, this.count);
-			if(numBytes && (numBytes == 24 || numBytes == 32)){ //This if accounts for RFC 4880 3.7.1.1 -- If hash size is greater than block size, use leftmost bits.  If blocksize larger than hash size, we need to rehash isp and prepend with 0.
-			    var key = openpgp_crypto_hashData(this.hashAlgorithm,isp);
-			    return key + openpgp_crypto_hashData(this.hashAlgorithm,String.fromCharCode(0)+isp);
-			}
-			return openpgp_crypto_hashData(this.hashAlgorithm,isp);
-		} else return null;
-	}
-	
-	this.read = read;
-	this.write = write;
-	this.produce_key = produce_key;
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_config.html b/doc/openpgp_config.html deleted file mode 100644 index 425b6ffd..00000000 --- a/doc/openpgp_config.html +++ /dev/null @@ -1,674 +0,0 @@ - - - - - JSDoc: Class: openpgp_config - - - - - - - - - - -
- -

Class: openpgp_config

- - - - - -
- -
-

- openpgp_config -

- -
Implementation of the GPG4Browsers config object
- -
- -
-
- - - - -
-

new openpgp_config()

- - -
-
- - -
- This object contains configuration values and implements -storing and retrieving configuration them from HTML5 local storage. - -This object can be accessed after calling openpgp.init() -using openpgp.config -Stored config parameters can be accessed using -openpgp.config.config -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - -

Members

- -
- -
-

config

- - -
-
- -
- The variable with the actual configuration -
- - - -
- - -
Properties:
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
prefer_hash_algorithm - - -Integer - - - -
encryption_cipher - - -Integer - - - -
compression - - -Integer - - - -
show_version - - -Boolean - - - -
show_comment - - -Boolean - - - -
integrity_protect - - -Boolean - - - -
composition_behavior - - -Integer - - - -
keyserver - - -String - - - -
- - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

debug

- - -
-
- -
- If enabled, debug messages will be printed -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

default_config

- - -
-
- -
- The default config object which is used if no -configuration was in place -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- -
- - - -

Methods

- -
- -
-

<inner> read()

- - -
-
- - -
- Reads the config out of the HTML5 local storage -and initializes the object config. -if config is null the default config will be used -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

<inner> write()

- - -
-
- - -
- Writes the config to HTML5 local storage -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_keyring.html b/doc/openpgp_keyring.html deleted file mode 100644 index f04414da..00000000 --- a/doc/openpgp_keyring.html +++ /dev/null @@ -1,1729 +0,0 @@ - - - - - JSDoc: Class: openpgp_keyring - - - - - - - - - - -
- -

Class: openpgp_keyring

- - - - - -
- -
-

- openpgp_keyring -

- -
The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
- -
- -
-
- - - - -
-

new openpgp_keyring()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> exportPrivateKey(index) → {openpgp_msg_privatekey}

- - -
-
- - -
- returns the openpgp_msg_privatekey representation of the private key at private key ring index -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
index - - -Integer - - - - the index of the private key within the privateKeys array
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- the private key object -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey - - -
-
- - - - -
- - - -
-

<inner> exportPublicKey(index) → {openpgp_msg_privatekey}

- - -
-
- - -
- returns the openpgp_msg_privatekey representation of the public key at public key ring index -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
index - - -Integer - - - - the index of the public key within the publicKeys array
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- the public key object -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey - - -
-
- - - - -
- - - -
-

<inner> getPrivateKeyForAddress(email_address) → {openpgp_msg_privatekey[]}

- - -
-
- - -
- Searches the keyring for a private key containing the specified email address -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
email_address - - -String - - - - email address to search for
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- private keys found -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey[] - - -
-
- - - - -
- - - -
-

<inner> getPrivateKeyForKeyId(keyId) → {openpgp_msg_privatekey[]}

- - -
-
- - -
- Searches the keyring for private keys having the specified key id -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyId - - -String - - - - 8 bytes as string containing the key id to look for
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- private keys found -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey[] - - -
-
- - - - -
- - - -
-

<inner> getPublicKeyForAddress(email_address) → {openpgp_msg_publickey[]}

- - -
-
- - -
- searches all public keys in the keyring matching the address or address part of the user ids -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
email_address - - -String - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The public keys associated with provided email address. -
- - - -
-
- Type -
-
- -openpgp_msg_publickey[] - - -
-
- - - - -
- - - -
-

<inner> getPublicKeysForKeyId(keyId) → {openpgp_msg_privatekey[]}

- - -
-
- - -
- Searches the keyring for public keys having the specified key id -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyId - - -String - - - - provided as string of hex number (lowercase)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- public keys found -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey[] - - -
-
- - - - -
- - - -
-

<inner> hasPrivateKey() → {Boolean}

- - -
-
- - -
- Checks if at least one private key is in the keyring -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- True if there are private keys, else false. -
- - - -
-
- Type -
-
- -Boolean - - -
-
- - - - -
- - - -
-

<inner> importPrivateKey(armored_text)

- - -
-
- - -
- Imports a private key from an exported ascii armored message -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
armored_text - - -String - - - - PRIVATE KEY BLOCK message to read the private key from
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

<inner> importPublicKey(armored_text)

- - -
-
- - -
- Imports a public key from an exported ascii armored message -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
armored_text - - -String - - - - PUBLIC KEY BLOCK message to read the public key from
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

<inner> init()

- - -
-
- - -
- Initialization routine for the keyring. This method reads the -keyring from HTML5 local storage and initializes this instance. -This method is called by openpgp.init(). -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

<inner> removePrivateKey(index) → {openpgp_msg_privatekey}

- - -
-
- - -
- Removes a private key from the private key keyring at the specified index -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
index - - -Integer - - - - the index of the private key within the privateKeys array
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The private key object which has been removed -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey - - -
-
- - - - -
- - - -
-

<inner> removePublicKey(index) → {openpgp_msg_privatekey}

- - -
-
- - -
- Removes a public key from the public key keyring at the specified index -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
index - - -Integer - - - - the index of the public key within the publicKeys array
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The public key object which has been removed -
- - - -
-
- Type -
-
- -openpgp_msg_privatekey - - -
-
- - - - -
- - - -
-

<inner> store()

- - -
-
- - -
- Saves the current state of the keyring to HTML5 local storage. -The privateKeys array and publicKeys array gets Stringified using JSON -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_msg_message.html b/doc/openpgp_msg_message.html deleted file mode 100644 index 7ad75c13..00000000 --- a/doc/openpgp_msg_message.html +++ /dev/null @@ -1,639 +0,0 @@ - - - - - JSDoc: Class: openpgp_msg_message - - - - - - - - - - -
- -

Class: openpgp_msg_message

- - - - - -
- -
-

- openpgp_msg_message -

- -
Top-level message object. Contains information from one or more packets
- -
- -
-
- - - - -
-

<protected> new openpgp_msg_message()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> decrypt(private_key, sessionkey) → {String}

- - -
-
- - -
- Decrypts a message and generates user interface message out of the found. -MDC will be verified as well as message signatures -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
private_key - - -openpgp_msg_privatekey - - - - the private the message is encrypted with (corresponding to the session key)
sessionkey - - -openpgp_packet_encryptedsessionkey - - - - the session key to be used to decrypt the message
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- plaintext of the message or null on error -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> decryptAndVerifySignature(private_key, sessionkey, pubkey) → {String}

- - -
-
- - -
- Decrypts a message and generates user interface message out of the found. -MDC will be verified as well as message signatures -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
private_key - - -openpgp_msg_privatekey - - - - the private the message is encrypted with (corresponding to the session key)
sessionkey - - -openpgp_packet_encryptedsessionkey - - - - the session key to be used to decrypt the message
pubkey - - -openpgp_msg_publickey - - - - Array of public keys to check signature against. If not provided, checks local keystore.
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- plaintext of the message or null on error -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> verifySignature(pubkey) → {boolean}

- - -
-
- - -
- Verifies a message signature. This function can be called after read_message if the message was signed only. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
pubkey - - -openpgp_msg_publickey - - - - Array of public keys to check signature against. If not provided, checks local keystore.
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- true if the signature was correct; otherwise false -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_msg_privatekey.html b/doc/openpgp_msg_privatekey.html deleted file mode 100644 index c101f5d3..00000000 --- a/doc/openpgp_msg_privatekey.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - JSDoc: Class: openpgp_msg_privatekey - - - - - - - - - - -
- -

Class: openpgp_msg_privatekey

- - - - - -
- -
-

- openpgp_msg_privatekey -

- -
Class that represents a decoded private key for internal openpgp.js use
- -
- -
-
- - - - -
-

new openpgp_msg_privatekey()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> extractPublicKey() → {String}

- - -
-
- - -
- extracts the public key part -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- OpenPGP armored text containing the public key - returns null if no sufficient data to extract public key -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> read_nodes()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- last position -
- - - - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_msg_publickey.html b/doc/openpgp_msg_publickey.html deleted file mode 100644 index 29d0c7ca..00000000 --- a/doc/openpgp_msg_publickey.html +++ /dev/null @@ -1,480 +0,0 @@ - - - - - JSDoc: Class: openpgp_msg_publickey - - - - - - - - - - -
- -

Class: openpgp_msg_publickey

- - - - - -
- -
-

- openpgp_msg_publickey -

- -
Decoded public key object for internal openpgp.js use
- -
- -
-
- - - - -
-

new openpgp_msg_publickey()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> getEncryptionKey()

- - -
-
- - -
- finds an encryption key for this public key -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- null if no encryption key has been found -
- - - - - - -
- - - -
-

<inner> read_nodes()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- last position -
- - - - - - -
- - - -
-

<inner> verifyBasicSignatures() → {Boolean}

- - -
-
- - -
- verifies: - - revocation certificates directly on key - - self signatures - - subkey binding and revocation certificates - - This is useful for validating the key -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- true if the basic signatures are all valid -
- - - -
-
- Type -
-
- -Boolean - - -
-
- - - - -
- - - -
-

<inner> verifyCertificationSignatures()

- - -
-
- - -
- verifies all signatures -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a 2 dimensional array. the first dimension corresponds to the userids available -
- - - - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_compressed.html b/doc/openpgp_packet_compressed.html deleted file mode 100644 index f9d2688a..00000000 --- a/doc/openpgp_packet_compressed.html +++ /dev/null @@ -1,846 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_compressed - - - - - - - - - - -
- -

Class: openpgp_packet_compressed

- - - - - -
- -
-

- openpgp_packet_compressed -

- -
Implementation of the Compressed Data Packet (Tag 8) - -RFC4880 5.6: -The Compressed Data packet contains compressed data. Typically, this -packet is found as the contents of an encrypted packet, or following -a Signature or One-Pass Signature packet, and contains a literal data -packet.
- -
- -
-
- - - - -
-

new openpgp_packet_compressed()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> compress(type, data) → {String}

- - -
-
- - -
- Compress the packet data (member decompressedData) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
type - - -Integer - - - - Algorithm to be used // See RFC 4880 9.3
data - - -String - - - - Data to be compressed
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The compressed data stored in attribute compressedData -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> decompress() → {String}

- - -
-
- - -
- Decompression method for decompressing the compressed data -read by read_packet -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The decompressed data -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> read_packet(input, position, len) → {openpgp_packet_compressed}

- - -
-
- - -
- Parsing function for the packet. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of a tag 8 packet
position - - -Integer - - - - Position to start reading from the input string
len - - -Integer - - - - Length of the packet or the remaining length of -input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Object representation -
- - - -
-
- Type -
-
- -openpgp_packet_compressed - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- Pretty printing the packet (useful for debug purposes) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> write_packet(algorithm, data) → {String}

- - -
-
- - -
- Creates a string representation of the packet -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algorithm - - -Integer - - - - Algorithm to be used // See RFC 4880 9.3
data - - -String - - - - Data to be compressed
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String-representation of the packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_encrypteddata.html b/doc/openpgp_packet_encrypteddata.html deleted file mode 100644 index beaabb3e..00000000 --- a/doc/openpgp_packet_encrypteddata.html +++ /dev/null @@ -1,680 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_encrypteddata - - - - - - - - - - -
- -

Class: openpgp_packet_encrypteddata

- - - - - -
- -
-

- openpgp_packet_encrypteddata -

- -
Implementation of the Symmetrically Encrypted Data Packet (Tag 9) - -RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted -with a symmetric-key algorithm. When it has been decrypted, it contains other -packets (usually a literal data packet or compressed data packet, but in -theory other Symmetrically Encrypted Data packets or sequences of packets -that form whole OpenPGP messages).
- -
- -
-
- - - - -
-

new openpgp_packet_encrypteddata()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> decrypt_sym(symmetric_algorithm_type, key)

- - -
-
- - -
- Symmetrically decrypt the packet data -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
symmetric_algorithm_type - - -Integer - - - - Symmetric key algorithm to use // See RFC4880 9.2
key - - -String - - - - Key as string with the corresponding length to the - algorithm
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The decrypted data; -
- - - - - - -
- - - -
-

<inner> read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- Parsing function for the packet. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of a tag 9 packet
position - - -Integer - - - - Position to start reading from the input string
len - - -Integer - - - - Length of the packet or the remaining length of - input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> write_packet(algo, key, data) → {String}

- - -
-
- - -
- Creates a string representation of the packet -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
algo - - -Integer - - - - Symmetric key algorithm to use // See RFC4880 9.2
key - - -String - - - - Key as string with the corresponding length to the - algorithm
data - - -String - - - - Data to be
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String-representation of the packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_encryptedintegrityprotecteddata.html b/doc/openpgp_packet_encryptedintegrityprotecteddata.html deleted file mode 100644 index 2d031cf8..00000000 --- a/doc/openpgp_packet_encryptedintegrityprotecteddata.html +++ /dev/null @@ -1,694 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_encryptedintegrityprotecteddata - - - - - - - - - - -
- -

Class: openpgp_packet_encryptedintegrityprotecteddata

- - - - - -
- -
-

- openpgp_packet_encryptedintegrityprotecteddata -

- -
Implementation of the Sym. Encrypted Integrity Protected Data -Packet (Tag 18) - -RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is -a variant of the Symmetrically Encrypted Data packet. It is a new feature -created for OpenPGP that addresses the problem of detecting a modification to -encrypted data. It is used in combination with a Modification Detection Code -packet.
- -
- -
-
- - - - -
-

new openpgp_packet_encryptedintegrityprotecteddata()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> decrypt(symmetric_algorithm_type, key) → {String}

- - -
-
- - -
- Decrypts the encrypted data contained in this object read_packet must -have been called before -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
symmetric_algorithm_type - - -Integer - - - - The selected symmetric encryption algorithm to be used
key - - -String - - - - The key of cipher blocksize length to be used
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The decrypted data of this packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> read_packet(input, position, len) → {openpgp_packet_encryptedintegrityprotecteddata}

- - -
-
- - -
- Parsing function for the packet. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of a tag 18 packet
position - - -Integer - - - - position to start reading from the input string
len - - -Integer - - - - Length of the packet or the remaining length of - input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- object - representation -
- - - -
-
- Type -
-
- -openpgp_packet_encryptedintegrityprotecteddata - - -
-
- - - - -
- - - -
-

<inner> write_packet(symmetric_algorithm, key, data) → {String}

- - -
-
- - -
- Creates a string representation of a Sym. Encrypted Integrity Protected -Data Packet (tag 18) (see RFC4880 5.13) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
symmetric_algorithm - - -Integer - - - - The selected symmetric encryption algorithm to be used
key - - -String - - - - The key of cipher blocksize length to be used
data - - -String - - - - Plaintext data to be encrypted within the packet
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A string representation of the packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_encryptedsessionkey.html b/doc/openpgp_packet_encryptedsessionkey.html deleted file mode 100644 index bbea283e..00000000 --- a/doc/openpgp_packet_encryptedsessionkey.html +++ /dev/null @@ -1,1024 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_encryptedsessionkey - - - - - - - - - - -
- -

Class: openpgp_packet_encryptedsessionkey

- - - - - -
- -
-

- openpgp_packet_encryptedsessionkey -

- -
Public-Key Encrypted Session Key Packets (Tag 1) - -RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key -used to encrypt a message. Zero or more Public-Key Encrypted Session Key -packets and/or Symmetric-Key Encrypted Session Key packets may precede a -Symmetrically Encrypted Data Packet, which holds an encrypted message. The -message is encrypted with the session key, and the session key is itself -encrypted and stored in the Encrypted Session Key packet(s). The -Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted -Session Key packet for each OpenPGP key to which the message is encrypted. -The recipient of the message finds a session key that is encrypted to their -public key, decrypts the session key, and then uses the session key to -decrypt the message.
- -
- -
-
- - - - -
-

new openpgp_packet_encryptedsessionkey()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> decrypt(msg, key) → {String}

- - -
-
- - -
- Decrypts the session key (only for public key encrypted session key -packets (tag 1) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - -openpgp_msg_message - - - - The message object (with member encryptedData
key - - -openpgp_msg_privatekey - - - - Private key with secMPIs unlocked
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The unencrypted session key -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> read_pub_key_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- Parsing function for a publickey encrypted session key packet (tag 1). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of a tag 1 packet
position - - -Integer - - - - Position to start reading from the input string
len - - -Integer - - - - Length of the packet or the remaining length of - input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> read_symmetric_key_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- Parsing function for a symmetric encrypted session key packet (tag 3). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of a tag 1 packet
position - - -Integer - - - - Position to start reading from the input string
len - - -Integer - - - - Length of the packet or the remaining length of - input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- Creates a string representation of this object (useful for debug -purposes) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The string containing a openpgp description -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> write_pub_key_packet(publicKeyId, publicMPIs, pubalgo, symmalgo, sessionkey) → {String}

- - -
-
- - -
- Create a string representation of a tag 1 packet -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
publicKeyId - - -String - - - - The public key id corresponding to publicMPIs key as string
publicMPIs - - -openpgp_type_mpi[] - - - - Multiprecision integer objects describing the public key
pubalgo - - -Integer - - - - The corresponding public key algorithm // See RFC4880 9.1
symmalgo - - -Integer - - - - The symmetric cipher algorithm used to encrypt the data - within an encrypteddatapacket or encryptedintegrity- - protecteddatapacket - following this packet //See RFC4880 9.2
sessionkey - - -String - - - - A string of randombytes representing the session key
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- The string representation -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_keymaterial.html b/doc/openpgp_packet_keymaterial.html deleted file mode 100644 index e1e57dfc..00000000 --- a/doc/openpgp_packet_keymaterial.html +++ /dev/null @@ -1,1959 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_keymaterial - - - - - - - - - - -
- -

Class: openpgp_packet_keymaterial

- - - - - -
- -
-

- openpgp_packet_keymaterial -

- -
Implementation of the Key Material Packet (Tag 5,6,7,14) - -RFC4480 5.5: -A key material packet contains all the information about a public or -private key. There are four variants of this packet type, and two -major versions. Consequently, this section is complex.
- -
- -
-
- - - - -
-

new openpgp_packet_keymaterial()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> decryptSecretMPIs(str_passphrase) → {Boolean}

- - -
-
- - -
- Decrypts the private key MPIs which are needed to use the key. -openpgp_packet_keymaterial.hasUnencryptedSecretKeyData should be -false otherwise -a call to this function is not needed -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str_passphrase - - -String - - - - The passphrase for this private key -as string
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- True if the passphrase was correct; false if not -
- - - -
-
- Type -
-
- -Boolean - - -
-
- - - - -
- - - -
-

<inner> getFingerprint() → {String}

- - -
-
- - -
- Calculates the fingerprint of the key -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A string containing the fingerprint -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> getKeyId() → {String}

- - -
-
- - -
- Calculates the key id of they key -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A 8 byte key id -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> read_nodes(parent_node, input, position, len) → {Integer}

- - -
-
- - -
- Continue parsing packets belonging to the key material such as signatures -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
parent_node - - -Object - - - - The parent object
input - - -String - - - - Input string to read the packet(s) from
position - - -Integer - - - - Start position for the parser
len - - -Integer - - - - Length of the packet(s) or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Length of nodes read -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

<inner> read_priv_key(input, position, len) → {Object}

- - -
-
- - -
- Internal parser for private keys as specified in RFC 4880 section 5.5.3 -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Input string to read the packet from
position - - -Integer - - - - Start position for the parser
len - - -Integer - - - - Length of the packet or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- This object with attributes set by the parser -
- - - -
-
- Type -
-
- -Object - - -
-
- - - - -
- - - -
-

<inner> read_pub_key(input, position, len) → {Object}

- - -
-
- - -
- Internal Parser for public keys as specified in RFC 4880 section -5.5.2 Public-Key Packet Formats -called by read_tag<num> -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Input string to read the packet from
position - - -Integer - - - - Start position for the parser
len - - -Integer - - - - Length of the packet or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- This object with attributes set by the parser -
- - - -
-
- Type -
-
- -Object - - -
-
- - - - -
- - - -
-

<inner> read_tag5(input, position, len) → {openpgp_packet_keymaterial}

- - -
-
- - -
- This function reads the payload of a secret key packet (Tag 5) -and initializes the openpgp_packet_keymaterial -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Input string to read the packet from
position - - -Integer - - - - Start position for the parser
len - - -Intefer - - - - Length of the packet or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -openpgp_packet_keymaterial - - -
-
- - - - -
- - - -
-

<inner> read_tag6(input, position, len) → {openpgp_packet_keymaterial}

- - -
-
- - -
- This function reads the payload of a public key packet (Tag 6) -and initializes the openpgp_packet_keymaterial -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Input string to read the packet from
position - - -Integer - - - - Start position for the parser
len - - -Integer - - - - Length of the packet or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -openpgp_packet_keymaterial - - -
-
- - - - -
- - - -
-

<inner> read_tag7(input, position, len) → {openpgp_packet_keymaterial}

- - -
-
- - -
- This function reads the payload of a secret key sub packet (Tag 7) -and initializes the openpgp_packet_keymaterial -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Input string to read the packet from
position - - -Integer - - - - Start position for the parser
len - - -Integer - - - - Length of the packet or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -openpgp_packet_keymaterial - - -
-
- - - - -
- - - -
-

<inner> read_tag14(input, position, len) → {openpgp_packet_keymaterial}

- - -
-
- - -
- This function reads the payload of a public key sub packet (Tag 14) -and initializes the openpgp_packet_keymaterial -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Input string to read the packet from
position - - -Integer - - - - Start position for the parser
len - - -Integer - - - - Length of the packet or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -openpgp_packet_keymaterial - - -
-
- - - - -
- - - -
-

<inner> toString()

- - -
-
- - -
- Generates Debug output -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the keymaterial -
- - - - - - -
- - - -
-

<inner> verifyKey() → {Integer}

- - -
-
- - -
- Checks the validity for usage of this (sub)key -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- 0 = bad key, 1 = expired, 2 = revoked, 3 = valid -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_literaldata.html b/doc/openpgp_packet_literaldata.html deleted file mode 100644 index d9ecab7f..00000000 --- a/doc/openpgp_packet_literaldata.html +++ /dev/null @@ -1,1117 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_literaldata - - - - - - - - - - -
- -

Class: openpgp_packet_literaldata

- - - - - -
- -
-

- openpgp_packet_literaldata -

- -
Implementation of the Literal Data Packet (Tag 11) - -RFC4880 5.9: A Literal Data packet contains the body of a message; data that -is not to be further interpreted.
- -
- -
-
- - - - -
-

new openpgp_packet_literaldata()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - -

Members

- -
- -
-

<static, readonly> formats :String

- - -
-
- -
- Data types in the literal packet -
- - - -
- - -
Properties:
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
binary - - -String - - - - - - b - - Binary data
text - - -String - - - - - - t - - Text data
utf8 - - -String - - - - - - u - - Utf8 data
- - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- -
- - - -

Methods

- -
- -
-

get_data_bytes() → {String}

- - -
-
- - -
- Get the byte sequence representing the literal packet data -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A sequence of bytes -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- Parsing function for a literal data packet (tag 11). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of a tag 11 packet
position - - -Integer - - - - Position to start reading from the input string
len - - -Integer - - - - Length of the packet or the remaining length of - input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

set_data(str, format)

- - -
-
- - -
- Set the packet data to a javascript native string or a squence of -bytes. Conversion to a proper utf8 encoding takes place when the -packet is written. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - Any native javascript string
format - - -openpgp_packet_literaldata.formats - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

set_data_bytes(bytes, format)

- - -
-
- - -
- Set the packet data to value represented by the provided string -of bytes together with the appropriate conversion format. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
bytes - - -String - - - - The string of bytes
format - - -openpgp_packet_literaldata.formats - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

toString() → {String}

- - -
-
- - -
- Generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the keymaterial -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

write_packet(data) → {String}

- - -
-
- - -
- Creates a string representation of the packet -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -String - - - - The data to be inserted as body
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- string-representation of the packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_marker.html b/doc/openpgp_packet_marker.html deleted file mode 100644 index 2fbb446a..00000000 --- a/doc/openpgp_packet_marker.html +++ /dev/null @@ -1,436 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_marker - - - - - - - - - - -
- -

Class: openpgp_packet_marker

- - - - - -
- -
-

- openpgp_packet_marker -

- -
Implementation of the strange "Marker packet" (Tag 10) - -RFC4880 5.8: An experimental version of PGP used this packet as the Literal -packet, but no released version of PGP generated Literal packets with this -tag. With PGP 5.x, this packet has been reassigned and is reserved for use as -the Marker packet. - -Such a packet MUST be ignored when received.
- -
- -
-
- - - - -
-

new openpgp_packet_marker()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- Parsing function for a literal data packet (tag 10). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of a tag 10 packet
position - - -Integer - - - - Position to start reading from the input string
len - - -Integer - - - - Length of the packet or the remaining length of - input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- Generates Debug output -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the -keymaterial -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_modificationdetectioncode.html b/doc/openpgp_packet_modificationdetectioncode.html deleted file mode 100644 index 3f61f837..00000000 --- a/doc/openpgp_packet_modificationdetectioncode.html +++ /dev/null @@ -1,436 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_modificationdetectioncode - - - - - - - - - - -
- -

Class: openpgp_packet_modificationdetectioncode

- - - - - -
- -
-

- openpgp_packet_modificationdetectioncode -

- -
Implementation of the Modification Detection Code Packet (Tag 19) - -RFC4880 5.14: The Modification Detection Code packet contains a SHA-1 hash of -plaintext data, which is used to detect message modification. It is only used -with a Symmetrically Encrypted Integrity Protected Data packet. The -Modification Detection Code packet MUST be the last packet in the plaintext -data that is encrypted in the Symmetrically Encrypted Integrity Protected -Data packet, and MUST appear in no other place.
- -
- -
-
- - - - -
-

new openpgp_packet_modificationdetectioncode()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- parsing function for a modification detection code packet (tag 19). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - payload of a tag 19 packet
position - - -Integer - - - - position to start reading from the input string
len - - -Integer - - - - length of the packet or the remaining length of - input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the -modification detection code -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_onepasssignature.html b/doc/openpgp_packet_onepasssignature.html deleted file mode 100644 index 7e4104d3..00000000 --- a/doc/openpgp_packet_onepasssignature.html +++ /dev/null @@ -1,667 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_onepasssignature - - - - - - - - - - -
- -

Class: openpgp_packet_onepasssignature

- - - - - -
- -
-

- openpgp_packet_onepasssignature -

- -
Implementation of the One-Pass Signature Packets (Tag 4) - -RFC4880 5.4: -The One-Pass Signature packet precedes the signed data and contains -enough information to allow the receiver to begin calculating any -hashes needed to verify the signature. It allows the Signature -packet to be placed at the end of the message, so that the signer -can compute the entire signed message in one pass.
- -
- -
-
- - - - -
-

new openpgp_packet_onepasssignature()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- parsing function for a one-pass signature packet (tag 4). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - payload of a tag 4 packet
position - - -Integer - - - - position to start reading from the input string
len - - -Integer - - - - length of the packet or the remaining length of input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the one-pass signature packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> write_packet(type, hashalgorithm, privatekey, length, nested) → {String}

- - -
-
- - -
- creates a string representation of a one-pass signature packet -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
type - - -Integer - - - - Signature types as described in RFC4880 Section 5.2.1.
hashalgorithm - - -Integer - - - - the hash algorithm used within the signature
privatekey - - -openpgp_msg_privatekey - - - - the private key used to generate the signature
length - - -Integer - - - - length of data to be signed
nested - - -boolean - - - - boolean showing whether the signature is nested. - "true" indicates that the next packet is another One-Pass Signature packet - that describes another signature to be applied to the same message data.
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a string representation of a one-pass signature packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_signature.html b/doc/openpgp_packet_signature.html deleted file mode 100644 index f35ddf99..00000000 --- a/doc/openpgp_packet_signature.html +++ /dev/null @@ -1,1124 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_signature - - - - - - - - - - -
- -

Class: openpgp_packet_signature

- - - - - -
- -
-

- openpgp_packet_signature -

- -
Implementation of the Signature Packet (Tag 2) - -RFC4480 5.2: -A Signature packet describes a binding between some public key and -some data. The most common signatures are a signature of a file or a -block of text, and a signature that is a certification of a User ID.
- -
- -
-
- - - - -
-

new openpgp_packet_signature()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> getIssuer() → {String}

- - -
-
- - -
- gets the issuer key id of this signature -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- issuer key id as string (8bytes) -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> getIssuerKey() → {Object}

- - -
-
- - -
- Tries to get the corresponding public key out of the public keyring for the issuer created this signature -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise -
- - - -
-
- Type -
-
- -Object - - -
-
- - - - -
- - - -
-

<inner> read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- parsing function for a signature packet (tag 2). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - payload of a tag 2 packet
position - - -Integer - - - - position to start reading from the input string
len - - -Integer - - - - length of the packet or the remaining length of input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the signature packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> verify(data, key) → {boolean}

- - -
-
- - -
- verifys the signature packet. Note: not signature types are implemented -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -String - - - - data which on the signature applies
key - - -openpgp_msg_privatekey - - - - the public key to verify the signature
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- True if message is verified, else false. -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - -
- - - -
-

<inner> write_message_signature(signature_type, data, privatekey) → {String}

- - -
-
- - -
- creates a string representation of a message signature packet (tag 2). -This can be only used on text data -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
signature_type - - -Integer - - - - should be 1 (one)
data - - -String - - - - data to be signed
privatekey - - -openpgp_msg_privatekey - - - - private key used to sign the message. (secMPIs MUST be unlocked)
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- string representation of a signature packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> write_sub_signature_packet(type, data) → {String}

- - -
-
- - -
- creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1) -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
type - - -Integer - - - - subpacket signature type. Signature types as described in RFC4880 Section 5.2.3.2
data - - -String - - - - data to be included
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a string-representation of a sub signature packet (See RFC 4880 5.2.3.1) -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_userattribute.html b/doc/openpgp_packet_userattribute.html deleted file mode 100644 index 34b6e68f..00000000 --- a/doc/openpgp_packet_userattribute.html +++ /dev/null @@ -1,648 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_userattribute - - - - - - - - - - -
- -

Class: openpgp_packet_userattribute

- - - - - -
- -
-

- openpgp_packet_userattribute -

- -
Implementation of the User Attribute Packet (Tag 17) - The User Attribute packet is a variation of the User ID packet. It - is capable of storing more types of data than the User ID packet, - which is limited to text. Like the User ID packet, a User Attribute - packet may be certified by the key owner ("self-signed") or any other - key owner who cares to certify it. Except as noted, a User Attribute - packet may be used anywhere that a User ID packet may be used. - - While User Attribute packets are not a required part of the OpenPGP - standard, implementations SHOULD provide at least enough - compatibility to properly handle a certification signature on the - User Attribute packet. A simple way to do this is by treating the - User Attribute packet as a User ID packet with opaque contents, but - an implementation may use any method desired.
- -
- -
-
- - - - -
-

new openpgp_packet_userattribute()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> read_nodes(parent_node, input, position, len) → {Integer}

- - -
-
- - -
- Continue parsing packets belonging to the user attribute packet such as signatures -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
parent_node - - -Object - - - - the parent object
input - - -String - - - - input string to read the packet(s) from
position - - -Integer - - - - start position for the parser
len - - -Integer - - - - length of the packet(s) or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- length of nodes read -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

<inner> read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- parsing function for a user attribute packet (tag 17). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - payload of a tag 17 packet
position - - -Integer - - - - position to start reading from the input string
len - - -Integer - - - - length of the packet or the remaining length of input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the user attribute packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_packet_userid.html b/doc/openpgp_packet_userid.html deleted file mode 100644 index ee95ebcb..00000000 --- a/doc/openpgp_packet_userid.html +++ /dev/null @@ -1,1459 +0,0 @@ - - - - - JSDoc: Class: openpgp_packet_userid - - - - - - - - - - -
- -

Class: openpgp_packet_userid

- - - - - -
- -
-

- openpgp_packet_userid -

- -
Implementation of the User ID Packet (Tag 13) -A User ID packet consists of UTF-8 text that is intended to represent -the name and email address of the key holder. By convention, it -includes an RFC 2822 [RFC2822] mail name-addr, but there are no -restrictions on its content. The packet length in the header -specifies the length of the User ID.
- -
- -
-
- - - - -
-

new openpgp_packet_userid()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

get_text_bytes() → {String}

- - -
-
- - -
- Get the byte sequence representing the text of this packet. -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- A sequence of bytes -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

hasCertificationRevocationSignature(keyId)

- - -
-
- - -
- lookup function to find certification revocation signatures -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyId - - -String - - - - string containing the key id of the issuer of this signature
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- a CertificationRevocationSignature if found; otherwise null -
- - - - - - -
- - - -
-

read_nodes(parent_node, input, position, len) → {Integer}

- - -
-
- - -
- Continue parsing packets belonging to the userid packet such as signatures -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
parent_node - - -Object - - - - the parent object
input - - -String - - - - input string to read the packet(s) from
position - - -Integer - - - - start position for the parser
len - - -Integer - - - - length of the packet(s) or remaining length of input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- length of nodes read -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

read_packet(input, position, len) → {openpgp_packet_encrypteddata}

- - -
-
- - -
- Parsing function for a user id packet (tag 13). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - payload of a tag 13 packet
position - - -Integer - - - - position to start reading from the input string
len - - -Integer - - - - length of the packet or the remaining length of input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- object representation -
- - - -
-
- Type -
-
- -openpgp_packet_encrypteddata - - -
-
- - - - -
- - - -
-

set_text(str)

- - -
-
- - -
- Set the packet text field to a native javascript string -Conversion to a proper utf8 encoding takes place when the -packet is written. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - - Any native javascript string
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

set_text_bytes(bytes)

- - -
-
- - -
- Set the packet text to value represented by the provided string -of bytes. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
bytes - - -String - - - - A string of bytes
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - - -
-

toString() → {String}

- - -
-
- - -
- generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the user id packet -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

verify()

- - -
-
- - -
- verifies the signatures of the user id -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- 0 if the userid is valid; 1 = userid expired; 2 = userid revoked -
- - - - - - -
- - - -
-

verifyCertificationSignatures(publicKeyPacket) → {Integer[]}

- - -
-
- - -
- Verifies all certification signatures. This method does not consider possible revocation signatures. -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
publicKeyPacket - - -Object - - - - the top level key material
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- An array of integers corresponding to the array of certification signatures. The meaning of each integer is the following: -0 = bad signature -1 = signature expired -2 = issuer key not available -3 = revoked -4 = signature valid -5 = signature by key owner expired -6 = signature by key owner revoked -
- - - -
-
- Type -
-
- -Integer[] - - -
-
- - - - -
- - - -
-

write_packet(user_id) → {String}

- - -
-
- - -
- Creates a string representation of the user id packet -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
user_id - - -String - - - - the user id as string ("John Doe -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- string representation -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:42 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_type_keyid.html b/doc/openpgp_type_keyid.html deleted file mode 100644 index 63cc1821..00000000 --- a/doc/openpgp_type_keyid.html +++ /dev/null @@ -1,409 +0,0 @@ - - - - - JSDoc: Class: openpgp_type_keyid - - - - - - - - - - -
- -

Class: openpgp_type_keyid

- - - - - -
- -
-

- openpgp_type_keyid -

- -
Implementation of type key id (RFC4880 3.3) - A Key ID is an eight-octet scalar that identifies a key. - Implementations SHOULD NOT assume that Key IDs are unique. The - section "Enhanced Key Formats" below describes how Key IDs are - formed.
- -
- -
-
- - - - -
-

new openpgp_type_keyid()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> read_packet(input, position) → {openpgp_type_keyid}

- - -
-
- - -
- Parsing method for a key id -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Input to read the key id from
position - - -integer - - - - Position where to start reading the key -id from input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- This object -
- - - -
-
- Type -
-
- -openpgp_type_keyid - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- Generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Key Id as hexadecimal string -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:43 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_type_mpi.html b/doc/openpgp_type_mpi.html deleted file mode 100644 index 9c781cc1..00000000 --- a/doc/openpgp_type_mpi.html +++ /dev/null @@ -1,831 +0,0 @@ - - - - - JSDoc: Class: openpgp_type_mpi - - - - - - - - - - -
- -

Class: openpgp_type_mpi

- - - - - -
- -
-

- openpgp_type_mpi -

- -
- -
-
- - - - -
-

new openpgp_type_mpi()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> create(data) → {openpgp_type_mpi}

- - -
-
- - -
- Creates an mpi from the specified string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -String - - - - Data to read the mpi from
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -openpgp_type_mpi - - -
-
- - - - -
- - - -
-

<inner> getBigInteger() → {BigInteger}

- - -
-
- - -
- Converts the mpi to an BigInteger object -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - -
- - - -
-

<inner> getByteLength() → {Integer}

- - -
-
- - -
- Gets the length of the mpi in bytes -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Mpi byte length -
- - - -
-
- Type -
-
- -Integer - - -
-
- - - - -
- - - -
-

<inner> read(input, position, len) → {openpgp_type_mpi}

- - -
-
- - -
- Parsing function for a mpi (RFC 4880 3.2). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of mpi data
position - - -Integer - - - - Position to start reading from the input -string
len - - -Integer - - - - Length of the packet or the remaining length of -input at position
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Object representation -
- - - -
-
- Type -
-
- -openpgp_type_mpi - - -
-
- - - - -
- - - -
-

<inner> toBin() → {String}

- - -
-
- - -
- Converts the mpi object to a string as specified in RFC4880 3.2 -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- mpi Byte representation -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> toString() → {String}

- - -
-
- - -
- Generates debug output (pretty print) -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String which gives some information about the mpi -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:43 GMT+0200 (CEST) -
- - - - diff --git a/doc/openpgp_type_s2k.html b/doc/openpgp_type_s2k.html deleted file mode 100644 index 2a553c0f..00000000 --- a/doc/openpgp_type_s2k.html +++ /dev/null @@ -1,550 +0,0 @@ - - - - - JSDoc: Class: openpgp_type_s2k - - - - - - - - - - -
- -

Class: openpgp_type_s2k

- - - - - -
- -
-

- openpgp_type_s2k -

- -
Implementation of the String-to-key specifier (RFC4880 3.7) -String-to-key (S2K) specifiers are used to convert passphrase strings - into symmetric-key encryption/decryption keys. They are used in two - places, currently: to encrypt the secret part of private keys in the - private keyring, and to convert passphrases to encryption keys for - symmetrically encrypted messages.
- -
- -
-
- - - - -
-

new openpgp_type_s2k()

- - -
-
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<inner> produce_key(passphrase) → {String}

- - -
-
- - -
- Produces a key using the specified passphrase and the defined -hashAlgorithm -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
passphrase - - -String - - - - Passphrase containing user input
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Produced key with a length corresponding to -hashAlgorithm hash length -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> read(input, position) → {openpgp_type_s2k}

- - -
-
- - -
- Parsing function for a string-to-key specifier (RFC 4880 3.7). -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
input - - -String - - - - Payload of string-to-key specifier
position - - -Integer - - - - Position to start reading from the input string
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Object representation -
- - - -
-
- Type -
-
- -openpgp_type_s2k - - -
-
- - - - -
- - - -
-

<inner> write() → {String}

- - -
-
- - -
- writes an s2k hash based on the inputs. -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- Produced key of hashAlgorithm hash length -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:43 GMT+0200 (CEST) -
- - - - diff --git a/doc/_openpgp_packet.html b/doc/packet.html similarity index 51% rename from doc/_openpgp_packet.html rename to doc/packet.html index 5d0390d1..63fc7f2f 100644 --- a/doc/_openpgp_packet.html +++ b/doc/packet.html @@ -2,7 +2,7 @@ - JSDoc: Class: _openpgp_packet + JSDoc: Module: packet/packet @@ -17,7 +17,7 @@
-

Class: _openpgp_packet

+

Module: packet/packet

@@ -27,12 +27,9 @@

- _openpgp_packet + packet/packet

-
Parent openpgp packet class. Operations focus on determining -packet types and packet header.
-
@@ -41,22 +38,8 @@ packet types and packet header.
-
-

new _openpgp_packet()

- - -
-
- - - - - - - - - - + +
@@ -79,7 +62,7 @@ packet types and packet header.
Source:
@@ -90,20 +73,8 @@ packet types and packet header.
- - - - - - - - - - - - -
- + + @@ -112,6 +83,14 @@ packet types and packet header. +

Requires

+ + + @@ -125,147 +104,7 @@ packet types and packet header.
-

<inner> encode_length(length) → {String}

- - -
-
- - -
- Encodes a given integer of length to the openpgp length specifier to a -string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
length - - -Integer - - - - The length to encode
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String with openpgp length representation -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> read_packet(input, position, len) → {Object}

+

<static> read(input, position, len) → {Object}

@@ -400,7 +239,7 @@ string
Source:
@@ -425,7 +264,7 @@ string
- Returns a parsed openpgp_packet + Returns a parsed module:packet/packet
@@ -450,170 +289,7 @@ string
-

<inner> write_old_packet_header(tag_type, length) → {String}

- - -
-
- - -
- Writes a packet header Version 3 with the given tag_type and length to a -string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag_type - - -Integer - - - - Tag type
length - - -Integer - - - - Length of the payload
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- String of the header -
- - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<inner> write_packet_header(tag_type, length) → {String}

+

<static> writeHeader(tag_type, length) → {String}

@@ -726,7 +402,7 @@ string
Source:
@@ -771,6 +447,309 @@ string + + + + +
+

<static> writeOldHeader(tag_type, length) → {String}

+ + +
+
+ + +
+ Writes a packet header Version 3 with the given tag_type and length to a +string +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tag_type + + +Integer + + + + Tag type
length + + +Integer + + + + Length of the payload
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ String of the header +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> writeSimpleLength(length) → {String}

+ + +
+
+ + +
+ Encodes a given integer of length to the openpgp length specifier to a +string +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
length + + +Integer + + + + The length to encode
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ String with openpgp length representation +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + +
@@ -789,15 +768,16 @@ string
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:41 GMT+0200 (CEST) + Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST)
+ - + \ No newline at end of file diff --git a/doc/packet.js.html b/doc/packet.js.html new file mode 100644 index 00000000..fbce2eff --- /dev/null +++ b/doc/packet.js.html @@ -0,0 +1,313 @@ + + + + + JSDoc: Source: packet/packet.js + + + + + + + + + + +
+ +

Source: packet/packet.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @requires enums
+ * @requires util
+ * @module packet/packet
+ */
+
+var enums = require('../enums.js'),
+  util = require('../util');
+
+
+module.exports = {
+  readSimpleLength: function(bytes) {
+    var len = 0,
+      offset,
+      type = bytes.charCodeAt(0);
+
+
+    if (type < 192) {
+      len = bytes.charCodeAt(0);
+      offset = 1;
+    } else if (type < 255) {
+      len = ((bytes.charCodeAt(0) - 192) << 8) + (bytes.charCodeAt(1)) + 192;
+      offset = 2;
+    } else if (type == 255) {
+      len = util.readNumber(bytes.substr(1, 4));
+      offset = 5;
+    }
+
+    return {
+      len: len,
+      offset: offset
+    };
+  },
+
+  /**
+   * Encodes a given integer of length to the openpgp length specifier to a
+   * string
+   * 
+   * @param {Integer} length The length to encode
+   * @return {String} String with openpgp length representation
+   */
+  writeSimpleLength: function(length) {
+    var result = "";
+    if (length < 192) {
+      result += String.fromCharCode(length);
+    } else if (length > 191 && length < 8384) {
+      /*
+       * let a = (total data packet length) - 192 let bc = two octet
+       * representation of a let d = b + 192
+       */
+      result += String.fromCharCode(((length - 192) >> 8) + 192);
+      result += String.fromCharCode((length - 192) & 0xFF);
+    } else {
+      result += String.fromCharCode(255);
+      result += util.writeNumber(length, 4);
+    }
+    return result;
+  },
+
+  /**
+   * Writes a packet header version 4 with the given tag_type and length to a
+   * string
+   * 
+   * @param {Integer} tag_type Tag type
+   * @param {Integer} length Length of the payload
+   * @return {String} String of the header
+   */
+  writeHeader: function(tag_type, length) {
+    /* we're only generating v4 packet headers here */
+    var result = "";
+    result += String.fromCharCode(0xC0 | tag_type);
+    result += this.writeSimpleLength(length);
+    return result;
+  },
+
+  /**
+   * Writes a packet header Version 3 with the given tag_type and length to a
+   * string
+   * 
+   * @param {Integer} tag_type Tag type
+   * @param {Integer} length Length of the payload
+   * @return {String} String of the header
+   */
+  writeOldHeader: function(tag_type, length) {
+    var result = "";
+    if (length < 256) {
+      result += String.fromCharCode(0x80 | (tag_type << 2));
+      result += String.fromCharCode(length);
+    } else if (length < 65536) {
+      result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
+      result += util.writeNumber(length, 2);
+    } else {
+      result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
+      result += util.writeNumber(length, 4);
+    }
+    return result;
+  },
+
+  /**
+   * Generic static Packet Parser function
+   * 
+   * @param {String} input Input stream as string
+   * @param {integer} position Position to start parsing
+   * @param {integer} len Length of the input from position on
+   * @return {Object} Returns a parsed module:packet/packet
+   */
+  read: function(input, position, len) {
+    // some sanity checks
+    if (input == null || input.length <= position || input.substring(position).length < 2 || (input.charCodeAt(position) &
+      0x80) == 0) {
+      throw new Error("Error during parsing. This message / key is probably not containing a valid OpenPGP format.");
+    }
+    var mypos = position;
+    var tag = -1;
+    var format = -1;
+    var packet_length;
+
+    format = 0; // 0 = old format; 1 = new format
+    if ((input.charCodeAt(mypos) & 0x40) != 0) {
+      format = 1;
+    }
+
+    var packet_length_type;
+    if (format) {
+      // new format header
+      tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0
+    } else {
+      // old format header
+      tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2
+      packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0
+    }
+
+    // header octet parsing done
+    mypos++;
+
+    // parsed length from length field
+    var bodydata = null;
+
+    // used for partial body lengths
+    var real_packet_length = -1;
+    if (!format) {
+      // 4.2.1. Old Format Packet Lengths
+      switch (packet_length_type) {
+        case 0:
+          // The packet has a one-octet length. The header is 2 octets
+          // long.
+          packet_length = input.charCodeAt(mypos++);
+          break;
+        case 1:
+          // The packet has a two-octet length. The header is 3 octets
+          // long.
+          packet_length = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
+          break;
+        case 2:
+          // The packet has a four-octet length. The header is 5
+          // octets long.
+          packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) <<
+            8) | input.charCodeAt(mypos++);
+          break;
+        default:
+          // 3 - The packet is of indeterminate length. The header is 1
+          // octet long, and the implementation must determine how long
+          // the packet is. If the packet is in a file, this means that
+          // the packet extends until the end of the file. In general, 
+          // an implementation SHOULD NOT use indeterminate-length 
+          // packets except where the end of the data will be clear 
+          // from the context, and even then it is better to use a 
+          // definite length, or a new format header. The new format 
+          // headers described below have a mechanism for precisely
+          // encoding data of indeterminate length.
+          packet_length = len;
+          break;
+      }
+
+    } else // 4.2.2. New Format Packet Lengths
+    {
+
+      // 4.2.2.1. One-Octet Lengths
+      if (input.charCodeAt(mypos) < 192) {
+        packet_length = input.charCodeAt(mypos++);
+        util.print_debug("1 byte length:" + packet_length);
+        // 4.2.2.2. Two-Octet Lengths
+      } else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) {
+        packet_length = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192;
+        util.print_debug("2 byte length:" + packet_length);
+        // 4.2.2.4. Partial Body Lengths
+      } else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) {
+        packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F);
+        util.print_debug("4 byte length:" + packet_length);
+        // EEEK, we're reading the full data here...
+        var mypos2 = mypos + packet_length;
+        bodydata = input.substring(mypos, mypos + packet_length);
+        while (true) {
+          if (input.charCodeAt(mypos2) < 192) {
+            var tmplen = input.charCodeAt(mypos2++);
+            packet_length += tmplen;
+            bodydata += input.substring(mypos2, mypos2 + tmplen);
+            mypos2 += tmplen;
+            break;
+          } else if (input.charCodeAt(mypos2) >= 192 && input.charCodeAt(mypos2) < 224) {
+            var tmplen = ((input.charCodeAt(mypos2++) - 192) << 8) + (input.charCodeAt(mypos2++)) + 192;
+            packet_length += tmplen;
+            bodydata += input.substring(mypos2, mypos2 + tmplen);
+            mypos2 += tmplen;
+            break;
+          } else if (input.charCodeAt(mypos2) > 223 && input.charCodeAt(mypos2) < 255) {
+            var tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F);
+            packet_length += tmplen;
+            bodydata += input.substring(mypos2, mypos2 + tmplen);
+            mypos2 += tmplen;
+          } else {
+            mypos2++;
+            var tmplen = (input.charCodeAt(mypos2++) << 24) | (input.charCodeAt(mypos2++) << 16) | (input[mypos2++]
+              .charCodeAt() << 8) | input.charCodeAt(mypos2++);
+            bodydata += input.substring(mypos2, mypos2 + tmplen);
+            packet_length += tmplen;
+            mypos2 += tmplen;
+            break;
+          }
+        }
+        real_packet_length = mypos2;
+        // 4.2.2.3. Five-Octet Lengths
+      } else {
+        mypos++;
+        packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) <<
+          8) | input.charCodeAt(mypos++);
+      }
+    }
+
+    // if there was'nt a partial body length: use the specified
+    // packet_length
+    if (real_packet_length == -1) {
+      real_packet_length = packet_length;
+    }
+
+    if (bodydata == null) {
+      bodydata = input.substring(mypos, mypos + real_packet_length);
+    }
+
+    return {
+      tag: tag,
+      packet: bodydata,
+      offset: mypos + real_packet_length
+    };
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/packetlist.html b/doc/packetlist.html new file mode 100644 index 00000000..6ba2a3fb --- /dev/null +++ b/doc/packetlist.html @@ -0,0 +1,1103 @@ + + + + + JSDoc: Module: packet/packetlist + + + + + + + + + + +
+ +

Module: packet/packetlist

+ + + + + +
+ +
+

+ packet/packetlist +

+ +
+ +
+
+ + +
This class represents a list of openpgp packets. +Take care when iterating over it - the packets themselves +are stored as numerical indices.
+ + +
+

new (require("packet/packetlist"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

<readonly> length :Integer

+ + +
+
+ +
+ The number of packets contained within the list. +
+ + + +
Type:
+
    +
  • + +Integer + + +
  • +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

concat()

+ + +
+
+ + +
+ Concatenates packetlist or array of packets +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

filter()

+ + +
+
+ + +
+ Creates a new packetList with all packets that pass the test implemented by the provided function. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

filterByTag()

+ + +
+
+ + +
+ Creates a new packetList with all packets from the given types +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

findPacket(type) → {module:packet/packet|null}

+ + +
+
+ + +
+ Traverses packet tree and returns first matching packet +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
type + + +module:enums.packet + + + + The packet type
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +module:packet/packet +| + +null + + +
+
+ + + + +
+ + + +
+

forEach()

+ + +
+
+ + +
+ Executes the provided callback once for each element +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

indexOfTag()

+ + +
+
+ + +
+ Returns array of found indices by tag +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

push()

+ + +
+
+ + +
+ Adds a packet to the list. This is the only supported method of doing so; +writing to packetlist[i] directly will result in an error. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

read(A)

+ + +
+
+ + +
+ Reads a stream of binary data and interprents it as a list of packets. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
A + + +String + + + + binary string of bytes.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

slice()

+ + +
+
+ + +
+ Returns slice of packetlist +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ Creates a binary representation of openpgp objects contained within the +class instance. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A binary string of bytes containing valid openpgp packets. +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:43 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/packetlist.js.html b/doc/packetlist.js.html new file mode 100644 index 00000000..55c8aaa0 --- /dev/null +++ b/doc/packetlist.js.html @@ -0,0 +1,227 @@ + + + + + JSDoc: Source: packet/packetlist.js + + + + + + + + + + +
+ +

Source: packet/packetlist.js

+ + + + + +
+
+
/**
+ * This class represents a list of openpgp packets.
+ * Take care when iterating over it - the packets themselves
+ * are stored as numerical indices.
+ * @requires enums
+ * @requires packet
+ * @requires packet/packet
+ * @module packet/packetlist
+ */
+
+var packetParser = require('./packet.js'),
+  packets = require('./all_packets.js'),
+  enums = require('../enums.js');
+
+/**
+ * @constructor
+ */
+module.exports = function packetlist() {
+  /** The number of packets contained within the list.
+   * @readonly
+   * @type {Integer} */
+  this.length = 0;
+
+  /**
+   * Reads a stream of binary data and interprents it as a list of packets.
+   * @param {String} A binary string of bytes.
+   */
+  this.read = function (bytes) {
+    var i = 0;
+
+    while (i < bytes.length) {
+      var parsed = packetParser.read(bytes, i, bytes.length - i);
+      i = parsed.offset;
+
+      var tag = enums.read(enums.packet, parsed.tag);
+      var packet = new packets[tag]();
+
+      this.push(packet);
+
+      packet.read(parsed.packet);
+    }
+  }
+
+  /**
+   * Creates a binary representation of openpgp objects contained within the
+   * class instance.
+   * @returns {String} A binary string of bytes containing valid openpgp packets.
+   */
+  this.write = function () {
+    var bytes = '';
+
+    for (var i = 0; i < this.length; i++) {
+      var packetbytes = this[i].write();
+      bytes += packetParser.writeHeader(this[i].tag, packetbytes.length);
+      bytes += packetbytes;
+    }
+
+    return bytes;
+  }
+
+  /**
+   * Adds a packet to the list. This is the only supported method of doing so;
+   * writing to packetlist[i] directly will result in an error.
+   */
+  this.push = function (packet) {
+    if (!packet) return;
+
+    packet.packets = packet.packets || new packetlist();
+
+    this[this.length] = packet;
+    this.length++;
+  }
+
+  /**
+  * Creates a new packetList with all packets that pass the test implemented by the provided function.
+  */
+  this.filter = function (callback) {
+
+    var filtered = new packetlist();
+
+    for (var i = 0; i < this.length; i++) {
+      if (callback(this[i], i, this)) {
+        filtered.push(this[i]);
+      }
+    }
+
+    return filtered;
+  }
+
+  /**
+  * Creates a new packetList with all packets from the given types
+  */
+  this.filterByTag = function () {
+    var args = Array.prototype.slice.call(arguments);
+    var filtered = new packetlist();
+    var that = this;
+
+    for (var i = 0; i < this.length; i++) {
+      if (args.some(function(packetType) {return that[i].tag == packetType})) {
+        filtered.push(this[i]);
+      }
+    }
+
+    return filtered;
+  } 
+
+  /**
+  * Executes the provided callback once for each element
+  */
+  this.forEach = function (callback) {
+    for (var i = 0; i < this.length; i++) {
+      callback(this[i]);
+    }
+  }
+
+  /**
+   * Traverses packet tree and returns first matching packet
+   * @param  {module:enums.packet} type The packet type
+   * @return {module:packet/packet|null}      
+   */
+  this.findPacket = function (type) {
+    var packetlist = this.filterByTag(type);
+    if (packetlist.length) {
+      return packetlist[0];
+    } else {
+      var found = null;
+      for (var i = 0; i < this.length; i++) {
+        if (this[i].packets.length) {
+          found = this[i].packets.findPacket(type);
+          if (found) return found;
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Returns array of found indices by tag
+   */
+  this.indexOfTag = function () {
+    var args = Array.prototype.slice.call(arguments);
+    var tagIndex = [];
+    var that = this;
+    for (var i = 0; i < this.length; i++) {
+      if (args.some(function(packetType) {return that[i].tag == packetType})) {
+        tagIndex.push(i);
+      }
+    }
+    return tagIndex;
+  }
+
+  /**
+   * Returns slice of packetlist
+   */
+  this.slice = function (begin, end) {
+    if (!end) {
+      end = this.length
+    }
+    var part = new packetlist();
+    for (var i = begin; i < end; i++) {
+      part.push(this[i]);
+    }
+    return part;
+  }
+
+  /**
+   * Concatenates packetlist or array of packets
+   */
+  this.concat = function (packetlist) {
+    if (packetlist) {
+      for (var i = 0; i < packetlist.length; i++) {
+        this.push(packetlist[i]);
+      }
+    }
+  }
+
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/pkcs1.html b/doc/pkcs1.html new file mode 100644 index 00000000..6b427486 --- /dev/null +++ b/doc/pkcs1.html @@ -0,0 +1,194 @@ + + + + + JSDoc: Module: crypto/pkcs1 + + + + + + + + + + +
+ +

Module: crypto/pkcs1

+ + + + + +
+ +
+

+ crypto/pkcs1 +

+ +
+ +
+
+ + + + +
PKCS1 encoding
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

<inner> hash_headers

+ + +
+
+ +
+ ASN1 object identifiers for hashes (See RFC4880 5.2.2) +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/pkcs1.js.html b/doc/pkcs1.js.html new file mode 100644 index 00000000..8a7734d2 --- /dev/null +++ b/doc/pkcs1.js.html @@ -0,0 +1,194 @@ + + + + + JSDoc: Source: crypto/pkcs1.js + + + + + + + + + + +
+ +

Source: crypto/pkcs1.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * PKCS1 encoding
+ * @requires crypto/crypto
+ * @requires crypto/hash
+ * @requires crypto/public_key/jsbn
+ * @requires crypto/random
+ * @requires util
+ * @module crypto/pkcs1
+ */
+
+/**
+ * ASN1 object identifiers for hashes (See RFC4880 5.2.2)
+ */
+hash_headers = new Array();
+hash_headers[1] = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04,
+    0x10
+];
+hash_headers[2] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14];
+hash_headers[3] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14];
+hash_headers[8] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
+    0x04, 0x20
+];
+hash_headers[9] = [0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00,
+    0x04, 0x30
+];
+hash_headers[10] = [0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+    0x00, 0x04, 0x40
+];
+hash_headers[11] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
+    0x00, 0x04, 0x1C
+];
+
+var crypto = require('./crypto.js'),
+  random = require('./random.js'),
+  util = require('../util'),
+  BigInteger = require('./public_key/jsbn.js'),
+  hash = require('./hash');
+
+module.exports = {
+  eme: {
+    /**
+     * create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1)
+     * @param {String} message message to be padded
+     * @param {Integer} length Length to the resulting message
+     * @return {String} EME-PKCS1 padded message
+     */
+    encode: function(message, length) {
+      if (message.length > length - 11)
+        return -1;
+      var result = "";
+      result += String.fromCharCode(0);
+      result += String.fromCharCode(2);
+      for (var i = 0; i < length - message.length - 3; i++) {
+        result += String.fromCharCode(random.getPseudoRandom(1, 255));
+      }
+      result += String.fromCharCode(0);
+      result += message;
+      return result;
+    },
+
+    /**
+     * decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2)
+     * @param {String} message EME-PKCS1 padded message
+     * @return {String} decoded message 
+     */
+    decode: function(message, len) {
+      if (message.length < len)
+        message = String.fromCharCode(0) + message;
+      if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2)
+        return -1;
+      var i = 2;
+      while (message.charCodeAt(i) != 0 && message.length > i)
+        i++;
+      return message.substring(i + 1, message.length);
+    }
+  },
+
+  emsa: {
+
+    /**
+     * create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3)
+     * @param {Integer} algo Hash algorithm type used
+     * @param {String} data Data to be hashed
+     * @param {Integer} keylength Key size of the public mpi in bytes
+     * @returns {String} Hashcode with pkcs1padding as string
+     */
+    encode: function(algo, data, keylength) {
+      var data2 = "";
+      data2 += String.fromCharCode(0x00);
+      data2 += String.fromCharCode(0x01);
+      for (var i = 0; i < (keylength - hash_headers[algo].length - 3 -
+        hash.getHashByteLength(algo)); i++)
+
+        data2 += String.fromCharCode(0xff);
+
+      data2 += String.fromCharCode(0x00);
+
+      for (var i = 0; i < hash_headers[algo].length; i++)
+        data2 += String.fromCharCode(hash_headers[algo][i]);
+
+      data2 += hash.digest(algo, data);
+      return new BigInteger(util.hexstrdump(data2), 16);
+    },
+
+    /**
+     * extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3) 
+     * @param {String} data Hash in pkcs1 encoding
+     * @returns {String} The hash as string
+     */
+    decode: function(algo, data) {
+      var i = 0;
+      if (data.charCodeAt(0) == 0) i++;
+      else if (data.charCodeAt(0) != 1) return -1;
+      else i++;
+
+      while (data.charCodeAt(i) == 0xFF) i++;
+      if (data.charCodeAt(i++) != 0) return -1;
+      var j = 0;
+      for (j = 0; j < hash_headers[algo].length && j + i < data.length; j++) {
+        if (data.charCodeAt(j + i) != hash_headers[algo][j]) return -1;
+      }
+      i += j;
+      if (data.substring(i).length < hash.getHashByteLength(algo)) return -1;
+      return data.substring(i);
+    }
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/public_key.html b/doc/public_key.html new file mode 100644 index 00000000..3a2d20cd --- /dev/null +++ b/doc/public_key.html @@ -0,0 +1,305 @@ + + + + + JSDoc: Module: crypto/public_key + + + + + + + + + + +
+ +

Module: crypto/public_key

+ + + + + +
+ +
+

+ crypto/public_key +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

<static> dsa

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> elgamal

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ + + +
+

<static> rsa

+ + +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + +
+ +
+ + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/public_key.js.html b/doc/public_key.js.html new file mode 100644 index 00000000..7c71f987 --- /dev/null +++ b/doc/public_key.js.html @@ -0,0 +1,237 @@ + + + + + JSDoc: Source: packet/public_key.js + + + + + + + + + + +
+ +

Source: packet/public_key.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the Key Material Packet (Tag 5,6,7,14)<br/>
+ * <br/>
+ * RFC4480 5.5:
+ * A key material packet contains all the information about a public or
+ * private key.  There are four variants of this packet type, and two
+ * major versions.  Consequently, this section is complex.
+ * @requires crypto
+ * @requires enums
+ * @requires type/keyid
+ * @requires type/mpi
+ * @requires util
+ * @module packet/public_key
+ */
+
+var util = require('../util'),
+  type_mpi = require('../type/mpi.js'),
+  type_keyid = require('../type/keyid.js'),
+  enums = require('../enums.js'),
+  crypto = require('../crypto');
+
+/**
+ * @constructor
+ */
+module.exports = function public_key() {
+  this.version = 4;
+  /** Key creation date.
+   * @type {Date} */
+  this.created = new Date();
+  /** A list of multiprecision integers
+   * @type {module:type/mpi} */
+  this.mpi = [];
+  /** Public key algorithm
+   * @type {module:enums.publicKey} */
+  this.algorithm = 'rsa_sign';
+  // time in days (V3 only)
+  this.expirationTimeV3 = 0;
+
+
+  /**
+   * Internal Parser for public keys as specified in RFC 4880 section 
+   * 5.5.2 Public-Key Packet Formats
+   * called by read_tag<num>
+   * @param {String} input Input string to read the packet from
+   * @return {Object} This object with attributes set by the parser
+   */
+  this.read = function (bytes) {
+    var pos = 0;
+    // A one-octet version number (3 or 4).
+    this.version = bytes.charCodeAt(pos++);
+
+    if (this.version == 3 || this.version == 4) {
+      // - A four-octet number denoting the time that the key was created.
+      this.created = util.readDate(bytes.substr(pos, 4));
+      pos += 4;
+
+      if (this.version == 3) {
+        // - A two-octet number denoting the time in days that this key is
+        //   valid.  If this number is zero, then it does not expire.
+        this.expirationTimeV3 = util.readNumber(bytes.substr(pos, 2));
+        pos += 2;
+      }
+
+      // - A one-octet number denoting the public-key algorithm of this key.
+      this.algorithm = enums.read(enums.publicKey, bytes.charCodeAt(pos++));
+
+      var mpicount = crypto.getPublicMpiCount(this.algorithm);
+      this.mpi = [];
+
+      var bmpi = bytes.substr(pos);
+      var p = 0;
+
+      for (var i = 0; i < mpicount && p < bmpi.length; i++) {
+
+        this.mpi[i] = new type_mpi();
+
+        p += this.mpi[i].read(bmpi.substr(p))
+
+        if (p > bmpi.length) {
+          throw new Error('Error reading MPI @:' + p);
+        }
+      }
+
+      return p + 6;
+    } else {
+      throw new Error('Version ' + version + ' of the key packet is unsupported.');
+    }
+  };
+
+  /**
+   * Alias of read()
+   * @function module:packet/public_key#readPublicKey
+   * @see module:packet/public_key#read
+   */
+  this.readPublicKey = this.read;
+
+  /**
+   * Same as write_private_key, but has less information because of 
+   * public key.
+   * @return {Object} {body: [string]OpenPGP packet body contents,
+   * header: [string] OpenPGP packet header, string: [string] header+body}
+   */
+  this.write = function () {
+    // Version
+    var result = String.fromCharCode(this.version);
+    result += util.writeDate(this.created);
+    if (this.version == 3) {
+      result += util.writeNumber(this.expirationTimeV3, 2);
+    }
+    result += String.fromCharCode(enums.write(enums.publicKey, this.algorithm));
+
+    var mpicount = crypto.getPublicMpiCount(this.algorithm);
+
+    for (var i = 0; i < mpicount; i++) {
+      result += this.mpi[i].write();
+    }
+
+    return result;
+  };
+
+  /**
+   * Alias of write()
+   * @function module:packet/public_key#writePublicKey
+   * @see module:packet/public_key#write
+   */
+  this.writePublicKey = this.write;
+
+  /**
+   * Write an old version packet - it's used by some of the internal routines.
+   */
+  this.writeOld = function () {
+    var bytes = this.writePublicKey();
+
+    return String.fromCharCode(0x99) +
+      util.writeNumber(bytes.length, 2) +
+      bytes;
+  };
+
+  /**
+   * Calculates the key id of the key 
+   * @return {String} A 8 byte key id
+   */
+  this.getKeyId = function () {
+    var keyid = new type_keyid();
+    if (this.version == 4) {
+      keyid.read(this.getFingerprint().substr(12, 8));
+    } else if (this.version == 3) {
+      keyid.read(this.mpi[0].write().substr(-8));
+    }
+    return keyid;
+  };
+
+  /**
+   * Calculates the fingerprint of the key
+   * @return {String} A string containing the fingerprint
+   */
+  this.getFingerprint = function () {
+    var toHash = '';
+    if (this.version == 4) {
+      toHash = this.writeOld();
+      return crypto.hash.sha1(toHash);
+    } else if (this.version == 3) {
+      var mpicount = crypto.getPublicMpiCount(this.algorithm);
+      for (var i = 0; i < mpicount; i++) {
+        toHash += this.mpi[i].toBytes();
+      }
+      return crypto.hash.md5(toHash)
+    }
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/public_key_.html b/doc/public_key_.html new file mode 100644 index 00000000..dd604703 --- /dev/null +++ b/doc/public_key_.html @@ -0,0 +1,1044 @@ + + + + + JSDoc: Module: packet/public_key + + + + + + + + + + +
+ +

Module: packet/public_key

+ + + + + +
+ +
+

+ packet/public_key +

+ +
+ +
+
+ + +
Implementation of the Key Material Packet (Tag 5,6,7,14)
+
+RFC4480 5.5: +A key material packet contains all the information about a public or +private key. There are four variants of this packet type, and two +major versions. Consequently, this section is complex.
+ + +
+

new (require("packet/public_key"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

algorithm :module:enums.publicKey

+ + +
+
+ +
+ Public key algorithm +
+ + + +
Type:
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

created :Date

+ + +
+
+ +
+ Key creation date. +
+ + + +
Type:
+
    +
  • + +Date + + +
  • +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

mpi :module:type/mpi

+ + +
+
+ +
+ A list of multiprecision integers +
+ + + +
Type:
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

getFingerprint() → {String}

+ + +
+
+ + +
+ Calculates the fingerprint of the key +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A string containing the fingerprint +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getKeyId() → {String}

+ + +
+
+ + +
+ Calculates the key id of the key +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A 8 byte key id +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(input) → {Object}

+ + +
+
+ + +
+ Internal Parser for public keys as specified in RFC 4880 section +5.5.2 Public-Key Packet Formats +called by read_tag<num> +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Input string to read the packet from
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ This object with attributes set by the parser +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

readPublicKey()

+ + +
+
+ + +
+ Alias of read() +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ + + +
+

write() → {Object}

+ + +
+
+ + +
+ Same as write_private_key, but has less information because of +public key. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ {body: [string]OpenPGP packet body contents, +header: [string] OpenPGP packet header, string: [string] header+body} +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

writeOld()

+ + +
+
+ + +
+ Write an old version packet - it's used by some of the internal routines. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

writePublicKey()

+ + +
+
+ + +
+ Alias of write() +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/public_key_encrypted_session_key.html b/doc/public_key_encrypted_session_key.html new file mode 100644 index 00000000..b5864e74 --- /dev/null +++ b/doc/public_key_encrypted_session_key.html @@ -0,0 +1,842 @@ + + + + + JSDoc: Module: packet/public_key_encrypted_session_key + + + + + + + + + + +
+ +

Module: packet/public_key_encrypted_session_key

+ + + + + +
+ +
+

+ packet/public_key_encrypted_session_key +

+ +
+ +
+
+ + +
Public-Key Encrypted Session Key Packets (Tag 1)
+
+RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key +used to encrypt a message. Zero or more Public-Key Encrypted Session Key +packets and/or Symmetric-Key Encrypted Session Key packets may precede a +Symmetrically Encrypted Data Packet, which holds an encrypted message. The +message is encrypted with the session key, and the session key is itself +encrypted and stored in the Encrypted Session Key packet(s). The +Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted +Session Key packet for each OpenPGP key to which the message is encrypted. +The recipient of the message finds a session key that is encrypted to their +public key, decrypts the session key, and then uses the session key to +decrypt the message.
+ + +
+

new (require("packet/public_key_encrypted_session_key"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

encrypted :Array.<module:type/mpi>

+ + +
+
+ + + +
Type:
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

decrypt(key) → {String}

+ + +
+
+ + +
+ Decrypts the session key (only for public key encrypted session key +packets (tag 1) +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + + +module:packet/secret_key + + + + Private key with secMPIs unlocked
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The unencrypted session key +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(input, position, len) → {module:packet/public_key_encrypted_session_key}

+ + +
+
+ + +
+ Parsing function for a publickey encrypted session key packet (tag 1). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Payload of a tag 1 packet
position + + +Integer + + + + Position to start reading from the input string
len + + +Integer + + + + Length of the packet or the remaining length of + input at position
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Object representation +
+ + + +
+
+ Type +
+
+ +module:packet/public_key_encrypted_session_key + + +
+
+ + + + +
+ + + +
+

write(publicKeyId, publicMPIs, pubalgo, symmalgo, sessionkey) → {String}

+ + +
+
+ + +
+ Create a string representation of a tag 1 packet +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
publicKeyId + + +String + + + + The public key id corresponding to publicMPIs key as string
publicMPIs + + +Array.<module:type/mpi> + + + + Multiprecision integer objects describing the public key
pubalgo + + +Integer + + + + The corresponding public key algorithm // See RFC4880 9.1
symmalgo + + +Integer + + + + The symmetric cipher algorithm used to encrypt the data + within an encrypteddatapacket or encryptedintegrity- + protecteddatapacket + following this packet //See RFC4880 9.2
sessionkey + + +String + + + + A string of randombytes representing the session key
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The string representation +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/public_key_encrypted_session_key.js.html b/doc/public_key_encrypted_session_key.js.html new file mode 100644 index 00000000..8f23c2da --- /dev/null +++ b/doc/public_key_encrypted_session_key.js.html @@ -0,0 +1,232 @@ + + + + + JSDoc: Source: packet/public_key_encrypted_session_key.js + + + + + + + + + + +
+ +

Source: packet/public_key_encrypted_session_key.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Public-Key Encrypted Session Key Packets (Tag 1)<br/>
+ * <br/>
+ * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
+ * used to encrypt a message. Zero or more Public-Key Encrypted Session Key
+ * packets and/or Symmetric-Key Encrypted Session Key packets may precede a
+ * Symmetrically Encrypted Data Packet, which holds an encrypted message. The
+ * message is encrypted with the session key, and the session key is itself
+ * encrypted and stored in the Encrypted Session Key packet(s). The
+ * Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
+ * Session Key packet for each OpenPGP key to which the message is encrypted.
+ * The recipient of the message finds a session key that is encrypted to their
+ * public key, decrypts the session key, and then uses the session key to
+ * decrypt the message.
+ * @requires crypto
+ * @requires enums
+ * @requires type/keyid
+ * @requires type/mpi
+ * @requires util
+ * @module packet/public_key_encrypted_session_key
+ */
+
+var type_keyid = require('../type/keyid.js'),
+  util = require('../util'),
+  type_mpi = require('../type/mpi.js'),
+  enums = require('../enums.js'),
+  crypto = require('../crypto');
+
+/**
+ * @constructor
+ */
+module.exports = function public_key_encrypted_session_key() {
+  this.version = 3;
+
+  this.publicKeyId = new type_keyid();
+  this.publicKeyAlgorithm = 'rsa_encrypt';
+
+  this.sessionKey = null;
+  this.sessionKeyAlgorithm = 'aes256';
+
+  /** @type {Array<module:type/mpi>} */
+  this.encrypted = [];
+
+  /**
+   * Parsing function for a publickey encrypted session key packet (tag 1).
+   * 
+   * @param {String} input Payload of a tag 1 packet
+   * @param {Integer} position Position to start reading from the input string
+   * @param {Integer} len Length of the packet or the remaining length of
+   *            input at position
+   * @return {module:packet/public_key_encrypted_session_key} Object representation
+   */
+  this.read = function (bytes) {
+
+    this.version = bytes.charCodeAt(0);
+    this.publicKeyId.read(bytes.substr(1));
+    this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(9));
+
+    var i = 10;
+
+    var integerCount = (function(algo) {
+      switch (algo) {
+        case 'rsa_encrypt':
+        case 'rsa_encrypt_sign':
+          return 1;
+
+        case 'elgamal':
+          return 2;
+
+        default:
+          throw new Error("Invalid algorithm.");
+      }
+    })(this.publicKeyAlgorithm);
+
+    this.encrypted = [];
+
+    for (var j = 0; j < integerCount; j++) {
+      var mpi = new type_mpi();
+      i += mpi.read(bytes.substr(i));
+      this.encrypted.push(mpi);
+    }
+  };
+
+  /**
+   * Create a string representation of a tag 1 packet
+   * 
+   * @param {String} publicKeyId
+   *             The public key id corresponding to publicMPIs key as string
+   * @param {Array<module:type/mpi>} publicMPIs
+   *            Multiprecision integer objects describing the public key
+   * @param {Integer} pubalgo
+   *            The corresponding public key algorithm // See RFC4880 9.1
+   * @param {Integer} symmalgo
+   *            The symmetric cipher algorithm used to encrypt the data 
+   *            within an encrypteddatapacket or encryptedintegrity-
+   *            protecteddatapacket 
+   *            following this packet //See RFC4880 9.2
+   * @param {String} sessionkey
+   *            A string of randombytes representing the session key
+   * @return {String} The string representation
+   */
+  this.write = function () {
+
+    var result = String.fromCharCode(this.version);
+    result += this.publicKeyId.write();
+    result += String.fromCharCode(
+      enums.write(enums.publicKey, this.publicKeyAlgorithm));
+
+    for (var i = 0; i < this.encrypted.length; i++) {
+      result += this.encrypted[i].write()
+    }
+
+    return result;
+  };
+
+  this.encrypt = function (key) {
+    var data = String.fromCharCode(
+      enums.write(enums.symmetric, this.sessionKeyAlgorithm));
+
+    data += this.sessionKey;
+    var checksum = util.calc_checksum(this.sessionKey);
+    data += util.writeNumber(checksum, 2);
+
+    var mpi = new type_mpi();
+    mpi.fromBytes(crypto.pkcs1.eme.encode(
+      data,
+      key.mpi[0].byteLength()));
+
+    this.encrypted = crypto.publicKeyEncrypt(
+      this.publicKeyAlgorithm,
+      key.mpi,
+      mpi);
+  };
+
+  /**
+   * Decrypts the session key (only for public key encrypted session key
+   * packets (tag 1)
+   * 
+   * @param {module:packet/secret_key} key
+   *            Private key with secMPIs unlocked
+   * @return {String} The unencrypted session key
+   */
+  this.decrypt = function (key) {
+    var result = crypto.publicKeyDecrypt(
+      this.publicKeyAlgorithm,
+      key.mpi,
+      this.encrypted).toBytes();
+
+    var checksum = util.readNumber(result.substr(result.length - 2));
+
+    var decoded = crypto.pkcs1.eme.decode(
+      result,
+      key.mpi[0].byteLength());
+
+    var key = decoded.substring(1, decoded.length - 2);
+
+    if (checksum != util.calc_checksum(key)) {
+      throw new Error('Checksum mismatch');
+    } else {
+      this.sessionKey = key;
+      this.sessionKeyAlgorithm =
+        enums.read(enums.symmetric, decoded.charCodeAt(0));
+    }
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/public_subkey.html b/doc/public_subkey.html new file mode 100644 index 00000000..47434920 --- /dev/null +++ b/doc/public_subkey.html @@ -0,0 +1,1079 @@ + + + + + JSDoc: Module: packet/public_subkey + + + + + + + + + + +
+ +

Module: packet/public_subkey

+ + + + + +
+ +
+

+ packet/public_subkey +

+ +
+ +
+
+ + + +
+

new (require("packet/public_subkey"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

algorithm :module:enums.publicKey

+ + +
+
+ +
+ Public key algorithm +
+ + + +
Type:
+ + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

created :Date

+ + +
+
+ +
+ Key creation date. +
+ + + +
Type:
+
    +
  • + +Date + + +
  • +
+ + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

mpi :module:type/mpi

+ + +
+
+ +
+ A list of multiprecision integers +
+ + + +
Type:
+ + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

getFingerprint() → {String}

+ + +
+
+ + +
+ Calculates the fingerprint of the key +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A string containing the fingerprint +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getKeyId() → {String}

+ + +
+
+ + +
+ Calculates the key id of the key +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A 8 byte key id +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(input) → {Object}

+ + +
+
+ + +
+ Internal Parser for public keys as specified in RFC 4880 section +5.5.2 Public-Key Packet Formats +called by read_tag<num> +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Input string to read the packet from
+ + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ This object with attributes set by the parser +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

readPublicKey()

+ + +
+
+ + +
+ Alias of read() +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ + + +
+

write() → {Object}

+ + +
+
+ + +
+ Same as write_private_key, but has less information because of +public key. +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ {body: [string]OpenPGP packet body contents, +header: [string] OpenPGP packet header, string: [string] header+body} +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + +
+ + + +
+

writeOld()

+ + +
+
+ + +
+ Write an old version packet - it's used by some of the internal routines. +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

writePublicKey()

+ + +
+
+ + +
+ Alias of write() +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/public_subkey.js.html b/doc/public_subkey.js.html new file mode 100644 index 00000000..95da9223 --- /dev/null +++ b/doc/public_subkey.js.html @@ -0,0 +1,81 @@ + + + + + JSDoc: Source: packet/public_subkey.js + + + + + + + + + + +
+ +

Source: packet/public_subkey.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @requires packet/public_key
+ * @module packet/public_subkey
+ */
+
+var publicKey = require('./public_key.js');
+
+/**
+ * @constructor
+ * @extends module:packet/public_key
+ */
+module.exports = function public_subkey() {
+  publicKey.call(this);
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/random.html b/doc/random.html new file mode 100644 index 00000000..c5543d9c --- /dev/null +++ b/doc/random.html @@ -0,0 +1,732 @@ + + + + + JSDoc: Module: crypto/random + + + + + + + + + + +
+ +

Module: crypto/random

+ + + + + +
+ +
+

+ crypto/random +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

<static> getPseudoRandom(from, to) → {Integer}

+ + +
+
+ + +
+ Return a pseudo-random number in the specified range +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
from + + +Integer + + + + Min of the random number
to + + +Integer + + + + Max of the random number (max 32bit)
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A pseudo random number +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ + + +
+

<static> getRandomBigInteger(bits) → {BigInteger}

+ + +
+
+ + +
+ Create a secure random big integer of bits length +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bits + + +Integer + + + + Bit length of the MPI to create
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Resulting big integer +
+ + + +
+
+ Type +
+
+ +BigInteger + + +
+
+ + + + +
+ + + +
+

<static> getRandomBytes(length) → {String}

+ + +
+
+ + +
+ Retrieve secure random byte string of the specified length +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
length + + +Integer + + + + Length in bytes to generate
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Random byte string +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> getSecureRandom(from, to) → {Integer}

+ + +
+
+ + +
+ Return a secure random number in the specified range +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
from + + +Integer + + + + Min of the random number
to + + +Integer + + + + Max of the random number (max 32bit)
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A secure random number +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/random.js.html b/doc/random.js.html new file mode 100644 index 00000000..bbe2c829 --- /dev/null +++ b/doc/random.js.html @@ -0,0 +1,159 @@ + + + + + JSDoc: Source: crypto/random.js + + + + + + + + + + +
+ +

Source: crypto/random.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+
+// The GPG4Browsers crypto interface
+
+/**
+ * @requires type/mpi
+ * @module crypto/random
+ */
+
+var type_mpi = require('../type/mpi.js');
+
+module.exports = {
+  /**
+   * Retrieve secure random byte string of the specified length
+   * @param {Integer} length Length in bytes to generate
+   * @return {String} Random byte string
+   */
+  getRandomBytes: function(length) {
+    var result = '';
+    for (var i = 0; i < length; i++) {
+      result += String.fromCharCode(this.getSecureRandomOctet());
+    }
+    return result;
+  },
+
+  /**
+   * Return a pseudo-random number in the specified range
+   * @param {Integer} from Min of the random number
+   * @param {Integer} to Max of the random number (max 32bit)
+   * @return {Integer} A pseudo random number
+   */
+  getPseudoRandom: function(from, to) {
+    return Math.round(Math.random() * (to - from)) + from;
+  },
+
+  /**
+   * Return a secure random number in the specified range
+   * @param {Integer} from Min of the random number
+   * @param {Integer} to Max of the random number (max 32bit)
+   * @return {Integer} A secure random number
+   */
+  getSecureRandom: function(from, to) {
+    var buf = new Uint32Array(1);
+    window.crypto.getRandomValues(buf);
+    var bits = ((to - from)).toString(2).length;
+    while ((buf[0] & (Math.pow(2, bits) - 1)) > (to - from))
+      window.crypto.getRandomValues(buf);
+    return from + (Math.abs(buf[0] & (Math.pow(2, bits) - 1)));
+  },
+
+  getSecureRandomOctet: function() {
+    var buf = new Uint32Array(1);
+    window.crypto.getRandomValues(buf);
+    return buf[0] & 0xFF;
+  },
+
+  /**
+   * Create a secure random big integer of bits length
+   * @param {Integer} bits Bit length of the MPI to create
+   * @return {BigInteger} Resulting big integer
+   */
+  getRandomBigInteger: function(bits) {
+    if (bits < 0) {
+      return null;
+    }
+    var numBytes = Math.floor((bits + 7) / 8);
+
+    var randomBits = this.getRandomBytes(numBytes);
+    if (bits % 8 > 0) {
+
+      randomBits = String.fromCharCode(
+      (Math.pow(2, bits % 8) - 1) &
+        randomBits.charCodeAt(0)) +
+        randomBits.substring(1);
+    }
+    var mpi = new type_mpi();
+    mpi.fromBytes(randomBits);
+    return mpi.toBigInteger();
+  },
+
+  getRandomBigIntegerInRange: function(min, max) {
+    if (max.compareTo(min) <= 0) {
+      return;
+    }
+
+    var range = max.subtract(min);
+    var r = this.getRandomBigInteger(range.bitLength());
+    while (r > range) {
+      r = this.getRandomBigInteger(range.bitLength());
+    }
+    return min.add(r);
+  }
+
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/ripe-md.html b/doc/ripe-md.html new file mode 100644 index 00000000..40e1b351 --- /dev/null +++ b/doc/ripe-md.html @@ -0,0 +1,120 @@ + + + + + JSDoc: Module: crypto/hash/ripe-md + + + + + + + + + + +
+ +

Module: crypto/hash/ripe-md

+ + + + + +
+ +
+

+ crypto/hash/ripe-md +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/ripe-md.js.html b/doc/ripe-md.js.html new file mode 100644 index 00000000..a9e5d17b --- /dev/null +++ b/doc/ripe-md.js.html @@ -0,0 +1,345 @@ + + + + + JSDoc: Source: crypto/hash/ripe-md.js + + + + + + + + + + +
+ +

Source: crypto/hash/ripe-md.js

+ + + + + +
+
+
/*
+ * CryptoMX Tools
+ * Copyright (C) 2004 - 2006 Derek Buitenhuis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/* Modified by Recurity Labs GmbH
+ */
+
+/**
+ * @module crypto/hash/ripe-md
+ */
+
+var RMDsize = 160;
+var X = new Array();
+
+function ROL(x, n) {
+  return new Number((x << n) | (x >>> (32 - n)));
+}
+
+function F(x, y, z) {
+  return new Number(x ^ y ^ z);
+}
+
+function G(x, y, z) {
+  return new Number((x & y) | (~x & z));
+}
+
+function H(x, y, z) {
+  return new Number((x | ~y) ^ z);
+}
+
+function I(x, y, z) {
+  return new Number((x & z) | (y & ~z));
+}
+
+function J(x, y, z) {
+  return new Number(x ^ (y | ~z));
+}
+
+function mixOneRound(a, b, c, d, e, x, s, roundNumber) {
+  switch (roundNumber) {
+    case 0:
+      a += F(b, c, d) + x + 0x00000000;
+      break;
+    case 1:
+      a += G(b, c, d) + x + 0x5a827999;
+      break;
+    case 2:
+      a += H(b, c, d) + x + 0x6ed9eba1;
+      break;
+    case 3:
+      a += I(b, c, d) + x + 0x8f1bbcdc;
+      break;
+    case 4:
+      a += J(b, c, d) + x + 0xa953fd4e;
+      break;
+    case 5:
+      a += J(b, c, d) + x + 0x50a28be6;
+      break;
+    case 6:
+      a += I(b, c, d) + x + 0x5c4dd124;
+      break;
+    case 7:
+      a += H(b, c, d) + x + 0x6d703ef3;
+      break;
+    case 8:
+      a += G(b, c, d) + x + 0x7a6d76e9;
+      break;
+    case 9:
+      a += F(b, c, d) + x + 0x00000000;
+      break;
+
+    default:
+      document.write("Bogus round number");
+      break;
+  }
+
+  a = ROL(a, s) + e;
+  c = ROL(c, 10);
+
+  a &= 0xffffffff;
+  b &= 0xffffffff;
+  c &= 0xffffffff;
+  d &= 0xffffffff;
+  e &= 0xffffffff;
+
+  var retBlock = new Array();
+  retBlock[0] = a;
+  retBlock[1] = b;
+  retBlock[2] = c;
+  retBlock[3] = d;
+  retBlock[4] = e;
+  retBlock[5] = x;
+  retBlock[6] = s;
+
+  return retBlock;
+}
+
+function MDinit(MDbuf) {
+  MDbuf[0] = 0x67452301;
+  MDbuf[1] = 0xefcdab89;
+  MDbuf[2] = 0x98badcfe;
+  MDbuf[3] = 0x10325476;
+  MDbuf[4] = 0xc3d2e1f0;
+}
+
+var ROLs = [
+  [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
+  [7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12],
+  [11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5],
+  [11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12],
+  [9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6],
+  [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6],
+  [9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11],
+  [9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5],
+  [15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8],
+  [8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11]
+];
+
+var indexes = [
+  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+  [7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8],
+  [3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12],
+  [1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2],
+  [4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13],
+  [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12],
+  [6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2],
+  [15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13],
+  [8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14],
+  [12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]
+];
+
+function compress(MDbuf, X) {
+  blockA = new Array();
+  blockB = new Array();
+
+  var retBlock;
+
+  for (var i = 0; i < 5; i++) {
+    blockA[i] = new Number(MDbuf[i]);
+    blockB[i] = new Number(MDbuf[i]);
+  }
+
+  var step = 0;
+  for (var j = 0; j < 5; j++) {
+    for (var i = 0; i < 16; i++) {
+      retBlock = mixOneRound(
+        blockA[(step + 0) % 5],
+        blockA[(step + 1) % 5],
+        blockA[(step + 2) % 5],
+        blockA[(step + 3) % 5],
+        blockA[(step + 4) % 5],
+        X[indexes[j][i]],
+        ROLs[j][i],
+        j);
+
+      blockA[(step + 0) % 5] = retBlock[0];
+      blockA[(step + 1) % 5] = retBlock[1];
+      blockA[(step + 2) % 5] = retBlock[2];
+      blockA[(step + 3) % 5] = retBlock[3];
+      blockA[(step + 4) % 5] = retBlock[4];
+
+      step += 4;
+    }
+  }
+
+  step = 0;
+  for (var j = 5; j < 10; j++) {
+    for (var i = 0; i < 16; i++) {
+      retBlock = mixOneRound(
+        blockB[(step + 0) % 5],
+        blockB[(step + 1) % 5],
+        blockB[(step + 2) % 5],
+        blockB[(step + 3) % 5],
+        blockB[(step + 4) % 5],
+        X[indexes[j][i]],
+        ROLs[j][i],
+        j);
+
+      blockB[(step + 0) % 5] = retBlock[0];
+      blockB[(step + 1) % 5] = retBlock[1];
+      blockB[(step + 2) % 5] = retBlock[2];
+      blockB[(step + 3) % 5] = retBlock[3];
+      blockB[(step + 4) % 5] = retBlock[4];
+
+      step += 4;
+    }
+  }
+
+  blockB[3] += blockA[2] + MDbuf[1];
+  MDbuf[1] = MDbuf[2] + blockA[3] + blockB[4];
+  MDbuf[2] = MDbuf[3] + blockA[4] + blockB[0];
+  MDbuf[3] = MDbuf[4] + blockA[0] + blockB[1];
+  MDbuf[4] = MDbuf[0] + blockA[1] + blockB[2];
+  MDbuf[0] = blockB[3];
+}
+
+function zeroX(X) {
+  for (var i = 0; i < 16; i++) {
+    X[i] = 0;
+  }
+}
+
+function MDfinish(MDbuf, strptr, lswlen, mswlen) {
+  var X = new Array(16);
+  zeroX(X);
+
+  var j = 0;
+  for (var i = 0; i < (lswlen & 63); i++) {
+    X[i >>> 2] ^= (strptr.charCodeAt(j++) & 255) << (8 * (i & 3));
+  }
+
+  X[(lswlen >>> 2) & 15] ^= 1 << (8 * (lswlen & 3) + 7);
+
+  if ((lswlen & 63) > 55) {
+    compress(MDbuf, X);
+    var X = new Array(16);
+    zeroX(X);
+  }
+
+  X[14] = lswlen << 3;
+  X[15] = (lswlen >>> 29) | (mswlen << 3);
+
+  compress(MDbuf, X);
+}
+
+function BYTES_TO_DWORD(fourChars) {
+  var tmp = (fourChars.charCodeAt(3) & 255) << 24;
+  tmp |= (fourChars.charCodeAt(2) & 255) << 16;
+  tmp |= (fourChars.charCodeAt(1) & 255) << 8;
+  tmp |= (fourChars.charCodeAt(0) & 255);
+
+  return tmp;
+}
+
+function RMD(message) {
+  var MDbuf = new Array(RMDsize / 32);
+  var hashcode = new Array(RMDsize / 8);
+  var length;
+  var nbytes;
+
+  MDinit(MDbuf);
+  length = message.length;
+
+  var X = new Array(16);
+  zeroX(X);
+
+  var j = 0;
+  for (var nbytes = length; nbytes > 63; nbytes -= 64) {
+    for (var i = 0; i < 16; i++) {
+      X[i] = BYTES_TO_DWORD(message.substr(j, 4));
+      j += 4;
+    }
+    compress(MDbuf, X);
+  }
+
+  MDfinish(MDbuf, message.substr(j), length, 0);
+
+  for (var i = 0; i < RMDsize / 8; i += 4) {
+    hashcode[i] = MDbuf[i >>> 2] & 255;
+    hashcode[i + 1] = (MDbuf[i >>> 2] >>> 8) & 255;
+    hashcode[i + 2] = (MDbuf[i >>> 2] >>> 16) & 255;
+    hashcode[i + 3] = (MDbuf[i >>> 2] >>> 24) & 255;
+  }
+
+  return hashcode;
+}
+
+
+function RMDstring(message) {
+  var hashcode = RMD(message);
+  var retString = "";
+
+  for (var i = 0; i < RMDsize / 8; i++) {
+    retString += String.fromCharCode(hashcode[i]);
+  }
+
+  return retString;
+}
+
+module.exports = RMDstring;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/rsa.html b/doc/rsa.html new file mode 100644 index 00000000..e71cdc92 --- /dev/null +++ b/doc/rsa.html @@ -0,0 +1,130 @@ + + + + + JSDoc: Module: crypto/public_key/rsa + + + + + + + + + + +
+ +

Module: crypto/public_key/rsa

+ + + + + +
+ +
+

+ crypto/public_key/rsa +

+ +
+ + + +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/rsa.js.html b/doc/rsa.js.html index 78ffbd27..08b16e34 100644 --- a/doc/rsa.js.html +++ b/doc/rsa.js.html @@ -2,7 +2,7 @@ - JSDoc: Source: ciphers/asymmetric/rsa.js + JSDoc: Source: crypto/public_key/rsa.js @@ -17,7 +17,7 @@
-

Source: ciphers/asymmetric/rsa.js

+

Source: crypto/public_key/rsa.js

@@ -44,122 +44,139 @@ // // RSA implementation -function SecureRandom(){ - function nextBytes(byteArray){ - for(var n = 0; n < byteArray.length;n++){ - byteArray[n] = openpgp_crypto_getSecureRandomOctet(); - } +/** + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/public_key/rsa + */ + +var BigInteger = require('./jsbn.js'), + util = require('../../util'), + random = require('../random.js'); + +function SecureRandom() { + function nextBytes(byteArray) { + for (var n = 0; n < byteArray.length; n++) { + byteArray[n] = random.getSecureRandomOctet(); } - this.nextBytes = nextBytes; + } + this.nextBytes = nextBytes; } function RSA() { - /** - * This function uses jsbn Big Num library to decrypt RSA - * @param m - * message - * @param d - * RSA d as BigInteger - * @param p - * RSA p as BigInteger - * @param q - * RSA q as BigInteger - * @param u - * RSA u as BigInteger - * @return {BigInteger} The decrypted value of the message - */ - function decrypt(m, d, p, q, u) { - var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); - var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); - util.print_debug("rsa.js decrypt\nxpn:"+util.hexstrdump(xp.toMPI())+"\nxqn:"+util.hexstrdump(xq.toMPI())); + /** + * This function uses jsbn Big Num library to decrypt RSA + * @param m + * message + * @param d + * RSA d as BigInteger + * @param p + * RSA p as BigInteger + * @param q + * RSA q as BigInteger + * @param u + * RSA u as BigInteger + * @return {BigInteger} The decrypted value of the message + */ + function decrypt(m, d, p, q, u) { + var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); + var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); + util.print_debug("rsa.js decrypt\nxpn:" + util.hexstrdump(xp.toMPI()) + "\nxqn:" + util.hexstrdump(xq.toMPI())); - var t = xq.subtract(xp); - if (t[0] == 0) { - t = xp.subtract(xq); - t = t.multiply(u).mod(q); - t = q.subtract(t); - } else { - t = t.multiply(u).mod(q); - } - return t.multiply(p).add(xp); - } - - /** - * encrypt message - * @param m message as BigInteger - * @param e public MPI part as BigInteger - * @param n public MPI part as BigInteger - * @return BigInteger - */ - function encrypt(m,e,n) { - return m.modPowInt(e, n); - } - - /* Sign and Verify */ - function sign(m,d,n) { - return m.modPow(d, n); - } - - function verify(x,e,n) { - return x.modPowInt(e, n); - } - - // "empty" RSA key constructor - function keyObject() { - this.n = null; - this.e = 0; - this.ee = null; - this.d = null; - this.p = null; - this.q = null; - this.dmp1 = null; - this.dmq1 = null; - this.u = null; + var t = xq.subtract(xp); + if (t[0] == 0) { + t = xp.subtract(xq); + t = t.multiply(u).mod(q); + t = q.subtract(t); + } else { + t = t.multiply(u).mod(q); } - - // Generate a new random private key B bits long, using public expt E - function generate(B,E) { - var key = new keyObject(); - var rng = new SecureRandom(); - var qs = B>>1; - key.e = parseInt(E,16); - key.ee = new BigInteger(E,16); - for(;;) { - for(;;) { - key.p = new BigInteger(B-qs,1,rng); - if(key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) break; - } - for(;;) { - key.q = new BigInteger(qs,1,rng); - if(key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) break; - } - if(key.p.compareTo(key.q) <= 0) { - var t = key.p; - key.p = key.q; - key.q = t; - } - var p1 = key.p.subtract(BigInteger.ONE); - var q1 = key.q.subtract(BigInteger.ONE); - var phi = p1.multiply(q1); - if(phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) { - key.n = key.p.multiply(key.q); - key.d = key.ee.modInverse(phi); - key.dmp1 = key.d.mod(p1); - key.dmq1 = key.d.mod(q1); - key.u = key.p.modInverse(key.q); - break; - } - } - return key; + return t.multiply(p).add(xp); + } + + /** + * encrypt message + * @param m message as BigInteger + * @param e public MPI part as BigInteger + * @param n public MPI part as BigInteger + * @return BigInteger + */ + function encrypt(m, e, n) { + return m.modPowInt(e, n); + } + + /* Sign and Verify */ + function sign(m, d, n) { + return m.modPow(d, n); + } + + function verify(x, e, n) { + return x.modPowInt(e, n); + } + + // "empty" RSA key constructor + + function keyObject() { + this.n = null; + this.e = 0; + this.ee = null; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.u = null; + } + + // Generate a new random private key B bits long, using public expt E + + function generate(B, E) { + var key = new keyObject(); + var rng = new SecureRandom(); + var qs = B >> 1; + key.e = parseInt(E, 16); + key.ee = new BigInteger(E, 16); + for (;;) { + for (;;) { + key.p = new BigInteger(B - qs, 1, rng); + if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) + break; + } + for (;;) { + key.q = new BigInteger(qs, 1, rng); + if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) + break; + } + if (key.p.compareTo(key.q) <= 0) { + var t = key.p; + key.p = key.q; + key.q = t; + } + var p1 = key.p.subtract(BigInteger.ONE); + var q1 = key.q.subtract(BigInteger.ONE); + var phi = p1.multiply(q1); + if (phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) { + key.n = key.p.multiply(key.q); + key.d = key.ee.modInverse(phi); + key.dmp1 = key.d.mod(p1); + key.dmq1 = key.d.mod(q1); + key.u = key.p.modInverse(key.q); + break; + } } - - this.encrypt = encrypt; - this.decrypt = decrypt; - this.verify = verify; - this.sign = sign; - this.generate = generate; - this.keyObject = keyObject; + return key; + } + + this.encrypt = encrypt; + this.decrypt = decrypt; + this.verify = verify; + this.sign = sign; + this.generate = generate; + this.keyObject = keyObject; } + +module.exports = RSA; @@ -170,15 +187,16 @@ function RSA() {

- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:40 GMT+0200 (CEST) + Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST)
+ diff --git a/doc/s2k.html b/doc/s2k.html new file mode 100644 index 00000000..dc10b2d5 --- /dev/null +++ b/doc/s2k.html @@ -0,0 +1,767 @@ + + + + + JSDoc: Module: type/s2k + + + + + + + + + + +
+ +

Module: type/s2k

+ + + + + +
+ +
+

+ type/s2k +

+ +
+ +
+
+ + +
Implementation of the String-to-key specifier (RFC4880 3.7)
+
+String-to-key (S2K) specifiers are used to convert passphrase strings +into symmetric-key encryption/decryption keys. They are used in two +places, currently: to encrypt the secret part of private keys in the +private keyring, and to convert passphrases to encryption keys for +symmetrically encrypted messages.
+ + +
+

new (require("type/s2k"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

algorithm :module:enums.hash

+ + +
+
+ + + +
Type:
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

salt :String

+ + +
+
+ +
+ Eight bytes of salt in a binary string. +
+ + + +
Type:
+
    +
  • + +String + + +
  • +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

type :module:enums.s2k

+ + +
+
+ + + +
Type:
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

produce_key(passphrase) → {String}

+ + +
+
+ + +
+ Produces a key using the specified passphrase and the defined +hashAlgorithm +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
passphrase + + +String + + + + Passphrase containing user input
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Produced key with a length corresponding to +hashAlgorithm hash length +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(input) → {Integer}

+ + +
+
+ + +
+ Parsing function for a string-to-key specifier (RFC 4880 3.7). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Payload of string-to-key specifier
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Actual length of the object +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ writes an s2k hash based on the inputs. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Produced key of hashAlgorithm hash length +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:45 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/s2k.js.html b/doc/s2k.js.html new file mode 100644 index 00000000..a3117f95 --- /dev/null +++ b/doc/s2k.js.html @@ -0,0 +1,230 @@ + + + + + JSDoc: Source: type/s2k.js + + + + + + + + + + +
+ +

Source: type/s2k.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the String-to-key specifier (RFC4880 3.7)<br/>
+ * <br/>
+ * String-to-key (S2K) specifiers are used to convert passphrase strings
+ * into symmetric-key encryption/decryption keys.  They are used in two
+ * places, currently: to encrypt the secret part of private keys in the
+ * private keyring, and to convert passphrases to encryption keys for
+ * symmetrically encrypted messages.
+ * @requires crypto
+ * @requires enums
+ * @requires util
+ * @module type/s2k
+ */
+
+var enums = require('../enums.js'),
+  util = require('../util'),
+  crypto = require('../crypto');
+
+/**
+ * @constructor
+ */
+module.exports = function s2k() {
+  /** @type {module:enums.hash} */
+  this.algorithm = 'sha256';
+  /** @type {module:enums.s2k} */
+  this.type = 'iterated';
+  this.c = 96;
+  /** Eight bytes of salt in a binary string.
+   * @type {String}
+   */
+  this.salt = crypto.random.getRandomBytes(8);
+
+
+  // Exponent bias, defined in RFC4880
+  var expbias = 6;
+
+  this.get_count = function () {
+    return (16 + (this.c & 15)) << ((this.c >> 4) + expbias);
+  };
+
+  /**
+   * Parsing function for a string-to-key specifier (RFC 4880 3.7).
+   * @param {String} input Payload of string-to-key specifier
+   * @return {Integer} Actual length of the object
+   */
+  this.read = function (bytes) {
+    var i = 0;
+    this.type = enums.read(enums.s2k, bytes.charCodeAt(i++));
+    this.algorithm = enums.read(enums.hash, bytes.charCodeAt(i++));
+
+    switch (this.type) {
+      case 'simple':
+        break;
+
+      case 'salted':
+        this.salt = bytes.substr(i, 8);
+        i += 8;
+        break;
+
+      case 'iterated':
+        this.salt = bytes.substr(i, 8);
+        i += 8;
+
+        // Octet 10: count, a one-octet, coded value
+        this.c = bytes.charCodeAt(i++);
+        break;
+
+      case 'gnu':
+        if (bytes.substr(i, 3) == "GNU") {
+          i += 3; // GNU
+          var gnuExtType = 1000 + bytes.charCodeAt(i++);
+          if (gnuExtType == 1001) {
+            this.type = gnuExtType;
+            // GnuPG extension mode 1001 -- don't write secret key at all
+          } else {
+            throw new Error("Unknown s2k gnu protection mode.");
+          }
+        } else {
+          throw new Error("Unknown s2k type.");
+        }
+        break;
+
+      default:
+        throw new Error("Unknown s2k type.");
+        break;
+    }
+
+    return i;
+  };
+
+
+  /**
+   * writes an s2k hash based on the inputs.
+   * @return {String} Produced key of hashAlgorithm hash length
+   */
+  this.write = function () {
+    var bytes = String.fromCharCode(enums.write(enums.s2k, this.type));
+    bytes += String.fromCharCode(enums.write(enums.hash, this.algorithm));
+
+    switch (this.type) {
+      case 'simple':
+        break;
+      case 'salted':
+        bytes += this.salt;
+        break;
+      case 'iterated':
+        bytes += this.salt;
+        bytes += String.fromCharCode(this.c);
+        break;
+    }
+
+    return bytes;
+  };
+
+  /**
+   * Produces a key using the specified passphrase and the defined 
+   * hashAlgorithm 
+   * @param {String} passphrase Passphrase containing user input
+   * @return {String} Produced key with a length corresponding to 
+   * hashAlgorithm hash length
+   */
+  this.produce_key = function (passphrase, numBytes) {
+    passphrase = util.encode_utf8(passphrase);
+
+    function round(prefix, s2k) {
+      var algorithm = enums.write(enums.hash, s2k.algorithm);
+
+      switch (s2k.type) {
+        case 'simple':
+          return crypto.hash.digest(algorithm, prefix + passphrase);
+
+        case 'salted':
+          return crypto.hash.digest(algorithm,
+            prefix + s2k.salt + passphrase);
+
+        case 'iterated':
+          var isp = [],
+            count = s2k.get_count();
+          data = s2k.salt + passphrase;
+
+          while (isp.length * data.length < count)
+            isp.push(data);
+
+          isp = isp.join('');
+
+          if (isp.length > count)
+            isp = isp.substr(0, count);
+
+          return crypto.hash.digest(algorithm, prefix + isp);
+      }
+    }
+
+    var result = '',
+      prefix = '';
+
+    while (result.length <= numBytes) {
+      result += round(prefix, this);
+      prefix += String.fromCharCode(0);
+    }
+
+    return result.substr(0, numBytes);
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/scripts/linenumber.js b/doc/scripts/linenumber.js new file mode 100644 index 00000000..a0c570d5 --- /dev/null +++ b/doc/scripts/linenumber.js @@ -0,0 +1,17 @@ +(function() { + var counter = 0; + var numbered; + var source = document.getElementsByClassName('prettyprint source'); + + if (source && source[0]) { + source = source[0].getElementsByTagName('code')[0]; + + numbered = source.innerHTML.split('\n'); + numbered = numbered.map(function(item) { + counter++; + return '' + item; + }); + + source.innerHTML = numbered.join('\n'); + } +})(); diff --git a/doc/secret_key.html b/doc/secret_key.html new file mode 100644 index 00000000..59857a24 --- /dev/null +++ b/doc/secret_key.html @@ -0,0 +1,1250 @@ + + + + + JSDoc: Module: packet/secret_key + + + + + + + + + + +
+ +

Module: packet/secret_key

+ + + + + +
+ +
+

+ packet/secret_key +

+ +
+ +
+
+ + +
Implementation of the Key Material Packet (Tag 5,6,7,14)
+
+RFC4480 5.5: +A key material packet contains all the information about a public or +private key. There are four variants of this packet type, and two +major versions. Consequently, this section is complex.
+ + +
+

new (require("packet/secret_key"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

algorithm :module:enums.publicKey

+ + +
+
+ +
+ Public key algorithm +
+ + + +
Type:
+ + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

created :Date

+ + +
+
+ +
+ Key creation date. +
+ + + +
Type:
+
    +
  • + +Date + + +
  • +
+ + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

decrypt(str_passphrase) → {Boolean}

+ + +
+
+ + +
+ Decrypts the private key MPIs which are needed to use the key. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str_passphrase + + +String + + + + The passphrase for this private key +as string
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ True if the passphrase was correct or MPI already + decrypted; false if not +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

encrypt(passphrase)

+ + +
+
+ + +
+ Encrypt the payload. By default, we use aes256 and iterated, salted string +to key specifier +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
passphrase + + +String + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

getFingerprint() → {String}

+ + +
+
+ + +
+ Calculates the fingerprint of the key +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A string containing the fingerprint +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getKeyId() → {String}

+ + +
+
+ + +
+ Calculates the key id of the key +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A 8 byte key id +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(bytes)

+ + +
+
+ + +
+ Internal parser for private keys as specified in RFC 4880 section 5.5.3 +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bytes + + +String + + + + Input string to read the packet from
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

readPublicKey()

+ + +
+
+ + +
+ Alias of read() +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ Creates an OpenPGP key packet for the given key. +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A string of bytes containing the secret key OpenPGP packet +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

writeOld()

+ + +
+
+ + +
+ Write an old version packet - it's used by some of the internal routines. +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

writePublicKey()

+ + +
+
+ + +
+ Alias of write() +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/secret_key.js.html b/doc/secret_key.js.html new file mode 100644 index 00000000..9dd5a367 --- /dev/null +++ b/doc/secret_key.js.html @@ -0,0 +1,316 @@ + + + + + JSDoc: Source: packet/secret_key.js + + + + + + + + + + +
+ +

Source: packet/secret_key.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the Key Material Packet (Tag 5,6,7,14)<br/>
+ * <br/>
+ * RFC4480 5.5:
+ * A key material packet contains all the information about a public or
+ * private key.  There are four variants of this packet type, and two
+ * major versions.  Consequently, this section is complex.
+ * @requires crypto
+ * @requires enums
+ * @requires packet/public_key
+ * @requires type/mpi
+ * @requires type/s2k
+ * @requires util
+ * @module packet/secret_key
+ */
+
+var publicKey = require('./public_key.js'),
+  enums = require('../enums.js'),
+  util = require('../util'),
+  crypto = require('../crypto'),
+  type_mpi = require('../type/mpi.js'),
+  type_s2k = require('../type/s2k.js');
+
+/**
+ * @constructor
+ * @extends module:packet/public_key
+ */
+module.exports = function secret_key() {
+  publicKey.call(this);
+  // encrypted secret-key data
+  this.encrypted = null;
+  // indicator if secret-key data is available in decrypted form
+  this.isDecrypted = false;
+
+
+  function get_hash_len(hash) {
+    if (hash == 'sha1')
+      return 20;
+    else
+      return 2;
+  }
+
+  function get_hash_fn(hash) {
+    if (hash == 'sha1')
+      return crypto.hash.sha1;
+    else
+      return function(c) {
+        return util.writeNumber(util.calc_checksum(c), 2);
+    };
+  }
+
+  // Helper function
+
+  function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
+    var hashlen = get_hash_len(hash_algorithm),
+      hashfn = get_hash_fn(hash_algorithm);
+
+    var hashtext = cleartext.substr(cleartext.length - hashlen);
+    cleartext = cleartext.substr(0, cleartext.length - hashlen);
+
+    var hash = hashfn(cleartext);
+
+    if (hash != hashtext)
+      return new Error("Hash mismatch.");
+
+    var mpis = crypto.getPrivateMpiCount(algorithm);
+
+    var j = 0;
+    var mpi = [];
+
+    for (var i = 0; i < mpis && j < cleartext.length; i++) {
+      mpi[i] = new type_mpi();
+      j += mpi[i].read(cleartext.substr(j));
+    }
+
+    return mpi;
+  }
+
+  function write_cleartext_mpi(hash_algorithm, algorithm, mpi) {
+    var bytes = '';
+    var discard = crypto.getPublicMpiCount(algorithm);
+
+    for (var i = discard; i < mpi.length; i++) {
+      bytes += mpi[i].write();
+    }
+
+
+    bytes += get_hash_fn(hash_algorithm)(bytes);
+
+    return bytes;
+  }
+
+
+  // 5.5.3.  Secret-Key Packet Formats
+
+  /**
+   * Internal parser for private keys as specified in RFC 4880 section 5.5.3
+   * @param {String} bytes Input string to read the packet from
+   */
+  this.read = function (bytes) {
+    // - A Public-Key or Public-Subkey packet, as described above.
+    var len = this.readPublicKey(bytes);
+
+    bytes = bytes.substr(len);
+
+
+    // - One octet indicating string-to-key usage conventions.  Zero
+    //   indicates that the secret-key data is not encrypted.  255 or 254
+    //   indicates that a string-to-key specifier is being given.  Any
+    //   other value is a symmetric-key encryption algorithm identifier.
+    var isEncrypted = bytes.charCodeAt(0);
+
+    if (isEncrypted) {
+      this.encrypted = bytes;
+    } else {
+
+      // - Plain or encrypted multiprecision integers comprising the secret
+      //   key data.  These algorithm-specific fields are as described
+      //   below.
+      var parsedMPI = parse_cleartext_mpi('mod', bytes.substr(1), this.algorithm);
+      if (parsedMPI instanceof Error)
+        throw parsedMPI;
+      this.mpi = this.mpi.concat(parsedMPI);
+      this.isDecrypted = true;
+    }
+
+  };
+
+  /** Creates an OpenPGP key packet for the given key.
+    * @return {String} A string of bytes containing the secret key OpenPGP packet
+    */
+  this.write = function () {
+    var bytes = this.writePublicKey();
+
+    if (!this.encrypted) {
+      bytes += String.fromCharCode(0);
+
+      bytes += write_cleartext_mpi('mod', this.algorithm, this.mpi);
+    } else {
+      bytes += this.encrypted;
+    }
+
+    return bytes;
+  };
+
+
+
+
+  /** Encrypt the payload. By default, we use aes256 and iterated, salted string
+   * to key specifier
+   * @param {String} passphrase
+   */
+  this.encrypt = function (passphrase) {
+
+    var s2k = new type_s2k(),
+      symmetric = 'aes256',
+      cleartext = write_cleartext_mpi('sha1', this.algorithm, this.mpi),
+      key = produceEncryptionKey(s2k, passphrase, symmetric),
+      blockLen = crypto.cipher[symmetric].blockSize,
+      iv = crypto.random.getRandomBytes(blockLen);
+
+
+    this.encrypted = '';
+    this.encrypted += String.fromCharCode(254);
+    this.encrypted += String.fromCharCode(enums.write(enums.symmetric, symmetric));
+    this.encrypted += s2k.write();
+    this.encrypted += iv;
+
+    this.encrypted += crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv);
+  };
+
+  function produceEncryptionKey(s2k, passphrase, algorithm) {
+    return s2k.produce_key(passphrase,
+      crypto.cipher[algorithm].keySize);
+  }
+
+  /**
+   * Decrypts the private key MPIs which are needed to use the key.
+   * @link module:packet/secret_key.isDecrypted should be
+   * false otherwise a call to this function is not needed
+   * 
+   * @param {String} str_passphrase The passphrase for this private key 
+   * as string
+   * @return {Boolean} True if the passphrase was correct or MPI already
+   *                   decrypted; false if not
+   */
+  this.decrypt = function (passphrase) {
+    if (this.isDecrypted)
+      return true;
+
+    var i = 0,
+      symmetric,
+      key;
+
+    var s2k_usage = this.encrypted.charCodeAt(i++);
+
+    // - [Optional] If string-to-key usage octet was 255 or 254, a one-
+    //   octet symmetric encryption algorithm.
+    if (s2k_usage == 255 || s2k_usage == 254) {
+      symmetric = this.encrypted.charCodeAt(i++);
+      symmetric = enums.read(enums.symmetric, symmetric);
+
+      // - [Optional] If string-to-key usage octet was 255 or 254, a
+      //   string-to-key specifier.  The length of the string-to-key
+      //   specifier is implied by its type, as described above.
+      var s2k = new type_s2k();
+      i += s2k.read(this.encrypted.substr(i));
+
+      key = produceEncryptionKey(s2k, passphrase, symmetric);
+    } else {
+      symmetric = s2k_usage;
+      symmetric = enums.read(enums.symmetric, symmetric);
+      key = crypto.hash.md5(passphrase);
+    }
+
+
+    // - [Optional] If secret data is encrypted (string-to-key usage octet
+    //   not zero), an Initial Vector (IV) of the same length as the
+    //   cipher's block size.
+    var iv = this.encrypted.substr(i,
+      crypto.cipher[symmetric].blockSize);
+
+    i += iv.length;
+
+    var cleartext,
+      ciphertext = this.encrypted.substr(i);
+
+    cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv);
+
+    var hash = s2k_usage == 254 ?
+      'sha1' :
+      'mod';
+
+    var parsedMPI = parse_cleartext_mpi(hash, cleartext, this.algorithm);
+    if (parsedMPI instanceof Error)
+      return false;
+    this.mpi = this.mpi.concat(parsedMPI);
+    this.isDecrypted = true;
+    return true;
+  };
+
+  this.generate = function (bits) {
+    this.mpi = crypto.generateMpi(this.algorithm, bits);
+    this.isDecrypted = true;
+  };
+
+}
+
+module.exports.prototype = new publicKey();
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/secret_subkey.html b/doc/secret_subkey.html new file mode 100644 index 00000000..4bbb38ec --- /dev/null +++ b/doc/secret_subkey.html @@ -0,0 +1,1253 @@ + + + + + JSDoc: Module: packet/secret_subkey + + + + + + + + + + +
+ +

Module: packet/secret_subkey

+ + + + + +
+ +
+

+ packet/secret_subkey +

+ +
+ +
+
+ + + +
+

new (require("packet/secret_subkey"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

algorithm :module:enums.publicKey

+ + +
+
+ +
+ Public key algorithm +
+ + + +
Type:
+ + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

created :Date

+ + +
+
+ +
+ Key creation date. +
+ + + +
Type:
+
    +
  • + +Date + + +
  • +
+ + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

decrypt(str_passphrase) → {Boolean}

+ + +
+
+ + +
+ Decrypts the private key MPIs which are needed to use the key. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str_passphrase + + +String + + + + The passphrase for this private key +as string
+ + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ True if the passphrase was correct or MPI already + decrypted; false if not +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

encrypt(passphrase)

+ + +
+
+ + +
+ Encrypt the payload. By default, we use aes256 and iterated, salted string +to key specifier +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
passphrase + + +String + + + +
+ + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

getFingerprint() → {String}

+ + +
+
+ + +
+ Calculates the fingerprint of the key +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A string containing the fingerprint +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

getKeyId() → {String}

+ + +
+
+ + +
+ Calculates the key id of the key +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A 8 byte key id +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(bytes)

+ + +
+
+ + +
+ Internal parser for private keys as specified in RFC 4880 section 5.5.3 +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bytes + + +String + + + + Input string to read the packet from
+ + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

readPublicKey()

+ + +
+
+ + +
+ Alias of read() +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ Creates an OpenPGP key packet for the given key. +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A string of bytes containing the secret key OpenPGP packet +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

writeOld()

+ + +
+
+ + +
+ Write an old version packet - it's used by some of the internal routines. +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

writePublicKey()

+ + +
+
+ + +
+ Alias of write() +
+ + + + + + + + + +
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/secret_subkey.js.html b/doc/secret_subkey.js.html new file mode 100644 index 00000000..ed2be443 --- /dev/null +++ b/doc/secret_subkey.js.html @@ -0,0 +1,81 @@ + + + + + JSDoc: Source: packet/secret_subkey.js + + + + + + + + + + +
+ +

Source: packet/secret_subkey.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @requires packet/secret_key
+ * @module packet/secret_subkey
+ */
+
+var secretKey = require('./secret_key.js');
+
+/**
+ * @constructor
+ * @extends module:packet/secret_key
+ */
+module.exports = function secret_subkey() {
+  secretKey.call(this);
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/sha.html b/doc/sha.html new file mode 100644 index 00000000..820eddea --- /dev/null +++ b/doc/sha.html @@ -0,0 +1,469 @@ + + + + + JSDoc: Module: crypto/hash/sha + + + + + + + + + + +
+ +

Module: crypto/hash/sha

+ + + + + +
+ +
+

+ crypto/hash/sha +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

<static> sha1()

+ + +
+
+ + +
+ SHA1 hash +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

<static> sha224()

+ + +
+
+ + +
+ SHA224 hash +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

<static> sha256()

+ + +
+
+ + +
+ SHA256 hash +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

<static> sha384()

+ + +
+
+ + +
+ SHA384 hash +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

<static> sha512()

+ + +
+
+ + +
+ SHA512 hash +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/sha.js.html b/doc/sha.js.html new file mode 100644 index 00000000..1a78a0d6 --- /dev/null +++ b/doc/sha.js.html @@ -0,0 +1,1175 @@ + + + + + JSDoc: Source: crypto/hash/sha.js + + + + + + + + + + +
+ +

Source: crypto/hash/sha.js

+ + + + + +
+
+
/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS 
+ * PUB 180-2 as well as the corresponding HMAC implementation as defined in
+ * FIPS PUB 198a
+ *
+ * Version 1.3 Copyright Brian Turek 2008-2010
+ * Distributed under the BSD License
+ * See http://jssha.sourceforge.net/ for more information
+ *
+ * Several functions taken from Paul Johnson
+ */
+
+/* Modified by Recurity Labs GmbH
+ * 
+ * This code has been slightly modified direct string output:
+ * - bin2bstr has been added
+ * - following wrappers of this library have been added:
+ *   - str_sha1
+ *   - str_sha256
+ *   - str_sha224
+ *   - str_sha384
+ *   - str_sha512
+ */
+
+/**
+ * @module crypto/hash/sha
+ */
+
+var jsSHA = (function() {
+
+  /*
+   * Configurable variables. Defaults typically work
+   */
+  /* Number of Bits Per character (8 for ASCII, 16 for Unicode) */
+  var charSize = 8,
+    /* base-64 pad character. "=" for strict RFC compliance */
+    b64pad = "",
+    /* hex output format. 0 - lowercase; 1 - uppercase */
+    hexCase = 0,
+
+    /*
+     * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number
+     *
+     * @constructor
+     * @param {Number} msint_32 The most significant 32-bits of a 64-bit number
+     * @param {Number} lsint_32 The least significant 32-bits of a 64-bit number
+     */
+    Int_64 = function(msint_32, lsint_32) {
+      this.highOrder = msint_32;
+      this.lowOrder = lsint_32;
+    },
+
+    /*
+     * Convert a string to an array of big-endian words
+     * If charSize is ASCII, characters >255 have their hi-byte silently
+     * ignored.
+     *
+     * @param {String} str String to be converted to binary representation
+     * @return Integer array representation of the parameter
+     */
+    str2binb = function(str) {
+      var bin = [],
+        mask = (1 << charSize) - 1,
+        length = str.length * charSize,
+        i;
+
+      for (i = 0; i < length; i += charSize) {
+        bin[i >> 5] |= (str.charCodeAt(i / charSize) & mask) <<
+          (32 - charSize - (i % 32));
+      }
+
+      return bin;
+    },
+
+    /*
+     * Convert a hex string to an array of big-endian words
+     *
+     * @param {String} str String to be converted to binary representation
+     * @return Integer array representation of the parameter
+     */
+    hex2binb = function(str) {
+      var bin = [],
+        length = str.length,
+        i, num;
+
+      for (i = 0; i < length; i += 2) {
+        num = parseInt(str.substr(i, 2), 16);
+        if (!isNaN(num)) {
+          bin[i >> 3] |= num << (24 - (4 * (i % 8)));
+        } else {
+          return "INVALID HEX STRING";
+        }
+      }
+
+      return bin;
+    },
+
+    /*
+     * Convert an array of big-endian words to a hex string.
+     *
+     * @private
+     * @param {Array} binarray Array of integers to be converted to hexidecimal
+     *	 representation
+     * @return Hexidecimal representation of the parameter in String form
+     */
+    binb2hex = function(binarray) {
+      var hex_tab = (hexCase) ? "0123456789ABCDEF" : "0123456789abcdef",
+        str = "",
+        length = binarray.length * 4,
+        i, srcByte;
+
+      for (i = 0; i < length; i += 1) {
+        srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8);
+        str += hex_tab.charAt((srcByte >> 4) & 0xF) +
+          hex_tab.charAt(srcByte & 0xF);
+      }
+
+      return str;
+    },
+
+    /*
+     * Convert an array of big-endian words to a base-64 string
+     *
+     * @private
+     * @param {Array} binarray Array of integers to be converted to base-64
+     *	 representation
+     * @return Base-64 encoded representation of the parameter in String form
+     */
+    binb2b64 = function(binarray) {
+      var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
+        "0123456789+/",
+        str = "",
+        length = binarray.length * 4,
+        i, j,
+        triplet;
+
+      for (i = 0; i < length; i += 3) {
+        triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) |
+          (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) |
+          ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF);
+        for (j = 0; j < 4; j += 1) {
+          if (i * 8 + j * 6 <= binarray.length * 32) {
+            str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
+          } else {
+            str += b64pad;
+          }
+        }
+      }
+      return str;
+    },
+
+    /*
+     * Convert an array of big-endian words to a string
+     */
+    binb2str = function(bin) {
+      var str = "";
+      var mask = (1 << 8) - 1;
+      for (var i = 0; i < bin.length * 32; i += 8)
+        str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask);
+      return str;
+    },
+    /*
+     * The 32-bit implementation of circular rotate left
+     *
+     * @private
+     * @param {Number} x The 32-bit integer argument
+     * @param {Number} n The number of bits to shift
+     * @return The x shifted circularly by n bits
+     */
+    rotl_32 = function(x, n) {
+      return (x << n) | (x >>> (32 - n));
+    },
+
+    /*
+     * The 32-bit implementation of circular rotate right
+     *
+     * @private
+     * @param {Number} x The 32-bit integer argument
+     * @param {Number} n The number of bits to shift
+     * @return The x shifted circularly by n bits
+     */
+    rotr_32 = function(x, n) {
+      return (x >>> n) | (x << (32 - n));
+    },
+
+    /*
+     * The 64-bit implementation of circular rotate right
+     *
+     * @private
+     * @param {Int_64} x The 64-bit integer argument
+     * @param {Number} n The number of bits to shift
+     * @return The x shifted circularly by n bits
+     */
+    rotr_64 = function(x, n) {
+      if (n <= 32) {
+        return new Int_64(
+        (x.highOrder >>> n) | (x.lowOrder << (32 - n)), (x.lowOrder >>> n) | (x.highOrder << (32 - n)));
+      } else {
+        return new Int_64(
+        (x.lowOrder >>> n) | (x.highOrder << (32 - n)), (x.highOrder >>> n) | (x.lowOrder << (32 - n)));
+      }
+    },
+
+    /*
+     * The 32-bit implementation of shift right
+     *
+     * @private
+     * @param {Number} x The 32-bit integer argument
+     * @param {Number} n The number of bits to shift
+     * @return The x shifted by n bits
+     */
+    shr_32 = function(x, n) {
+      return x >>> n;
+    },
+
+    /*
+     * The 64-bit implementation of shift right
+     *
+     * @private
+     * @param {Int_64} x The 64-bit integer argument
+     * @param {Number} n The number of bits to shift
+     * @return The x shifted by n bits
+     */
+    shr_64 = function(x, n) {
+      if (n <= 32) {
+        return new Int_64(
+          x.highOrder >>> n,
+          x.lowOrder >>> n | (x.highOrder << (32 - n)));
+      } else {
+        return new Int_64(
+          0,
+          x.highOrder << (32 - n));
+      }
+    },
+
+    /*
+     * The 32-bit implementation of the NIST specified Parity function
+     *
+     * @private
+     * @param {Number} x The first 32-bit integer argument
+     * @param {Number} y The second 32-bit integer argument
+     * @param {Number} z The third 32-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    parity_32 = function(x, y, z) {
+      return x ^ y ^ z;
+    },
+
+    /*
+     * The 32-bit implementation of the NIST specified Ch function
+     *
+     * @private
+     * @param {Number} x The first 32-bit integer argument
+     * @param {Number} y The second 32-bit integer argument
+     * @param {Number} z The third 32-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    ch_32 = function(x, y, z) {
+      return (x & y) ^ (~x & z);
+    },
+
+    /*
+     * The 64-bit implementation of the NIST specified Ch function
+     *
+     * @private
+     * @param {Int_64} x The first 64-bit integer argument
+     * @param {Int_64} y The second 64-bit integer argument
+     * @param {Int_64} z The third 64-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    ch_64 = function(x, y, z) {
+      return new Int_64(
+      (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder));
+    },
+
+    /*
+     * The 32-bit implementation of the NIST specified Maj function
+     *
+     * @private
+     * @param {Number} x The first 32-bit integer argument
+     * @param {Number} y The second 32-bit integer argument
+     * @param {Number} z The third 32-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    maj_32 = function(x, y, z) {
+      return (x & y) ^ (x & z) ^ (y & z);
+    },
+
+    /*
+     * The 64-bit implementation of the NIST specified Maj function
+     *
+     * @private
+     * @param {Int_64} x The first 64-bit integer argument
+     * @param {Int_64} y The second 64-bit integer argument
+     * @param {Int_64} z The third 64-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    maj_64 = function(x, y, z) {
+      return new Int_64(
+      (x.highOrder & y.highOrder) ^
+        (x.highOrder & z.highOrder) ^
+        (y.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^
+        (x.lowOrder & z.lowOrder) ^
+        (y.lowOrder & z.lowOrder));
+    },
+
+    /*
+     * The 32-bit implementation of the NIST specified Sigma0 function
+     *
+     * @private
+     * @param {Number} x The 32-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    sigma0_32 = function(x) {
+      return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22);
+    },
+
+    /*
+     * The 64-bit implementation of the NIST specified Sigma0 function
+     *
+     * @private
+     * @param {Int_64} x The 64-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    sigma0_64 = function(x) {
+      var rotr28 = rotr_64(x, 28),
+        rotr34 = rotr_64(x, 34),
+        rotr39 = rotr_64(x, 39);
+
+      return new Int_64(
+        rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder,
+        rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder);
+    },
+
+    /*
+     * The 32-bit implementation of the NIST specified Sigma1 function
+     *
+     * @private
+     * @param {Number} x The 32-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    sigma1_32 = function(x) {
+      return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25);
+    },
+
+    /*
+     * The 64-bit implementation of the NIST specified Sigma1 function
+     *
+     * @private
+     * @param {Int_64} x The 64-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    sigma1_64 = function(x) {
+      var rotr14 = rotr_64(x, 14),
+        rotr18 = rotr_64(x, 18),
+        rotr41 = rotr_64(x, 41);
+
+      return new Int_64(
+        rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder,
+        rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder);
+    },
+
+    /*
+     * The 32-bit implementation of the NIST specified Gamma0 function
+     *
+     * @private
+     * @param {Number} x The 32-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    gamma0_32 = function(x) {
+      return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3);
+    },
+
+    /*
+     * The 64-bit implementation of the NIST specified Gamma0 function
+     *
+     * @private
+     * @param {Int_64} x The 64-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    gamma0_64 = function(x) {
+      var rotr1 = rotr_64(x, 1),
+        rotr8 = rotr_64(x, 8),
+        shr7 = shr_64(x, 7);
+
+      return new Int_64(
+        rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder,
+        rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder);
+    },
+
+    /*
+     * The 32-bit implementation of the NIST specified Gamma1 function
+     *
+     * @private
+     * @param {Number} x The 32-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    gamma1_32 = function(x) {
+      return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10);
+    },
+
+    /*
+     * The 64-bit implementation of the NIST specified Gamma1 function
+     *
+     * @private
+     * @param {Int_64} x The 64-bit integer argument
+     * @return The NIST specified output of the function
+     */
+    gamma1_64 = function(x) {
+      var rotr19 = rotr_64(x, 19),
+        rotr61 = rotr_64(x, 61),
+        shr6 = shr_64(x, 6);
+
+      return new Int_64(
+        rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder,
+        rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder);
+    },
+
+    /*
+     * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations
+     * internally to work around bugs in some JS interpreters.
+     *
+     * @private
+     * @param {Number} x The first 32-bit integer argument to be added
+     * @param {Number} y The second 32-bit integer argument to be added
+     * @return The sum of x + y
+     */
+    safeAdd_32_2 = function(x, y) {
+      var lsw = (x & 0xFFFF) + (y & 0xFFFF),
+        msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16);
+
+      return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+    },
+
+    /*
+     * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations
+     * internally to work around bugs in some JS interpreters.
+     *
+     * @private
+     * @param {Number} a The first 32-bit integer argument to be added
+     * @param {Number} b The second 32-bit integer argument to be added
+     * @param {Number} c The third 32-bit integer argument to be added
+     * @param {Number} d The fourth 32-bit integer argument to be added
+     * @return The sum of a + b + c + d
+     */
+    safeAdd_32_4 = function(a, b, c, d) {
+      var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF),
+        msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) +
+          (lsw >>> 16);
+
+      return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+    },
+
+    /*
+     * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations
+     * internally to work around bugs in some JS interpreters.
+     *
+     * @private
+     * @param {Number} a The first 32-bit integer argument to be added
+     * @param {Number} b The second 32-bit integer argument to be added
+     * @param {Number} c The third 32-bit integer argument to be added
+     * @param {Number} d The fourth 32-bit integer argument to be added
+     * @param {Number} e The fifth 32-bit integer argument to be added
+     * @return The sum of a + b + c + d + e
+     */
+    safeAdd_32_5 = function(a, b, c, d, e) {
+      var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) +
+        (e & 0xFFFF),
+        msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) +
+          (e >>> 16) + (lsw >>> 16);
+
+      return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+    },
+
+    /*
+     * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations
+     * internally to work around bugs in some JS interpreters.
+     *
+     * @private
+     * @param {Int_64} x The first 64-bit integer argument to be added
+     * @param {Int_64} y The second 64-bit integer argument to be added
+     * @return The sum of x + y
+     */
+    safeAdd_64_2 = function(x, y) {
+      var lsw, msw, lowOrder, highOrder;
+
+      lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF);
+      msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16);
+      lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+
+      lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16);
+      msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16);
+      highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+
+      return new Int_64(highOrder, lowOrder);
+    },
+
+    /*
+     * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations
+     * internally to work around bugs in some JS interpreters.
+     *
+     * @private
+     * @param {Int_64} a The first 64-bit integer argument to be added
+     * @param {Int_64} b The second 64-bit integer argument to be added
+     * @param {Int_64} c The third 64-bit integer argument to be added
+     * @param {Int_64} d The fouth 64-bit integer argument to be added
+     * @return The sum of a + b + c + d
+     */
+    safeAdd_64_4 = function(a, b, c, d) {
+      var lsw, msw, lowOrder, highOrder;
+
+      lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) +
+        (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF);
+      msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) +
+        (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16);
+      lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+
+      lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) +
+        (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16);
+      msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) +
+        (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16);
+      highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+
+      return new Int_64(highOrder, lowOrder);
+    },
+
+    /*
+     * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations
+     * internally to work around bugs in some JS interpreters.
+     *
+     * @private
+     * @param {Int_64} a The first 64-bit integer argument to be added
+     * @param {Int_64} b The second 64-bit integer argument to be added
+     * @param {Int_64} c The third 64-bit integer argument to be added
+     * @param {Int_64} d The fouth 64-bit integer argument to be added
+     * @param {Int_64} e The fouth 64-bit integer argument to be added
+     * @return The sum of a + b + c + d + e
+     */
+    safeAdd_64_5 = function(a, b, c, d, e) {
+      var lsw, msw, lowOrder, highOrder;
+
+      lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) +
+        (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) +
+        (e.lowOrder & 0xFFFF);
+      msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) +
+        (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) +
+        (lsw >>> 16);
+      lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+
+      lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) +
+        (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) +
+        (e.highOrder & 0xFFFF) + (msw >>> 16);
+      msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) +
+        (c.highOrder >>> 16) + (d.highOrder >>> 16) +
+        (e.highOrder >>> 16) + (lsw >>> 16);
+      highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
+
+      return new Int_64(highOrder, lowOrder);
+    },
+
+    /*
+     * Calculates the SHA-1 hash of the string set at instantiation
+     *
+     * @private
+     * @param {Array} message The binary array representation of the string to
+     *	 hash
+     * @param {Number} messageLen The number of bits in the message
+     * @return The array of integers representing the SHA-1 hash of message
+     */
+    coreSHA1 = function(message, messageLen) {
+      var W = [],
+        a, b, c, d, e, T, ch = ch_32,
+        parity = parity_32,
+        maj = maj_32,
+        rotl = rotl_32,
+        safeAdd_2 = safeAdd_32_2,
+        i, t,
+        safeAdd_5 = safeAdd_32_5,
+        appendedMessageLength,
+        H = [
+            0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
+        ],
+        K = [
+            0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
+            0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
+            0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
+            0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
+            0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
+            0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
+            0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
+            0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
+            0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
+            0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
+            0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
+            0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
+            0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
+            0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
+            0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
+            0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
+            0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
+            0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
+            0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
+            0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6
+        ];
+
+      /* Append '1' at the end of the binary string */
+      message[messageLen >> 5] |= 0x80 << (24 - (messageLen % 32));
+      /* Append length of binary string in the position such that the new
+		length is a multiple of 512.  Logic does not work for even multiples
+		of 512 but there can never be even multiples of 512 */
+      message[(((messageLen + 65) >> 9) << 4) + 15] = messageLen;
+
+      appendedMessageLength = message.length;
+
+      for (i = 0; i < appendedMessageLength; i += 16) {
+        a = H[0];
+        b = H[1];
+        c = H[2];
+        d = H[3];
+        e = H[4];
+
+        for (t = 0; t < 80; t += 1) {
+          if (t < 16) {
+            W[t] = message[t + i];
+          } else {
+            W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
+          }
+
+          if (t < 20) {
+            T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, K[t], W[t]);
+          } else if (t < 40) {
+            T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]);
+          } else if (t < 60) {
+            T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, K[t], W[t]);
+          } else {
+            T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]);
+          }
+
+          e = d;
+          d = c;
+          c = rotl(b, 30);
+          b = a;
+          a = T;
+        }
+
+        H[0] = safeAdd_2(a, H[0]);
+        H[1] = safeAdd_2(b, H[1]);
+        H[2] = safeAdd_2(c, H[2]);
+        H[3] = safeAdd_2(d, H[3]);
+        H[4] = safeAdd_2(e, H[4]);
+      }
+
+      return H;
+    },
+
+    /*
+     * Calculates the desired SHA-2 hash of the string set at instantiation
+     *
+     * @private
+     * @param {Array} The binary array representation of the string to hash
+     * @param {Number} The number of bits in message
+     * @param {String} variant The desired SHA-2 variant
+     * @return The array of integers representing the SHA-2 hash of message
+     */
+    coreSHA2 = function(message, messageLen, variant) {
+      var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t,
+        binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5,
+        gamma0, gamma1, sigma0, sigma1, ch, maj, Int, K, W = [],
+        appendedMessageLength;
+
+      /* Set up the various function handles and variable for the specific 
+       * variant */
+      if (variant === "SHA-224" || variant === "SHA-256") {
+        /* 32-bit variant */
+        numRounds = 64;
+        lengthPosition = (((messageLen + 65) >> 9) << 4) + 15;
+        binaryStringInc = 16;
+        binaryStringMult = 1;
+        Int = Number;
+        safeAdd_2 = safeAdd_32_2;
+        safeAdd_4 = safeAdd_32_4;
+        safeAdd_5 = safeAdd_32_5;
+        gamma0 = gamma0_32;
+        gamma1 = gamma1_32;
+        sigma0 = sigma0_32;
+        sigma1 = sigma1_32;
+        maj = maj_32;
+        ch = ch_32;
+        K = [
+            0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+            0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+            0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+            0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+            0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+            0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+            0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+            0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+            0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+            0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+            0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+            0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+            0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+            0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+            0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+            0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
+        ];
+
+        if (variant === "SHA-224") {
+          H = [
+              0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+              0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
+          ];
+        } else {
+          H = [
+              0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+              0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
+          ];
+        }
+      } else if (variant === "SHA-384" || variant === "SHA-512") {
+        /* 64-bit variant */
+        numRounds = 80;
+        lengthPosition = (((messageLen + 128) >> 10) << 5) + 31;
+        binaryStringInc = 32;
+        binaryStringMult = 2;
+        Int = Int_64;
+        safeAdd_2 = safeAdd_64_2;
+        safeAdd_4 = safeAdd_64_4;
+        safeAdd_5 = safeAdd_64_5;
+        gamma0 = gamma0_64;
+        gamma1 = gamma1_64;
+        sigma0 = sigma0_64;
+        sigma1 = sigma1_64;
+        maj = maj_64;
+        ch = ch_64;
+
+        K = [
+            new Int(0x428a2f98, 0xd728ae22), new Int(0x71374491, 0x23ef65cd),
+            new Int(0xb5c0fbcf, 0xec4d3b2f), new Int(0xe9b5dba5, 0x8189dbbc),
+            new Int(0x3956c25b, 0xf348b538), new Int(0x59f111f1, 0xb605d019),
+            new Int(0x923f82a4, 0xaf194f9b), new Int(0xab1c5ed5, 0xda6d8118),
+            new Int(0xd807aa98, 0xa3030242), new Int(0x12835b01, 0x45706fbe),
+            new Int(0x243185be, 0x4ee4b28c), new Int(0x550c7dc3, 0xd5ffb4e2),
+            new Int(0x72be5d74, 0xf27b896f), new Int(0x80deb1fe, 0x3b1696b1),
+            new Int(0x9bdc06a7, 0x25c71235), new Int(0xc19bf174, 0xcf692694),
+            new Int(0xe49b69c1, 0x9ef14ad2), new Int(0xefbe4786, 0x384f25e3),
+            new Int(0x0fc19dc6, 0x8b8cd5b5), new Int(0x240ca1cc, 0x77ac9c65),
+            new Int(0x2de92c6f, 0x592b0275), new Int(0x4a7484aa, 0x6ea6e483),
+            new Int(0x5cb0a9dc, 0xbd41fbd4), new Int(0x76f988da, 0x831153b5),
+            new Int(0x983e5152, 0xee66dfab), new Int(0xa831c66d, 0x2db43210),
+            new Int(0xb00327c8, 0x98fb213f), new Int(0xbf597fc7, 0xbeef0ee4),
+            new Int(0xc6e00bf3, 0x3da88fc2), new Int(0xd5a79147, 0x930aa725),
+            new Int(0x06ca6351, 0xe003826f), new Int(0x14292967, 0x0a0e6e70),
+            new Int(0x27b70a85, 0x46d22ffc), new Int(0x2e1b2138, 0x5c26c926),
+            new Int(0x4d2c6dfc, 0x5ac42aed), new Int(0x53380d13, 0x9d95b3df),
+            new Int(0x650a7354, 0x8baf63de), new Int(0x766a0abb, 0x3c77b2a8),
+            new Int(0x81c2c92e, 0x47edaee6), new Int(0x92722c85, 0x1482353b),
+            new Int(0xa2bfe8a1, 0x4cf10364), new Int(0xa81a664b, 0xbc423001),
+            new Int(0xc24b8b70, 0xd0f89791), new Int(0xc76c51a3, 0x0654be30),
+            new Int(0xd192e819, 0xd6ef5218), new Int(0xd6990624, 0x5565a910),
+            new Int(0xf40e3585, 0x5771202a), new Int(0x106aa070, 0x32bbd1b8),
+            new Int(0x19a4c116, 0xb8d2d0c8), new Int(0x1e376c08, 0x5141ab53),
+            new Int(0x2748774c, 0xdf8eeb99), new Int(0x34b0bcb5, 0xe19b48a8),
+            new Int(0x391c0cb3, 0xc5c95a63), new Int(0x4ed8aa4a, 0xe3418acb),
+            new Int(0x5b9cca4f, 0x7763e373), new Int(0x682e6ff3, 0xd6b2b8a3),
+            new Int(0x748f82ee, 0x5defb2fc), new Int(0x78a5636f, 0x43172f60),
+            new Int(0x84c87814, 0xa1f0ab72), new Int(0x8cc70208, 0x1a6439ec),
+            new Int(0x90befffa, 0x23631e28), new Int(0xa4506ceb, 0xde82bde9),
+            new Int(0xbef9a3f7, 0xb2c67915), new Int(0xc67178f2, 0xe372532b),
+            new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207),
+            new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178),
+            new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6),
+            new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b),
+            new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493),
+            new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c),
+            new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a),
+            new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817)
+        ];
+
+        if (variant === "SHA-384") {
+          H = [
+              new Int(0xcbbb9d5d, 0xc1059ed8), new Int(0x0629a292a, 0x367cd507),
+              new Int(0x9159015a, 0x3070dd17), new Int(0x0152fecd8, 0xf70e5939),
+              new Int(0x67332667, 0xffc00b31), new Int(0x98eb44a87, 0x68581511),
+              new Int(0xdb0c2e0d, 0x64f98fa7), new Int(0x047b5481d, 0xbefa4fa4)
+          ];
+        } else {
+          H = [
+              new Int(0x6a09e667, 0xf3bcc908), new Int(0xbb67ae85, 0x84caa73b),
+              new Int(0x3c6ef372, 0xfe94f82b), new Int(0xa54ff53a, 0x5f1d36f1),
+              new Int(0x510e527f, 0xade682d1), new Int(0x9b05688c, 0x2b3e6c1f),
+              new Int(0x1f83d9ab, 0xfb41bd6b), new Int(0x5be0cd19, 0x137e2179)
+          ];
+        }
+      }
+
+      /* Append '1' at the end of the binary string */
+      message[messageLen >> 5] |= 0x80 << (24 - messageLen % 32);
+      /* Append length of binary string in the position such that the new
+       * length is correct */
+      message[lengthPosition] = messageLen;
+
+      appendedMessageLength = message.length;
+
+      for (i = 0; i < appendedMessageLength; i += binaryStringInc) {
+        a = H[0];
+        b = H[1];
+        c = H[2];
+        d = H[3];
+        e = H[4];
+        f = H[5];
+        g = H[6];
+        h = H[7];
+
+        for (t = 0; t < numRounds; t += 1) {
+          if (t < 16) {
+            /* Bit of a hack - for 32-bit, the second term is ignored */
+            W[t] = new Int(message[t * binaryStringMult + i],
+              message[t * binaryStringMult + i + 1]);
+          } else {
+            W[t] = safeAdd_4(
+              gamma1(W[t - 2]), W[t - 7],
+              gamma0(W[t - 15]), W[t - 16]);
+          }
+
+          T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]);
+          T2 = safeAdd_2(sigma0(a), maj(a, b, c));
+          h = g;
+          g = f;
+          f = e;
+          e = safeAdd_2(d, T1);
+          d = c;
+          c = b;
+          b = a;
+          a = safeAdd_2(T1, T2);
+        }
+
+        H[0] = safeAdd_2(a, H[0]);
+        H[1] = safeAdd_2(b, H[1]);
+        H[2] = safeAdd_2(c, H[2]);
+        H[3] = safeAdd_2(d, H[3]);
+        H[4] = safeAdd_2(e, H[4]);
+        H[5] = safeAdd_2(f, H[5]);
+        H[6] = safeAdd_2(g, H[6]);
+        H[7] = safeAdd_2(h, H[7]);
+      }
+
+      switch (variant) {
+        case "SHA-224":
+          return [
+            H[0], H[1], H[2], H[3],
+            H[4], H[5], H[6]];
+        case "SHA-256":
+          return H;
+        case "SHA-384":
+          return [
+            H[0].highOrder, H[0].lowOrder,
+            H[1].highOrder, H[1].lowOrder,
+            H[2].highOrder, H[2].lowOrder,
+            H[3].highOrder, H[3].lowOrder,
+            H[4].highOrder, H[4].lowOrder,
+            H[5].highOrder, H[5].lowOrder];
+        case "SHA-512":
+          return [
+            H[0].highOrder, H[0].lowOrder,
+            H[1].highOrder, H[1].lowOrder,
+            H[2].highOrder, H[2].lowOrder,
+            H[3].highOrder, H[3].lowOrder,
+            H[4].highOrder, H[4].lowOrder,
+            H[5].highOrder, H[5].lowOrder,
+            H[6].highOrder, H[6].lowOrder,
+            H[7].highOrder, H[7].lowOrder];
+        default:
+          /* This should never be reached */
+          return [];
+      }
+    },
+
+    /*
+     * jsSHA is the workhorse of the library.  Instantiate it with the string to
+     * be hashed as the parameter
+     *
+     * @constructor
+     * @param {String} srcString The string to be hashed
+     * @param {String} inputFormat The format of srcString, ASCII or HEX
+     */
+    jsSHA = function(srcString, inputFormat) {
+
+      this.sha1 = null;
+      this.sha224 = null;
+      this.sha256 = null;
+      this.sha384 = null;
+      this.sha512 = null;
+
+      this.strBinLen = null;
+      this.strToHash = null;
+
+      /* Convert the input string into the correct type */
+      if ("HEX" === inputFormat) {
+        if (0 !== (srcString.length % 2)) {
+          return "TEXT MUST BE IN BYTE INCREMENTS";
+        }
+        this.strBinLen = srcString.length * 4;
+        this.strToHash = hex2binb(srcString);
+      } else if (("ASCII" === inputFormat) ||
+        ('undefined' === typeof(inputFormat))) {
+        this.strBinLen = srcString.length * charSize;
+        this.strToHash = str2binb(srcString);
+      } else {
+        return "UNKNOWN TEXT INPUT TYPE";
+      }
+    };
+
+  jsSHA.prototype = {
+    /*
+     * Returns the desired SHA hash of the string specified at instantiation
+     * using the specified parameters
+     *
+     * @param {String} variant The desired SHA variant (SHA-1, SHA-224,
+     *	 SHA-256, SHA-384, or SHA-512)
+     * @param {String} format The desired output formatting (B64 or HEX)
+     * @return The string representation of the hash in the format specified
+     */
+    getHash: function(variant, format) {
+      var formatFunc = null,
+        message = this.strToHash.slice();
+
+      switch (format) {
+        case "HEX":
+          formatFunc = binb2hex;
+          break;
+        case "B64":
+          formatFunc = binb2b64;
+          break;
+        case "ASCII":
+          formatFunc = binb2str;
+          break;
+        default:
+          return "FORMAT NOT RECOGNIZED";
+      }
+
+      switch (variant) {
+        case "SHA-1":
+          if (null === this.sha1) {
+            this.sha1 = coreSHA1(message, this.strBinLen);
+          }
+          return formatFunc(this.sha1);
+        case "SHA-224":
+          if (null === this.sha224) {
+            this.sha224 = coreSHA2(message, this.strBinLen, variant);
+          }
+          return formatFunc(this.sha224);
+        case "SHA-256":
+          if (null === this.sha256) {
+            this.sha256 = coreSHA2(message, this.strBinLen, variant);
+          }
+          return formatFunc(this.sha256);
+        case "SHA-384":
+          if (null === this.sha384) {
+            this.sha384 = coreSHA2(message, this.strBinLen, variant);
+          }
+          return formatFunc(this.sha384);
+        case "SHA-512":
+          if (null === this.sha512) {
+            this.sha512 = coreSHA2(message, this.strBinLen, variant);
+          }
+          return formatFunc(this.sha512);
+        default:
+          return "HASH NOT RECOGNIZED";
+      }
+    },
+
+    /*
+     * Returns the desired HMAC of the string specified at instantiation
+     * using the key and variant param.
+     *
+     * @param {String} key The key used to calculate the HMAC
+     * @param {String} inputFormat The format of key, ASCII or HEX
+     * @param {String} variant The desired SHA variant (SHA-1, SHA-224,
+     *	 SHA-256, SHA-384, or SHA-512)
+     * @param {String} outputFormat The desired output formatting
+     *	 (B64 or HEX)
+     * @return The string representation of the hash in the format specified
+     */
+    getHMAC: function(key, inputFormat, variant, outputFormat) {
+      var formatFunc, keyToUse, blockByteSize, blockBitSize, i,
+        retVal, lastArrayIndex, keyBinLen, hashBitSize,
+        keyWithIPad = [],
+        keyWithOPad = [];
+
+      /* Validate the output format selection */
+      switch (outputFormat) {
+        case "HEX":
+          formatFunc = binb2hex;
+          break;
+        case "B64":
+          formatFunc = binb2b64;
+          break;
+        case "ASCII":
+          formatFunc = binb2str;
+          break;
+        default:
+          return "FORMAT NOT RECOGNIZED";
+      }
+
+      /* Validate the hash variant selection and set needed variables */
+      switch (variant) {
+        case "SHA-1":
+          blockByteSize = 64;
+          hashBitSize = 160;
+          break;
+        case "SHA-224":
+          blockByteSize = 64;
+          hashBitSize = 224;
+          break;
+        case "SHA-256":
+          blockByteSize = 64;
+          hashBitSize = 256;
+          break;
+        case "SHA-384":
+          blockByteSize = 128;
+          hashBitSize = 384;
+          break;
+        case "SHA-512":
+          blockByteSize = 128;
+          hashBitSize = 512;
+          break;
+        default:
+          return "HASH NOT RECOGNIZED";
+      }
+
+      /* Validate input format selection */
+      if ("HEX" === inputFormat) {
+        /* Nibbles must come in pairs */
+        if (0 !== (key.length % 2)) {
+          return "KEY MUST BE IN BYTE INCREMENTS";
+        }
+        keyToUse = hex2binb(key);
+        keyBinLen = key.length * 4;
+      } else if ("ASCII" === inputFormat) {
+        keyToUse = str2binb(key);
+        keyBinLen = key.length * charSize;
+      } else {
+        return "UNKNOWN KEY INPUT TYPE";
+      }
+
+      /* These are used multiple times, calculate and store them */
+      blockBitSize = blockByteSize * 8;
+      lastArrayIndex = (blockByteSize / 4) - 1;
+
+      /* Figure out what to do with the key based on its size relative to
+       * the hash's block size */
+      if (blockByteSize < (keyBinLen / 8)) {
+        if ("SHA-1" === variant) {
+          keyToUse = coreSHA1(keyToUse, keyBinLen);
+        } else {
+          keyToUse = coreSHA2(keyToUse, keyBinLen, variant);
+        }
+        /* For all variants, the block size is bigger than the output
+         * size so there will never be a useful byte at the end of the
+         * string */
+        keyToUse[lastArrayIndex] &= 0xFFFFFF00;
+      } else if (blockByteSize > (keyBinLen / 8)) {
+        /* If the blockByteSize is greater than the key length, there
+         * will always be at LEAST one "useless" byte at the end of the
+         * string */
+        keyToUse[lastArrayIndex] &= 0xFFFFFF00;
+      }
+
+      /* Create ipad and opad */
+      for (i = 0; i <= lastArrayIndex; i += 1) {
+        keyWithIPad[i] = keyToUse[i] ^ 0x36363636;
+        keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C;
+      }
+
+      /* Calculate the HMAC */
+      if ("SHA-1" === variant) {
+        retVal = coreSHA1(
+          keyWithIPad.concat(this.strToHash),
+          blockBitSize + this.strBinLen);
+        retVal = coreSHA1(
+          keyWithOPad.concat(retVal),
+          blockBitSize + hashBitSize);
+      } else {
+        retVal = coreSHA2(
+          keyWithIPad.concat(this.strToHash),
+          blockBitSize + this.strBinLen, variant);
+        retVal = coreSHA2(
+          keyWithOPad.concat(retVal),
+          blockBitSize + hashBitSize, variant);
+      }
+
+      return (formatFunc(retVal));
+    }
+  };
+
+  return jsSHA;
+}());
+
+module.exports = {
+  /** SHA1 hash */
+  sha1: function(str) {
+    var shaObj = new jsSHA(str, "ASCII");
+    return shaObj.getHash("SHA-1", "ASCII");
+  },
+  /** SHA224 hash */
+  sha224: function(str) {
+    var shaObj = new jsSHA(str, "ASCII");
+    return shaObj.getHash("SHA-224", "ASCII");
+  },
+  /** SHA256 hash */
+  sha256: function(str) {
+    var shaObj = new jsSHA(str, "ASCII");
+    return shaObj.getHash("SHA-256", "ASCII");
+  },
+  /** SHA384 hash */
+  sha384: function(str) {
+    var shaObj = new jsSHA(str, "ASCII");
+    return shaObj.getHash("SHA-384", "ASCII");
+
+  },
+  /** SHA512 hash */
+  sha512: function(str) {
+    var shaObj = new jsSHA(str, "ASCII");
+    return shaObj.getHash("SHA-512", "ASCII");
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/signature.html b/doc/signature.html new file mode 100644 index 00000000..fd7e7186 --- /dev/null +++ b/doc/signature.html @@ -0,0 +1,590 @@ + + + + + JSDoc: Module: crypto/signature + + + + + + + + + + +
+ +

Module: crypto/signature

+ + + + + +
+ +
+

+ crypto/signature +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

<static> sign(hash_algo, algo, publicMPIs, secretMPIs, data) → {Array.<module:type/mpi>}

+ + +
+
+ + +
+ Create a signature on data using the specified algorithm +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hash_algo + + +Integer + + + + hash Algorithm to use (See RFC4880 9.4)
algo + + +Integer + + + + Asymmetric cipher algorithm to use (See RFC4880 9.1)
publicMPIs + + +Array.<module:type/mpi> + + + + Public key multiprecision integers +of the private key
secretMPIs + + +Array.<module:type/mpi> + + + + Private key multiprecision +integers which is used to sign the data
data + + +String + + + + Data to be signed
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<module:type/mpi> + + +
+
+ + + + +
+ + + +
+

<static> verify(algo, hash_algo, msg_MPIs, publickey_MPIs, data) → {Boolean}

+ + +
+
+ + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
algo + + +Integer + + + + public Key algorithm
hash_algo + + +Integer + + + + Hash algorithm
msg_MPIs + + +Array.<module:type/mpi> + + + + Signature multiprecision integers
publickey_MPIs + + +Array.<module:type/mpi> + + + + Public key multiprecision integers
data + + +String + + + + Data on where the signature was computed on.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ true if signature (sig_data was equal to data over hash) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:41 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/signature.js.html b/doc/signature.js.html new file mode 100644 index 00000000..d2f11bc7 --- /dev/null +++ b/doc/signature.js.html @@ -0,0 +1,161 @@ + + + + + JSDoc: Source: crypto/signature.js + + + + + + + + + + +
+ +

Source: crypto/signature.js

+ + + + + +
+
+
/**
+ * @requires crypto/hash
+ * @requires crypto/pkcs1
+ * @requires crypto/public_key
+ * @module crypto/signature */
+
+var publicKey = require('./public_key'),
+  pkcs1 = require('./pkcs1.js'),
+  hashModule = require('./hash');
+
+module.exports = {
+  /**
+   * 
+   * @param {Integer} algo public Key algorithm
+   * @param {Integer} hash_algo Hash algorithm
+   * @param {Array<module:type/mpi>} msg_MPIs Signature multiprecision integers
+   * @param {Array<module:type/mpi>} publickey_MPIs Public key multiprecision integers 
+   * @param {String} data Data on where the signature was computed on.
+   * @return {Boolean} true if signature (sig_data was equal to data over hash)
+   */
+  verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
+    var calc_hash = hashModule.digest(hash_algo, data);
+
+    switch (algo) {
+      case 1:
+        // RSA (Encrypt or Sign) [HAC]  
+      case 2:
+        // RSA Encrypt-Only [HAC]
+      case 3:
+        // RSA Sign-Only [HAC]
+        var rsa = new publicKey.rsa();
+        var n = publickey_MPIs[0].toBigInteger();
+        var e = publickey_MPIs[1].toBigInteger();
+        var x = msg_MPIs[0].toBigInteger();
+        var dopublic = rsa.verify(x, e, n);
+        var hash = pkcs1.emsa.decode(hash_algo, dopublic.toMPI().substring(2));
+        if (hash == -1) {
+          throw new Error('PKCS1 padding in message or key incorrect. Aborting...');
+        }
+        return hash == calc_hash;
+
+      case 16:
+        // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
+        throw new Error("signing with Elgamal is not defined in the OpenPGP standard.");
+      case 17:
+        // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
+        var dsa = new publicKey.dsa();
+        var s1 = msg_MPIs[0].toBigInteger();
+        var s2 = msg_MPIs[1].toBigInteger();
+        var p = publickey_MPIs[0].toBigInteger();
+        var q = publickey_MPIs[1].toBigInteger();
+        var g = publickey_MPIs[2].toBigInteger();
+        var y = publickey_MPIs[3].toBigInteger();
+        var m = data;
+        var dopublic = dsa.verify(hash_algo, s1, s2, m, p, q, g, y);
+        return dopublic.compareTo(s1) == 0;
+      default:
+        throw new Error('Invalid signature algorithm.');
+    }
+
+  },
+
+  /**
+   * Create a signature on data using the specified algorithm
+   * @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4)
+   * @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1)
+   * @param {Array<module:type/mpi>} publicMPIs Public key multiprecision integers 
+   * of the private key 
+   * @param {Array<module:type/mpi>} secretMPIs Private key multiprecision 
+   * integers which is used to sign the data
+   * @param {String} data Data to be signed
+   * @return {Array<module:type/mpi>}
+   */
+  sign: function(hash_algo, algo, keyIntegers, data) {
+
+    switch (algo) {
+      case 1:
+        // RSA (Encrypt or Sign) [HAC]  
+      case 2:
+        // RSA Encrypt-Only [HAC]
+      case 3:
+        // RSA Sign-Only [HAC]
+        var rsa = new publicKey.rsa();
+        var d = keyIntegers[2].toBigInteger();
+        var n = keyIntegers[0].toBigInteger();
+        var m = pkcs1.emsa.encode(hash_algo,
+          data, keyIntegers[0].byteLength());
+
+        return rsa.sign(m, d, n).toMPI();
+
+      case 17:
+        // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
+        var dsa = new publicKey.dsa();
+
+        var p = keyIntegers[0].toBigInteger();
+        var q = keyIntegers[1].toBigInteger();
+        var g = keyIntegers[2].toBigInteger();
+        var y = keyIntegers[3].toBigInteger();
+        var x = keyIntegers[4].toBigInteger();
+        var m = data;
+        var result = dsa.sign(hash_algo, m, g, p, q, x);
+
+        return result[0].toString() + result[1].toString();
+      case 16:
+        // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
+        throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
+      default:
+        throw new Error('Invalid signature algorithm.');
+    }
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/signature.js_.html b/doc/signature.js_.html new file mode 100644 index 00000000..f3a3d0ab --- /dev/null +++ b/doc/signature.js_.html @@ -0,0 +1,690 @@ + + + + + JSDoc: Source: packet/signature.js + + + + + + + + + + +
+ +

Source: packet/signature.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the Signature Packet (Tag 2)<br/>
+ * <br/>
+ * RFC4480 5.2:
+ * A Signature packet describes a binding between some public key and
+ * some data.  The most common signatures are a signature of a file or a
+ * block of text, and a signature that is a certification of a User ID.
+ * @requires crypto
+ * @requires enums
+ * @requires packet/packet
+ * @requires type/keyid
+ * @requires type/mpi
+ * @requires util
+ * @module packet/signature
+ */
+
+var util = require('../util'),
+  packet = require('./packet.js'),
+  enums = require('../enums.js'),
+  crypto = require('../crypto'),
+  type_mpi = require('../type/mpi.js'),
+  type_keyid = require('../type/keyid.js');
+
+/**
+ * @constructor
+ */
+module.exports = function signature() {
+
+  this.version = 4;
+  this.signatureType = null;
+  this.hashAlgorithm = null;
+  this.publicKeyAlgorithm = null;
+
+  this.signatureData = null;
+  this.signedHashValue = null;
+  this.mpi = null;
+
+  this.created = new Date();
+  this.signatureExpirationTime = null;
+  this.signatureNeverExpires = true;
+  this.exportable = null;
+  this.trustLevel = null;
+  this.trustAmount = null;
+  this.regularExpression = null;
+  this.revocable = null;
+  this.keyExpirationTime = null;
+  this.keyNeverExpires = null;
+  this.preferredSymmetricAlgorithms = null;
+  this.revocationKeyClass = null;
+  this.revocationKeyAlgorithm = null;
+  this.revocationKeyFingerprint = null;
+  this.issuerKeyId = new type_keyid();
+  this.notation = null;
+  this.preferredHashAlgorithms = null;
+  this.preferredCompressionAlgorithms = null;
+  this.keyServerPreferences = null;
+  this.preferredKeyServer = null;
+  this.isPrimaryUserID = null;
+  this.policyURI = null;
+  this.keyFlags = null;
+  this.signersUserId = null;
+  this.reasonForRevocationFlag = null;
+  this.reasonForRevocationString = null;
+  this.features = null;
+  this.signatureTargetPublicKeyAlgorithm = null;
+  this.signatureTargetHashAlgorithm = null;
+  this.signatureTargetHash = null;
+  this.embeddedSignature = null;
+
+  this.verified = false;
+
+  /**
+   * parsing function for a signature packet (tag 2).
+   * @param {String} bytes payload of a tag 2 packet
+   * @param {Integer} position position to start reading from the bytes string
+   * @param {Integer} len length of the packet or the remaining length of bytes at position
+   * @return {module:packet/signature} object representation
+   */
+  this.read = function (bytes) {
+    var i = 0;
+
+    this.version = bytes.charCodeAt(i++);
+    // switch on version (3 and 4)
+    switch (this.version) {
+      case 3:
+        // One-octet length of following hashed material. MUST be 5.
+        if (bytes.charCodeAt(i++) != 5)
+          util.print_debug("packet/signature.js\n" +
+            'invalid One-octet length of following hashed material.' +
+            'MUST be 5. @:' + (i - 1));
+
+        var sigpos = i;
+        // One-octet signature type.
+        this.signatureType = bytes.charCodeAt(i++);
+
+        // Four-octet creation time.
+        this.created = util.readDate(bytes.substr(i, 4));
+        i += 4;
+
+        // storing data appended to data which gets verified
+        this.signatureData = bytes.substring(sigpos, i);
+
+        // Eight-octet Key ID of signer.
+        this.issuerKeyId.read(bytes.substring(i, i + 8));
+        i += 8;
+
+        // One-octet public-key algorithm.
+        this.publicKeyAlgorithm = bytes.charCodeAt(i++);
+
+        // One-octet hash algorithm.
+        this.hashAlgorithm = bytes.charCodeAt(i++);
+        break;
+      case 4:
+        this.signatureType = bytes.charCodeAt(i++);
+        this.publicKeyAlgorithm = bytes.charCodeAt(i++);
+        this.hashAlgorithm = bytes.charCodeAt(i++);
+
+        function subpackets(bytes) {
+          // Two-octet scalar octet count for following subpacket data.
+          var subpacket_length = util.readNumber(
+            bytes.substr(0, 2));
+
+          var i = 2;
+
+          // subpacket data set (zero or more subpackets)
+          var subpacked_read = 0;
+          while (i < 2 + subpacket_length) {
+
+            var len = packet.readSimpleLength(bytes.substr(i));
+            i += len.offset;
+
+            this.read_sub_packet(bytes.substr(i, len.len));
+
+            i += len.len;
+          }
+
+          return i;
+        }
+
+        // hashed subpackets
+        i += subpackets.call(this, bytes.substr(i), true);
+
+        // A V4 signature hashes the packet body
+        // starting from its first field, the version number, through the end
+        // of the hashed subpacket data.  Thus, the fields hashed are the
+        // signature version, the signature type, the public-key algorithm, the
+        // hash algorithm, the hashed subpacket length, and the hashed
+        // subpacket body.
+        this.signatureData = bytes.substr(0, i);
+
+        // unhashed subpackets
+        i += subpackets.call(this, bytes.substr(i), false);
+
+        break;
+      default:
+        throw new Error('Version ' + version + ' of the signature is unsupported.');
+        break;
+    }
+
+    // Two-octet field holding left 16 bits of signed hash value.
+    this.signedHashValue = bytes.substr(i, 2);
+    i += 2;
+
+    this.signature = bytes.substr(i);
+  };
+
+  this.write = function () {
+    return this.signatureData +
+      util.writeNumber(0, 2) + // Number of unsigned subpackets.
+      this.signedHashValue +
+      this.signature;
+  };
+
+  /**
+   * Signs provided data. This needs to be done prior to serialization.
+   * @param {module:packet/secret_key} key private key used to sign the message. 
+   * @param {Object} data Contains packets to be signed.
+   */
+  this.sign = function (key, data) {
+    var signatureType = enums.write(enums.signature, this.signatureType),
+      publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
+      hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
+
+    var result = String.fromCharCode(4);
+    result += String.fromCharCode(signatureType);
+    result += String.fromCharCode(publicKeyAlgorithm);
+    result += String.fromCharCode(hashAlgorithm);
+
+    this.issuerKeyId = key.getKeyId();
+
+    // Add hashed subpackets
+    result += this.write_all_sub_packets();
+
+    this.signatureData = result;
+
+    var trailer = this.calculateTrailer();
+
+    var toHash = this.toSign(signatureType, data) +
+      this.signatureData + trailer;
+
+    var hash = crypto.hash.digest(hashAlgorithm, toHash);
+
+    this.signedHashValue = hash.substr(0, 2);
+
+    this.signature = crypto.signature.sign(hashAlgorithm,
+      publicKeyAlgorithm, key.mpi, toHash);
+  };
+
+  /**
+   * Creates string of bytes with all subpacket data
+   * @return {String} a string-representation of a all subpacket data
+   */
+  this.write_all_sub_packets = function () {
+    var sub = enums.signatureSubpacket;
+    var result = '';
+    var bytes = '';
+    if (this.created !== null) {
+      result += write_sub_packet(sub.signature_creation_time, util.writeDate(this.created));
+    }
+    if (this.signatureExpirationTime !== null) {
+      result += write_sub_packet(sub.signature_expiration_time, util.writeNumber(this.signatureExpirationTime, 4));
+    }
+    if (this.exportable !== null) {
+      result += write_sub_packet(sub.exportable_certification, String.fromCharCode(this.exportable ? 1 : 0));
+    }
+    if (this.trustLevel !== null) {
+      bytes = String.fromCharCode(this.trustLevel) + String.fromCharCode(this.trustAmount);
+      result += write_sub_packet(sub.trust_signature, bytes);
+    }
+    if (this.regularExpression !== null) {
+      result += write_sub_packet(sub.regular_expression, this.regularExpression);
+    }
+    if (this.revocable !== null) {
+      result += write_sub_packet(sub.revocable, String.fromCharCode(this.revocable ? 1 : 0));
+    }
+    if (this.keyExpirationTime !== null) {
+      result += write_sub_packet(sub.key_expiration_time, util.writeNumber(this.keyExpirationTime, 4));
+    }
+    if (this.preferredSymmetricAlgorithms !== null) {
+      bytes = util.bin2str(this.preferredSymmetricAlgorithms);
+      result += write_sub_packet(sub.preferred_symmetric_algorithms, bytes);
+    }
+    if (this.revocationKeyClass !== null) {
+      bytes = String.fromCharCode(this.revocationKeyClass);
+      bytes += String.fromCharCode(this.revocationKeyAlgorithm);
+      bytes += this.revocationKeyFingerprint;
+      result += write_sub_packet(sub.revocation_key, bytes);
+    }
+    if (!this.issuerKeyId.isNull()) {
+      result += write_sub_packet(sub.issuer, this.issuerKeyId.write());
+    }
+    if (this.notation !== null) {
+      for (var name in this.notation) {
+        if (this.notation.hasOwnProperty(name)) {
+          var value = this.notation[name];
+          bytes = String.fromCharCode(0x80);
+          bytes += String.fromCharCode(0);
+          bytes += String.fromCharCode(0);
+          bytes += String.fromCharCode(0);
+          // 2 octets of name length
+          bytes += util.writeNumber(name.length, 2);
+          // 2 octets of value length
+          bytes += util.writeNumber(value.length, 2);
+          bytes += name + value;
+          result += write_sub_packet(sub.notation_data, bytes);
+        }
+      }
+    } 
+    if (this.preferredHashAlgorithms !== null) {
+      bytes = util.bin2str(this.preferredHashAlgorithms);
+      result += write_sub_packet(sub.preferred_hash_algorithms, bytes);
+    }
+    if (this.preferredCompressionAlgorithms !== null) {
+      bytes = util.bin2str(this.preferredCompressionAlgorithms);
+      result += write_sub_packet(sub.preferred_hash_algorithms, bytes);
+    }
+    if (this.keyServerPreferences !== null) {
+      bytes = util.bin2str(this.keyServerPreferences);
+      result += write_sub_packet(sub.key_server_preferences, bytes);
+    }
+    if (this.preferredKeyServer !== null) {
+      result += write_sub_packet(sub.preferred_key_server, this.preferredKeyServer);
+    }
+    if (this.isPrimaryUserID !== null) {
+      result += write_sub_packet(sub.primary_user_id, String.fromCharCode(this.isPrimaryUserID ? 1 : 0));
+    }
+    if (this.policyURI !== null) {
+      result += write_sub_packet(sub.policy_uri, this.policyURI); 
+    }
+    if (this.keyFlags !== null) {
+      bytes = util.bin2str(this.keyFlags);
+      result += write_sub_packet(sub.key_flags, bytes);
+    }
+    if (this.signersUserId !== null) {
+      result += write_sub_packet(sub.signers_user_id, this.signersUserId); 
+    }
+    if (this.reasonForRevocationFlag !== null) {
+      bytes = String.fromCharCode(this.reasonForRevocationFlag);
+      bytes += this.reasonForRevocationString;
+      result += write_sub_packet(sub.reason_for_revocation, bytes);
+    }
+    if (this.features !== null) {
+      bytes = util.bin2str(this.features);
+      result += write_sub_packet(sub.features, bytes);
+    }
+    if (this.signatureTargetPublicKeyAlgorithm !== null) {
+      bytes = String.fromCharCode(this.signatureTargetPublicKeyAlgorithm);
+      bytes += String.fromCharCode(this.signatureTargetHashAlgorithm);
+      bytes += this.signatureTargetHash;
+      result += write_sub_packet(sub.signature_target, bytes);
+    }
+    if (this.embeddedSignature !== null) {
+      result += write_sub_packet(sub.embedded_signature, this.embeddedSignature.write());
+    }
+    result = util.writeNumber(result.length, 2) + result;
+    return result;
+  };
+
+  /**
+   * creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
+   * @param {Integer} type subpacket signature type. Signature types as described 
+   * in RFC4880 Section 5.2.3.2
+   * @param {String} data data to be included
+   * @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1)
+   */
+  function write_sub_packet(type, data) {
+    var result = "";
+    result += packet.writeSimpleLength(data.length + 1);
+    result += String.fromCharCode(type);
+    result += data;
+    return result;
+  }
+
+  // V4 signature sub packets
+
+  this.read_sub_packet = function (bytes) {
+    var mypos = 0;
+
+    function read_array(prop, bytes) {
+      this[prop] = [];
+
+      for (var i = 0; i < bytes.length; i++) {
+        this[prop].push(bytes.charCodeAt(i));
+      }
+    }
+
+    // The leftwost bit denotes a "critical" packet, but we ignore it.
+    var type = bytes.charCodeAt(mypos++) & 0x7F;
+
+    // subpacket type
+    switch (type) {
+      case 2:
+        // Signature Creation Time
+        this.created = util.readDate(bytes.substr(mypos));
+        break;
+      case 3:
+        // Signature Expiration Time in seconds
+        var seconds = util.readNumber(bytes.substr(mypos));
+
+        this.signatureNeverExpires = seconds == 0;
+        this.signatureExpirationTime = seconds;
+
+        break;
+      case 4:
+        // Exportable Certification
+        this.exportable = bytes.charCodeAt(mypos++) == 1;
+        break;
+      case 5:
+        // Trust Signature
+        this.trustLevel = bytes.charCodeAt(mypos++);
+        this.trustAmount = bytes.charCodeAt(mypos++);
+        break;
+      case 6:
+        // Regular Expression
+        this.regularExpression = bytes.substr(mypos);
+        break;
+      case 7:
+        // Revocable
+        this.revocable = bytes.charCodeAt(mypos++) == 1;
+        break;
+      case 9:
+        // Key Expiration Time in seconds
+        var seconds = util.readNumber(bytes.substr(mypos));
+
+        this.keyExpirationTime = seconds;
+        this.keyNeverExpires = seconds == 0;
+
+        break;
+      case 11:
+        // Preferred Symmetric Algorithms
+        this.preferredSymmetricAlgorithms = [];
+
+        while (mypos != bytes.length) {
+          this.preferredSymmetricAlgorithms.push(bytes.charCodeAt(mypos++));
+        }
+
+        break;
+      case 12:
+        // Revocation Key
+        // (1 octet of class, 1 octet of public-key algorithm ID, 20
+        // octets of
+        // fingerprint)
+        this.revocationKeyClass = bytes.charCodeAt(mypos++);
+        this.revocationKeyAlgorithm = bytes.charCodeAt(mypos++);
+        this.revocationKeyFingerprint = bytes.substr(mypos, 20);
+        break;
+
+      case 16:
+        // Issuer
+        this.issuerKeyId.read(bytes.substr(mypos));
+        break;
+
+      case 20:
+        // Notation Data
+        // We don't know how to handle anything but a text flagged data.
+        if (bytes.charCodeAt(mypos) == 0x80) {
+
+          // We extract key/value tuple from the byte stream.
+          mypos += 4;
+          var m = util.readNumber(bytes.substr(mypos, 2));
+          mypos += 2
+          var n = util.readNumber(bytes.substr(mypos, 2));
+          mypos += 2
+
+          var name = bytes.substr(mypos, m),
+            value = bytes.substr(mypos + m, n);
+
+          this.notation = this.notation || {};
+          this.notation[name] = value;
+        } else throw new Error("Unsupported notation flag.");
+        break;
+      case 21:
+        // Preferred Hash Algorithms
+        read_array.call(this, 'preferredHashAlgorithms', bytes.substr(mypos));
+        break;
+      case 22:
+        // Preferred Compression Algorithms
+        read_array.call(this, 'preferredCompressionAlgorithms ', bytes.substr(mypos));
+        break;
+      case 23:
+        // Key Server Preferences
+        read_array.call(this, 'keyServerPreferencess', bytes.substr(mypos));
+        break;
+      case 24:
+        // Preferred Key Server
+        this.preferredKeyServer = bytes.substr(mypos);
+        break;
+      case 25:
+        // Primary User ID
+        this.isPrimaryUserID = bytes[mypos++] != 0;
+        break;
+      case 26:
+        // Policy URI
+        this.policyURI = bytes.substr(mypos);
+        break;
+      case 27:
+        // Key Flags
+        read_array.call(this, 'keyFlags', bytes.substr(mypos));
+        break;
+      case 28:
+        // Signer's User ID
+        this.signersUserId += bytes.substr(mypos);
+        break;
+      case 29:
+        // Reason for Revocation
+        this.reasonForRevocationFlag = bytes.charCodeAt(mypos++);
+        this.reasonForRevocationString = bytes.substr(mypos);
+        break;
+      case 30:
+        // Features
+        read_array.call(this, 'features', bytes.substr(mypos));
+        break;
+      case 31:
+        // Signature Target
+        // (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
+        this.signatureTargetPublicKeyAlgorithm = bytes.charCodeAt(mypos++);
+        this.signatureTargetHashAlgorithm = bytes.charCodeAt(mypos++);
+
+        var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm);
+
+        this.signatureTargetHash = bytes.substr(mypos, len);
+        break;
+      case 32:
+        // Embedded Signature
+        this.embeddedSignature = new signature();
+        this.embeddedSignature.read(bytes.substr(mypos));
+        break;
+      default:
+        throw new Error("Unknown signature subpacket type " + type + " @:" + mypos);
+        break;
+    }
+  };
+
+  // Produces data to produce signature on
+  this.toSign = function (type, data) {
+    var t = enums.signature;
+
+    switch (type) {
+      case t.binary:
+      case t.text:
+        return data.getBytes();
+
+      case t.standalone:
+        return '';
+
+      case t.cert_generic:
+      case t.cert_persona:
+      case t.cert_casual:
+      case t.cert_positive:
+      case t.cert_revocation:
+        var packet, tag;
+
+        if (data.userid !== undefined) {
+          tag = 0xB4;
+          packet = data.userid;
+        } else if (data.userattribute !== undefined) {
+          tag = 0xD1;
+          packet = data.userattribute;
+        } else throw new Error('Either a userid or userattribute packet needs to be ' +
+            'supplied for certification.');
+
+        var bytes = packet.write();
+
+        if (this.version == 4) {
+          return this.toSign(t.key, data) +
+          String.fromCharCode(tag) +
+          util.writeNumber(bytes.length, 4) +
+          bytes; 
+        } else if (this.version == 3) {
+          return this.toSign(t.key, data) +
+          bytes;
+        }
+        break;
+
+      case t.subkey_binding:
+      case t.key_binding:
+        return this.toSign(t.key, data) + this.toSign(t.key, {
+          key: data.bind
+        });
+
+      case t.key:
+        if (data.key == undefined)
+          throw new Error('Key packet is required for this sigtature.');
+
+        return data.key.writeOld();
+
+      case t.key_revocation:
+      case t.subkey_revocation:
+        return this.toSign(t.key, data);
+      case t.timestamp:
+        return '';
+      case t.third_party:
+        throw new Error('Not implemented');
+        break;
+      default:
+        throw new Error('Unknown signature type.')
+    }
+  }
+
+
+  this.calculateTrailer = function () {
+    // calculating the trailer
+    var trailer = '';
+    // V3 signatures don't have a trailer
+    if (this.version == 3) return trailer;
+    trailer += String.fromCharCode(4); // Version
+    trailer += String.fromCharCode(0xFF);
+    trailer += util.writeNumber(this.signatureData.length, 4);
+    return trailer
+  }
+
+
+  /**
+   * verifys the signature packet. Note: not signature types are implemented
+   * @param {String|Object} data data which on the signature applies
+   * @param {module:packet/public_subkey|module:packet/public_key} key the public key to verify the signature
+   * @return {boolean} True if message is verified, else false.
+   */
+  this.verify = function (key, data) {
+    var signatureType = enums.write(enums.signature, this.signatureType),
+      publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
+      hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
+
+    var bytes = this.toSign(signatureType, data),
+      trailer = this.calculateTrailer();
+
+
+    var mpicount = 0;
+    // Algorithm-Specific Fields for RSA signatures:
+    //      - multiprecision number (MPI) of RSA signature value m**d mod n.
+    if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4)
+      mpicount = 1;
+    //    Algorithm-Specific Fields for DSA signatures:
+    //      - MPI of DSA value r.
+    //      - MPI of DSA value s.
+    else if (publicKeyAlgorithm == 17)
+      mpicount = 2;
+
+    var mpi = [],
+      i = 0;
+    for (var j = 0; j < mpicount; j++) {
+      mpi[j] = new type_mpi();
+      i += mpi[j].read(this.signature.substr(i));
+    }
+
+    this.verified = crypto.signature.verify(publicKeyAlgorithm,
+      hashAlgorithm, mpi, key.mpi,
+      bytes + this.signatureData + trailer);
+
+    return this.verified;
+  }
+
+  /**
+   * Verifies signature expiration date
+   * @return {Boolean} true if expired
+   */
+  this.isExpired = function () {
+    if (!this.signatureNeverExpires) {
+      return Date.now() > (this.created.getTime() + this.signatureExpirationTime*1000);
+    }
+    return false;
+  }
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/signature_.html b/doc/signature_.html new file mode 100644 index 00000000..ddf712fe --- /dev/null +++ b/doc/signature_.html @@ -0,0 +1,1051 @@ + + + + + JSDoc: Module: packet/signature + + + + + + + + + + +
+ +

Module: packet/signature

+ + + + + +
+ +
+

+ packet/signature +

+ +
+ +
+
+ + +
Implementation of the Signature Packet (Tag 2)
+
+RFC4480 5.2: +A Signature packet describes a binding between some public key and +some data. The most common signatures are a signature of a file or a +block of text, and a signature that is a certification of a User ID.
+ + +
+

new (require("packet/signature"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

isExpired() → {Boolean}

+ + +
+
+ + +
+ Verifies signature expiration date +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ true if expired +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + +
+ + + +
+

read(bytes, position, len) → {module:packet/signature}

+ + +
+
+ + +
+ parsing function for a signature packet (tag 2). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bytes + + +String + + + + payload of a tag 2 packet
position + + +Integer + + + + position to start reading from the bytes string
len + + +Integer + + + + length of the packet or the remaining length of bytes at position
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ object representation +
+ + + +
+
+ Type +
+
+ +module:packet/signature + + +
+
+ + + + +
+ + + +
+

sign(key, data)

+ + +
+
+ + +
+ Signs provided data. This needs to be done prior to serialization. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + + +module:packet/secret_key + + + + private key used to sign the message.
data + + +Object + + + + Contains packets to be signed.
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

verify(data, key) → {boolean}

+ + +
+
+ + +
+ verifys the signature packet. Note: not signature types are implemented +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +String +| + +Object + + + + data which on the signature applies
key + + +module:packet/public_subkey +| + +module:packet/public_key + + + + the public key to verify the signature
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ True if message is verified, else false. +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + +
+ + + +
+

write_all_sub_packets() → {String}

+ + +
+
+ + +
+ Creates string of bytes with all subpacket data +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ a string-representation of a all subpacket data +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<inner> write_sub_packet(type, data) → {String}

+ + +
+
+ + +
+ creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1) +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
type + + +Integer + + + + subpacket signature type. Signature types as described +in RFC4880 Section 5.2.3.2
data + + +String + + + + data to be included
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ a string-representation of a sub signature packet (See RFC 4880 5.2.3.1) +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/sym_encrypted_integrity_protected.html b/doc/sym_encrypted_integrity_protected.html new file mode 100644 index 00000000..80784815 --- /dev/null +++ b/doc/sym_encrypted_integrity_protected.html @@ -0,0 +1,494 @@ + + + + + JSDoc: Module: packet/sym_encrypted_integrity_protected + + + + + + + + + + +
+ +

Module: packet/sym_encrypted_integrity_protected

+ + + + + +
+ +
+

+ packet/sym_encrypted_integrity_protected +

+ +
+ +
+
+ + +
Implementation of the Sym. Encrypted Integrity Protected Data +Packet (Tag 18)
+
+RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is +a variant of the Symmetrically Encrypted Data packet. It is a new feature +created for OpenPGP that addresses the problem of detecting a modification to +encrypted data. It is used in combination with a Modification Detection Code +packet.
+ + +
+

new (require("packet/sym_encrypted_integrity_protected"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

encrypted

+ + +
+
+ +
+ The encrypted payload. +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ + + +
+

modification :Boolean

+ + +
+
+ +
+ If after decrypting the packet this is set to true, +a modification has been detected and thus the contents +should be discarded. +
+ + + +
Type:
+
    +
  • + +Boolean + + +
  • +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

decrypt(sessionKeyAlgorithm, key) → {String}

+ + +
+
+ + +
+ Decrypts the encrypted data contained in this object read_packet must +have been called before +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sessionKeyAlgorithm + + +Integer + + + + The selected symmetric encryption algorithm to be used
key + + +String + + + + The key of cipher blocksize length to be used
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The decrypted data of this packet +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/sym_encrypted_integrity_protected.js.html b/doc/sym_encrypted_integrity_protected.js.html new file mode 100644 index 00000000..a83f5c41 --- /dev/null +++ b/doc/sym_encrypted_integrity_protected.js.html @@ -0,0 +1,171 @@ + + + + + JSDoc: Source: packet/sym_encrypted_integrity_protected.js + + + + + + + + + + +
+ +

Source: packet/sym_encrypted_integrity_protected.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the Sym. Encrypted Integrity Protected Data
+ * Packet (Tag 18)<br/>
+ * <br/>
+ * RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is
+ * a variant of the Symmetrically Encrypted Data packet. It is a new feature
+ * created for OpenPGP that addresses the problem of detecting a modification to
+ * encrypted data. It is used in combination with a Modification Detection Code
+ * packet.
+ * @requires crypto
+ * @requires util
+ * @module packet/sym_encrypted_integrity_protected
+ */
+
+var util = require('../util'),
+  crypto = require('../crypto');
+
+/**
+ * @constructor
+ */
+module.exports = function sym_encrypted_integrity_protected() {
+  /** The encrypted payload. */
+  this.encrypted = null; // string
+  /**
+   * If after decrypting the packet this is set to true,
+   * a modification has been detected and thus the contents
+   * should be discarded.
+   * @type {Boolean}
+   */
+  this.modification = false;
+  this.packets = null;
+
+
+  this.read = function (bytes) {
+    // - A one-octet version number. The only currently defined value is 1.
+    var version = bytes.charCodeAt(0);
+
+    if (version != 1) {
+      throw new Error('Invalid packet version.');
+    }
+
+    // - Encrypted data, the output of the selected symmetric-key cipher
+    //   operating in Cipher Feedback mode with shift amount equal to the
+    //   block size of the cipher (CFB-n where n is the block size).
+    this.encrypted = bytes.substr(1);
+  };
+
+  this.write = function () {
+
+    return String.fromCharCode(1) // Version
+    + this.encrypted;
+  };
+
+  this.encrypt = function (sessionKeyAlgorithm, key) {
+    var bytes = this.packets.write()
+
+    var prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm);
+    var prefix = prefixrandom + prefixrandom.charAt(prefixrandom.length - 2) + prefixrandom.charAt(prefixrandom.length -
+      1)
+
+    var tohash = bytes;
+
+
+    // Modification detection code packet.
+    tohash += String.fromCharCode(0xD3);
+    tohash += String.fromCharCode(0x14);
+
+
+    tohash += crypto.hash.sha1(prefix + tohash);
+
+
+    this.encrypted = crypto.cfb.encrypt(prefixrandom,
+      sessionKeyAlgorithm, tohash, key, false).substring(0,
+      prefix.length + tohash.length);
+  };
+
+  /**
+   * Decrypts the encrypted data contained in this object read_packet must
+   * have been called before
+   * 
+   * @param {Integer} sessionKeyAlgorithm
+   *            The selected symmetric encryption algorithm to be used
+   * @param {String} key The key of cipher blocksize length to be used
+   * @return {String} The decrypted data of this packet
+   */
+  this.decrypt = function (sessionKeyAlgorithm, key) {
+    var decrypted = crypto.cfb.decrypt(
+      sessionKeyAlgorithm, key, this.encrypted, false);
+
+
+    // there must be a modification detection code packet as the
+    // last packet and everything gets hashed except the hash itself
+    this.hash = crypto.hash.sha1(
+      crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted) + decrypted.substring(0, decrypted.length - 20));
+
+
+    var mdc = decrypted.substr(decrypted.length - 20, 20);
+
+    if (this.hash != mdc) {
+      throw new Error('Modification detected.');
+    } else
+      this.packets.read(decrypted.substr(0, decrypted.length - 22));
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/sym_encrypted_session_key.html b/doc/sym_encrypted_session_key.html new file mode 100644 index 00000000..82399392 --- /dev/null +++ b/doc/sym_encrypted_session_key.html @@ -0,0 +1,492 @@ + + + + + JSDoc: Module: packet/sym_encrypted_session_key + + + + + + + + + + +
+ +

Module: packet/sym_encrypted_session_key

+ + + + + +
+ +
+

+ packet/sym_encrypted_session_key +

+ +
+ +
+
+ + +
Public-Key Encrypted Session Key Packets (Tag 1)
+
+RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key +used to encrypt a message. Zero or more Public-Key Encrypted Session Key +packets and/or Symmetric-Key Encrypted Session Key packets may precede a +Symmetrically Encrypted Data Packet, which holds an encrypted message. The +message is encrypted with the session key, and the session key is itself +encrypted and stored in the Encrypted Session Key packet(s). The +Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted +Session Key packet for each OpenPGP key to which the message is encrypted. +The recipient of the message finds a session key that is encrypted to their +public key, decrypts the session key, and then uses the session key to +decrypt the message.
+ + +
+

new (require("packet/sym_encrypted_session_key"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

decrypt() → {String}

+ + +
+
+ + +
+ Decrypts the session key (only for public key encrypted session key +packets (tag 1) +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The unencrypted session key +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

read(input, position, len) → {module:packet/sym_encrypted_session_key}

+ + +
+
+ + +
+ Parsing function for a symmetric encrypted session key packet (tag 3). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Payload of a tag 1 packet
position + + +Integer + + + + Position to start reading from the input string
len + + +Integer + + + + Length of the packet or the remaining length of + input at position
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Object representation +
+ + + +
+
+ Type +
+
+ +module:packet/sym_encrypted_session_key + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/sym_encrypted_session_key.js.html b/doc/sym_encrypted_session_key.js.html new file mode 100644 index 00000000..5fa2357c --- /dev/null +++ b/doc/sym_encrypted_session_key.js.html @@ -0,0 +1,190 @@ + + + + + JSDoc: Source: packet/sym_encrypted_session_key.js + + + + + + + + + + +
+ +

Source: packet/sym_encrypted_session_key.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Public-Key Encrypted Session Key Packets (Tag 1)<br/>
+ * <br/>
+ * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
+ * used to encrypt a message. Zero or more Public-Key Encrypted Session Key
+ * packets and/or Symmetric-Key Encrypted Session Key packets may precede a
+ * Symmetrically Encrypted Data Packet, which holds an encrypted message. The
+ * message is encrypted with the session key, and the session key is itself
+ * encrypted and stored in the Encrypted Session Key packet(s). The
+ * Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
+ * Session Key packet for each OpenPGP key to which the message is encrypted.
+ * The recipient of the message finds a session key that is encrypted to their
+ * public key, decrypts the session key, and then uses the session key to
+ * decrypt the message.
+ * @requires crypto
+ * @requires enums
+ * @requires type/s2k
+ * @module packet/sym_encrypted_session_key
+ */
+
+var type_s2k = require('../type/s2k.js'),
+  enums = require('../enums.js'),
+  crypto = require('../crypto');
+
+/**
+ * @constructor
+ */
+module.exports = function sym_encrypted_session_key() {
+  this.tag = 3;
+  this.sessionKeyEncryptionAlgorithm = null;
+  this.sessionKeyAlgorithm = 'aes256';
+  this.encrypted = null;
+  this.s2k = new type_s2k();
+
+  /**
+   * Parsing function for a symmetric encrypted session key packet (tag 3).
+   * 
+   * @param {String} input Payload of a tag 1 packet
+   * @param {Integer} position Position to start reading from the input string
+   * @param {Integer} len
+   *            Length of the packet or the remaining length of
+   *            input at position
+   * @return {module:packet/sym_encrypted_session_key} Object representation
+   */
+  this.read = function(bytes) {
+    // A one-octet version number. The only currently defined version is 4.
+    this.version = bytes.charCodeAt(0);
+
+    // A one-octet number describing the symmetric algorithm used.
+    var algo = enums.read(enums.symmetric, bytes.charCodeAt(1));
+
+    // A string-to-key (S2K) specifier, length as defined above.
+    var s2klength = this.s2k.read(bytes.substr(2));
+
+    // Optionally, the encrypted session key itself, which is decrypted
+    // with the string-to-key object.
+    var done = s2klength + 2;
+
+    if (done < bytes.length) {
+      this.encrypted = bytes.substr(done);
+      this.sessionKeyEncryptionAlgorithm = algo
+    } else
+      this.sessionKeyAlgorithm = algo;
+  };
+
+  this.write = function() {
+    var algo = this.encrypted == null ?
+      this.sessionKeyAlgorithm :
+      this.sessionKeyEncryptionAlgorithm;
+
+    var bytes = String.fromCharCode(this.version) +
+      String.fromCharCode(enums.write(enums.symmetric, algo)) +
+      this.s2k.write();
+
+    if (this.encrypted != null)
+      bytes += this.encrypted;
+    return bytes;
+  };
+
+  /**
+   * Decrypts the session key (only for public key encrypted session key
+   * packets (tag 1)
+   * 
+   * @return {String} The unencrypted session key
+   */
+  this.decrypt = function(passphrase) {
+    var algo = this.sessionKeyEncryptionAlgorithm != null ?
+      this.sessionKeyEncryptionAlgorithm :
+      this.sessionKeyAlgorithm;
+
+
+    var length = crypto.cipher[algo].keySize;
+    var key = this.s2k.produce_key(passphrase, length);
+
+    if (this.encrypted == null) {
+      this.sessionKey = key;
+
+    } else {
+      var decrypted = crypto.cfb.decrypt(
+        this.sessionKeyEncryptionAlgorithm, key, this.encrypted, true);
+
+      this.sessionKeyAlgorithm = enums.read(enums.symmetric,
+        decrypted[0].keyCodeAt());
+
+      this.sessionKey = decrypted.substr(1);
+    }
+  };
+
+  this.encrypt = function(passphrase) {
+    var length = crypto.getKeyLength(this.sessionKeyEncryptionAlgorithm);
+    var key = this.s2k.produce_key(passphrase, length);
+
+    var private_key = String.fromCharCode(
+      enums.write(enums.symmetric, this.sessionKeyAlgorithm)) +
+
+    crypto.getRandomBytes(
+      crypto.getKeyLength(this.sessionKeyAlgorithm));
+
+    this.encrypted = crypto.cfb.encrypt(
+      crypto.getPrefixRandom(this.sessionKeyEncryptionAlgorithm),
+      this.sessionKeyEncryptionAlgorithm, key, private_key, true);
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/symmetrically_encrypted.html b/doc/symmetrically_encrypted.html new file mode 100644 index 00000000..ad3006af --- /dev/null +++ b/doc/symmetrically_encrypted.html @@ -0,0 +1,413 @@ + + + + + JSDoc: Module: packet/symmetrically_encrypted + + + + + + + + + + +
+ +

Module: packet/symmetrically_encrypted

+ + + + + +
+ +
+

+ packet/symmetrically_encrypted +

+ +
+ +
+
+ + +
Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
+
+RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted +with a symmetric-key algorithm. When it has been decrypted, it contains other +packets (usually a literal data packet or compressed data packet, but in +theory other Symmetrically Encrypted Data packets or sequences of packets +that form whole OpenPGP messages).
+ + +
+

new (require("packet/symmetrically_encrypted"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

packets :module:packet/packetlist

+ + +
+
+ +
+ Decrypted packets contained within. +
+ + + +
Type:
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

decrypt(sessionKeyAlgorithm, key)

+ + +
+
+ + +
+ Symmetrically decrypt the packet data +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sessionKeyAlgorithm + + +Integer + + + + Symmetric key algorithm to use // See RFC4880 9.2
key + + +String + + + + Key as string with the corresponding length to the + algorithm
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/symmetrically_encrypted.js.html b/doc/symmetrically_encrypted.js.html new file mode 100644 index 00000000..befbf8e1 --- /dev/null +++ b/doc/symmetrically_encrypted.js.html @@ -0,0 +1,121 @@ + + + + + JSDoc: Source: packet/symmetrically_encrypted.js + + + + + + + + + + +
+ +

Source: packet/symmetrically_encrypted.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the Symmetrically Encrypted Data Packet (Tag 9)<br/>
+ * <br/>
+ * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted
+ * with a symmetric-key algorithm. When it has been decrypted, it contains other
+ * packets (usually a literal data packet or compressed data packet, but in
+ * theory other Symmetrically Encrypted Data packets or sequences of packets
+ * that form whole OpenPGP messages).
+ * @requires crypto
+ * @module packet/symmetrically_encrypted
+ */
+
+var crypto = require('../crypto');
+
+/**
+ * @constructor
+ */
+module.exports = function symmetrically_encrypted() {
+  this.encrypted = null;
+  /** Decrypted packets contained within. 
+   * @type {module:packet/packetlist} */
+  this.packets =  null;
+
+  this.read = function(bytes) {
+    this.encrypted = bytes;
+  };
+
+  this.write = function() {
+    return this.encrypted;
+  };
+
+  /**
+   * Symmetrically decrypt the packet data
+   * 
+   * @param {Integer} sessionKeyAlgorithm
+   *             Symmetric key algorithm to use // See RFC4880 9.2
+   * @param {String} key
+   *             Key as string with the corresponding length to the
+   *            algorithm
+   */
+  this.decrypt = function(sessionKeyAlgorithm, key) {
+    var decrypted = crypto.cfb.decrypt(
+      sessionKeyAlgorithm, key, this.encrypted, true);
+
+    this.packets.read(decrypted);
+  };
+
+  this.encrypt = function(algo, key) {
+    var data = this.packets.write();
+
+    this.encrypted = crypto.cfb.encrypt(
+      crypto.getPrefixRandom(algo), algo, data, key, true);
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/trust.html b/doc/trust.html new file mode 100644 index 00000000..4ab78f4c --- /dev/null +++ b/doc/trust.html @@ -0,0 +1,186 @@ + + + + + JSDoc: Module: packet/trust + + + + + + + + + + +
+ +

Module: packet/trust

+ + + + + +
+ +
+

+ packet/trust +

+ +
+ +
+
+ + + +
+

new (require("packet/trust"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/trust.js.html b/doc/trust.js.html new file mode 100644 index 00000000..aa796bc7 --- /dev/null +++ b/doc/trust.js.html @@ -0,0 +1,60 @@ + + + + + JSDoc: Source: packet/trust.js + + + + + + + + + + +
+ +

Source: packet/trust.js

+ + + + + +
+
+
/**
+ * @module packet/trust
+ */
+
+/**
+ * @constructor
+ */
+module.exports = function trust() {
+
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/twofish.html b/doc/twofish.html new file mode 100644 index 00000000..a13b1507 --- /dev/null +++ b/doc/twofish.html @@ -0,0 +1,120 @@ + + + + + JSDoc: Module: crypto/cipher/twofish + + + + + + + + + + +
+ +

Module: crypto/cipher/twofish

+ + + + + +
+ +
+

+ crypto/cipher/twofish +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:40 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/twofish.js.html b/doc/twofish.js.html new file mode 100644 index 00000000..a4354261 --- /dev/null +++ b/doc/twofish.js.html @@ -0,0 +1,432 @@ + + + + + JSDoc: Source: crypto/cipher/twofish.js + + + + + + + + + + +
+ +

Source: crypto/cipher/twofish.js

+ + + + + +
+
+
/* Modified by Recurity Labs GmbH 
+ * 
+ * Cipher.js
+ * A block-cipher algorithm implementation on JavaScript
+ * See Cipher.readme.txt for further information.
+ *
+ * Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ]
+ * This script file is distributed under the LGPL
+ *
+ * ACKNOWLEDGMENT
+ *
+ *     The main subroutines are written by Michiel van Everdingen.
+ * 
+ *     Michiel van Everdingen
+ *     http://home.versatel.nl/MAvanEverdingen/index.html
+ * 
+ *     All rights for these routines are reserved to Michiel van Everdingen.
+ *
+ */
+
+/**
+ * @module crypto/cipher/twofish
+ */
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//Math
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+var MAXINT = 0xFFFFFFFF;
+
+function rotb(b, n) {
+  return (b << n | b >>> (8 - n)) & 0xFF;
+}
+
+function rotw(w, n) {
+  return (w << n | w >>> (32 - n)) & MAXINT;
+}
+
+function getW(a, i) {
+  return a[i] | a[i + 1] << 8 | a[i + 2] << 16 | a[i + 3] << 24;
+}
+
+function setW(a, i, w) {
+  a.splice(i, 4, w & 0xFF, (w >>> 8) & 0xFF, (w >>> 16) & 0xFF, (w >>> 24) & 0xFF);
+}
+
+function setWInv(a, i, w) {
+  a.splice(i, 4, (w >>> 24) & 0xFF, (w >>> 16) & 0xFF, (w >>> 8) & 0xFF, w & 0xFF);
+}
+
+function getB(x, n) {
+  return (x >>> (n * 8)) & 0xFF;
+}
+
+function getNrBits(i) {
+  var n = 0;
+  while (i > 0) {
+    n++;
+    i >>>= 1;
+  }
+  return n;
+}
+
+function getMask(n) {
+  return (1 << n) - 1;
+}
+
+//added 2008/11/13 XXX MUST USE ONE-WAY HASH FUNCTION FOR SECURITY REASON
+
+function randByte() {
+  return Math.floor(Math.random() * 256);
+}
+// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Twofish
+// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+function createTwofish() {
+  //
+  var keyBytes = null;
+  var dataBytes = null;
+  var dataOffset = -1;
+  // var dataLength = -1;
+  var algorithmName = null;
+  // var idx2 = -1;
+  //
+
+  algorithmName = "twofish";
+
+  var tfsKey = [];
+  var tfsM = [
+    [],
+    [],
+    [],
+    []
+  ];
+
+  function tfsInit(key) {
+    keyBytes = key;
+    var i, a, b, c, d, meKey = [],
+      moKey = [],
+      inKey = [];
+    var kLen;
+    var sKey = [];
+    var f01, f5b, fef;
+
+    var q0 = [
+      [8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4],
+      [2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5]
+    ];
+    var q1 = [
+      [14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13],
+      [1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8]
+    ];
+    var q2 = [
+      [11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1],
+      [4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15]
+    ];
+    var q3 = [
+      [13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10],
+      [11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10]
+    ];
+    var ror4 = [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15];
+    var ashx = [0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7];
+    var q = [
+      [],
+      []
+    ];
+    var m = [
+      [],
+      [],
+      [],
+      []
+    ];
+
+    function ffm5b(x) {
+      return x ^ (x >> 2) ^ [0, 90, 180, 238][x & 3];
+    }
+
+    function ffmEf(x) {
+      return x ^ (x >> 1) ^ (x >> 2) ^ [0, 238, 180, 90][x & 3];
+    }
+
+    function mdsRem(p, q) {
+      var i, t, u;
+      for (i = 0; i < 8; i++) {
+        t = q >>> 24;
+        q = ((q << 8) & MAXINT) | p >>> 24;
+        p = (p << 8) & MAXINT;
+        u = t << 1;
+        if (t & 128) {
+          u ^= 333;
+        }
+        q ^= t ^ (u << 16);
+        u ^= t >>> 1;
+        if (t & 1) {
+          u ^= 166;
+        }
+        q ^= u << 24 | u << 8;
+      }
+      return q;
+    }
+
+    function qp(n, x) {
+      var a, b, c, d;
+      a = x >> 4;
+      b = x & 15;
+      c = q0[n][a ^ b];
+      d = q1[n][ror4[b] ^ ashx[a]];
+      return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d];
+    }
+
+    function hFun(x, key) {
+      var a = getB(x, 0),
+        b = getB(x, 1),
+        c = getB(x, 2),
+        d = getB(x, 3);
+      switch (kLen) {
+        case 4:
+          a = q[1][a] ^ getB(key[3], 0);
+          b = q[0][b] ^ getB(key[3], 1);
+          c = q[0][c] ^ getB(key[3], 2);
+          d = q[1][d] ^ getB(key[3], 3);
+        case 3:
+          a = q[1][a] ^ getB(key[2], 0);
+          b = q[1][b] ^ getB(key[2], 1);
+          c = q[0][c] ^ getB(key[2], 2);
+          d = q[0][d] ^ getB(key[2], 3);
+        case 2:
+          a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0);
+          b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1);
+          c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2);
+          d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3);
+      }
+      return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d];
+    }
+
+    keyBytes = keyBytes.slice(0, 32);
+    i = keyBytes.length;
+    while (i != 16 && i != 24 && i != 32)
+      keyBytes[i++] = 0;
+
+    for (i = 0; i < keyBytes.length; i += 4) {
+      inKey[i >> 2] = getW(keyBytes, i);
+    }
+    for (i = 0; i < 256; i++) {
+      q[0][i] = qp(0, i);
+      q[1][i] = qp(1, i);
+    }
+    for (i = 0; i < 256; i++) {
+      f01 = q[1][i];
+      f5b = ffm5b(f01);
+      fef = ffmEf(f01);
+      m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
+      m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);
+      f01 = q[0][i];
+      f5b = ffm5b(f01);
+      fef = ffmEf(f01);
+      m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
+      m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
+    }
+
+    kLen = inKey.length / 2;
+    for (i = 0; i < kLen; i++) {
+      a = inKey[i + i];
+      meKey[i] = a;
+      b = inKey[i + i + 1];
+      moKey[i] = b;
+      sKey[kLen - i - 1] = mdsRem(a, b);
+    }
+    for (i = 0; i < 40; i += 2) {
+      a = 0x1010101 * i;
+      b = a + 0x1010101;
+      a = hFun(a, meKey);
+      b = rotw(hFun(b, moKey), 8);
+      tfsKey[i] = (a + b) & MAXINT;
+      tfsKey[i + 1] = rotw(a + 2 * b, 9);
+    }
+    for (i = 0; i < 256; i++) {
+      a = b = c = d = i;
+      switch (kLen) {
+        case 4:
+          a = q[1][a] ^ getB(sKey[3], 0);
+          b = q[0][b] ^ getB(sKey[3], 1);
+          c = q[0][c] ^ getB(sKey[3], 2);
+          d = q[1][d] ^ getB(sKey[3], 3);
+        case 3:
+          a = q[1][a] ^ getB(sKey[2], 0);
+          b = q[1][b] ^ getB(sKey[2], 1);
+          c = q[0][c] ^ getB(sKey[2], 2);
+          d = q[0][d] ^ getB(sKey[2], 3);
+        case 2:
+          tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)] ^ getB(sKey[0], 0)];
+          tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)] ^ getB(sKey[0], 1)];
+          tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)] ^ getB(sKey[0], 2)];
+          tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)] ^ getB(sKey[0], 3)];
+      }
+    }
+  }
+
+  function tfsG0(x) {
+    return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)] ^ tfsM[3][getB(x, 3)];
+  }
+
+  function tfsG1(x) {
+    return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)] ^ tfsM[3][getB(x, 2)];
+  }
+
+  function tfsFrnd(r, blk) {
+    var a = tfsG0(blk[0]);
+    var b = tfsG1(blk[1]);
+    blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31);
+    blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT;
+    a = tfsG0(blk[2]);
+    b = tfsG1(blk[3]);
+    blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31);
+    blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT;
+  }
+
+  function tfsIrnd(i, blk) {
+    var a = tfsG0(blk[0]);
+    var b = tfsG1(blk[1]);
+    blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT;
+    blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31);
+    a = tfsG0(blk[2]);
+    b = tfsG1(blk[3]);
+    blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT;
+    blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31);
+  }
+
+  function tfsClose() {
+    tfsKey = [];
+    tfsM = [
+      [],
+      [],
+      [],
+      []
+    ];
+  }
+
+  function tfsEncrypt(data, offset) {
+    dataBytes = data;
+    dataOffset = offset;
+    var blk = [getW(dataBytes, dataOffset) ^ tfsKey[0],
+        getW(dataBytes, dataOffset + 4) ^ tfsKey[1],
+        getW(dataBytes, dataOffset + 8) ^ tfsKey[2],
+        getW(dataBytes, dataOffset + 12) ^ tfsKey[3]
+    ];
+    for (var j = 0; j < 8; j++) {
+      tfsFrnd(j, blk);
+    }
+    setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]);
+    setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]);
+    setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]);
+    setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]);
+    dataOffset += 16;
+    return dataBytes;
+  }
+
+  function tfsDecrypt(data, offset) {
+    dataBytes = data;
+    dataOffset = offset;
+    var blk = [getW(dataBytes, dataOffset) ^ tfsKey[4],
+        getW(dataBytes, dataOffset + 4) ^ tfsKey[5],
+        getW(dataBytes, dataOffset + 8) ^ tfsKey[6],
+        getW(dataBytes, dataOffset + 12) ^ tfsKey[7]
+    ];
+    for (var j = 7; j >= 0; j--) {
+      tfsIrnd(j, blk);
+    }
+    setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]);
+    setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]);
+    setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]);
+    setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]);
+    dataOffset += 16;
+  }
+
+  // added by Recurity Labs
+
+  function tfsFinal() {
+    return dataBytes;
+  }
+
+  return {
+    name: "twofish",
+    blocksize: 128 / 8,
+    open: tfsInit,
+    close: tfsClose,
+    encrypt: tfsEncrypt,
+    decrypt: tfsDecrypt,
+    // added by Recurity Labs
+    finalize: tfsFinal
+  };
+}
+
+var util = require('../../util');
+
+// added by Recurity Labs
+
+function TFencrypt(block, key) {
+  var block_copy = [].concat(block);
+  var tf = createTwofish();
+  tf.open(util.str2bin(key), 0);
+  var result = tf.encrypt(block_copy, 0);
+  tf.close();
+  return result;
+}
+
+function TF(key) {
+  this.tf = createTwofish();
+  this.tf.open(util.str2bin(key), 0);
+
+  this.encrypt = function(block) {
+    return this.tf.encrypt([].concat(block), 0);
+  }
+}
+
+
+module.exports = TF;
+module.exports.keySize = TF.prototype.keySize = 32;
+module.exports.blockSize = TF.prototype.blockSize = 16;
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/user_attribute.html b/doc/user_attribute.html new file mode 100644 index 00000000..044cd0e1 --- /dev/null +++ b/doc/user_attribute.html @@ -0,0 +1,324 @@ + + + + + JSDoc: Module: packet/user_attribute + + + + + + + + + + +
+ +

Module: packet/user_attribute

+ + + + + +
+ +
+

+ packet/user_attribute +

+ +
+ +
+
+ + +
Implementation of the User Attribute Packet (Tag 17)
+
+The User Attribute packet is a variation of the User ID packet. It +is capable of storing more types of data than the User ID packet, +which is limited to text. Like the User ID packet, a User Attribute +packet may be certified by the key owner ("self-signed") or any other +key owner who cares to certify it. Except as noted, a User Attribute +packet may be used anywhere that a User ID packet may be used. +
+While User Attribute packets are not a required part of the OpenPGP +standard, implementations SHOULD provide at least enough +compatibility to properly handle a certification signature on the +User Attribute packet. A simple way to do this is by treating the +User Attribute packet as a User ID packet with opaque contents, but +an implementation may use any method desired. +module packet/user_attribute
+ + +
+

new (require("packet/user_attribute"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

read(input)

+ + +
+
+ + +
+ parsing function for a user attribute packet (tag 17). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + payload of a tag 17 packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/user_attribute.js.html b/doc/user_attribute.js.html new file mode 100644 index 00000000..81e0c7cf --- /dev/null +++ b/doc/user_attribute.js.html @@ -0,0 +1,112 @@ + + + + + JSDoc: Source: packet/user_attribute.js + + + + + + + + + + +
+ +

Source: packet/user_attribute.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the User Attribute Packet (Tag 17)<br/>
+ * <br/>
+ * The User Attribute packet is a variation of the User ID packet.  It
+ * is capable of storing more types of data than the User ID packet,
+ * which is limited to text.  Like the User ID packet, a User Attribute
+ * packet may be certified by the key owner ("self-signed") or any other
+ * key owner who cares to certify it.  Except as noted, a User Attribute
+ * packet may be used anywhere that a User ID packet may be used.
+ * <br/>
+ * While User Attribute packets are not a required part of the OpenPGP
+ * standard, implementations SHOULD provide at least enough
+ * compatibility to properly handle a certification signature on the
+ * User Attribute packet.  A simple way to do this is by treating the
+ * User Attribute packet as a User ID packet with opaque contents, but
+ * an implementation may use any method desired.
+ * module packet/user_attribute
+ * @module packet/user_attribute
+ */
+
+var util = require('../util'),
+  packet = require('./packet.js');
+
+/**
+ * @constructor
+ */
+module.exports = function user_attribute() {
+  this.tag = 17;
+  this.attributes = [];
+
+  /**
+   * parsing function for a user attribute packet (tag 17).
+   * @param {String} input payload of a tag 17 packet
+   */
+  this.read = function(bytes) {
+    var i = 0;
+    while (i < bytes.length) {
+      var len = packet.readSimpleLength(bytes.substr(i));
+      i += len.offset;
+
+      this.attributes.push(bytes.substr(i, len.len));
+      i += len.len;
+    }
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/userid.html b/doc/userid.html new file mode 100644 index 00000000..577681ef --- /dev/null +++ b/doc/userid.html @@ -0,0 +1,481 @@ + + + + + JSDoc: Module: packet/userid + + + + + + + + + + +
+ +

Module: packet/userid

+ + + + + +
+ +
+

+ packet/userid +

+ +
+ +
+
+ + +
Implementation of the User ID Packet (Tag 13)
+
+A User ID packet consists of UTF-8 text that is intended to represent +the name and email address of the key holder. By convention, it +includes an RFC 2822 [RFC2822] mail name-addr, but there are no +restrictions on its content. The packet length in the header +specifies the length of the User ID.
+ + +
+

new (require("packet/userid"))()

+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + +

Members

+ +
+ +
+

userid :String

+ + +
+
+ +
+ A string containing the user id. Usually in the form +John Doe +
+ + + +
Type:
+
    +
  • + +String + + +
  • +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

read(input)

+ + +
+
+ + +
+ Parsing function for a user id packet (tag 13). +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + payload of a tag 13 packet
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

write() → {String}

+ + +
+
+ + +
+ Creates a string representation of the user id packet +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ string representation +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:44 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/userid.js.html b/doc/userid.js.html new file mode 100644 index 00000000..25f1adf3 --- /dev/null +++ b/doc/userid.js.html @@ -0,0 +1,108 @@ + + + + + JSDoc: Source: packet/userid.js + + + + + + + + + + +
+ +

Source: packet/userid.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * Implementation of the User ID Packet (Tag 13)<br/>
+ * <br/>
+ * A User ID packet consists of UTF-8 text that is intended to represent
+ * the name and email address of the key holder.  By convention, it
+ * includes an RFC 2822 [RFC2822] mail name-addr, but there are no
+ * restrictions on its content.  The packet length in the header
+ * specifies the length of the User ID.
+ * @requires util
+ * @module packet/userid
+ */
+
+var util = require('../util');
+
+/**
+ * @constructor
+ */
+module.exports = function userid() {
+  /** A string containing the user id. Usually in the form
+   * John Doe <john@example.com>
+   * @type {String} 
+   */
+  this.userid = '';
+
+
+  /**
+   * Parsing function for a user id packet (tag 13).
+   * @param {String} input payload of a tag 13 packet
+   */
+  this.read = function (bytes) {
+    this.userid = util.decode_utf8(bytes);
+  };
+
+  /**
+   * Creates a string representation of the user id packet
+   * @return {String} string representation
+   */
+  this.write = function () {
+    return util.encode_utf8(this.userid);
+  };
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST) +
+ + + + + diff --git a/doc/util.html b/doc/util.html new file mode 100644 index 00000000..bbbe6e34 --- /dev/null +++ b/doc/util.html @@ -0,0 +1,2015 @@ + + + + + JSDoc: Module: util/util + + + + + + + + + + +
+ +

Module: util/util

+ + + + + +
+ +
+

+ util/util +

+ +
+ +
+
+ + + + +
This object contains utility functions
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + +
+ + + + + + +

Requires

+ + + + + + + + + + + +

Methods

+ +
+ +
+

<static> bin2str(bin) → {String}

+ + +
+
+ + +
+ Convert an array of integers(0.255) to a string +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bin + + +Array.<Integer> + + + + An array of (binary) integers to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The string representation of the array +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> calc_checksum(text) → {Integer}

+ + +
+
+ + +
+ Calculates a 16bit sum of a string by adding each character +codes modulus 65535 +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + String to create a sum of
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ An integer containing the sum of all character +codes % 65535 +
+ + + +
+
+ Type +
+
+ +Integer + + +
+
+ + + + +
+ + + +
+

<static> decode_utf8(utf8) → {String}

+ + +
+
+ + +
+ Convert a string of utf8 bytes to a native javascript string +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
utf8 + + +String + + + + A valid squence of utf8 bytes
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A native javascript string +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> encode_utf8(str) → {String}

+ + +
+
+ + +
+ Convert a native javascript string to a string of utf8 bytes +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + The string to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ A valid squence of utf8 bytes +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> get_hashAlgorithmString() → {String}

+ + +
+
+ + +
+ Return the algorithm type as string +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ String representing the message type +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> hex2bin(str) → {String}

+ + +
+
+ + +
+ Create binary string from a hex encoded string +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + Hex string to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ String containing the binary values +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> hexidump(str) → {String}

+ + +
+
+ + +
+ Creating a hex string from an binary array of integers (0..255) +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + Array of bytes to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Hexadecimal representation of the array +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> hexstrdump(str) → {String}

+ + +
+
+ + +
+ Create hexstring from a binary +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + String to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ String containing the hexadecimal values +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+ + + +
+
+ + +
+ Helper function to print a debug message. Debug +messages are only printed if +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + String of the debug message
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+ + + +
+
+ + +
+ Helper function to print a debug message. Debug +messages are only printed if +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + String of the debug message
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+

<static> shiftRight(value, bitcount) → {String}

+ + +
+
+ + +
+ Shifting a string to n bits right +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +String + + + + The string to shift
bitcount + + +Integer + + + + Amount of bits to shift (MUST be smaller +than 9)
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ Resulting string. +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ + + +
+

<static> str2bin(str) → {Array.<Integer>}

+ + +
+
+ + +
+ Convert a string to an array of integers(0.255) +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + String to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ An array of (binary) integers +
+ + + +
+
+ Type +
+
+ +Array.<Integer> + + +
+
+ + + + +
+ + + +
+

<static> str2Uint8Array(str) → {Uint8Array}

+ + +
+
+ + +
+ Convert a string to a Uint8Array +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
str + + +String + + + + String to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ The array of (binary) integers +
+ + + +
+
+ Type +
+
+ +Uint8Array + + +
+
+ + + + +
+ + + +
+

<static> Uint8Array2str(bin) → {String}

+ + +
+
+ + +
+ Convert a Uint8Array to a string. This currently functions +the same as bin2str. +
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bin + + +Uint8Array + + + + An array of (binary) integers to convert
+ + + +
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+ String representation of the array +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:45 GMT-0800 (PST) +
+ + + + + \ No newline at end of file diff --git a/doc/util.js.html b/doc/util.js.html index d90e97b1..dac2954e 100644 --- a/doc/util.js.html +++ b/doc/util.js.html @@ -42,293 +42,293 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -var Util = function() { - - this.emailRegEx = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; - - this.hexdump = function(str) { - var r=[]; - var e=str.length; - var c=0; - var h; - var i = 0; - while(c<e){ - h=str.charCodeAt(c++).toString(16); - while(h.length<2) h="0"+h; - r.push(" "+h); - i++; - if (i % 32 == 0) - r.push("\n "); - } - return r.join(''); - }; - - /** - * Create hexstring from a binary - * @param {String} str String to convert - * @return {String} String containing the hexadecimal values - */ - this.hexstrdump = function(str) { - if (str == null) - return ""; - var r=[]; - var e=str.length; - var c=0; - var h; - while(c<e){ - h=str[c++].charCodeAt().toString(16); - while(h.length<2) h="0"+h; - r.push(""+h); - } - return r.join(''); - }; - - /** - * Create binary string from a hex encoded string - * @param {String} str Hex string to convert - * @return {String} String containing the binary values - */ - this.hex2bin = function(hex) { - var str = ''; - for (var i = 0; i < hex.length; i += 2) - str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); - return str; - }; - - /** - * Creating a hex string from an binary array of integers (0..255) - * @param {String} str Array of bytes to convert - * @return {String} Hexadecimal representation of the array - */ - this.hexidump = function(str) { - var r=[]; - var e=str.length; - var c=0; - var h; - while(c<e){ - h=str[c++].toString(16); - while(h.length<2) h="0"+h; - r.push(""+h); - } - return r.join(''); - }; - - - /** - * Convert a native javascript string to a string of utf8 bytes - * @param {String} str The string to convert - * @return {String} A valid squence of utf8 bytes - */ - this.encode_utf8 = function(str) { - return unescape(encodeURIComponent(str)); - }; - - /** - * Convert a string of utf8 bytes to a native javascript string - * @param {String} utf8 A valid squence of utf8 bytes - * @return {String} A native javascript string - */ - this.decode_utf8 = function(utf8) { - return decodeURIComponent(escape(utf8)); - }; - - var str2bin = function(str, result) { - for (var i = 0; i < str.length; i++) { - result[i] = str.charCodeAt(i); - } - - return result; - }; - - var bin2str = function(bin) { - var result = []; - - for (var i = 0; i < bin.length; i++) { - result.push(String.fromCharCode(bin[i])); - } - - return result.join(''); - }; - - /** - * Convert a string to an array of integers(0.255) - * @param {String} str String to convert - * @return {Integer[]} An array of (binary) integers - */ - this.str2bin = function(str) { - return str2bin(str, new Array(str.length)); - }; - - - /** - * Convert an array of integers(0.255) to a string - * @param {Integer[]} bin An array of (binary) integers to convert - * @return {String} The string representation of the array - */ - this.bin2str = bin2str; - - /** - * Convert a string to a Uint8Array - * @param {String} str String to convert - * @return {Uint8Array} The array of (binary) integers - */ - this.str2Uint8Array = function(str) { - return str2bin(str, new Uint8Array(new ArrayBuffer(str.length))); - }; - - /** - * Convert a Uint8Array to a string. This currently functions - * the same as bin2str. - * @param {Uint8Array} bin An array of (binary) integers to convert - * @return {String} String representation of the array - */ - this.Uint8Array2str = bin2str; - - /** - * Calculates a 16bit sum of a string by adding each character - * codes modulus 65535 - * @param {String} text String to create a sum of - * @return {Integer} An integer containing the sum of all character - * codes % 65535 - */ - this.calc_checksum = function(text) { - var checksum = { s: 0, add: function (sadd) { this.s = (this.s + sadd) % 65536; }}; - for (var i = 0; i < text.length; i++) { - checksum.add(text.charCodeAt(i)); - } - return checksum.s; - }; - - /** - * Helper function to print a debug message. Debug - * messages are only printed if - * openpgp.config.debug is set to true. The calling - * Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '<br/>' - * @param {String} str String of the debug message - * @return {String} An HTML tt entity containing a paragraph with a - * style attribute where the debug message is HTMLencoded in. - */ - this.print_debug = function(str) { - if (openpgp.config.debug) { - str = openpgp_encoding_html_encode(str); - showMessages("<tt><p style=\"background-color: #ffffff; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\">"+str.replace(/\n/g,"<br>")+"</p></tt>"); - } - }; - - /** - * Helper function to print a debug message. Debug - * messages are only printed if - * openpgp.config.debug is set to true. The calling - * Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '<br/>' - * Different than print_debug because will call hexstrdump iff necessary. - * @param {String} str String of the debug message - * @return {String} An HTML tt entity containing a paragraph with a - * style attribute where the debug message is HTMLencoded in. - */ - this.print_debug_hexstr_dump = function(str,strToHex) { - if (openpgp.config.debug) { - str = str + this.hexstrdump(strToHex); - str = openpgp_encoding_html_encode(str); - showMessages("<tt><p style=\"background-color: #ffffff; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\">"+str.replace(/\n/g,"<br>")+"</p></tt>"); - } - }; - - /** - * Helper function to print an error message. - * The calling Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '<br/>' - * @param {String} str String of the error message - * @return {String} A HTML paragraph entity with a style attribute - * containing the HTML encoded error message - */ - this.print_error = function(str) { - str = openpgp_encoding_html_encode(str); - showMessages("<p style=\"font-size: 80%; background-color: #FF8888; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>ERROR:</b></span> "+str.replace(/\n/g,"<br>")+"</p>"); - }; - - /** - * Helper function to print an info message. - * The calling Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '<br/>'. - * @param {String} str String of the info message - * @return {String} A HTML paragraph entity with a style attribute - * containing the HTML encoded info message - */ - this.print_info = function(str) { - str = openpgp_encoding_html_encode(str); - showMessages("<p style=\"font-size: 80%; background-color: #88FF88; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>INFO:</b></span> "+str.replace(/\n/g,"<br>")+"</p>"); - }; - - this.print_warning = function(str) { - str = openpgp_encoding_html_encode(str); - showMessages("<p style=\"font-size: 80%; background-color: #FFAA88; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>WARNING:</b></span> "+str.replace(/\n/g,"<br>")+"</p>"); - }; - - this.getLeftNBits = function (string, bitcount) { - var rest = bitcount % 8; - if (rest == 0) - return string.substring(0, bitcount / 8); - var bytes = (bitcount - rest) / 8 +1; - var result = string.substring(0, bytes); - return this.shiftRight(result, 8-rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF); - }; - - /** - * Shifting a string to n bits right - * @param {String} value The string to shift - * @param {Integer} bitcount Amount of bits to shift (MUST be smaller - * than 9) - * @return {String} Resulting string. - */ - this.shiftRight = function(value, bitcount) { - var temp = util.str2bin(value); - if (bitcount % 8 != 0) { - for (var i = temp.length-1; i >= 0; i--) { - temp[i] >>= bitcount % 8; - if (i > 0) - temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF; - } - } else { - return value; - } - return util.bin2str(temp); - }; - - /** - * Return the algorithm type as string - * @return {String} String representing the message type - */ - this.get_hashAlgorithmString = function(algo) { - switch(algo) { - case 1: - return "MD5"; - case 2: - return "SHA1"; - case 3: - return "RIPEMD160"; - case 8: - return "SHA256"; - case 9: - return "SHA384"; - case 10: - return "SHA512"; - case 11: - return "SHA224"; - } - return "unknown"; - }; -}; - /** - * an instance that should be used. + * This object contains utility functions + * @requires config + * @module util/util */ -var util = new Util(); + +var config = require('../config'); + +module.exports = { + readNumber: function (bytes) { + var n = 0; + + for (var i = 0; i < bytes.length; i++) { + n <<= 8; + n += bytes.charCodeAt(i); + } + + return n; + }, + + writeNumber: function (n, bytes) { + var b = ''; + for (var i = 0; i < bytes; i++) { + b += String.fromCharCode((n >> (8 * (bytes - i - 1))) & 0xFF); + } + + return b; + }, + + readDate: function (bytes) { + var n = this.readNumber(bytes); + var d = new Date(); + d.setTime(n * 1000); + return d; + }, + + writeDate: function (time) { + var numeric = Math.round(time.getTime() / 1000); + + return this.writeNumber(numeric, 4); + }, + + emailRegEx: /^[+a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,6}$/, + + hexdump: function (str) { + var r = []; + var e = str.length; + var c = 0; + var h; + var i = 0; + while (c < e) { + h = str.charCodeAt(c++).toString(16); + while (h.length < 2) h = "0" + h; + r.push(" " + h); + i++; + if (i % 32 == 0) + r.push("\n "); + } + return r.join(''); + }, + + /** + * Create hexstring from a binary + * @param {String} str String to convert + * @return {String} String containing the hexadecimal values + */ + hexstrdump: function (str) { + if (str == null) + return ""; + var r = []; + var e = str.length; + var c = 0; + var h; + while (c < e) { + h = str.charCodeAt(c++).toString(16); + while (h.length < 2) h = "0" + h; + r.push("" + h); + } + return r.join(''); + }, + + /** + * Create binary string from a hex encoded string + * @param {String} str Hex string to convert + * @return {String} String containing the binary values + */ + hex2bin: function (hex) { + var str = ''; + for (var i = 0; i < hex.length; i += 2) + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + return str; + }, + + /** + * Creating a hex string from an binary array of integers (0..255) + * @param {String} str Array of bytes to convert + * @return {String} Hexadecimal representation of the array + */ + hexidump: function (str) { + var r = []; + var e = str.length; + var c = 0; + var h; + while (c < e) { + h = str[c++].toString(16); + while (h.length < 2) h = "0" + h; + r.push("" + h); + } + return r.join(''); + }, + + + /** + * Convert a native javascript string to a string of utf8 bytes + * @param {String} str The string to convert + * @return {String} A valid squence of utf8 bytes + */ + encode_utf8: function (str) { + return unescape(encodeURIComponent(str)); + }, + + /** + * Convert a string of utf8 bytes to a native javascript string + * @param {String} utf8 A valid squence of utf8 bytes + * @return {String} A native javascript string + */ + decode_utf8: function (utf8) { + try { + return decodeURIComponent(escape(utf8)); + } catch (e) { + return utf8; + } + }, + + /** + * Convert an array of integers(0.255) to a string + * @param {Array<Integer>} bin An array of (binary) integers to convert + * @return {String} The string representation of the array + */ + bin2str: function (bin) { + var result = []; + + for (var i = 0; i < bin.length; i++) { + result.push(String.fromCharCode(bin[i])); + } + + return result.join(''); + }, + + _str2bin: function (str, result) { + for (var i = 0; i < str.length; i++) { + result[i] = str.charCodeAt(i); + } + + return result; + }, + + /** + * Convert a string to an array of integers(0.255) + * @param {String} str String to convert + * @return {Array<Integer>} An array of (binary) integers + */ + str2bin: function (str) { + return this._str2bin(str, new Array(str.length)); + }, + + + /** + * Convert a string to a Uint8Array + * @param {String} str String to convert + * @return {Uint8Array} The array of (binary) integers + */ + str2Uint8Array: function (str) { + return this._str2bin(str, new Uint8Array(new ArrayBuffer(str.length))); + }, + + /** + * Convert a Uint8Array to a string. This currently functions + * the same as bin2str. + * @function module:util/util.Uint8Array2str + * @param {Uint8Array} bin An array of (binary) integers to convert + * @return {String} String representation of the array + */ + Uint8Array2str: function (bin) { + return this.bin2str(bin); + }, + + /** + * Calculates a 16bit sum of a string by adding each character + * codes modulus 65535 + * @param {String} text String to create a sum of + * @return {Integer} An integer containing the sum of all character + * codes % 65535 + */ + calc_checksum: function (text) { + var checksum = { + s: 0, + add: function (sadd) { + this.s = (this.s + sadd) % 65536; + } + }; + for (var i = 0; i < text.length; i++) { + checksum.add(text.charCodeAt(i)); + } + return checksum.s; + }, + + /** + * Helper function to print a debug message. Debug + * messages are only printed if + * @link module:config/config.debug is set to true. + * @param {String} str String of the debug message + */ + print_debug: function (str) { + if (config.debug) { + console.log(str); + } + }, + + /** + * Helper function to print a debug message. Debug + * messages are only printed if + * @link module:config/config.debug is set to true. + * Different than print_debug because will call hexstrdump iff necessary. + * @param {String} str String of the debug message + */ + print_debug_hexstr_dump: function (str, strToHex) { + if (config.debug) { + str = str + this.hexstrdump(strToHex); + console.log(str); + } + }, + + getLeftNBits: function (string, bitcount) { + var rest = bitcount % 8; + if (rest == 0) + return string.substring(0, bitcount / 8); + var bytes = (bitcount - rest) / 8 + 1; + var result = string.substring(0, bytes); + return this.shiftRight(result, 8 - rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF); + }, + + /** + * Shifting a string to n bits right + * @param {String} value The string to shift + * @param {Integer} bitcount Amount of bits to shift (MUST be smaller + * than 9) + * @return {String} Resulting string. + */ + shiftRight: function (value, bitcount) { + var temp = util.str2bin(value); + if (bitcount % 8 != 0) { + for (var i = temp.length - 1; i >= 0; i--) { + temp[i] >>= bitcount % 8; + if (i > 0) + temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF; + } + } else { + return value; + } + return util.bin2str(temp); + }, + + /** + * Return the algorithm type as string + * @return {String} String representing the message type + */ + get_hashAlgorithmString: function (algo) { + switch (algo) { + case 1: + return "MD5"; + case 2: + return "SHA1"; + case 3: + return "RIPEMD160"; + case 8: + return "SHA256"; + case 9: + return "SHA384"; + case 10: + return "SHA512"; + case 11: + return "SHA224"; + } + return "unknown"; + } +}; @@ -339,15 +339,16 @@ var util = new Util();
- Documentation generated by JSDoc 3.2.0-dev on Tue Apr 16 2013 10:42:39 GMT+0200 (CEST) + Documentation generated by JSDoc 3.2.0 on Thu Jan 02 2014 13:02:39 GMT-0800 (PST)
+ diff --git a/test/encryption.html b/example/encryption.html similarity index 100% rename from test/encryption.html rename to example/encryption.html diff --git a/test/parser.html b/example/parser.html similarity index 100% rename from test/parser.html rename to example/parser.html diff --git a/jsdoc.template/README.md b/jsdoc.template/README.md new file mode 100644 index 00000000..a7bd96bf --- /dev/null +++ b/jsdoc.template/README.md @@ -0,0 +1 @@ +The default template for JSDoc 3 uses: [the Taffy Database library](http://taffydb.com/) and the [Underscore Template library](http://documentcloud.github.com/underscore/#template). diff --git a/jsdoc.template/publish.js b/jsdoc.template/publish.js new file mode 100644 index 00000000..ad23b506 --- /dev/null +++ b/jsdoc.template/publish.js @@ -0,0 +1,565 @@ +/*global env: true */ +var template = require('jsdoc/template'), + fs = require('jsdoc/fs'), + path = require('jsdoc/path'), + taffy = require('taffydb').taffy, + handle = require('jsdoc/util/error').handle, + helper = require('jsdoc/util/templateHelper'), + htmlsafe = helper.htmlsafe, + linkto = helper.linkto, + resolveAuthorLinks = helper.resolveAuthorLinks, + scopeToPunc = helper.scopeToPunc, + hasOwnProp = Object.prototype.hasOwnProperty, + data, + view, + outdir = env.opts.destination; + + +function find(spec) { + return helper.find(data, spec); +} + +function tutoriallink(tutorial) { + return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' }); +} + +function getAncestorLinks(doclet) { + return helper.getAncestorLinks(data, doclet); +} + +function hashToLink(doclet, hash) { + if ( !/^(#.+)/.test(hash) ) { return hash; } + + var url = helper.createLink(doclet); + + url = url.replace(/(#.+|$)/, hash); + return '' + hash + ''; +} + +function needsSignature(doclet) { + var needsSig = false; + + // function and class definitions always get a signature + if (doclet.kind === 'function' || doclet.kind === 'class') { + needsSig = true; + } + // typedefs that contain functions get a signature, too + else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names && + doclet.type.names.length) { + for (var i = 0, l = doclet.type.names.length; i < l; i++) { + if (doclet.type.names[i].toLowerCase() === 'function') { + needsSig = true; + break; + } + } + } + + return needsSig; +} + +function addSignatureParams(f) { + var params = helper.getSignatureParams(f, 'optional'); + + f.signature = (f.signature || '') + '('+params.join(', ')+')'; +} + +function addSignatureReturns(f) { + var returnTypes = helper.getSignatureReturns(f); + + f.signature = ''+(f.signature || '') + '' + ''+(returnTypes.length? ' → {'+returnTypes.join('|')+'}' : '')+''; +} + +function addSignatureTypes(f) { + var types = helper.getSignatureTypes(f); + + f.signature = (f.signature || '') + ''+(types.length? ' :'+types.join('|') : '')+''; +} + +function addAttribs(f) { + var attribs = helper.getAttribs(f); + + f.attribs = ''+htmlsafe(attribs.length? '<'+attribs.join(', ')+'> ' : '')+''; +} + +function shortenPaths(files, commonPrefix) { + // always use forward slashes + var regexp = new RegExp('\\\\', 'g'); + + Object.keys(files).forEach(function(file) { + files[file].shortened = files[file].resolved.replace(commonPrefix, '') + .replace(regexp, '/'); + }); + + return files; +} + +function resolveSourcePath(filepath) { + return path.resolve(process.cwd(), filepath); +} + +function getPathFromDoclet(doclet) { + if (!doclet.meta) { + return; + } + + var filepath = doclet.meta.path && doclet.meta.path !== 'null' ? + doclet.meta.path + '/' + doclet.meta.filename : + doclet.meta.filename; + + return filepath; +} + +function generate(title, docs, filename, resolveLinks) { + resolveLinks = resolveLinks === false ? false : true; + + var docData = { + title: title, + docs: docs + }; + + var outpath = path.join(outdir, filename), + html = view.render('container.tmpl', docData); + + if (resolveLinks) { + html = helper.resolveLinks(html); // turn {@link foo} into foo + } + + fs.writeFileSync(outpath, html, 'utf8'); +} + +function generateSourceFiles(sourceFiles) { + Object.keys(sourceFiles).forEach(function(file) { + var source; + // links are keyed to the shortened path in each doclet's `meta.filename` property + var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened); + helper.registerLink(sourceFiles[file].shortened, sourceOutfile); + + try { + source = { + kind: 'source', + code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, 'utf8') ) + }; + } + catch(e) { + handle(e); + } + + generate('Source: ' + sourceFiles[file].shortened, [source], sourceOutfile, + false); + }); +} + +/** + * Look for classes or functions with the same name as modules (which indicates that the module + * exports only that class or function), then attach the classes or functions to the `module` + * property of the appropriate module doclets. The name of each class or function is also updated + * for display purposes. This function mutates the original arrays. + * + * @private + * @param {Array.} doclets - The array of classes and functions to + * check. + * @param {Array.} modules - The array of module doclets to search. + */ +function attachModuleSymbols(doclets, modules) { + var symbols = {}; + + // build a lookup table + doclets.forEach(function(symbol) { + symbols[symbol.longname] = symbol; + }); + + return modules.map(function(module) { + if (symbols[module.longname]) { + module.module = symbols[module.longname]; + if (module.module.kind == 'class') { + module.module.name = module.module.name.replace('module:', '(require("') + '"))'; + } else { + module.module.name = module.module.name.replace('module:', 'require("') + '")'; + } + } + }); +} + +/** + * Create the navigation sidebar. + * @param {object} members The members that will be used to create the sidebar. + * @param {array} members.classes + * @param {array} members.externals + * @param {array} members.globals + * @param {array} members.mixins + * @param {array} members.modules + * @param {array} members.namespaces + * @param {array} members.tutorials + * @param {array} members.events + * @return {string} The HTML for the navigation sidebar. + */ +function buildNav(members) { + var nav = '

Index

', + seen = {}, + hasClassList = false, + classNav = '', + globalNav = ''; + + if (members.modules.length) { + nav += '

Modules

    '; + members.modules.forEach(function(m) { + if ( !hasOwnProp.call(seen, m.longname) ) { + nav += '
  • '+linkto(m.longname, m.name)+'
  • '; + } + seen[m.longname] = true; + }); + + nav += '
'; + } + + if (members.externals.length) { + nav += '

Externals

    '; + members.externals.forEach(function(e) { + if ( !hasOwnProp.call(seen, e.longname) ) { + nav += '
  • '+linkto( e.longname, e.name.replace(/(^"|"$)/g, '') )+'
  • '; + } + seen[e.longname] = true; + }); + + nav += '
'; + } + + if (members.classes.length) { + members.classes.forEach(function(c) { + if ( !hasOwnProp.call(seen, c.longname) ) { + classNav += '
  • '+linkto(c.longname, c.name)+'
  • '; + } + seen[c.longname] = true; + }); + + if (classNav !== '') { + nav += '

    Classes

      '; + nav += classNav; + nav += '
    '; + } + } + + if (members.events.length) { + nav += '

    Events

      '; + members.events.forEach(function(e) { + if ( !hasOwnProp.call(seen, e.longname) ) { + nav += '
    • '+linkto(e.longname, e.name)+'
    • '; + } + seen[e.longname] = true; + }); + + nav += '
    '; + } + + if (members.namespaces.length) { + nav += '

    Namespaces

      '; + members.namespaces.forEach(function(n) { + if ( !hasOwnProp.call(seen, n.longname) ) { + nav += '
    • '+linkto(n.longname, n.name)+'
    • '; + } + seen[n.longname] = true; + }); + + nav += '
    '; + } + + if (members.mixins.length) { + nav += '

    Mixins

      '; + members.mixins.forEach(function(m) { + if ( !hasOwnProp.call(seen, m.longname) ) { + nav += '
    • '+linkto(m.longname, m.name)+'
    • '; + } + seen[m.longname] = true; + }); + + nav += '
    '; + } + + if (members.tutorials.length) { + nav += '

    Tutorials

      '; + members.tutorials.forEach(function(t) { + nav += '
    • '+tutoriallink(t.name)+'
    • '; + }); + + nav += '
    '; + } + + if (members.globals.length) { + members.globals.forEach(function(g) { + if ( g.kind !== 'typedef' && !hasOwnProp.call(seen, g.longname) ) { + globalNav += '
  • ' + linkto(g.longname, g.name) + '
  • '; + } + seen[g.longname] = true; + }); + + if (!globalNav) { + // turn the heading into a link so you can actually get to the global page + nav += '

    ' + linkto('global', 'Global') + '

    '; + } + else { + nav += '

    Global

      ' + globalNav + '
    '; + } + } + + return nav; +} + + +/** + @param {TAFFY} taffyData See . + @param {object} opts + @param {Tutorial} tutorials + */ +exports.publish = function(taffyData, opts, tutorials) { + data = taffyData; + + var conf = env.conf.templates || {}; + conf['default'] = conf['default'] || {}; + + var templatePath = opts.template; + view = new template.Template(templatePath + '/tmpl'); + + // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness + // doesn't try to hand them out later + var indexUrl = helper.getUniqueFilename('index'); + // don't call registerLink() on this one! 'index' is also a valid longname + + var globalUrl = helper.getUniqueFilename('global'); + helper.registerLink('global', globalUrl); + + // set up templating + view.layout = 'layout.tmpl'; + + // set up tutorials for helper + helper.setTutorials(tutorials); + + data = helper.prune(data); + data.sort('longname, version, since'); + helper.addEventListeners(data); + + var sourceFiles = {}; + var sourceFilePaths = []; + data().each(function(doclet) { + doclet.attribs = ''; + + if (doclet.examples) { + doclet.examples = doclet.examples.map(function(example) { + var caption, code; + + if (example.match(/^\s*([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { + caption = RegExp.$1; + code = RegExp.$3; + } + + return { + caption: caption || '', + code: code || example + }; + }); + } + if (doclet.see) { + doclet.see.forEach(function(seeItem, i) { + doclet.see[i] = hashToLink(doclet, seeItem); + }); + } + + // build a list of source files + var sourcePath; + var resolvedSourcePath; + if (doclet.meta) { + sourcePath = getPathFromDoclet(doclet); + resolvedSourcePath = resolveSourcePath(sourcePath); + sourceFiles[sourcePath] = { + resolved: resolvedSourcePath, + shortened: null + }; + sourceFilePaths.push(resolvedSourcePath); + } + }); + + // update outdir if necessary, then create outdir + var packageInfo = ( find({kind: 'package'}) || [] ) [0]; + if (packageInfo && packageInfo.name) { + outdir = path.join(outdir, packageInfo.name, packageInfo.version); + } + fs.mkPath(outdir); + + // copy the template's static files to outdir + var fromDir = path.join(templatePath, 'static'); + var staticFiles = fs.ls(fromDir, 3); + + staticFiles.forEach(function(fileName) { + var toDir = fs.toDir( fileName.replace(fromDir, outdir) ); + fs.mkPath(toDir); + fs.copyFileSync(fileName, toDir); + }); + + // copy user-specified static files to outdir + var staticFilePaths; + var staticFileFilter; + var staticFileScanner; + if (conf['default'].staticFiles) { + staticFilePaths = conf['default'].staticFiles.paths || []; + staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf['default'].staticFiles); + staticFileScanner = new (require('jsdoc/src/scanner')).Scanner(); + + staticFilePaths.forEach(function(filePath) { + var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); + + extraStaticFiles.forEach(function(fileName) { + var sourcePath = fs.statSync(filePath).isDirectory() ? filePath : + path.dirname(filePath); + var toDir = fs.toDir( fileName.replace(sourcePath, outdir) ); + fs.mkPath(toDir); + fs.copyFileSync(fileName, toDir); + }); + }); + } + + if (sourceFilePaths.length) { + sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); + } + data().each(function(doclet) { + var url = helper.createLink(doclet); + helper.registerLink(doclet.longname, url); + + // replace the filename with a shortened version of the full path + var docletPath; + if (doclet.meta) { + docletPath = getPathFromDoclet(doclet); + docletPath = sourceFiles[docletPath].shortened; + if (docletPath) { + doclet.meta.filename = docletPath; + } + } + }); + + data().each(function(doclet) { + var url = helper.longnameToUrl[doclet.longname]; + + if (url.indexOf('#') > -1) { + doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); + } + else { + doclet.id = doclet.name; + } + + if ( needsSignature(doclet) ) { + addSignatureParams(doclet); + addSignatureReturns(doclet); + addAttribs(doclet); + } + }); + + // do this after the urls have all been generated + data().each(function(doclet) { + doclet.ancestors = getAncestorLinks(doclet); + + if (doclet.kind === 'member') { + addSignatureTypes(doclet); + addAttribs(doclet); + } + + if (doclet.kind === 'constant') { + addSignatureTypes(doclet); + addAttribs(doclet); + doclet.kind = 'member'; + } + }); + + var members = helper.getMembers(data); + members.tutorials = tutorials.children; + + // add template helpers + view.find = find; + view.linkto = linkto; + view.resolveAuthorLinks = resolveAuthorLinks; + view.tutoriallink = tutoriallink; + view.htmlsafe = htmlsafe; + + // once for all + view.nav = buildNav(members); + attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }), + members.modules ); + + // only output pretty-printed source files if requested; do this before generating any other + // pages, so the other pages can link to the source files + if (conf['default'].outputSourceFiles) { + generateSourceFiles(sourceFiles); + } + + if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } + + // index page displays information from package.json and lists files + var files = find({kind: 'file'}), + packages = find({kind: 'package'}); + + generate('Index', + packages.concat( + [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}] + ).concat(files), + indexUrl); + + // set up the lists that we'll use to generate pages + var classes = taffy(members.classes); + var modules = taffy(members.modules); + var namespaces = taffy(members.namespaces); + var mixins = taffy(members.mixins); + var externals = taffy(members.externals); + + for (var longname in helper.longnameToUrl) { + if ( hasOwnProp.call(helper.longnameToUrl, longname) ) { + var myClasses = helper.find(classes, {longname: longname}); + if (myClasses.length) { + generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); + } + + var myModules = helper.find(modules, {longname: longname}); + if (myModules.length) { + generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); + } + + var myNamespaces = helper.find(namespaces, {longname: longname}); + if (myNamespaces.length) { + generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); + } + + var myMixins = helper.find(mixins, {longname: longname}); + if (myMixins.length) { + generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); + } + + var myExternals = helper.find(externals, {longname: longname}); + if (myExternals.length) { + generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); + } + } + } + + // TODO: move the tutorial functions to templateHelper.js + function generateTutorial(title, tutorial, filename) { + var tutorialData = { + title: title, + header: tutorial.title, + content: tutorial.parse(), + children: tutorial.children + }; + + var tutorialPath = path.join(outdir, filename), + html = view.render('tutorial.tmpl', tutorialData); + + // yes, you can use {@link} in tutorials too! + html = helper.resolveLinks(html); // turn {@link foo} into foo + + fs.writeFileSync(tutorialPath, html, 'utf8'); + } + + // tutorials can have only one parent so there is no risk for loops + function saveChildren(node) { + node.children.forEach(function(child) { + generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); + saveChildren(child); + }); + } + saveChildren(tutorials); +}; diff --git a/jsdoc.template/static/scripts/linenumber.js b/jsdoc.template/static/scripts/linenumber.js new file mode 100644 index 00000000..a0c570d5 --- /dev/null +++ b/jsdoc.template/static/scripts/linenumber.js @@ -0,0 +1,17 @@ +(function() { + var counter = 0; + var numbered; + var source = document.getElementsByClassName('prettyprint source'); + + if (source && source[0]) { + source = source[0].getElementsByTagName('code')[0]; + + numbered = source.innerHTML.split('\n'); + numbered = numbered.map(function(item) { + counter++; + return '' + item; + }); + + source.innerHTML = numbered.join('\n'); + } +})(); diff --git a/jsdoc.template/static/scripts/prettify/Apache-License-2.0.txt b/jsdoc.template/static/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/jsdoc.template/static/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/jsdoc.template/static/scripts/prettify/lang-css.js b/jsdoc.template/static/scripts/prettify/lang-css.js new file mode 100644 index 00000000..041e1f59 --- /dev/null +++ b/jsdoc.template/static/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/jsdoc.template/static/scripts/prettify/prettify.js b/jsdoc.template/static/scripts/prettify/prettify.js new file mode 100644 index 00000000..eef5ad7e --- /dev/null +++ b/jsdoc.template/static/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p + + + + + + + +
    + +
    +

    + + + + + +

    + +
    + +
    + +
    +
    + + +
    + + + + + + + + +
    + + + + + +

    Example 1? 's':'' ?>

    + + + +
    + + +

    Extends

    + +
      +
    • +
    + + + +

    Mixes In

    + +
      +
    • +
    + + + +

    Requires

    + +
      +
    • +
    + + + +

    Classes

    + +
    +
    +
    +
    + + + +

    Namespaces

    + +
    +
    +
    +
    + + + +

    Members

    + +
    + +
    + + + +

    Methods

    + +
    + +
    + + + +

    Type Definitions

    + +
    + + + +
    + + + +

    Events

    + +
    + +
    + +
    + +
    + + + diff --git a/jsdoc.template/tmpl/details.tmpl b/jsdoc.template/tmpl/details.tmpl new file mode 100644 index 00000000..d3b35522 --- /dev/null +++ b/jsdoc.template/tmpl/details.tmpl @@ -0,0 +1,98 @@ + +
    + + +
    Properties:
    + +
    + + + + +
    Version:
    +
    + + + +
    Since:
    +
    + + + +
    Inherited From:
    +
    • + +
    + + + +
    Deprecated:
    • Yes
      + + + +
      Author:
      +
      +
        +
      • +
      +
      + + + + + + + + +
      License:
      +
      + + + +
      Default Value:
      +
      + + + +
      Source:
      +
      • + , +
      + + + +
      Tutorials:
      +
      +
        +
      • +
      +
      + + + +
      See:
      +
      +
        +
      • +
      +
      + + + +
      To Do:
      +
      +
        +
      • +
      +
      + +
      diff --git a/jsdoc.template/tmpl/example.tmpl b/jsdoc.template/tmpl/example.tmpl new file mode 100644 index 00000000..e87caa5b --- /dev/null +++ b/jsdoc.template/tmpl/example.tmpl @@ -0,0 +1,2 @@ + +
      diff --git a/jsdoc.template/tmpl/examples.tmpl b/jsdoc.template/tmpl/examples.tmpl new file mode 100644 index 00000000..23384c9d --- /dev/null +++ b/jsdoc.template/tmpl/examples.tmpl @@ -0,0 +1,11 @@ + +

      + +
      + \ No newline at end of file diff --git a/jsdoc.template/tmpl/exceptions.tmpl b/jsdoc.template/tmpl/exceptions.tmpl new file mode 100644 index 00000000..78c4e250 --- /dev/null +++ b/jsdoc.template/tmpl/exceptions.tmpl @@ -0,0 +1,30 @@ + + +
      +
      +
      + +
      +
      +
      +
      +
      + Type +
      +
      + +
      +
      +
      +
      + +
      + + + + + +
      + diff --git a/jsdoc.template/tmpl/layout.tmpl b/jsdoc.template/tmpl/layout.tmpl new file mode 100644 index 00000000..827b5acb --- /dev/null +++ b/jsdoc.template/tmpl/layout.tmpl @@ -0,0 +1,38 @@ + + + + + JSDoc: <?js= title ?> + + + + + + + + + + +
      + +

      + + +
      + + + +
      + +
      + Documentation generated by JSDoc on +
      + + + + + diff --git a/jsdoc.template/tmpl/mainpage.tmpl b/jsdoc.template/tmpl/mainpage.tmpl new file mode 100644 index 00000000..64e9e594 --- /dev/null +++ b/jsdoc.template/tmpl/mainpage.tmpl @@ -0,0 +1,14 @@ + + + +

      + + + +
      +
      +
      + diff --git a/jsdoc.template/tmpl/members.tmpl b/jsdoc.template/tmpl/members.tmpl new file mode 100644 index 00000000..3fded716 --- /dev/null +++ b/jsdoc.template/tmpl/members.tmpl @@ -0,0 +1,34 @@ + +
      +

      + + +

      + +
      +
      + +
      + +
      + + + +
      Type:
      +
        +
      • + +
      • +
      + + + + + +
      Example 1? 's':'' ?>
      + + +
      diff --git a/jsdoc.template/tmpl/method.tmpl b/jsdoc.template/tmpl/method.tmpl new file mode 100644 index 00000000..1fff9b86 --- /dev/null +++ b/jsdoc.template/tmpl/method.tmpl @@ -0,0 +1,90 @@ + +
      +

      + + +

      + +
      +
      + + +
      + +
      + + + +
      Type:
      +
        +
      • + +
      • +
      + + + +
      This:
      +
      + + + +
      Parameters:
      + + + + + + +
      Fires:
      +
        +
      • +
      + + + +
      Listens to Events:
      +
        +
      • +
      + + + +
      Listeners of This Event:
      +
        +
      • +
      + + + +
      Throws:
      + 1) { ?>
        +
      • +
      + + + + +
      Returns:
      + 1) { ?>
        +
      • +
      + + + + +
      Example 1? 's':'' ?>
      + + +
      diff --git a/jsdoc.template/tmpl/params.tmpl b/jsdoc.template/tmpl/params.tmpl new file mode 100644 index 00000000..7b951149 --- /dev/null +++ b/jsdoc.template/tmpl/params.tmpl @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      NameTypeArgumentDefaultDescription
      + + + + + + <optional>
      + + + + <nullable>
      + + + + <repeatable>
      + +
      + + + + +
      Properties
      + +
      \ No newline at end of file diff --git a/jsdoc.template/tmpl/properties.tmpl b/jsdoc.template/tmpl/properties.tmpl new file mode 100644 index 00000000..97a3d23a --- /dev/null +++ b/jsdoc.template/tmpl/properties.tmpl @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      NameTypeArgumentDefaultDescription
      + + + + + + <optional>
      + + + + <nullable>
      + +
      + + + + +
      Properties
      +
      \ No newline at end of file diff --git a/jsdoc.template/tmpl/returns.tmpl b/jsdoc.template/tmpl/returns.tmpl new file mode 100644 index 00000000..32e059ed --- /dev/null +++ b/jsdoc.template/tmpl/returns.tmpl @@ -0,0 +1,19 @@ + +
      + +
      + + + +
      +
      + Type +
      +
      + +
      +
      + \ No newline at end of file diff --git a/jsdoc.template/tmpl/source.tmpl b/jsdoc.template/tmpl/source.tmpl new file mode 100644 index 00000000..e1092ef2 --- /dev/null +++ b/jsdoc.template/tmpl/source.tmpl @@ -0,0 +1,8 @@ + +
      +
      +
      +
      +
      \ No newline at end of file diff --git a/jsdoc.template/tmpl/tutorial.tmpl b/jsdoc.template/tmpl/tutorial.tmpl new file mode 100644 index 00000000..b0c79c1d --- /dev/null +++ b/jsdoc.template/tmpl/tutorial.tmpl @@ -0,0 +1,19 @@ +
      + +
      + 0) { ?> +
        +
      • +
      + + +

      +
      + +
      + +
      + +
      diff --git a/jsdoc.template/tmpl/type.tmpl b/jsdoc.template/tmpl/type.tmpl new file mode 100644 index 00000000..db8194d6 --- /dev/null +++ b/jsdoc.template/tmpl/type.tmpl @@ -0,0 +1,7 @@ + + +| + \ No newline at end of file diff --git a/package.json b/package.json index 38b4abf2..ba2fe493 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,29 @@ { - "name": "openpgpjs", - "version": "0.1.0-dev", - "engines": { - "node": ">=0.8" - }, - "scripts": { - "pretest": "make minify", - "test": "grunt test", - "start": "grunt dev" - }, - "dependencies": {}, - "devDependencies": { - "grunt": "0.4.1", - "mocha": "1.13.0", - "phantomjs": "1.9.1-9", - "requirejs": "2.1.8", - "chai": "1.7.2", - "sinon": "1.7.3", - "phantomjs": "1.9.1-9", - "grunt-contrib-connect": "0.5.0", - "grunt-contrib-copy": "0.4.1", - "grunt-mocha": "0.4.1" - } -} \ No newline at end of file + "name": "openpgp", + "version": "0.0.1", + "engines": { + "node": ">=0.8" + }, + "main": "./src/index.js", + "scripts": { + "pretest": "grunt browserify", + "test": "grunt test", + "start": "grunt dev" + }, + "devDependencies": { + "browserify": "~2.35", + "grunt": "~0.4.2", + "mocha": "~1.15.1", + "mocha-phantomjs": "~3.1.6", + "phantomjs": "~1.9.2-5", + "chai": "~1.8.1", + "sinon": "~1.7.3", + "grunt-contrib-copy": "~0.4.1", + "grunt-browserify": "~1.2.11", + "grunt-contrib-uglify": "*", + "grunt-text-replace": "*", + "grunt-jsbeautifier": "*", + "grunt-contrib-jshint": "*", + "grunt-jsdoc": "*" + } +} diff --git a/resources/keyring.js b/resources/keyring.js new file mode 100644 index 00000000..4208e1fd --- /dev/null +++ b/resources/keyring.js @@ -0,0 +1,260 @@ +require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o')[0].trim().toLowerCase(); + if (keyEmail == email) { + return true; + } + } + return false; + } + + /** + * Checks a key to see if it matches the specified keyid + * @param {String} id hex string keyid to search for + * @param {module:key~Key} key the key to be checked. + * @return {Boolean} true if the email address is defined in the specified key + * @inner + */ + function idCheck(id, key) { + var keyids = key.getKeyIds(); + for (var i = 0; i < keyids.length; i++) { + if (openpgp.util.hexstrdump(keyids[i].write()) == id) { + return true; + } + } + return false; + } + + /** + * searches all public keys in the keyring matching the address or address part of the user ids + * @param {Array} keys array of keys to search + * @param {module:keyring/keyring.checkCallback} identityFunction callback function which checks for a match + * @param {String} identityInput input to check against + * @param {module:enums.packet} keyType packet types of keys to check + * @return {Array} array of keys which match + */ + function checkForIdentityAndKeyTypeMatch(keys, identityFunction, identityInput, keyType) { + var results = []; + for (var p = 0; p < keys.length; p++) { + var key = keys[p]; + switch (keyType) { + case openpgp.enums.packet.public_key: + if (key.isPublic() && identityFunction(identityInput, key)) { + results.push(key); + } + break; + case openpgp.enums.packet.private_key: + if (key.isPrivate() && identityFunction(identityInput, key)) { + results.push(key); + } + break; + } + } + return results; + } + + /** + * searches all public keys in the keyring matching the address or address part of the user ids + * @param {String} email email address to search for + * @return {Array} The public keys associated with provided email address. + */ + this.getPublicKeyForAddress = function (email) { + return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, openpgp.enums.packet.public_key); + }; + + /** + * Searches the keyring for a private key containing the specified email address + * @param {String} email email address to search for + * @return {Array} private keys found + */ + this.getPrivateKeyForAddress = function (email) { + return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, openpgp.enums.packet.secret_key); + }; + + /** + * Searches the keyring for public keys having the specified key id + * @param {String} keyId provided as string of hex number (lowercase) + * @return {Array} public keys found + */ + this.getKeysForKeyId = function (keyId) { + return checkForIdentityAndKeyTypeMatch(this.keys, idCheck, keyId, openpgp.enums.packet.public_key); + }; + + /** + * Imports a key from an ascii armored message + * @param {String} armored message to read the keys/key from + */ + this.importKey = function (armored) { + this.keys = this.keys.concat(openpgp.key.readArmored(armored).keys); + + return true; + }; + + /** + * returns the armored message representation of the key at key ring index + * @param {Integer} index the index of the key within the array + * @return {String} armored message representing the key object + */ + this.exportKey = function (index) { + return this.keys[index].armor(); + }; + + /** + * Removes a public key from the public key keyring at the specified index + * @param {Integer} index the index of the public key within the publicKeys array + * @return {module:key~Key} The public key object which has been removed + */ + this.removeKey = function (index) { + var removed = this.keys.splice(index, 1); + + return removed; + }; + + /** + * returns the armored message representation of the public key portion of the key at key ring index + * @param {Integer} index the index of the key within the array + * @return {String} armored message representing the public key object + */ + this.exportPublicKey = function (index) { + return this.keys[index].toPublic().armor(); + }; +}; + +},{"./localstore.js":4}],4:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. + * @requires openpgp + * @module keyring/localstore + */ + +var openpgp = require('openpgp'); + +module.exports = function () { + /** + * Load the keyring from HTML5 local storage and initializes this instance. + * @return {Array} array of keys retrieved from localstore + */ + this.load = function () { + var armoredKeys = JSON.parse(window.localStorage.getItem("armoredKeys")); + var keys = []; + if (armoredKeys !== null && armoredKeys.length !== 0) { + var key; + for (var i = 0; i < armoredKeys.length; i++) { + key = openpgp.key.readArmored(armoredKeys[i]); + keys.push(key); + } + } + return keys; + } + + /** + * Saves the current state of the keyring to HTML5 local storage. + * The privateKeys array and publicKeys array gets Stringified using JSON + * @param {Array} keys array of keys to save in localstore + */ + this.store = function (keys) { + var armoredKeys = []; + for (var i = 0; i < keys.length; i++) { + armoredKeys.push(keys[i].armor()); + } + window.localStorage.setItem("armoredKeys", JSON.stringify(armoredKeys)); + } +}; + +},{}]},{},[]) +//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2tleXJpbmcvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2tleXJpbmcva2V5cmluZy5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMva2V5cmluZy9sb2NhbHN0b3JlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZXNDb250ZW50IjpbIlxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2tleXJpbmcuanMnKTtcbm1vZHVsZS5leHBvcnRzLmxvY2Fsc3RvcmUgPSByZXF1aXJlKCcuL2xvY2Fsc3RvcmUuanMnKTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogVGhlIGNsYXNzIHRoYXQgZGVhbHMgd2l0aCBzdG9yYWdlIG9mIHRoZSBrZXlyaW5nLiBDdXJyZW50bHkgdGhlIG9ubHkgb3B0aW9uIGlzIHRvIHVzZSBIVE1MNSBsb2NhbCBzdG9yYWdlLlxuICogQHJlcXVpcmVzIG9wZW5wZ3BcbiAqIEBtb2R1bGUga2V5cmluZy9rZXlyaW5nXG4gKi9cblxudmFyIG9wZW5wZ3AgPSByZXF1aXJlKCdvcGVucGdwJyk7XG5cbi8qKlxuICogQ2FsbGJhY2sgdG8gY2hlY2sgaWYgYSBrZXkgbWF0Y2hlcyB0aGUgaW5wdXRcbiAqIEBjYWxsYmFjayBtb2R1bGU6a2V5cmluZy9rZXlyaW5nLmNoZWNrQ2FsbGJhY2tcbiAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBpbnB1dCB0byBzZWFyY2ggZm9yXG4gKiBAcGFyYW0ge21vZHVsZTprZXl+S2V5fSBrZXkgVGhlIGtleSB0byBiZSBjaGVja2VkLlxuICogQHJldHVybiB7Qm9vbGVhbn0gVHJ1ZSBpZiB0aGUgaW5wdXQgbWF0Y2hlcyB0aGUgc3BlY2lmaWVkIGtleVxuICovXG5cbi8qKlxuICogSW5pdGlhbGl6YXRpb24gcm91dGluZSBmb3IgdGhlIGtleXJpbmcuIFRoaXMgbWV0aG9kIHJlYWRzIHRoZVxuICoga2V5cmluZyBmcm9tIEhUTUw1IGxvY2FsIHN0b3JhZ2UgYW5kIGluaXRpYWxpemVzIHRoaXMgaW5zdGFuY2UuXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7Y2xhc3N9IFtzdG9yZUhhbmRsZXJdIGNsYXNzIGltcGxlbWVudGluZyBsb2FkKCkgYW5kIHN0b3JlKCkgbWV0aG9kc1xuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHN0b3JlSGFuZGxlcikge1xuICBpZiAoIXN0b3JlSGFuZGxlcikge1xuICAgIHN0b3JlSGFuZGxlciA9IG5ldyAocmVxdWlyZSgnLi9sb2NhbHN0b3JlLmpzJykpKCk7XG4gIH1cbiAgdGhpcy5zdG9yZUhhbmRsZXIgPSBzdG9yZUhhbmRsZXI7XG4gIHRoaXMua2V5cyA9IHRoaXMuc3RvcmVIYW5kbGVyLmxvYWQoKTtcblxuICAvKipcbiAgICogQ2FsbHMgdGhlIHN0b3JlSGFuZGxlciB0byBzYXZlIHRoZSBrZXlzXG4gICAqL1xuICB0aGlzLnN0b3JlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuc3RvcmVIYW5kbGVyLnN0b3JlKHRoaXMua2V5cyk7XG4gIH07XG5cbiAgLyoqXG4gICAqIENsZWFyIHRoZSBrZXlyaW5nIC0gZXJhc2UgYWxsIHRoZSBrZXlzXG4gICAqL1xuICB0aGlzLmNsZWFyID0gZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5rZXlzID0gW107XG4gIH07XG5cbiAgLyoqXG4gICAqIENoZWNrcyBhIGtleSB0byBzZWUgaWYgaXQgbWF0Y2hlcyB0aGUgc3BlY2lmaWVkIGVtYWlsIGFkZHJlc3NcbiAgICogQHBhcmFtIHtTdHJpbmd9IGVtYWlsIGVtYWlsIGFkZHJlc3MgdG8gc2VhcmNoIGZvclxuICAgKiBAcGFyYW0ge21vZHVsZTprZXl+S2V5fSBrZXkgVGhlIGtleSB0byBiZSBjaGVja2VkLlxuICAgKiBAcmV0dXJuIHtCb29sZWFufSBUcnVlIGlmIHRoZSBlbWFpbCBhZGRyZXNzIGlzIGRlZmluZWQgaW4gdGhlIHNwZWNpZmllZCBrZXlcbiAgICovXG4gIGZ1bmN0aW9uIGVtYWlsQ2hlY2soZW1haWwsIGtleSkge1xuICAgIGVtYWlsID0gZW1haWwudG9Mb3dlckNhc2UoKTtcbiAgICB2YXIga2V5RW1haWxzID0ga2V5LmdldFVzZXJJZHMoKTtcbiAgICBmb3IgKHZhciBpOyBpIDwga2V5RW1haWxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAvL3dlIG5lZWQgdG8gZ2V0IGp1c3QgdGhlIGVtYWlsIGZyb20gdGhlIHVzZXJpZCBrZXlcbiAgICAgIGtleUVtYWlsID0ga2V5RW1haWxzW2ldLnNwbGl0KCc8JylbMV0uc3BsaXQoJz4nKVswXS50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgICAgIGlmIChrZXlFbWFpbCA9PSBlbWFpbCkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBhIGtleSB0byBzZWUgaWYgaXQgbWF0Y2hlcyB0aGUgc3BlY2lmaWVkIGtleWlkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBpZCBoZXggc3RyaW5nIGtleWlkIHRvIHNlYXJjaCBmb3JcbiAgICogQHBhcmFtIHttb2R1bGU6a2V5fktleX0ga2V5IHRoZSBrZXkgdG8gYmUgY2hlY2tlZC5cbiAgICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiB0aGUgZW1haWwgYWRkcmVzcyBpcyBkZWZpbmVkIGluIHRoZSBzcGVjaWZpZWQga2V5XG4gICAqIEBpbm5lclxuICAgKi9cbiAgZnVuY3Rpb24gaWRDaGVjayhpZCwga2V5KSB7XG4gICAgdmFyIGtleWlkcyA9IGtleS5nZXRLZXlJZHMoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGtleWlkcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKG9wZW5wZ3AudXRpbC5oZXhzdHJkdW1wKGtleWlkc1tpXS53cml0ZSgpKSA9PSBpZCkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIHNlYXJjaGVzIGFsbCBwdWJsaWMga2V5cyBpbiB0aGUga2V5cmluZyBtYXRjaGluZyB0aGUgYWRkcmVzcyBvciBhZGRyZXNzIHBhcnQgb2YgdGhlIHVzZXIgaWRzXG4gICAqIEBwYXJhbSB7QXJyYXk8bW9kdWxlOmtleX5LZXk+fSBrZXlzIGFycmF5IG9mIGtleXMgdG8gc2VhcmNoXG4gICAqIEBwYXJhbSB7bW9kdWxlOmtleXJpbmcva2V5cmluZy5jaGVja0NhbGxiYWNrfSBpZGVudGl0eUZ1bmN0aW9uIGNhbGxiYWNrIGZ1bmN0aW9uIHdoaWNoIGNoZWNrcyBmb3IgYSBtYXRjaFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaWRlbnRpdHlJbnB1dCBpbnB1dCB0byBjaGVjayBhZ2FpbnN0XG4gICAqIEBwYXJhbSB7bW9kdWxlOmVudW1zLnBhY2tldH0ga2V5VHlwZSBwYWNrZXQgdHlwZXMgb2Yga2V5cyB0byBjaGVja1xuICAgKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6a2V5fktleT59IGFycmF5IG9mIGtleXMgd2hpY2ggbWF0Y2hcbiAgICovXG4gIGZ1bmN0aW9uIGNoZWNrRm9ySWRlbnRpdHlBbmRLZXlUeXBlTWF0Y2goa2V5cywgaWRlbnRpdHlGdW5jdGlvbiwgaWRlbnRpdHlJbnB1dCwga2V5VHlwZSkge1xuICAgIHZhciByZXN1bHRzID0gW107XG4gICAgZm9yICh2YXIgcCA9IDA7IHAgPCBrZXlzLmxlbmd0aDsgcCsrKSB7XG4gICAgICB2YXIga2V5ID0ga2V5c1twXTtcbiAgICAgIHN3aXRjaCAoa2V5VHlwZSkge1xuICAgICAgICBjYXNlIG9wZW5wZ3AuZW51bXMucGFja2V0LnB1YmxpY19rZXk6XG4gICAgICAgICAgaWYgKGtleS5pc1B1YmxpYygpICYmIGlkZW50aXR5RnVuY3Rpb24oaWRlbnRpdHlJbnB1dCwga2V5KSkge1xuICAgICAgICAgICAgcmVzdWx0cy5wdXNoKGtleSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIG9wZW5wZ3AuZW51bXMucGFja2V0LnByaXZhdGVfa2V5OlxuICAgICAgICAgIGlmIChrZXkuaXNQcml2YXRlKCkgJiYgaWRlbnRpdHlGdW5jdGlvbihpZGVudGl0eUlucHV0LCBrZXkpKSB7XG4gICAgICAgICAgICByZXN1bHRzLnB1c2goa2V5KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLyoqXG4gICAqIHNlYXJjaGVzIGFsbCBwdWJsaWMga2V5cyBpbiB0aGUga2V5cmluZyBtYXRjaGluZyB0aGUgYWRkcmVzcyBvciBhZGRyZXNzIHBhcnQgb2YgdGhlIHVzZXIgaWRzXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBlbWFpbCBlbWFpbCBhZGRyZXNzIHRvIHNlYXJjaCBmb3JcbiAgICogQHJldHVybiB7QXJyYXk8bW9kdWxlOmtleX5LZXk+fSBUaGUgcHVibGljIGtleXMgYXNzb2NpYXRlZCB3aXRoIHByb3ZpZGVkIGVtYWlsIGFkZHJlc3MuXG4gICAqL1xuICB0aGlzLmdldFB1YmxpY0tleUZvckFkZHJlc3MgPSBmdW5jdGlvbiAoZW1haWwpIHtcbiAgICByZXR1cm4gY2hlY2tGb3JJZGVudGl0eUFuZEtleVR5cGVNYXRjaCh0aGlzLmtleXMsIGVtYWlsQ2hlY2ssIGVtYWlsLCBvcGVucGdwLmVudW1zLnBhY2tldC5wdWJsaWNfa2V5KTtcbiAgfTtcblxuICAvKipcbiAgICogU2VhcmNoZXMgdGhlIGtleXJpbmcgZm9yIGEgcHJpdmF0ZSBrZXkgY29udGFpbmluZyB0aGUgc3BlY2lmaWVkIGVtYWlsIGFkZHJlc3NcbiAgICogQHBhcmFtIHtTdHJpbmd9IGVtYWlsIGVtYWlsIGFkZHJlc3MgdG8gc2VhcmNoIGZvclxuICAgKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6a2V5fktleT59IHByaXZhdGUga2V5cyBmb3VuZFxuICAgKi9cbiAgdGhpcy5nZXRQcml2YXRlS2V5Rm9yQWRkcmVzcyA9IGZ1bmN0aW9uIChlbWFpbCkge1xuICAgIHJldHVybiBjaGVja0ZvcklkZW50aXR5QW5kS2V5VHlwZU1hdGNoKHRoaXMua2V5cywgZW1haWxDaGVjaywgZW1haWwsIG9wZW5wZ3AuZW51bXMucGFja2V0LnNlY3JldF9rZXkpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBTZWFyY2hlcyB0aGUga2V5cmluZyBmb3IgcHVibGljIGtleXMgaGF2aW5nIHRoZSBzcGVjaWZpZWQga2V5IGlkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBrZXlJZCBwcm92aWRlZCBhcyBzdHJpbmcgb2YgaGV4IG51bWJlciAobG93ZXJjYXNlKVxuICAgKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6a2V5fktleT59IHB1YmxpYyBrZXlzIGZvdW5kXG4gICAqL1xuICB0aGlzLmdldEtleXNGb3JLZXlJZCA9IGZ1bmN0aW9uIChrZXlJZCkge1xuICAgIHJldHVybiBjaGVja0ZvcklkZW50aXR5QW5kS2V5VHlwZU1hdGNoKHRoaXMua2V5cywgaWRDaGVjaywga2V5SWQsIG9wZW5wZ3AuZW51bXMucGFja2V0LnB1YmxpY19rZXkpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBJbXBvcnRzIGEga2V5IGZyb20gYW4gYXNjaWkgYXJtb3JlZCBtZXNzYWdlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBhcm1vcmVkIG1lc3NhZ2UgdG8gcmVhZCB0aGUga2V5cy9rZXkgZnJvbVxuICAgKi9cbiAgdGhpcy5pbXBvcnRLZXkgPSBmdW5jdGlvbiAoYXJtb3JlZCkge1xuICAgIHRoaXMua2V5cyA9IHRoaXMua2V5cy5jb25jYXQob3BlbnBncC5rZXkucmVhZEFybW9yZWQoYXJtb3JlZCkua2V5cyk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfTtcblxuICAvKipcbiAgICogcmV0dXJucyB0aGUgYXJtb3JlZCBtZXNzYWdlIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBrZXkgYXQga2V5IHJpbmcgaW5kZXhcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBpbmRleCB0aGUgaW5kZXggb2YgdGhlIGtleSB3aXRoaW4gdGhlIGFycmF5XG4gICAqIEByZXR1cm4ge1N0cmluZ30gYXJtb3JlZCBtZXNzYWdlIHJlcHJlc2VudGluZyB0aGUga2V5IG9iamVjdFxuICAgKi9cbiAgdGhpcy5leHBvcnRLZXkgPSBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICByZXR1cm4gdGhpcy5rZXlzW2luZGV4XS5hcm1vcigpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGEgcHVibGljIGtleSBmcm9tIHRoZSBwdWJsaWMga2V5IGtleXJpbmcgYXQgdGhlIHNwZWNpZmllZCBpbmRleFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGluZGV4IHRoZSBpbmRleCBvZiB0aGUgcHVibGljIGtleSB3aXRoaW4gdGhlIHB1YmxpY0tleXMgYXJyYXlcbiAgICogQHJldHVybiB7bW9kdWxlOmtleX5LZXl9IFRoZSBwdWJsaWMga2V5IG9iamVjdCB3aGljaCBoYXMgYmVlbiByZW1vdmVkXG4gICAqL1xuICB0aGlzLnJlbW92ZUtleSA9IGZ1bmN0aW9uIChpbmRleCkge1xuICAgIHZhciByZW1vdmVkID0gdGhpcy5rZXlzLnNwbGljZShpbmRleCwgMSk7XG5cbiAgICByZXR1cm4gcmVtb3ZlZDtcbiAgfTtcblxuICAvKipcbiAgICogcmV0dXJucyB0aGUgYXJtb3JlZCBtZXNzYWdlIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwdWJsaWMga2V5IHBvcnRpb24gb2YgdGhlIGtleSBhdCBrZXkgcmluZyBpbmRleFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGluZGV4IHRoZSBpbmRleCBvZiB0aGUga2V5IHdpdGhpbiB0aGUgYXJyYXlcbiAgICogQHJldHVybiB7U3RyaW5nfSBhcm1vcmVkIG1lc3NhZ2UgcmVwcmVzZW50aW5nIHRoZSBwdWJsaWMga2V5IG9iamVjdFxuICAgKi9cbiAgdGhpcy5leHBvcnRQdWJsaWNLZXkgPSBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICByZXR1cm4gdGhpcy5rZXlzW2luZGV4XS50b1B1YmxpYygpLmFybW9yKCk7XG4gIH07XG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBUaGUgY2xhc3MgdGhhdCBkZWFscyB3aXRoIHN0b3JhZ2Ugb2YgdGhlIGtleXJpbmcuIEN1cnJlbnRseSB0aGUgb25seSBvcHRpb24gaXMgdG8gdXNlIEhUTUw1IGxvY2FsIHN0b3JhZ2UuXG4gKiBAcmVxdWlyZXMgb3BlbnBncFxuICogQG1vZHVsZSBrZXlyaW5nL2xvY2Fsc3RvcmVcbiAqL1xuXG52YXIgb3BlbnBncCA9IHJlcXVpcmUoJ29wZW5wZ3AnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoKSB7XG4gIC8qKlxuICAgKiBMb2FkIHRoZSBrZXlyaW5nIGZyb20gSFRNTDUgbG9jYWwgc3RvcmFnZSBhbmQgaW5pdGlhbGl6ZXMgdGhpcyBpbnN0YW5jZS5cbiAgICogQHJldHVybiB7QXJyYXk8bW9kdWxlOmtleX5LZXk+fSBhcnJheSBvZiBrZXlzIHJldHJpZXZlZCBmcm9tIGxvY2Fsc3RvcmVcbiAgICovXG4gIHRoaXMubG9hZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYXJtb3JlZEtleXMgPSBKU09OLnBhcnNlKHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShcImFybW9yZWRLZXlzXCIpKTtcbiAgICB2YXIga2V5cyA9IFtdO1xuICAgIGlmIChhcm1vcmVkS2V5cyAhPT0gbnVsbCAmJiBhcm1vcmVkS2V5cy5sZW5ndGggIT09IDApIHtcbiAgICAgIHZhciBrZXk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFybW9yZWRLZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGtleSA9IG9wZW5wZ3Aua2V5LnJlYWRBcm1vcmVkKGFybW9yZWRLZXlzW2ldKTtcbiAgICAgICAga2V5cy5wdXNoKGtleSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBrZXlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNhdmVzIHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBrZXlyaW5nIHRvIEhUTUw1IGxvY2FsIHN0b3JhZ2UuXG4gICAqIFRoZSBwcml2YXRlS2V5cyBhcnJheSBhbmQgcHVibGljS2V5cyBhcnJheSBnZXRzIFN0cmluZ2lmaWVkIHVzaW5nIEpTT05cbiAgICogQHBhcmFtIHtBcnJheTxtb2R1bGU6a2V5fktleT59IGtleXMgYXJyYXkgb2Yga2V5cyB0byBzYXZlIGluIGxvY2Fsc3RvcmVcbiAgICovXG4gIHRoaXMuc3RvcmUgPSBmdW5jdGlvbiAoa2V5cykge1xuICAgIHZhciBhcm1vcmVkS2V5cyA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykge1xuICAgICAgYXJtb3JlZEtleXMucHVzaChrZXlzW2ldLmFybW9yKCkpO1xuICAgIH1cbiAgICB3aW5kb3cubG9jYWxTdG9yYWdlLnNldEl0ZW0oXCJhcm1vcmVkS2V5c1wiLCBKU09OLnN0cmluZ2lmeShhcm1vcmVkS2V5cykpO1xuICB9XG59O1xuIl19 +; \ No newline at end of file diff --git a/resources/keyring.min.js b/resources/keyring.min.js new file mode 100644 index 00000000..aed3bfb0 --- /dev/null +++ b/resources/keyring.min.js @@ -0,0 +1 @@ +/*! OpenPGPjs.org this is LGPL licensed code, see LICENSE/our website for more information.- v0.0.1 - 2014-01-02 */require=function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g")[0].trim().toLowerCase(),keyEmail==a)return!0;return!1}function e(a,b){for(var d=b.getKeyIds(),e=0;e + this.text = text.replace(/\r/g, '').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n"); + this.packets = packetlist || new packet.list(); +} + +/** + * Returns the key IDs of the keys that signed the cleartext message + * @return {Array} array of keyid objects + */ +CleartextMessage.prototype.getSigningKeyIds = function() { + var keyIds = []; + var signatureList = this.packets.filterByTag(enums.packet.signature); + signatureList.forEach(function(packet) { + keyIds.push(packet.issuerKeyId); + }); + return keyIds; +}; + +/** + * Sign the cleartext message + * @param {Array} privateKeys private keys with decrypted secret key data for signing + */ +CleartextMessage.prototype.sign = function(privateKeys) { + var packetlist = new packet.list(); + var literalDataPacket = new packet.literal(); + literalDataPacket.setText(this.text); + for (var i = 0; i < privateKeys.length; i++) { + var signaturePacket = new packet.signature(); + signaturePacket.signatureType = enums.signature.text; + signaturePacket.hashAlgorithm = config.prefer_hash_algorithm; + var signingKeyPacket = privateKeys[i].getSigningKeyPacket(); + signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; + if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.'); + signaturePacket.sign(signingKeyPacket, literalDataPacket); + packetlist.push(signaturePacket); + } + this.packets = packetlist; +}; + +/** + * Verify signatures of cleartext signed message + * @param {Array} publicKeys public keys to verify signatures + * @return {Array<{keyid: module:type/keyid, valid: Boolean}>} list of signer's keyid and validity of signature + */ +CleartextMessage.prototype.verify = function(publicKeys) { + var result = []; + var signatureList = this.packets.filterByTag(enums.packet.signature); + var literalDataPacket = new packet.literal(); + // we assume that cleartext signature is generated based on UTF8 cleartext + literalDataPacket.setText(this.text); + publicKeys.forEach(function(pubKey) { + for (var i = 0; i < signatureList.length; i++) { + var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]); + if (publicKeyPacket) { + var verifiedSig = {}; + verifiedSig.keyid = signatureList[i].issuerKeyId; + verifiedSig.valid = signatureList[i].verify(publicKeyPacket, literalDataPacket); + result.push(verifiedSig); + break; + } + } + }); + return result; +}; + +/** + * Get cleartext + * @return {String} cleartext of message + */ +CleartextMessage.prototype.getText = function() { + // normalize end of line to \n + return this.text.replace(/\r\n/g,"\n"); +}; + +/** + * Returns ASCII armored text of cleartext signed message + * @return {String} ASCII armor + */ +CleartextMessage.prototype.armor = function() { + var body = { + hash: enums.read(enums.hash, config.prefer_hash_algorithm).toUpperCase(), + text: this.text, + data: this.packets.write() + } + return armor.encode(enums.armor.signed, body); +}; + + +/** + * reads an OpenPGP cleartext signed message and returns a CleartextMessage object + * @param {String} armoredText text to be parsed + * @return {module:cleartext~CleartextMessage} new cleartext message object + * @static + */ +function readArmored(armoredText) { + var input = armor.decode(armoredText); + if (input.type !== enums.armor.signed) { + throw new Error('No cleartext signed message.'); + } + var packetlist = new packet.list(); + packetlist.read(input.data); + var newMessage = new CleartextMessage(input.text, packetlist); + return newMessage; +} + +exports.CleartextMessage = CleartextMessage; +exports.readArmored = readArmored; + +},{"./config":3,"./encoding/armor.js":25,"./enums.js":27,"./packet":35}],2:[function(require,module,exports){ +JXG = { + exists: (function(undefined) { + return function(v) { + return !(v === undefined || v === null); + } + })() +}; +JXG.decompress = function(str) { + return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip()[0][0]); +}; +/* + Copyright 2008-2012 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses. + + You should have received a copy of the GNU Lesser General Public License + along with JSXCompressor. If not, see . + + You should have received a copy of the Apache License along with JSXCompressor. + If not, see . + +*/ + +/** + * @class Util class + * @classdesc Utilities for uncompressing and base64 decoding + * Class for gunzipping, unzipping and base64 decoding of files. + * It is used for reading GEONExT, Geogebra and Intergeo files. + * + * Only Huffman codes are decoded in gunzip. + * The code is based on the source code for gunzip.c by Pasi Ojala + * {@link http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c} + * {@link http://www.cs.tut.fi/~albert} + */ +JXG.Util = {}; + +/** + * Unzip zip files + */ +JXG.Util.Unzip = function(barray) { + var outputArr = [], + output = "", + debug = false, + gpflags, + files = 0, + unzipped = [], + crc, + buf32k = new Array(32768), + bIdx = 0, + modeZIP = false, + + CRC, SIZE, + + bitReverse = [ + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff + ], + + cplens = [ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + ], + + cplext = [ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 + ], + /* 99==invalid */ + + cpdist = [ + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, + 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, + 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01, + 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001 + ], + + cpdext = [ + 0, 0, 0, 0, 1, 1, 2, 2, + 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13 + ], + + border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], + + bA = barray, + + bytepos = 0, + bitpos = 0, + bb = 1, + bits = 0, + + NAMEMAX = 256, + + nameBuf = [], + + fileout; + + function readByte() { + bits += 8; + if (bytepos < bA.length) { + //if (debug) + // document.write(bytepos+": "+bA[bytepos]+"
      "); + return bA[bytepos++]; + } else + return -1; + }; + + function byteAlign() { + bb = 1; + }; + + function readBit() { + var carry; + bits++; + carry = (bb & 1); + bb >>= 1; + if (bb == 0) { + bb = readByte(); + carry = (bb & 1); + bb = (bb >> 1) | 0x80; + } + return carry; + }; + + function readBits(a) { + var res = 0, + i = a; + + while (i--) { + res = (res << 1) | readBit(); + } + if (a) { + res = bitReverse[res] >> (8 - a); + } + return res; + }; + + function flushBuffer() { + //document.write('FLUSHBUFFER:'+buf32k); + bIdx = 0; + }; + + function addBuffer(a) { + SIZE++; + //CRC=updcrc(a,crc); + buf32k[bIdx++] = a; + outputArr.push(String.fromCharCode(a)); + //output+=String.fromCharCode(a); + if (bIdx == 0x8000) { + //document.write('ADDBUFFER:'+buf32k); + bIdx = 0; + } + }; + + function HufNode() { + this.b0 = 0; + this.b1 = 0; + this.jump = null; + this.jumppos = -1; + }; + + var LITERALS = 288; + + var literalTree = new Array(LITERALS); + var distanceTree = new Array(32); + var treepos = 0; + var Places = null; + var Places2 = null; + + var impDistanceTree = new Array(64); + var impLengthTree = new Array(64); + + var len = 0; + var fpos = new Array(17); + fpos[0] = 0; + var flens; + var fmax; + + function IsPat() { + while (1) { + if (fpos[len] >= fmax) + return -1; + if (flens[fpos[len]] == len) + return fpos[len]++; + fpos[len]++; + } + }; + + function Rec() { + var curplace = Places[treepos]; + var tmp; + if (debug) + document.write("
      len:" + len + " treepos:" + treepos); + if (len == 17) { //war 17 + return -1; + } + treepos++; + len++; + + tmp = IsPat(); + if (debug) + document.write("
      IsPat " + tmp); + if (tmp >= 0) { + curplace.b0 = tmp; /* leaf cell for 0-bit */ + if (debug) + document.write("
      b0 " + curplace.b0); + } else { + /* Not a Leaf cell */ + curplace.b0 = 0x8000; + if (debug) + document.write("
      b0 " + curplace.b0); + if (Rec()) + return -1; + } + tmp = IsPat(); + if (tmp >= 0) { + curplace.b1 = tmp; /* leaf cell for 1-bit */ + if (debug) + document.write("
      b1 " + curplace.b1); + curplace.jump = null; /* Just for the display routine */ + } else { + /* Not a Leaf cell */ + curplace.b1 = 0x8000; + if (debug) + document.write("
      b1 " + curplace.b1); + curplace.jump = Places[treepos]; + curplace.jumppos = treepos; + if (Rec()) + return -1; + } + len--; + return 0; + }; + + function CreateTree(currentTree, numval, lengths, show) { + var i; + /* Create the Huffman decode tree/table */ + //document.write("
      createtree
      "); + if (debug) + document.write("currentTree " + currentTree + " numval " + numval + " lengths " + lengths + " show " + show); + Places = currentTree; + treepos = 0; + flens = lengths; + fmax = numval; + for (i = 0; i < 17; i++) + fpos[i] = 0; + len = 0; + if (Rec()) { + //fprintf(stderr, "invalid huffman tree\n"); + if (debug) + alert("invalid huffman tree\n"); + return -1; + } + if (debug) { + document.write('
      Tree: ' + Places.length); + for (var a = 0; a < 32; a++) { + document.write("Places[" + a + "].b0=" + Places[a].b0 + "
      "); + document.write("Places[" + a + "].b1=" + Places[a].b1 + "
      "); + } + } + + /*if(show) { + var tmp; + for(tmp=currentTree;tmpjump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0); + if(!(tmp.b0 & 0x8000)) { + //fprintf(stdout, " 0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�'); + } + if(!(tmp.b1 & 0x8000)) { + if((tmp.b0 & 0x8000)) + fprintf(stdout, " "); + fprintf(stdout, " 0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�'); + } + fprintf(stdout, "\n"); + } + }*/ + return 0; + }; + + function DecodeValue(currentTree) { + var len, i, + xtreepos = 0, + X = currentTree[xtreepos], + b; + + /* decode one symbol of the data */ + while (1) { + b = readBit(); + if (debug) + document.write("b=" + b); + if (b) { + if (!(X.b1 & 0x8000)) { + if (debug) + document.write("ret1"); + return X.b1; /* If leaf node, return data */ + } + X = X.jump; + len = currentTree.length; + for (i = 0; i < len; i++) { + if (currentTree[i] === X) { + xtreepos = i; + break; + } + } + //xtreepos++; + } else { + if (!(X.b0 & 0x8000)) { + if (debug) + document.write("ret2"); + return X.b0; /* If leaf node, return data */ + } + //X++; //?????????????????? + xtreepos++; + X = currentTree[xtreepos]; + } + } + }; + + function DeflateLoop() { + var last, c, type, i, len; + + do { + /*if((last = readBit())){ + fprintf(errfp, "Last Block: "); + } else { + fprintf(errfp, "Not Last Block: "); + }*/ + last = readBit(); + type = readBits(2); + switch (type) { + case 0: + if (debug) + alert("Stored\n"); + break; + case 1: + if (debug) + alert("Fixed Huffman codes\n"); + break; + case 2: + if (debug) + alert("Dynamic Huffman codes\n"); + break; + case 3: + if (debug) + alert("Reserved block type!!\n"); + break; + default: + if (debug) + alert("Unexpected value %d!\n", type); + break; + } + + if (type == 0) { + var blockLen, cSum; + + // Stored + byteAlign(); + blockLen = readByte(); + blockLen |= (readByte() << 8); + + cSum = readByte(); + cSum |= (readByte() << 8); + + if (((blockLen ^ ~cSum) & 0xffff)) { + document.write("BlockLen checksum mismatch\n"); + } + while (blockLen--) { + c = readByte(); + addBuffer(c); + } + } else if (type == 1) { + var j; + + /* Fixed Huffman tables -- fixed decode routine */ + while (1) { + /* + 256 0000000 0 + : : : + 279 0010111 23 + 0 00110000 48 + : : : + 143 10111111 191 + 280 11000000 192 + : : : + 287 11000111 199 + 144 110010000 400 + : : : + 255 111111111 511 + + Note the bit order! + */ + + j = (bitReverse[readBits(7)] >> 1); + if (j > 23) { + j = (j << 1) | readBit(); /* 48..255 */ + + if (j > 199) { /* 200..255 */ + j -= 128; /* 72..127 */ + j = (j << 1) | readBit(); /* 144..255 << */ + } else { /* 48..199 */ + j -= 48; /* 0..151 */ + if (j > 143) { + j = j + 136; /* 280..287 << */ + /* 0..143 << */ + } + } + } else { /* 0..23 */ + j += 256; /* 256..279 << */ + } + if (j < 256) { + addBuffer(j); + //document.write("out:"+String.fromCharCode(j)); + /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/ + } else if (j == 256) { + /* EOF */ + break; + } else { + var len, dist; + + j -= 256 + 1; /* bytes + EOF */ + len = readBits(cplext[j]) + cplens[j]; + + j = bitReverse[readBits(5)] >> 3; + if (cpdext[j] > 8) { + dist = readBits(8); + dist |= (readBits(cpdext[j] - 8) << 8); + } else { + dist = readBits(cpdext[j]); + } + dist += cpdist[j]; + + /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/ + for (j = 0; j < len; j++) { + var c = buf32k[(bIdx - dist) & 0x7fff]; + addBuffer(c); + } + } + } // while + } else if (type == 2) { + var j, n, literalCodes, distCodes, lenCodes; + var ll = new Array(288 + 32); // "static" just to preserve stack + + // Dynamic Huffman tables + + literalCodes = 257 + readBits(5); + distCodes = 1 + readBits(5); + lenCodes = 4 + readBits(4); + //document.write("
      param: "+literalCodes+" "+distCodes+" "+lenCodes+"
      "); + for (j = 0; j < 19; j++) { + ll[j] = 0; + } + + // Get the decode tree code lengths + + //document.write("
      "); + for (j = 0; j < lenCodes; j++) { + ll[border[j]] = readBits(3); + //document.write(ll[border[j]]+" "); + } + //fprintf(errfp, "\n"); + //document.write('
      ll:'+ll); + len = distanceTree.length; + for (i = 0; i < len; i++) + distanceTree[i] = new HufNode(); + if (CreateTree(distanceTree, 19, ll, 0)) { + flushBuffer(); + return 1; + } + if (debug) { + document.write("
      distanceTree"); + for (var a = 0; a < distanceTree.length; a++) { + document.write("
      " + distanceTree[a].b0 + " " + distanceTree[a].b1 + " " + distanceTree[a].jump + " " + + distanceTree[a].jumppos); + /*if (distanceTree[a].jumppos!=-1) + document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1); + */ + } + } + //document.write('
      tree created'); + + //read in literal and distance code lengths + n = literalCodes + distCodes; + i = 0; + var z = -1; + if (debug) + document.write("
      n=" + n + " bits: " + bits + "
      "); + while (i < n) { + z++; + j = DecodeValue(distanceTree); + if (debug) + document.write("
      " + z + " i:" + i + " decode: " + j + " bits " + bits + "
      "); + if (j < 16) { // length of code in bits (0..15) + ll[i++] = j; + } else if (j == 16) { // repeat last length 3 to 6 times + var l; + j = 3 + readBits(2); + if (i + j > n) { + flushBuffer(); + return 1; + } + l = i ? ll[i - 1] : 0; + while (j--) { + ll[i++] = l; + } + } else { + if (j == 17) { // 3 to 10 zero length codes + j = 3 + readBits(3); + } else { // j == 18: 11 to 138 zero length codes + j = 11 + readBits(7); + } + if (i + j > n) { + flushBuffer(); + return 1; + } + while (j--) { + ll[i++] = 0; + } + } + } + /*for(j=0; jliteralTree"); + outer: while (1) { + j = DecodeValue(literalTree); + if (j >= 256) { // In C64: if carry set + var len, dist; + j -= 256; + if (j == 0) { + // EOF + break; + } + j--; + len = readBits(cplext[j]) + cplens[j]; + + j = DecodeValue(distanceTree); + if (cpdext[j] > 8) { + dist = readBits(8); + dist |= (readBits(cpdext[j] - 8) << 8); + } else { + dist = readBits(cpdext[j]); + } + dist += cpdist[j]; + while (len--) { + if (bIdx - dist < 0) { + break outer; + } + var c = buf32k[(bIdx - dist) & 0x7fff]; + addBuffer(c); + } + } else { + addBuffer(j); + } + } + } + } while (!last); + flushBuffer(); + + byteAlign(); + return 0; + }; + + JXG.Util.Unzip.prototype.unzipFile = function(name) { + var i; + this.unzip(); + //alert(unzipped[0][1]); + for (i = 0; i < unzipped.length; i++) { + if (unzipped[i][1] == name) { + return unzipped[i][0]; + } + } + + }; + + JXG.Util.Unzip.prototype.deflate = function() { + outputArr = []; + var tmp = []; + modeZIP = false; + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "DEFLATE"; + files++; + return unzipped; + } + + JXG.Util.Unzip.prototype.unzip = function() { + //convertToByteArray(input); + if (debug) + alert(bA); + /*for (i=0;i"); + } + */ + //alert(bA); + nextFile(); + return unzipped; + }; + + function nextFile() { + if (debug) + alert("NEXTFILE"); + outputArr = []; + var tmp = []; + modeZIP = false; + tmp[0] = readByte(); + tmp[1] = readByte(); + if (debug) + alert("type: " + tmp[0] + " " + tmp[1]); + if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("da", 16)) { //GZIP + if (debug) + alert("GEONExT-GZIP"); + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "geonext.gxt"; + files++; + } + if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("9c", 16)) { //ZLIB + if (debug) + alert("ZLIB"); + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "ZLIB"; + files++; + } + if (tmp[0] == parseInt("1f", 16) && tmp[1] == parseInt("8b", 16)) { //GZIP + if (debug) + alert("GZIP"); + //DeflateLoop(); + skipdir(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "file"; + files++; + } + if (tmp[0] == parseInt("50", 16) && tmp[1] == parseInt("4b", 16)) { //ZIP + modeZIP = true; + tmp[2] = readByte(); + tmp[3] = readByte(); + if (tmp[2] == parseInt("3", 16) && tmp[3] == parseInt("4", 16)) { + //MODE_ZIP + tmp[0] = readByte(); + tmp[1] = readByte(); + if (debug) + alert("ZIP-Version: " + tmp[1] + " " + tmp[0] / 10 + "." + tmp[0] % 10); + + gpflags = readByte(); + gpflags |= (readByte() << 8); + if (debug) + alert("gpflags: " + gpflags); + + var method = readByte(); + method |= (readByte() << 8); + if (debug) + alert("method: " + method); + + readByte(); + readByte(); + readByte(); + readByte(); + + var crc = readByte(); + crc |= (readByte() << 8); + crc |= (readByte() << 16); + crc |= (readByte() << 24); + + var compSize = readByte(); + compSize |= (readByte() << 8); + compSize |= (readByte() << 16); + compSize |= (readByte() << 24); + + var size = readByte(); + size |= (readByte() << 8); + size |= (readByte() << 16); + size |= (readByte() << 24); + + if (debug) + alert("local CRC: " + crc + "\nlocal Size: " + size + "\nlocal CompSize: " + compSize); + + var filelen = readByte(); + filelen |= (readByte() << 8); + + var extralen = readByte(); + extralen |= (readByte() << 8); + + if (debug) + alert("filelen " + filelen); + i = 0; + nameBuf = []; + while (filelen--) { + var c = readByte(); + if (c == "/" | c == ":") { + i = 0; + } else if (i < NAMEMAX - 1) + nameBuf[i++] = String.fromCharCode(c); + } + if (debug) + alert("nameBuf: " + nameBuf); + + //nameBuf[i] = "\0"; + if (!fileout) + fileout = nameBuf; + + var i = 0; + while (i < extralen) { + c = readByte(); + i++; + } + + CRC = 0xffffffff; + SIZE = 0; + + if (size == 0 && fileOut.charAt(fileout.length - 1) == "/") { + //skipdir + if (debug) + alert("skipdir"); + } + if (method == 8) { + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = nameBuf.join(''); + files++; + //return outputArr.join(''); + } + skipdir(); + } + } + }; + + function skipdir() { + var crc, + tmp = [], + compSize, size, os, i, c; + + if ((gpflags & 8)) { + tmp[0] = readByte(); + tmp[1] = readByte(); + tmp[2] = readByte(); + tmp[3] = readByte(); + + if (tmp[0] == parseInt("50", 16) && + tmp[1] == parseInt("4b", 16) && + tmp[2] == parseInt("07", 16) && + tmp[3] == parseInt("08", 16)) { + crc = readByte(); + crc |= (readByte() << 8); + crc |= (readByte() << 16); + crc |= (readByte() << 24); + } else { + crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24); + } + + compSize = readByte(); + compSize |= (readByte() << 8); + compSize |= (readByte() << 16); + compSize |= (readByte() << 24); + + size = readByte(); + size |= (readByte() << 8); + size |= (readByte() << 16); + size |= (readByte() << 24); + + if (debug) + alert("CRC:"); + } + + if (modeZIP) + nextFile(); + + tmp[0] = readByte(); + if (tmp[0] != 8) { + if (debug) + alert("Unknown compression method!"); + return 0; + } + + gpflags = readByte(); + if (debug) { + if ((gpflags & ~(parseInt("1f", 16)))) + alert("Unknown flags set!"); + } + + readByte(); + readByte(); + readByte(); + readByte(); + + readByte(); + os = readByte(); + + if ((gpflags & 4)) { + tmp[0] = readByte(); + tmp[2] = readByte(); + len = tmp[0] + 256 * tmp[1]; + if (debug) + alert("Extra field size: " + len); + for (i = 0; i < len; i++) + readByte(); + } + + if ((gpflags & 8)) { + i = 0; + nameBuf = []; + while (c = readByte()) { + if (c == "7" || c == ":") + i = 0; + if (i < NAMEMAX - 1) + nameBuf[i++] = c; + } + //nameBuf[i] = "\0"; + if (debug) + alert("original file name: " + nameBuf); + } + + if ((gpflags & 16)) { + while (c = readByte()) { + //FILE COMMENT + } + } + + if ((gpflags & 2)) { + readByte(); + readByte(); + } + + DeflateLoop(); + + crc = readByte(); + crc |= (readByte() << 8); + crc |= (readByte() << 16); + crc |= (readByte() << 24); + + size = readByte(); + size |= (readByte() << 8); + size |= (readByte() << 16); + size |= (readByte() << 24); + + if (modeZIP) + nextFile(); + + }; + +}; + +/** + * Base64 encoding / decoding + * {@link http://www.webtoolkit.info/} + */ +JXG.Util.Base64 = { + + // private property + _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + + // public method for encoding + encode: function(input) { + var output = [], + chr1, chr2, chr3, enc1, enc2, enc3, enc4, + i = 0; + + input = JXG.Util.Base64._utf8_encode(input); + + while (i < input.length) { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output.push([this._keyStr.charAt(enc1), + this._keyStr.charAt(enc2), + this._keyStr.charAt(enc3), + this._keyStr.charAt(enc4) + ].join('')); + } + + return output.join(''); + }, + + // public method for decoding + decode: function(input, utf8) { + var output = [], + chr1, chr2, chr3, + enc1, enc2, enc3, enc4, + i = 0; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + while (i < input.length) { + + enc1 = this._keyStr.indexOf(input.charAt(i++)); + enc2 = this._keyStr.indexOf(input.charAt(i++)); + enc3 = this._keyStr.indexOf(input.charAt(i++)); + enc4 = this._keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output.push(String.fromCharCode(chr1)); + + if (enc3 != 64) { + output.push(String.fromCharCode(chr2)); + } + if (enc4 != 64) { + output.push(String.fromCharCode(chr3)); + } + } + + output = output.join(''); + + if (utf8) { + output = JXG.Util.Base64._utf8_decode(output); + } + return output; + + }, + + // private method for UTF-8 encoding + _utf8_encode: function(string) { + string = string.replace(/\r\n/g, "\n"); + var utftext = ""; + + for (var n = 0; n < string.length; n++) { + + var c = string.charCodeAt(n); + + if (c < 128) { + utftext += String.fromCharCode(c); + } else if ((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + + return utftext; + }, + + // private method for UTF-8 decoding + _utf8_decode: function(utftext) { + var string = [], + i = 0, + c = 0, + c2 = 0, + c3 = 0; + + while (i < utftext.length) { + c = utftext.charCodeAt(i); + if (c < 128) { + string.push(String.fromCharCode(c)); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i + 1); + string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63))); + i += 2; + } else { + c2 = utftext.charCodeAt(i + 1); + c3 = utftext.charCodeAt(i + 2); + string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); + i += 3; + } + } + return string.join(''); + }, + + _destrip: function(stripped, wrap) { + var lines = [], + lineno, i, + destripped = []; + + if (wrap == null) + wrap = 76; + + stripped.replace(/ /g, ""); + lineno = stripped.length / wrap; + for (i = 0; i < lineno; i++) + lines[i] = stripped.substr(i * wrap, wrap); + if (lineno != stripped.length / wrap) + lines[lines.length] = stripped.substr(lineno * wrap, stripped.length - (lineno * wrap)); + + for (i = 0; i < lines.length; i++) + destripped.push(lines[i]); + return destripped.join('\n'); + }, + + decodeAsArray: function(input) { + var dec = this.decode(input), + ar = [], + i; + for (i = 0; i < dec.length; i++) { + ar[i] = dec.charCodeAt(i); + } + return ar; + }, + + decodeGEONExT: function(input) { + return decodeAsArray(destrip(input), false); + } +}; + +/** + * @private + */ +JXG.Util.asciiCharCodeAt = function(str, i) { + var c = str.charCodeAt(i); + if (c > 255) { + switch (c) { + case 8364: + c = 128; + break; + case 8218: + c = 130; + break; + case 402: + c = 131; + break; + case 8222: + c = 132; + break; + case 8230: + c = 133; + break; + case 8224: + c = 134; + break; + case 8225: + c = 135; + break; + case 710: + c = 136; + break; + case 8240: + c = 137; + break; + case 352: + c = 138; + break; + case 8249: + c = 139; + break; + case 338: + c = 140; + break; + case 381: + c = 142; + break; + case 8216: + c = 145; + break; + case 8217: + c = 146; + break; + case 8220: + c = 147; + break; + case 8221: + c = 148; + break; + case 8226: + c = 149; + break; + case 8211: + c = 150; + break; + case 8212: + c = 151; + break; + case 732: + c = 152; + break; + case 8482: + c = 153; + break; + case 353: + c = 154; + break; + case 8250: + c = 155; + break; + case 339: + c = 156; + break; + case 382: + c = 158; + break; + case 376: + c = 159; + break; + default: + break; + } + } + return c; +}; + +/** + * Decoding string into utf-8 + * @param {String} string to decode + * @return {String} utf8 decoded string + */ +JXG.Util.utf8Decode = function(utftext) { + var string = []; + var i = 0; + var c = 0, + c1 = 0, + c2 = 0, + c3; + if (!JXG.exists(utftext)) return ''; + + while (i < utftext.length) { + c = utftext.charCodeAt(i); + + if (c < 128) { + string.push(String.fromCharCode(c)); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i + 1); + string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63))); + i += 2; + } else { + c2 = utftext.charCodeAt(i + 1); + c3 = utftext.charCodeAt(i + 2); + string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); + i += 3; + } + }; + return string.join(''); +}; + +/** + * Generate a random uuid. + * http://www.broofa.com + * mailto:robert@broofa.com + * + * Copyright (c) 2010 Robert Kieffer + * Dual licensed under the MIT and GPL licenses. + * + * EXAMPLES: + * >>> Math.uuid() + * "92329D39-6F5C-4520-ABFC-AAB64544E172" + */ +JXG.Util.genUUID = function() { + // Private array of chars to use + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''), + uuid = new Array(36), + rnd = 0, + r; + + for (var i = 0; i < 36; i++) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + uuid[i] = '-'; + } else if (i == 14) { + uuid[i] = '4'; + } else { + if (rnd <= 0x02) rnd = 0x2000000 + (Math.random() * 0x1000000) | 0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + } + } + + return uuid.join(''); +}; + + +module.exports = JXG; + +},{}],3:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * This object contains configuration values. + * @requires enums + * @property {Integer} prefer_hash_algorithm + * @property {Integer} encryption_cipher + * @property {Integer} compression + * @property {Boolean} show_version + * @property {Boolean} show_comment + * @property {Boolean} integrity_protect + * @property {String} keyserver + * @property {Boolean} debug If enabled, debug messages will be printed + * @module config/config + */ + +var enums = require('../enums.js'); + +module.exports = { + prefer_hash_algorithm: enums.hash.sha256, + encryption_cipher: enums.symmetric.aes256, + compression: enums.compression.zip, + show_version: true, + show_comment: true, + integrity_protect: true, + keyserver: "keyserver.linux.it", // "pgp.mit.edu:11371" + + versionstring: "OpenPGP.js v0.0.1.20140102", + commentstring: "http://openpgpjs.org", + + debug: false +}; + +},{"../enums.js":27}],4:[function(require,module,exports){ +// Modified by Recurity Labs GmbH + +// modified version of http://www.hanewin.net/encrypt/PGdecode.js: + +/* OpenPGP encryption using RSA/AES + * Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de + * version 2.0, check www.haneWIN.de for the latest version + + * This software is provided as-is, without express or implied warranty. + * Permission to use, copy, modify, distribute or sell this software, with or + * without fee, for any purpose and by any individual or organization, is hereby + * granted, provided that the above copyright notice and this paragraph appear + * in all copies. Distribution as a part of an application or binary must + * include the above copyright notice in the documentation and/or other + * materials provided with the application or distribution. + */ + +/** + * @requires crypto/cipher + * @requires util + * @module crypto/cfb + */ + +var util = require('../util'), + cipher = require('./cipher'); + +module.exports = { + + /** + * This function encrypts a given with the specified prefixrandom + * using the specified blockcipher to encrypt a message + * @param {String} prefixrandom random bytes of block_size length provided + * as a string to be used in prefixing the data + * @param {String} cipherfn the algorithm cipher class to encrypt + * data in one block_size encryption, @see module:crypto/cipher. + * @param {String} plaintext data to be encrypted provided as a string + * @param {String} key binary string representation of key to be used to encrypt the plaintext. + * This will be passed to the cipherfn + * @param {Boolean} resync a boolean value specifying if a resync of the + * IV should be used or not. The encrypteddatapacket uses the + * "old" style with a resync. Encryption within an + * encryptedintegrityprotecteddata packet is not resyncing the IV. + * @return {String} a string with the encrypted data + */ + encrypt: function(prefixrandom, cipherfn, plaintext, key, resync) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var FR = new Array(block_size); + var FRE = new Array(block_size); + + prefixrandom = prefixrandom + prefixrandom.charAt(block_size - 2) + prefixrandom.charAt(block_size - 1); + util.print_debug("prefixrandom:" + util.hexstrdump(prefixrandom)); + var ciphertext = ""; + // 1. The feedback register (FR) is set to the IV, which is all zeros. + for (var i = 0; i < block_size; i++) FR[i] = 0; + + // 2. FR is encrypted to produce FRE (FR Encrypted). This is the + // encryption of an all-zero value. + FRE = cipherfn.encrypt(FR); + // 3. FRE is xored with the first BS octets of random data prefixed to + // the plaintext to produce C[1] through C[BS], the first BS octets + // of ciphertext. + for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i)); + + // 4. FR is loaded with C[1] through C[BS]. + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); + + // 5. FR is encrypted to produce FRE, the encryption of the first BS + // octets of ciphertext. + FRE = cipherfn.encrypt(FR); + + // 6. The left two octets of FRE get xored with the next two octets of + // data that were prefixed to the plaintext. This produces C[BS+1] + // and C[BS+2], the next two octets of ciphertext. + ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size)); + ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size + 1)); + + if (resync) { + // 7. (The resync step) FR is loaded with C3-C10. + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i + 2); + } else { + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); + } + // 8. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR, key); + + if (resync) { + // 9. FRE is xored with the first 8 octets of the given plaintext, now + // that we have finished encrypting the 10 octets of prefixed data. + // This produces C11-C18, the next 8 octets of ciphertext. + for (var i = 0; i < block_size; i++) + ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); + for (n = block_size + 2; n < plaintext.length; n += block_size) { + // 10. FR is loaded with C11-C18 + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n + i); + + // 11. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR); + + // 12. FRE is xored with the next 8 octets of plaintext, to produce the + // next 8 octets of ciphertext. These are loaded into FR and the + // process is repeated until the plaintext is used up. + for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n - 2) + + i)); + } + } else { + plaintext = " " + plaintext; + // 9. FRE is xored with the first 8 octets of the given plaintext, now + // that we have finished encrypting the 10 octets of prefixed data. + // This produces C11-C18, the next 8 octets of ciphertext. + for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); + var tempCiphertext = ciphertext.substring(0, 2 * block_size).split(''); + var tempCiphertextString = ciphertext.substring(block_size); + for (n = block_size; n < plaintext.length; n += block_size) { + // 10. FR is loaded with C11-C18 + for (var i = 0; i < block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i); + tempCiphertextString = ''; + + // 11. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR); + + // 12. FRE is xored with the next 8 octets of plaintext, to produce the + // next 8 octets of ciphertext. These are loaded into FR and the + // process is repeated until the plaintext is used up. + for (var i = 0; i < block_size; i++) { + tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i))); + tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i)); + } + } + ciphertext = tempCiphertext.join(''); + + } + + ciphertext = ciphertext.substring(0, plaintext.length + 2 + block_size); + + return ciphertext; + }, + + /** + * Decrypts the prefixed data for the Modification Detection Code (MDC) computation + * @param {String} cipherfn.encrypt Cipher function to use, + * @see module:crypto/cipher. + * @param {String} key binary string representation of key to be used to check the mdc + * This will be passed to the cipherfn + * @param {String} ciphertext The encrypted data + * @return {String} plaintext Data of D(ciphertext) with blocksize length +2 + */ + mdc: function(cipherfn, key, ciphertext) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var iblock = new Array(block_size); + var ablock = new Array(block_size); + var i; + + + // initialisation vector + for (i = 0; i < block_size; i++) iblock[i] = 0; + + iblock = cipherfn.encrypt(iblock); + for (i = 0; i < block_size; i++) { + ablock[i] = ciphertext.charCodeAt(i); + iblock[i] ^= ablock[i]; + } + + ablock = cipherfn.encrypt(ablock); + + return util.bin2str(iblock) + + String.fromCharCode(ablock[0] ^ ciphertext.charCodeAt(block_size)) + + String.fromCharCode(ablock[1] ^ ciphertext.charCodeAt(block_size + 1)); + }, + /** + * This function decrypts a given plaintext using the specified + * blockcipher to decrypt a message + * @param {String} cipherfn the algorithm cipher class to decrypt + * data in one block_size encryption, @see module:crypto/cipher. + * @param {String} key binary string representation of key to be used to decrypt the ciphertext. + * This will be passed to the cipherfn + * @param {String} ciphertext to be decrypted provided as a string + * @param {Boolean} resync a boolean value specifying if a resync of the + * IV should be used or not. The encrypteddatapacket uses the + * "old" style with a resync. Decryption within an + * encryptedintegrityprotecteddata packet is not resyncing the IV. + * @return {String} a string with the plaintext data + */ + + decrypt: function(cipherfn, key, ciphertext, resync) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var iblock = new Array(block_size); + var ablock = new Array(block_size); + var i, n = ''; + var text = []; + + // initialisation vector + for (i = 0; i < block_size; i++) iblock[i] = 0; + + iblock = cipherfn.encrypt(iblock, key); + for (i = 0; i < block_size; i++) { + ablock[i] = ciphertext.charCodeAt(i); + iblock[i] ^= ablock[i]; + } + + ablock = cipherfn.encrypt(ablock, key); + + // test check octets + if (iblock[block_size - 2] != (ablock[0] ^ ciphertext.charCodeAt(block_size)) || iblock[block_size - 1] != (ablock[ + 1] ^ ciphertext.charCodeAt(block_size + 1))) { + throw new Error('Invalid data.'); + } + + /* RFC4880: Tag 18 and Resync: + * [...] Unlike the Symmetrically Encrypted Data Packet, no + * special CFB resynchronization is done after encrypting this prefix + * data. See "OpenPGP CFB Mode" below for more details. + + */ + + if (resync) { + for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i + 2); + for (n = block_size + 2; n < ciphertext.length; n += block_size) { + ablock = cipherfn.encrypt(iblock); + + for (i = 0; i < block_size && i + n < ciphertext.length; i++) { + iblock[i] = ciphertext.charCodeAt(n + i); + text.push(String.fromCharCode(ablock[i] ^ iblock[i])); + } + } + } else { + for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i); + for (n = block_size; n < ciphertext.length; n += block_size) { + ablock = cipherfn.encrypt(iblock); + for (i = 0; i < block_size && i + n < ciphertext.length; i++) { + iblock[i] = ciphertext.charCodeAt(n + i); + text.push(String.fromCharCode(ablock[i] ^ iblock[i])); + } + } + } + + var n = resync ? 0 : 2; + + text = text.join(''); + + text = text.substring(n, ciphertext.length - block_size - 2 + n); + + + return text; + }, + + + normalEncrypt: function(cipherfn, key, plaintext, iv) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var blocki = ""; + var blockc = ""; + var pos = 0; + var cyphertext = []; + var tempBlock = []; + blockc = iv.substring(0, block_size); + while (plaintext.length > block_size * pos) { + var encblock = cipherfn.encrypt(util.str2bin(blockc)); + blocki = plaintext.substring((pos * block_size), (pos * block_size) + block_size); + for (var i = 0; i < blocki.length; i++) + tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i])); + blockc = tempBlock.join(''); + tempBlock = []; + cyphertext.push(blockc); + pos++; + } + return cyphertext.join(''); + }, + + normalDecrypt: function(cipherfn, key, ciphertext, iv) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var blockp = ""; + var pos = 0; + var plaintext = []; + var offset = 0; + if (iv == null) + for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0); + else + blockp = iv.substring(0, block_size); + while (ciphertext.length > (block_size * pos)) { + var decblock = cipherfn.encrypt(util.str2bin(blockp)); + blockp = ciphertext.substring((pos * (block_size)) + offset, (pos * (block_size)) + (block_size) + offset); + for (var i = 0; i < blockp.length; i++) { + plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i])); + } + pos++; + } + + return plaintext.join(''); + } +} + +},{"../util":56,"./cipher":9}],5:[function(require,module,exports){ +/* Rijndael (AES) Encryption + * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de + * version 1.1, check www.haneWIN.de for the latest version + + * This software is provided as-is, without express or implied warranty. + * Permission to use, copy, modify, distribute or sell this software, with or + * without fee, for any purpose and by any individual or organization, is hereby + * granted, provided that the above copyright notice and this paragraph appear + * in all copies. Distribution as a part of an application or binary must + * include the above copyright notice in the documentation and/or other + * materials provided with the application or distribution. + */ + +/** + * @requires util + * @module crypto/cipher/aes + */ + +var util = require('../../util'); + +// The round constants used in subkey expansion +var Rcon = [ + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, + 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 +]; + +// Precomputed lookup table for the SBox +var S = [ + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, + 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, + 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, + 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, + 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, + 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, + 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, + 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, + 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, + 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, + 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, + 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, + 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, + 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, + 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, + 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, + 22 +]; + +var T1 = [ + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, + 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, + 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, + 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, + 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, + 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, + 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, + 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, + 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, + 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, + 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, + 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, + 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, + 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, + 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, + 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, + 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, + 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, + 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, + 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, + 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, + 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, + 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, + 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, + 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, + 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, + 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, + 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, + 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, + 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, + 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, + 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, + 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, + 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, + 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, + 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, + 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, + 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, + 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, + 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, + 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, + 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, + 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, + 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, + 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, + 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, + 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, + 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, + 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, + 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, + 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, + 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, + 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, + 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, + 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, + 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, + 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, + 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c +]; + +var T2 = [ + 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, + 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, + 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, + 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, + 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, + 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, + 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, + 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, + 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, + 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, + 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, + 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, + 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, + 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, + 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, + 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, + 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, + 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, + 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, + 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, + 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, + 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, + 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, + 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, + 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, + 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, + 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, + 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, + 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, + 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, + 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, + 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, + 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, + 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, + 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, + 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, + 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, + 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, + 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, + 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, + 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, + 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, + 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, + 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, + 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, + 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, + 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, + 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, + 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, + 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, + 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, + 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, + 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, + 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, + 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, + 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, + 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, + 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, + 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, + 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, + 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, + 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, + 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, + 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a +]; + +var T3 = [ + 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, + 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, + 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, + 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, + 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, + 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, + 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, + 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, + 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, + 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, + 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, + 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, + 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, + 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, + 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, + 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, + 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, + 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, + 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, + 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, + 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, + 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, + 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, + 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, + 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, + 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, + 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, + 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, + 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, + 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, + 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, + 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, + 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, + 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, + 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, + 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, + 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, + 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, + 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, + 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, + 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, + 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, + 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, + 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, + 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, + 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, + 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, + 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, + 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, + 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, + 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, + 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, + 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, + 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, + 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, + 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, + 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, + 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, + 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, + 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, + 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, + 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, + 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, + 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16 +]; + +var T4 = [ + 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, + 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, + 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, + 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, + 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, + 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, + 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, + 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, + 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, + 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, + 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, + 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, + 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, + 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, + 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, + 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, + 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, + 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, + 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, + 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, + 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, + 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, + 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, + 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, + 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, + 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, + 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, + 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, + 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, + 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, + 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, + 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, + 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, + 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, + 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, + 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, + 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, + 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, + 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, + 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, + 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, + 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, + 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, + 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, + 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, + 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, + 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, + 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, + 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, + 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, + 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, + 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, + 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, + 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, + 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, + 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, + 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, + 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, + 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, + 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, + 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, + 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, + 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, + 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 +]; + +function B0(x) { + return (x & 255); +} + +function B1(x) { + return ((x >> 8) & 255); +} + +function B2(x) { + return ((x >> 16) & 255); +} + +function B3(x) { + return ((x >> 24) & 255); +} + +function F1(x0, x1, x2, x3) { + return B1(T1[x0 & 255]) | (B1(T1[(x1 >> 8) & 255]) << 8) | (B1(T1[(x2 >> 16) & 255]) << 16) | (B1(T1[x3 >>> 24]) << + 24); +} + +function packBytes(octets) { + var i, j; + var len = octets.length; + var b = new Array(len / 4); + + if (!octets || len % 4) return; + + for (i = 0, j = 0; j < len; j += 4) + b[i++] = octets[j] | (octets[j + 1] << 8) | (octets[j + 2] << 16) | (octets[j + 3] << 24); + + return b; +} + +function unpackBytes(packed) { + var j; + var i = 0, + l = packed.length; + var r = new Array(l * 4); + + for (j = 0; j < l; j++) { + r[i++] = B0(packed[j]); + r[i++] = B1(packed[j]); + r[i++] = B2(packed[j]); + r[i++] = B3(packed[j]); + } + return r; +} + +// ------------------------------------------------ + +var maxkc = 8; +var maxrk = 14; + +function keyExpansion(key) { + var kc, i, j, r, t; + var rounds; + var keySched = new Array(maxrk + 1); + var keylen = key.length; + var k = new Array(maxkc); + var tk = new Array(maxkc); + var rconpointer = 0; + + if (keylen == 16) { + rounds = 10; + kc = 4; + } else if (keylen == 24) { + rounds = 12; + kc = 6; + } else if (keylen == 32) { + rounds = 14; + kc = 8; + } else { + throw new Error('Invalid key-length for AES key:' + keylen); + } + + for (i = 0; i < maxrk + 1; i++) keySched[i] = new Array(4); + + for (i = 0, j = 0; j < keylen; j++, i += 4) + k[j] = key.charCodeAt(i) | (key.charCodeAt(i + 1) << 8) | (key.charCodeAt(i + 2) << 16) | (key.charCodeAt(i + 3) << + 24); + + for (j = kc - 1; j >= 0; j--) tk[j] = k[j]; + + r = 0; + t = 0; + for (j = 0; + (j < kc) && (r < rounds + 1);) { + for (; + (j < kc) && (t < 4); j++, t++) { + keySched[r][t] = tk[j]; + } + if (t == 4) { + r++; + t = 0; + } + } + + while (r < rounds + 1) { + var temp = tk[kc - 1]; + + tk[0] ^= S[B1(temp)] | (S[B2(temp)] << 8) | (S[B3(temp)] << 16) | (S[B0(temp)] << 24); + tk[0] ^= Rcon[rconpointer++]; + + if (kc != 8) { + for (j = 1; j < kc; j++) tk[j] ^= tk[j - 1]; + } else { + for (j = 1; j < kc / 2; j++) tk[j] ^= tk[j - 1]; + + temp = tk[kc / 2 - 1]; + tk[kc / 2] ^= S[B0(temp)] | (S[B1(temp)] << 8) | (S[B2(temp)] << 16) | (S[B3(temp)] << 24); + + for (j = kc / 2 + 1; j < kc; j++) tk[j] ^= tk[j - 1]; + } + + for (j = 0; + (j < kc) && (r < rounds + 1);) { + for (; + (j < kc) && (t < 4); j++, t++) { + keySched[r][t] = tk[j]; + } + if (t == 4) { + r++; + t = 0; + } + } + } + this.rounds = rounds; + this.rk = keySched; + return this; +} + +function AESencrypt(block, ctx) { + var r; + var t0, t1, t2, t3; + + var b = packBytes(block); + var rounds = ctx.rounds; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var b3 = b[3]; + + for (r = 0; r < rounds - 1; r++) { + t0 = b0 ^ ctx.rk[r][0]; + t1 = b1 ^ ctx.rk[r][1]; + t2 = b2 ^ ctx.rk[r][2]; + t3 = b3 ^ ctx.rk[r][3]; + + b0 = T1[t0 & 255] ^ T2[(t1 >> 8) & 255] ^ T3[(t2 >> 16) & 255] ^ T4[t3 >>> 24]; + b1 = T1[t1 & 255] ^ T2[(t2 >> 8) & 255] ^ T3[(t3 >> 16) & 255] ^ T4[t0 >>> 24]; + b2 = T1[t2 & 255] ^ T2[(t3 >> 8) & 255] ^ T3[(t0 >> 16) & 255] ^ T4[t1 >>> 24]; + b3 = T1[t3 & 255] ^ T2[(t0 >> 8) & 255] ^ T3[(t1 >> 16) & 255] ^ T4[t2 >>> 24]; + } + + // last round is special + r = rounds - 1; + + t0 = b0 ^ ctx.rk[r][0]; + t1 = b1 ^ ctx.rk[r][1]; + t2 = b2 ^ ctx.rk[r][2]; + t3 = b3 ^ ctx.rk[r][3]; + + b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0]; + b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1]; + b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2]; + b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3]; + + return unpackBytes(b); +} + +function makeClass(length) { + + var c = function(key) { + this.key = keyExpansion(key); + + this.encrypt = function(block) { + return AESencrypt(block, this.key); + } + } + + c.blockSize = c.prototype.blockSize = 16; + c.keySize = c.prototype.keySize = length / 8; + + return c; +} + +module.exports = {} + +var types = [128, 192, 256]; + +for (var i in types) { + module.exports[types[i]] = makeClass(types[i]); +} + +},{"../../util":56}],6:[function(require,module,exports){ +/* Modified by Recurity Labs GmbH + * + * Originally written by nklein software (nklein.com) + */ + +/** + * @module crypto/cipher/blowfish + */ + +/* + * Javascript implementation based on Bruce Schneier's reference implementation. + * + * + * The constructor doesn't do much of anything. It's just here + * so we can start defining properties and methods and such. + */ +function Blowfish() {}; + +/* + * Declare the block size so that protocols know what size + * Initialization Vector (IV) they will need. + */ +Blowfish.prototype.BLOCKSIZE = 8; + +/* + * These are the default SBOXES. + */ +Blowfish.prototype.SBOXES = [ + [ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, + 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, + 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, + 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, + 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, + 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, + 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, + 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, + 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, + 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, + 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, + 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, + 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, + 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, + 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, + 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, + 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, + 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, + 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, + 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, + 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, + 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + ], + [ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, + 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, + 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, + 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, + 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, + 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, + 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, + 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, + 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, + 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, + 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, + 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, + 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, + 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, + 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, + 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, + 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, + 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, + 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, + 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, + 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, + 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + ], + [ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, + 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, + 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, + 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, + 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, + 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, + 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, + 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, + 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, + 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, + 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, + 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, + 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, + 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, + 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, + 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, + 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, + 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, + 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, + 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, + 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, + 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + ], + [ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, + 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, + 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, + 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, + 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, + 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, + 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, + 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, + 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, + 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, + 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, + 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, + 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, + 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, + 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, + 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, + 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, + 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, + 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, + 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, + 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, + 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + ] +]; + +//* +//* This is the default PARRAY +//* +Blowfish.prototype.PARRAY = [ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b +]; + +//* +//* This is the number of rounds the cipher will go +//* +Blowfish.prototype.NN = 16; + +//* +//* This function is needed to get rid of problems +//* with the high-bit getting set. If we don't do +//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not +//* equal to ( bb & 0x00FFFFFFFF ) even when they +//* agree bit-for-bit for the first 32 bits. +//* +Blowfish.prototype._clean = function(xx) { + if (xx < 0) { + var yy = xx & 0x7FFFFFFF; + xx = yy + 0x80000000; + } + return xx; +}; + +//* +//* This is the mixing function that uses the sboxes +//* +Blowfish.prototype._F = function(xx) { + var aa; + var bb; + var cc; + var dd; + var yy; + + dd = xx & 0x00FF; + xx >>>= 8; + cc = xx & 0x00FF; + xx >>>= 8; + bb = xx & 0x00FF; + xx >>>= 8; + aa = xx & 0x00FF; + + yy = this.sboxes[0][aa] + this.sboxes[1][bb]; + yy = yy ^ this.sboxes[2][cc]; + yy = yy + this.sboxes[3][dd]; + + return yy; +}; + +//* +//* This method takes an array with two values, left and right +//* and does NN rounds of Blowfish on them. +//* +Blowfish.prototype._encrypt_block = function(vals) { + var dataL = vals[0]; + var dataR = vals[1]; + + var ii; + + for (ii = 0; ii < this.NN; ++ii) { + dataL = dataL ^ this.parray[ii]; + dataR = this._F(dataL) ^ dataR; + + var tmp = dataL; + dataL = dataR; + dataR = tmp; + } + + dataL = dataL ^ this.parray[this.NN + 0]; + dataR = dataR ^ this.parray[this.NN + 1]; + + vals[0] = this._clean(dataR); + vals[1] = this._clean(dataL); +}; + +//* +//* This method takes a vector of numbers and turns them +//* into long words so that they can be processed by the +//* real algorithm. +//* +//* Maybe I should make the real algorithm above take a vector +//* instead. That will involve more looping, but it won't require +//* the F() method to deconstruct the vector. +//* +Blowfish.prototype.encrypt_block = function(vector) { + var ii; + var vals = [0, 0]; + var off = this.BLOCKSIZE / 2; + for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) { + vals[0] = (vals[0] << 8) | (vector[ii + 0] & 0x00FF); + vals[1] = (vals[1] << 8) | (vector[ii + off] & 0x00FF); + } + + this._encrypt_block(vals); + + var ret = []; + for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) { + ret[ii + 0] = (vals[0] >>> (24 - 8 * (ii)) & 0x00FF); + ret[ii + off] = (vals[1] >>> (24 - 8 * (ii)) & 0x00FF); + // vals[ 0 ] = ( vals[ 0 ] >>> 8 ); + // vals[ 1 ] = ( vals[ 1 ] >>> 8 ); + } + + return ret; +}; + +//* +//* This method takes an array with two values, left and right +//* and undoes NN rounds of Blowfish on them. +//* +Blowfish.prototype._decrypt_block = function(vals) { + var dataL = vals[0]; + var dataR = vals[1]; + + var ii; + + for (ii = this.NN + 1; ii > 1; --ii) { + dataL = dataL ^ this.parray[ii]; + dataR = this._F(dataL) ^ dataR; + + var tmp = dataL; + dataL = dataR; + dataR = tmp; + } + + dataL = dataL ^ this.parray[1]; + dataR = dataR ^ this.parray[0]; + + vals[0] = this._clean(dataR); + vals[1] = this._clean(dataL); +}; + +//* +//* This method takes a key array and initializes the +//* sboxes and parray for this encryption. +//* +Blowfish.prototype.init = function(key) { + var ii; + var jj = 0; + + this.parray = []; + for (ii = 0; ii < this.NN + 2; ++ii) { + var data = 0x00000000; + var kk; + for (kk = 0; kk < 4; ++kk) { + data = (data << 8) | (key[jj] & 0x00FF); + if (++jj >= key.length) { + jj = 0; + } + } + this.parray[ii] = this.PARRAY[ii] ^ data; + } + + this.sboxes = []; + for (ii = 0; ii < 4; ++ii) { + this.sboxes[ii] = []; + for (jj = 0; jj < 256; ++jj) { + this.sboxes[ii][jj] = this.SBOXES[ii][jj]; + } + } + + var vals = [0x00000000, 0x00000000]; + + for (ii = 0; ii < this.NN + 2; ii += 2) { + this._encrypt_block(vals); + this.parray[ii + 0] = vals[0]; + this.parray[ii + 1] = vals[1]; + } + + for (ii = 0; ii < 4; ++ii) { + for (jj = 0; jj < 256; jj += 2) { + this._encrypt_block(vals); + this.sboxes[ii][jj + 0] = vals[0]; + this.sboxes[ii][jj + 1] = vals[1]; + } + } +}; + +var util = require('../../util'); + +// added by Recurity Labs + +function BFencrypt(block, key) { + var bf = new Blowfish(); + bf.init(util.str2bin(key)); + return bf.encrypt_block(block); +} + +function BF(key) { + this.bf = new Blowfish(); + this.bf.init(util.str2bin(key)); + + this.encrypt = function(block) { + return this.bf.encrypt_block(block); + } +} + + +module.exports = BF; +module.exports.keySize = BF.prototype.keySize = 16; +module.exports.blockSize = BF.prototype.blockSize = 16; + +},{"../../util":56}],7:[function(require,module,exports){ +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Copyright 2010 pjacobs@xeekr.com . All rights reserved. + +// Modified by Recurity Labs GmbH + +// fixed/modified by Herbert Hanewinkel, www.haneWIN.de +// check www.haneWIN.de for the latest version + +// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144. +// CAST-128 is a common OpenPGP cipher. + + +// CAST5 constructor + +/** @module crypto/cipher/cast5 */ + + + +function openpgp_symenc_cast5() { + this.BlockSize = 8; + this.KeySize = 16; + + this.setKey = function(key) { + this.masking = new Array(16); + this.rotate = new Array(16); + + this.reset(); + + if (key.length == this.KeySize) { + this.keySchedule(key); + } else { + throw new Error('CAST-128: keys must be 16 bytes'); + } + return true; + }; + + this.reset = function() { + for (var i = 0; i < 16; i++) { + this.masking[i] = 0; + this.rotate[i] = 0; + } + }; + + this.getBlockSize = function() { + return BlockSize; + }; + + this.encrypt = function(src) { + var dst = new Array(src.length); + + for (var i = 0; i < src.length; i += 8) { + var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3]; + var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7]; + var t; + + t = r; + r = l ^ f1(r, this.masking[0], this.rotate[0]); + l = t; + t = r; + r = l ^ f2(r, this.masking[1], this.rotate[1]); + l = t; + t = r; + r = l ^ f3(r, this.masking[2], this.rotate[2]); + l = t; + t = r; + r = l ^ f1(r, this.masking[3], this.rotate[3]); + l = t; + + t = r; + r = l ^ f2(r, this.masking[4], this.rotate[4]); + l = t; + t = r; + r = l ^ f3(r, this.masking[5], this.rotate[5]); + l = t; + t = r; + r = l ^ f1(r, this.masking[6], this.rotate[6]); + l = t; + t = r; + r = l ^ f2(r, this.masking[7], this.rotate[7]); + l = t; + + t = r; + r = l ^ f3(r, this.masking[8], this.rotate[8]); + l = t; + t = r; + r = l ^ f1(r, this.masking[9], this.rotate[9]); + l = t; + t = r; + r = l ^ f2(r, this.masking[10], this.rotate[10]); + l = t; + t = r; + r = l ^ f3(r, this.masking[11], this.rotate[11]); + l = t; + + t = r; + r = l ^ f1(r, this.masking[12], this.rotate[12]); + l = t; + t = r; + r = l ^ f2(r, this.masking[13], this.rotate[13]); + l = t; + t = r; + r = l ^ f3(r, this.masking[14], this.rotate[14]); + l = t; + t = r; + r = l ^ f1(r, this.masking[15], this.rotate[15]); + l = t; + + dst[i] = (r >>> 24) & 255; + dst[i + 1] = (r >>> 16) & 255; + dst[i + 2] = (r >>> 8) & 255; + dst[i + 3] = r & 255; + dst[i + 4] = (l >>> 24) & 255; + dst[i + 5] = (l >>> 16) & 255; + dst[i + 6] = (l >>> 8) & 255; + dst[i + 7] = l & 255; + } + + return dst; + }; + + this.decrypt = function(src) { + var dst = new Array(src.length); + + for (var i = 0; i < src.length; i += 8) { + var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3]; + var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7]; + var t; + + t = r; + r = l ^ f1(r, this.masking[15], this.rotate[15]); + l = t; + t = r; + r = l ^ f3(r, this.masking[14], this.rotate[14]); + l = t; + t = r; + r = l ^ f2(r, this.masking[13], this.rotate[13]); + l = t; + t = r; + r = l ^ f1(r, this.masking[12], this.rotate[12]); + l = t; + + t = r; + r = l ^ f3(r, this.masking[11], this.rotate[11]); + l = t; + t = r; + r = l ^ f2(r, this.masking[10], this.rotate[10]); + l = t; + t = r; + r = l ^ f1(r, this.masking[9], this.rotate[9]); + l = t; + t = r; + r = l ^ f3(r, this.masking[8], this.rotate[8]); + l = t; + + t = r; + r = l ^ f2(r, this.masking[7], this.rotate[7]); + l = t; + t = r; + r = l ^ f1(r, this.masking[6], this.rotate[6]); + l = t; + t = r; + r = l ^ f3(r, this.masking[5], this.rotate[5]); + l = t; + t = r; + r = l ^ f2(r, this.masking[4], this.rotate[4]); + l = t; + + t = r; + r = l ^ f1(r, this.masking[3], this.rotate[3]); + l = t; + t = r; + r = l ^ f3(r, this.masking[2], this.rotate[2]); + l = t; + t = r; + r = l ^ f2(r, this.masking[1], this.rotate[1]); + l = t; + t = r; + r = l ^ f1(r, this.masking[0], this.rotate[0]); + l = t; + + dst[i] = (r >>> 24) & 255; + dst[i + 1] = (r >>> 16) & 255; + dst[i + 2] = (r >>> 8) & 255; + dst[i + 3] = r & 255; + dst[i + 4] = (l >>> 24) & 255; + dst[i + 5] = (l >> 16) & 255; + dst[i + 6] = (l >> 8) & 255; + dst[i + 7] = l & 255; + } + + return dst; + }; + var scheduleA = new Array(4); + + scheduleA[0] = new Array(4); + scheduleA[0][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 0x8); + scheduleA[0][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); + scheduleA[0][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); + scheduleA[0][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); + + scheduleA[1] = new Array(4); + scheduleA[1][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); + scheduleA[1][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); + scheduleA[1][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); + scheduleA[1][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); + + scheduleA[2] = new Array(4); + scheduleA[2][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 8); + scheduleA[2][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); + scheduleA[2][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); + scheduleA[2][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); + + + scheduleA[3] = new Array(4); + scheduleA[3][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); + scheduleA[3][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); + scheduleA[3][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); + scheduleA[3][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); + + var scheduleB = new Array(4); + + scheduleB[0] = new Array(4); + scheduleB[0][0] = new Array(16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2); + scheduleB[0][1] = new Array(16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6); + scheduleB[0][2] = new Array(16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9); + scheduleB[0][3] = new Array(16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc); + + scheduleB[1] = new Array(4); + scheduleB[1][0] = new Array(3, 2, 0xc, 0xd, 8); + scheduleB[1][1] = new Array(1, 0, 0xe, 0xf, 0xd); + scheduleB[1][2] = new Array(7, 6, 8, 9, 3); + scheduleB[1][3] = new Array(5, 4, 0xa, 0xb, 7); + + + scheduleB[2] = new Array(4); + scheduleB[2][0] = new Array(16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9); + scheduleB[2][1] = new Array(16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc); + scheduleB[2][2] = new Array(16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2); + scheduleB[2][3] = new Array(16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6); + + + scheduleB[3] = new Array(4); + scheduleB[3][0] = new Array(8, 9, 7, 6, 3); + scheduleB[3][1] = new Array(0xa, 0xb, 5, 4, 7); + scheduleB[3][2] = new Array(0xc, 0xd, 3, 2, 8); + scheduleB[3][3] = new Array(0xe, 0xf, 1, 0, 0xd); + + // changed 'in' to 'inn' (in javascript 'in' is a reserved word) + this.keySchedule = function(inn) { + var t = new Array(8); + var k = new Array(32); + + for (var i = 0; i < 4; i++) { + var j = i * 4; + t[i] = inn[j] << 24 | inn[j + 1] << 16 | inn[j + 2] << 8 | inn[j + 3]; + } + + var x = [6, 7, 4, 5]; + var ki = 0; + + for (var half = 0; half < 2; half++) { + for (var round = 0; round < 4; round++) { + for (var j = 0; j < 4; j++) { + var a = scheduleA[round][j]; + var w = t[a[1]]; + + w ^= sBox[4][(t[a[2] >>> 2] >>> (24 - 8 * (a[2] & 3))) & 0xff]; + w ^= sBox[5][(t[a[3] >>> 2] >>> (24 - 8 * (a[3] & 3))) & 0xff]; + w ^= sBox[6][(t[a[4] >>> 2] >>> (24 - 8 * (a[4] & 3))) & 0xff]; + w ^= sBox[7][(t[a[5] >>> 2] >>> (24 - 8 * (a[5] & 3))) & 0xff]; + w ^= sBox[x[j]][(t[a[6] >>> 2] >>> (24 - 8 * (a[6] & 3))) & 0xff]; + t[a[0]] = w; + } + + for (var j = 0; j < 4; j++) { + var b = scheduleB[round][j]; + var w = sBox[4][(t[b[0] >>> 2] >>> (24 - 8 * (b[0] & 3))) & 0xff]; + + w ^= sBox[5][(t[b[1] >>> 2] >>> (24 - 8 * (b[1] & 3))) & 0xff]; + w ^= sBox[6][(t[b[2] >>> 2] >>> (24 - 8 * (b[2] & 3))) & 0xff]; + w ^= sBox[7][(t[b[3] >>> 2] >>> (24 - 8 * (b[3] & 3))) & 0xff]; + w ^= sBox[4 + j][(t[b[4] >>> 2] >>> (24 - 8 * (b[4] & 3))) & 0xff]; + k[ki] = w; + ki++; + } + } + } + + for (var i = 0; i < 16; i++) { + this.masking[i] = k[i]; + this.rotate[i] = k[16 + i] & 0x1f; + } + }; + + // These are the three 'f' functions. See RFC 2144, section 2.2. + + function f1(d, m, r) { + var t = m + d; + var I = (t << r) | (t >>> (32 - r)); + return ((sBox[0][I >>> 24] ^ sBox[1][(I >>> 16) & 255]) - sBox[2][(I >>> 8) & 255]) + sBox[3][I & 255]; + } + + function f2(d, m, r) { + var t = m ^ d; + var I = (t << r) | (t >>> (32 - r)); + return ((sBox[0][I >>> 24] - sBox[1][(I >>> 16) & 255]) + sBox[2][(I >>> 8) & 255]) ^ sBox[3][I & 255]; + } + + function f3(d, m, r) { + var t = m - d; + var I = (t << r) | (t >>> (32 - r)); + return ((sBox[0][I >>> 24] + sBox[1][(I >>> 16) & 255]) ^ sBox[2][(I >>> 8) & 255]) - sBox[3][I & 255]; + } + + var sBox = new Array(8); + sBox[0] = new Array( + 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, + 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, + 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, + 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, + 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, + 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, + 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, + 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, + 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, + 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, + 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, + 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, + 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, + 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, + 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, + 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, + 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, + 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, + 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, + 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, + 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, + 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, + 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, + 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, + 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, + 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, + 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, + 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, + 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, + 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, + 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, + 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf); + + sBox[1] = new Array( + 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, + 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, + 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, + 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, + 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, + 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, + 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, + 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, + 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, + 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, + 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, + 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, + 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, + 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, + 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, + 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, + 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, + 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, + 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, + 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, + 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, + 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, + 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, + 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, + 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, + 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, + 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, + 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, + 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, + 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, + 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, + 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1); + + sBox[2] = new Array( + 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, + 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, + 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, + 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, + 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, + 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, + 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, + 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, + 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, + 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, + 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, + 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, + 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, + 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, + 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, + 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, + 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, + 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, + 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, + 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, + 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, + 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, + 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, + 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, + 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, + 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, + 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, + 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, + 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, + 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, + 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, + 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783); + + sBox[3] = new Array( + 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, + 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, + 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, + 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, + 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, + 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, + 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, + 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, + 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, + 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, + 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, + 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, + 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, + 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, + 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, + 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, + 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, + 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, + 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, + 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, + 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, + 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, + 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, + 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, + 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, + 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, + 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, + 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, + 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, + 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, + 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, + 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2); + + sBox[4] = new Array( + 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, + 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, + 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, + 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, + 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, + 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, + 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, + 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, + 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, + 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, + 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, + 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, + 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, + 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, + 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, + 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, + 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, + 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, + 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, + 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, + 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, + 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, + 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, + 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, + 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, + 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, + 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, + 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, + 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, + 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, + 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, + 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4); + + sBox[5] = new Array( + 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, + 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, + 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, + 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, + 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, + 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, + 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, + 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, + 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, + 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, + 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, + 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, + 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, + 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, + 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, + 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, + 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, + 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, + 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, + 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, + 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, + 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, + 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, + 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, + 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, + 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, + 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, + 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, + 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, + 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, + 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, + 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f); + + sBox[6] = new Array( + 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, + 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, + 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, + 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, + 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, + 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, + 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, + 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, + 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, + 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, + 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, + 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, + 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, + 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, + 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, + 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, + 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, + 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, + 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, + 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, + 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, + 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, + 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, + 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, + 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, + 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, + 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, + 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, + 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, + 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, + 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, + 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3); + + sBox[7] = new Array( + 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, + 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, + 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, + 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, + 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, + 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, + 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, + 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, + 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, + 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, + 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, + 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, + 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, + 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, + 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, + 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, + 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, + 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, + 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, + 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, + 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, + 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, + 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, + 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, + 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, + 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, + 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, + 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, + 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, + 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, + 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, + 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e); + +}; + +var util = require('../../util'); + +function cast5(key) { + this.cast5 = new openpgp_symenc_cast5(); + this.cast5.setKey(util.str2bin(key)); + + this.encrypt = function(block) { + return this.cast5.encrypt(block); + } +} + +module.exports = cast5; +module.exports.blockSize = cast5.prototype.blockSize = 8; +module.exports.keySize = cast5.prototype.keySize = 16; + +},{"../../util":56}],8:[function(require,module,exports){ +//Paul Tero, July 2001 +//http://www.tero.co.uk/des/ +// +//Optimised for performance with large blocks by Michael Hayworth, November 2001 +//http://www.netdealing.com +// +// Modified by Recurity Labs GmbH + +//THIS SOFTWARE IS PROVIDED "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +//SUCH DAMAGE. + +//des +//this takes the key, the message, and whether to encrypt or decrypt + +/** + * @module crypto/cipher/des + */ + + +function des(keys, message, encrypt, mode, iv, padding) { + //declaring this locally speeds things up a bit + var spfunction1 = new Array(0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400, + 0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000, + 0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4, + 0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404, + 0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400, + 0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004); + var spfunction2 = new Array(-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, - + 0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020, - + 0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, - + 0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, - + 0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0, + 0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0, - + 0x7fef7fe0, 0x108000); + var spfunction3 = new Array(0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008, + 0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000, + 0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000, + 0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0, + 0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208, + 0x8020000, 0x20208, 0x8, 0x8020008, 0x20200); + var spfunction4 = new Array(0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000, + 0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080, + 0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0, + 0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001, + 0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080); + var spfunction5 = new Array(0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000, + 0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000, + 0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100, + 0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100, + 0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100, + 0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0, + 0x40080000, 0x2080100, 0x40000100); + var spfunction6 = new Array(0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000, + 0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010, + 0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000, + 0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000, + 0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000, + 0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010); + var spfunction7 = new Array(0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802, + 0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002, + 0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000, + 0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000, + 0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0, + 0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002); + var spfunction8 = new Array(0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000, + 0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000, + 0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040, + 0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040, + 0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000); + + //create the 16 or 48 subkeys we will need + var m = 0, + i, j, temp, temp2, right1, right2, left, right, looping; + var cbcleft, cbcleft2, cbcright, cbcright2 + var endloop, loopinc; + var len = message.length; + var chunk = 0; + //set up the loops for single and triple des + var iterations = keys.length == 32 ? 3 : 9; //single or triple des + if (iterations == 3) { + looping = encrypt ? new Array(0, 32, 2) : new Array(30, -2, -2); + } else { + looping = encrypt ? new Array(0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array(94, 62, -2, 32, 64, 2, 30, -2, -2); + } + + //pad the message depending on the padding parameter + //only add padding if encrypting - note that you need to use the same padding option for both encrypt and decrypt + if (encrypt) { + message = des_addPadding(message, padding); + len = message.length; + } + + //store the result here + result = ""; + tempresult = ""; + + if (mode == 1) { //CBC mode + cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); + cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); + m = 0; + } + + //loop through each 64 bit chunk of the message + while (m < len) { + left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message + .charCodeAt(m++); + right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | + message.charCodeAt(m++); + + //for Cipher Block Chaining mode, xor the message with the previous result + if (mode == 1) { + if (encrypt) { + left ^= cbcleft; + right ^= cbcright; + } else { + cbcleft2 = cbcleft; + cbcright2 = cbcright; + cbcleft = left; + cbcright = right; + } + } + + //first each 64 but chunk of the message must be permuted according to IP + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= (temp << 4); + temp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= temp; + left ^= (temp << 16); + temp = ((right >>> 2) ^ left) & 0x33333333; + left ^= temp; + right ^= (temp << 2); + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= (temp << 8); + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + + left = ((left << 1) | (left >>> 31)); + right = ((right << 1) | (right >>> 31)); + + //do this either 1 or 3 times for each chunk of the message + for (j = 0; j < iterations; j += 3) { + endloop = looping[j + 1]; + loopinc = looping[j + 2]; + //now go through and perform the encryption or decryption + for (i = looping[j]; i != endloop; i += loopinc) { //for efficiency + right1 = right ^ keys[i]; + right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1]; + //the result is attained by passing these bytes through the S selection functions + temp = left; + left = right; + right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f] | spfunction6[(right1 >>> + 8) & 0x3f] | spfunction8[right1 & 0x3f] | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & + 0x3f] | spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]); + } + temp = left; + left = right; + right = temp; //unreverse left and right + } //for either 1 or 3 iterations + + //move then each one bit to the right + left = ((left >>> 1) | (left << 31)); + right = ((right >>> 1) | (right << 31)); + + //now perform IP-1, which is IP in the opposite direction + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= (temp << 8); + temp = ((right >>> 2) ^ left) & 0x33333333; + left ^= temp; + right ^= (temp << 2); + temp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= temp; + left ^= (temp << 16); + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= (temp << 4); + + //for Cipher Block Chaining mode, xor the message with the previous result + if (mode == 1) { + if (encrypt) { + cbcleft = left; + cbcright = right; + } else { + left ^= cbcleft2; + right ^= cbcright2; + } + } + tempresult += String.fromCharCode((left >>> 24), ((left >>> 16) & 0xff), ((left >>> 8) & 0xff), (left & 0xff), ( + right >>> 24), ((right >>> 16) & 0xff), ((right >>> 8) & 0xff), (right & 0xff)); + + chunk += 8; + if (chunk == 512) { + result += tempresult; + tempresult = ""; + chunk = 0; + } + } //for every 8 characters, or 64 bits in the message + + //return the result as an array + result += tempresult; + + //only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt + if (!encrypt) { + result = des_removePadding(result, padding); + } + + return result; +} //end of des + + + +//des_createKeys +//this takes as input a 64 bit key (even though only 56 bits are used) +//as an array of 2 integers, and returns 16 48 bit keys + +function des_createKeys(key) { + //declaring this locally speeds things up a bit + pc2bytes0 = new Array(0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204, + 0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204); + pc2bytes1 = new Array(0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100, + 0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101); + pc2bytes2 = new Array(0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808, + 0x1000000, 0x1000008, 0x1000800, 0x1000808); + pc2bytes3 = new Array(0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000, + 0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000); + pc2bytes4 = new Array(0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000, + 0x41000, 0x1010, 0x41010); + pc2bytes5 = new Array(0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420, + 0x2000000, 0x2000400, 0x2000020, 0x2000420); + pc2bytes6 = new Array(0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000, + 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002); + pc2bytes7 = new Array(0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000, + 0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800); + pc2bytes8 = new Array(0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000, + 0x2000002, 0x2040002, 0x2000002, 0x2040002); + pc2bytes9 = new Array(0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408, + 0x10000408, 0x400, 0x10000400, 0x408, 0x10000408); + pc2bytes10 = new Array(0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020, + 0x102000, 0x102020, 0x102000, 0x102020); + pc2bytes11 = new Array(0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000, + 0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200); + pc2bytes12 = new Array(0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010, + 0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010); + pc2bytes13 = new Array(0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105); + + //how many iterations (1 for des, 3 for triple des) + var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys + //stores the return keys + var keys = new Array(32 * iterations); + //now define the left shifts which need to be done + var shifts = new Array(0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0); + //other variables + var lefttemp, righttemp, m = 0, + n = 0, + temp; + + for (var j = 0; j < iterations; j++) { //either 1 or 3 iterations + left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++); + right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++); + + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= (temp << 4); + temp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= temp; + right ^= (temp << -16); + temp = ((left >>> 2) ^ right) & 0x33333333; + right ^= temp; + left ^= (temp << 2); + temp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= temp; + right ^= (temp << -16); + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= (temp << 8); + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + + //the right side needs to be shifted and to get the last four bits of the left side + temp = (left << 8) | ((right >>> 20) & 0x000000f0); + //left needs to be put upside down + left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0); + right = temp; + + //now go through and perform these shifts on the left and right keys + for (i = 0; i < shifts.length; i++) { + //shift the keys either one or two bits to the left + if (shifts[i]) { + left = (left << 2) | (left >>> 26); + right = (right << 2) | (right >>> 26); + } else { + left = (left << 1) | (left >>> 27); + right = (right << 1) | (right >>> 27); + } + left &= -0xf; + right &= -0xf; + + //now apply PC-2, in such a way that E is easier when encrypting or decrypting + //this conversion will look like PC-2 except only the last 6 bits of each byte are used + //rather than 48 consecutive bits and the order of lines will be according to + //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 + lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[( + left >>> 16) & 0xf] | pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | pc2bytes6[(left >>> 4) & + 0xf]; + righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | pc2bytes9[(right >>> 20) & 0xf] | + pc2bytes10[(right >>> 16) & 0xf] | pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] | + pc2bytes13[(right >>> 4) & 0xf]; + temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff; + keys[n++] = lefttemp ^ temp; + keys[n++] = righttemp ^ (temp << 16); + } + } //for each iterations + //return the keys we've created + return keys; +} //end of des_createKeys + + +function des_addPadding(message, padding) { + var padLength = 8 - (message.length % 8); + if ((padding == 2) && (padLength < 8)) { //pad the message with spaces + message += " ".substr(0, padLength); + } else if (padding == 1) { //PKCS7 padding + message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength, + padLength).substr(0, padLength); + } else if (!padding && (padLength < 8)) { //pad the message out with null bytes + message += "\0\0\0\0\0\0\0\0".substr(0, padLength); + } + return message; +} + +function des_removePadding(message, padding) { + if (padding == 2) { // space padded + message = message.replace(/ *$/g, ""); + } else if (padding == 1) { // PKCS7 + var padCount = message.charCodeAt(message.length - 1); + message = message.substr(0, message.length - padCount); + } else if (!padding) { // null padding + message = message.replace(/\0*$/g, ""); + } + return message; +} + + +var util = require('../../util'); + +// added by Recurity Labs + +function Des(key) { + this.key = []; + + for (var i = 0; i < 3; i++) { + this.key.push(key.substr(i * 8, 8)); + } + + this.encrypt = function(block) { + return util.str2bin(des(des_createKeys(this.key[2]), + des(des_createKeys(this.key[1]), + des(des_createKeys(this.key[0]), + util.bin2str(block), true, 0, null, null), + false, 0, null, null), true, 0, null, null)); + } +} + +Des.keySize = Des.prototype.keySize = 24; +Des.blockSize = Des.prototype.blockSize = 8; + +// This is "original" DES - Des is actually Triple DES. +// This is only exported so we can unit test. + +function OriginalDes(key) { + this.key = key; + + this.encrypt = function(block, padding) { + var keys = des_createKeys(this.key); + return util.str2bin(des(keys, util.bin2str(block), true, 0, null, padding)); + } + + this.decrypt = function(block, padding) { + var keys = des_createKeys(this.key); + return util.str2bin(des(keys, util.bin2str(block), false, 0, null, padding)); + } +} + +module.exports = { + /** @static */ + des: Des, + /** @static */ + originalDes: OriginalDes +} + +},{"../../util":56}],9:[function(require,module,exports){ +/** + * @requires crypto/cipher/aes + * @requires crypto/cipher/blowfish + * @requires crypto/cipher/cast5 + * @requires crypto/cipher/twofish + * @module crypto/cipher + */ + +var desModule = require('./des.js'); + +module.exports = { + /** @see module:crypto/cipher/des.des */ + des: desModule['des'], + /** @see module:crypto/cipher/des.originalDes */ + originalDes: desModule['originalDes'], + /** @see module:crypto/cipher/cast5 */ + cast5: require('./cast5.js'), + /** @see module:crypto/cipher/twofish */ + twofish: require('./twofish.js'), + /** @see module:crypto/cipher/blowfish */ + blowfish: require('./blowfish.js') +} + +var aes = require('./aes.js'); + +for (var i in aes) { + module.exports['aes' + i] = aes[i]; +} + +},{"./aes.js":5,"./blowfish.js":6,"./cast5.js":7,"./des.js":8,"./twofish.js":10}],10:[function(require,module,exports){ +/* Modified by Recurity Labs GmbH + * + * Cipher.js + * A block-cipher algorithm implementation on JavaScript + * See Cipher.readme.txt for further information. + * + * Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ] + * This script file is distributed under the LGPL + * + * ACKNOWLEDGMENT + * + * The main subroutines are written by Michiel van Everdingen. + * + * Michiel van Everdingen + * http://home.versatel.nl/MAvanEverdingen/index.html + * + * All rights for these routines are reserved to Michiel van Everdingen. + * + */ + +/** + * @module crypto/cipher/twofish + */ + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Math +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +var MAXINT = 0xFFFFFFFF; + +function rotb(b, n) { + return (b << n | b >>> (8 - n)) & 0xFF; +} + +function rotw(w, n) { + return (w << n | w >>> (32 - n)) & MAXINT; +} + +function getW(a, i) { + return a[i] | a[i + 1] << 8 | a[i + 2] << 16 | a[i + 3] << 24; +} + +function setW(a, i, w) { + a.splice(i, 4, w & 0xFF, (w >>> 8) & 0xFF, (w >>> 16) & 0xFF, (w >>> 24) & 0xFF); +} + +function setWInv(a, i, w) { + a.splice(i, 4, (w >>> 24) & 0xFF, (w >>> 16) & 0xFF, (w >>> 8) & 0xFF, w & 0xFF); +} + +function getB(x, n) { + return (x >>> (n * 8)) & 0xFF; +} + +function getNrBits(i) { + var n = 0; + while (i > 0) { + n++; + i >>>= 1; + } + return n; +} + +function getMask(n) { + return (1 << n) - 1; +} + +//added 2008/11/13 XXX MUST USE ONE-WAY HASH FUNCTION FOR SECURITY REASON + +function randByte() { + return Math.floor(Math.random() * 256); +} +// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Twofish +// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +function createTwofish() { + // + var keyBytes = null; + var dataBytes = null; + var dataOffset = -1; + // var dataLength = -1; + var algorithmName = null; + // var idx2 = -1; + // + + algorithmName = "twofish"; + + var tfsKey = []; + var tfsM = [ + [], + [], + [], + [] + ]; + + function tfsInit(key) { + keyBytes = key; + var i, a, b, c, d, meKey = [], + moKey = [], + inKey = []; + var kLen; + var sKey = []; + var f01, f5b, fef; + + var q0 = [ + [8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4], + [2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5] + ]; + var q1 = [ + [14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13], + [1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8] + ]; + var q2 = [ + [11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1], + [4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15] + ]; + var q3 = [ + [13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10], + [11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10] + ]; + var ror4 = [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15]; + var ashx = [0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7]; + var q = [ + [], + [] + ]; + var m = [ + [], + [], + [], + [] + ]; + + function ffm5b(x) { + return x ^ (x >> 2) ^ [0, 90, 180, 238][x & 3]; + } + + function ffmEf(x) { + return x ^ (x >> 1) ^ (x >> 2) ^ [0, 238, 180, 90][x & 3]; + } + + function mdsRem(p, q) { + var i, t, u; + for (i = 0; i < 8; i++) { + t = q >>> 24; + q = ((q << 8) & MAXINT) | p >>> 24; + p = (p << 8) & MAXINT; + u = t << 1; + if (t & 128) { + u ^= 333; + } + q ^= t ^ (u << 16); + u ^= t >>> 1; + if (t & 1) { + u ^= 166; + } + q ^= u << 24 | u << 8; + } + return q; + } + + function qp(n, x) { + var a, b, c, d; + a = x >> 4; + b = x & 15; + c = q0[n][a ^ b]; + d = q1[n][ror4[b] ^ ashx[a]]; + return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d]; + } + + function hFun(x, key) { + var a = getB(x, 0), + b = getB(x, 1), + c = getB(x, 2), + d = getB(x, 3); + switch (kLen) { + case 4: + a = q[1][a] ^ getB(key[3], 0); + b = q[0][b] ^ getB(key[3], 1); + c = q[0][c] ^ getB(key[3], 2); + d = q[1][d] ^ getB(key[3], 3); + case 3: + a = q[1][a] ^ getB(key[2], 0); + b = q[1][b] ^ getB(key[2], 1); + c = q[0][c] ^ getB(key[2], 2); + d = q[0][d] ^ getB(key[2], 3); + case 2: + a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0); + b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1); + c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2); + d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3); + } + return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d]; + } + + keyBytes = keyBytes.slice(0, 32); + i = keyBytes.length; + while (i != 16 && i != 24 && i != 32) + keyBytes[i++] = 0; + + for (i = 0; i < keyBytes.length; i += 4) { + inKey[i >> 2] = getW(keyBytes, i); + } + for (i = 0; i < 256; i++) { + q[0][i] = qp(0, i); + q[1][i] = qp(1, i); + } + for (i = 0; i < 256; i++) { + f01 = q[1][i]; + f5b = ffm5b(f01); + fef = ffmEf(f01); + m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24); + m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24); + f01 = q[0][i]; + f5b = ffm5b(f01); + fef = ffmEf(f01); + m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24); + m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24); + } + + kLen = inKey.length / 2; + for (i = 0; i < kLen; i++) { + a = inKey[i + i]; + meKey[i] = a; + b = inKey[i + i + 1]; + moKey[i] = b; + sKey[kLen - i - 1] = mdsRem(a, b); + } + for (i = 0; i < 40; i += 2) { + a = 0x1010101 * i; + b = a + 0x1010101; + a = hFun(a, meKey); + b = rotw(hFun(b, moKey), 8); + tfsKey[i] = (a + b) & MAXINT; + tfsKey[i + 1] = rotw(a + 2 * b, 9); + } + for (i = 0; i < 256; i++) { + a = b = c = d = i; + switch (kLen) { + case 4: + a = q[1][a] ^ getB(sKey[3], 0); + b = q[0][b] ^ getB(sKey[3], 1); + c = q[0][c] ^ getB(sKey[3], 2); + d = q[1][d] ^ getB(sKey[3], 3); + case 3: + a = q[1][a] ^ getB(sKey[2], 0); + b = q[1][b] ^ getB(sKey[2], 1); + c = q[0][c] ^ getB(sKey[2], 2); + d = q[0][d] ^ getB(sKey[2], 3); + case 2: + tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)] ^ getB(sKey[0], 0)]; + tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)] ^ getB(sKey[0], 1)]; + tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)] ^ getB(sKey[0], 2)]; + tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)] ^ getB(sKey[0], 3)]; + } + } + } + + function tfsG0(x) { + return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)] ^ tfsM[3][getB(x, 3)]; + } + + function tfsG1(x) { + return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)] ^ tfsM[3][getB(x, 2)]; + } + + function tfsFrnd(r, blk) { + var a = tfsG0(blk[0]); + var b = tfsG1(blk[1]); + blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31); + blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT; + a = tfsG0(blk[2]); + b = tfsG1(blk[3]); + blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31); + blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT; + } + + function tfsIrnd(i, blk) { + var a = tfsG0(blk[0]); + var b = tfsG1(blk[1]); + blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT; + blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31); + a = tfsG0(blk[2]); + b = tfsG1(blk[3]); + blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT; + blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31); + } + + function tfsClose() { + tfsKey = []; + tfsM = [ + [], + [], + [], + [] + ]; + } + + function tfsEncrypt(data, offset) { + dataBytes = data; + dataOffset = offset; + var blk = [getW(dataBytes, dataOffset) ^ tfsKey[0], + getW(dataBytes, dataOffset + 4) ^ tfsKey[1], + getW(dataBytes, dataOffset + 8) ^ tfsKey[2], + getW(dataBytes, dataOffset + 12) ^ tfsKey[3] + ]; + for (var j = 0; j < 8; j++) { + tfsFrnd(j, blk); + } + setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]); + setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]); + setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]); + setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]); + dataOffset += 16; + return dataBytes; + } + + function tfsDecrypt(data, offset) { + dataBytes = data; + dataOffset = offset; + var blk = [getW(dataBytes, dataOffset) ^ tfsKey[4], + getW(dataBytes, dataOffset + 4) ^ tfsKey[5], + getW(dataBytes, dataOffset + 8) ^ tfsKey[6], + getW(dataBytes, dataOffset + 12) ^ tfsKey[7] + ]; + for (var j = 7; j >= 0; j--) { + tfsIrnd(j, blk); + } + setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]); + setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]); + setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]); + setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]); + dataOffset += 16; + } + + // added by Recurity Labs + + function tfsFinal() { + return dataBytes; + } + + return { + name: "twofish", + blocksize: 128 / 8, + open: tfsInit, + close: tfsClose, + encrypt: tfsEncrypt, + decrypt: tfsDecrypt, + // added by Recurity Labs + finalize: tfsFinal + }; +} + +var util = require('../../util'); + +// added by Recurity Labs + +function TFencrypt(block, key) { + var block_copy = [].concat(block); + var tf = createTwofish(); + tf.open(util.str2bin(key), 0); + var result = tf.encrypt(block_copy, 0); + tf.close(); + return result; +} + +function TF(key) { + this.tf = createTwofish(); + this.tf.open(util.str2bin(key), 0); + + this.encrypt = function(block) { + return this.tf.encrypt([].concat(block), 0); + } +} + + +module.exports = TF; +module.exports.keySize = TF.prototype.keySize = 32; +module.exports.blockSize = TF.prototype.blockSize = 16; + +},{"../../util":56}],11:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +// The GPG4Browsers crypto interface + +/** + * @requires crypto/cipher + * @requires crypto/public_key + * @requires crypto/random + * @requires type/mpi + * @module crypto/crypto + */ + +var random = require('./random.js'), + cipher = require('./cipher'), + publicKey = require('./public_key'), + type_mpi = require('../type/mpi.js'); + +module.exports = { + /** + * Encrypts data using the specified public key multiprecision integers + * and the specified algorithm. + * @param {Integer} algo Algorithm to be used (See RFC4880 9.1) + * @param {Array} publicMPIs Algorithm dependent multiprecision integers + * @param {module:type/mpi} data Data to be encrypted as MPI + * @return {Array} if RSA an module:type/mpi; + * if elgamal encryption an array of two module:type/mpi is returned; otherwise null + */ + publicKeyEncrypt: function(algo, publicMPIs, data) { + var result = (function() { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + var rsa = new publicKey.rsa(); + var n = publicMPIs[0].toBigInteger(); + var e = publicMPIs[1].toBigInteger(); + var m = data.toBigInteger(); + return [rsa.encrypt(m, e, n)]; + + case 'elgamal': + var elgamal = new publicKey.elgamal(); + var p = publicMPIs[0].toBigInteger(); + var g = publicMPIs[1].toBigInteger(); + var y = publicMPIs[2].toBigInteger(); + var m = data.toBigInteger(); + return elgamal.encrypt(m, g, p, y); + + default: + return []; + } + })(); + + return result.map(function(bn) { + var mpi = new type_mpi(); + mpi.fromBigInteger(bn); + return mpi; + }); + }, + + /** + * Decrypts data using the specified public key multiprecision integers of the private key, + * the specified secretMPIs of the private key and the specified algorithm. + * @param {Integer} algo Algorithm to be used (See RFC4880 9.1) + * @param {Array} publicMPIs Algorithm dependent multiprecision integers + * of the public key part of the private key + * @param {Array} secretMPIs Algorithm dependent multiprecision integers + * of the private key used + * @param {module:type/mpi} data Data to be encrypted as MPI + * @return {module:type/mpi} returns a big integer containing the decrypted data; otherwise null + */ + + publicKeyDecrypt: function(algo, keyIntegers, dataIntegers) { + var bn = (function() { + switch (algo) { + case 'rsa_encrypt_sign': + case 'rsa_encrypt': + var rsa = new publicKey.rsa(); + // 0 and 1 are the public key. + var d = keyIntegers[2].toBigInteger(); + var p = keyIntegers[3].toBigInteger(); + var q = keyIntegers[4].toBigInteger(); + var u = keyIntegers[5].toBigInteger(); + var m = dataIntegers[0].toBigInteger(); + return rsa.decrypt(m, d, p, q, u); + case 'elgamal': + var elgamal = new publicKey.elgamal(); + var x = keyIntegers[3].toBigInteger(); + var c1 = dataIntegers[0].toBigInteger(); + var c2 = dataIntegers[1].toBigInteger(); + var p = keyIntegers[0].toBigInteger(); + return elgamal.decrypt(c1, c2, p, x); + default: + return null; + } + })(); + + var result = new type_mpi(); + result.fromBigInteger(bn); + return result; + }, + + /** Returns the number of integers comprising the private key of an algorithm + * @param {String} algo The public key algorithm + * @return {Integer} The number of integers. + */ + getPrivateMpiCount: function(algo) { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + case 'rsa_sign': + // Algorithm-Specific Fields for RSA secret keys: + // - multiprecision integer (MPI) of RSA secret exponent d. + // - MPI of RSA secret prime value p. + // - MPI of RSA secret prime value q (p < q). + // - MPI of u, the multiplicative inverse of p, mod q. + return 4; + case 'elgamal': + // Algorithm-Specific Fields for Elgamal secret keys: + // - MPI of Elgamal secret exponent x. + return 1; + case 'dsa': + // Algorithm-Specific Fields for DSA secret keys: + // - MPI of DSA secret exponent x. + return 1; + default: + throw new Error('Unknown algorithm'); + } + }, + + getPublicMpiCount: function(algo) { + // - A series of multiprecision integers comprising the key material: + // Algorithm-Specific Fields for RSA public keys: + // - a multiprecision integer (MPI) of RSA public modulus n; + // - an MPI of RSA public encryption exponent e. + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + case 'rsa_sign': + return 2; + + // Algorithm-Specific Fields for Elgamal public keys: + // - MPI of Elgamal prime p; + // - MPI of Elgamal group generator g; + // - MPI of Elgamal public key value y (= g**x mod p where x is secret). + case 'elgamal': + return 3; + + // Algorithm-Specific Fields for DSA public keys: + // - MPI of DSA prime p; + // - MPI of DSA group order q (q is a prime divisor of p-1); + // - MPI of DSA group generator g; + // - MPI of DSA public-key value y (= g**x mod p where x is secret). + case 'dsa': + return 4; + + default: + throw new Error('Unknown algorithm.'); + } + }, + + generateMpi: function(algo, bits) { + var result = (function() { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + case 'rsa_sign': + //remember "publicKey" refers to the crypto/public_key dir + var rsa = new publicKey.rsa(); + var keyObject = rsa.generate(bits, "10001"); + var output = []; + output.push(keyObject.n); + output.push(keyObject.ee); + output.push(keyObject.d); + output.push(keyObject.p); + output.push(keyObject.q); + output.push(keyObject.u); + return output; + default: + throw new Error('Unsupported algorithm for key generation.'); + } + })(); + + return result.map(function(bn) { + var mpi = new type_mpi(); + mpi.fromBigInteger(bn); + return mpi; + }); + }, + + + /** + * generate random byte prefix as string for the specified algorithm + * @param {Integer} algo Algorithm to use (see RFC4880 9.2) + * @return {String} Random bytes with length equal to the block + * size of the cipher + */ + getPrefixRandom: function(algo) { + return random.getRandomBytes(cipher[algo].blockSize); + }, + + /** + * Generating a session key for the specified symmetric algorithm + * @param {Integer} algo Algorithm to use (see RFC4880 9.2) + * @return {String} Random bytes as a string to be used as a key + */ + generateSessionKey: function(algo) { + return random.getRandomBytes(cipher[algo].keySize); + } +}; + +},{"../type/mpi.js":54,"./cipher":9,"./public_key":20,"./random.js":23}],12:[function(require,module,exports){ +/** + * @requires crypto/hash/sha + * @module crypto/hash + */ +var sha = require('./sha.js'); + +module.exports = { + /** @see module:crypto/hash/md5 */ + md5: require('./md5.js'), + /** @see module:crypto/hash/sha.sha1 */ + sha1: sha.sha1, + /** @see module:crypto/hash/sha.sha224 */ + sha224: sha.sha224, + /** @see module:crypto/hash/sha.sha256 */ + sha256: sha.sha256, + /** @see module:crypto/hash/sha.sha384 */ + sha384: sha.sha384, + /** @see module:crypto/hash/sha.sha512 */ + sha512: sha.sha512, + /** @see module:crypto/hash/ripe-md */ + ripemd: require('./ripe-md.js'), + + /** + * Create a hash on the specified data using the specified algorithm + * @param {Integer} algo Hash algorithm type (see RFC4880 9.4) + * @param {String} data Data to be hashed + * @return {String} hash value + */ + digest: function(algo, data) { + switch (algo) { + case 1: + // - MD5 [HAC] + return this.md5(data); + case 2: + // - SHA-1 [FIPS180] + return this.sha1(data); + case 3: + // - RIPE-MD/160 [HAC] + return this.ripemd(data); + case 8: + // - SHA256 [FIPS180] + return this.sha256(data); + case 9: + // - SHA384 [FIPS180] + return this.sha384(data); + case 10: + // - SHA512 [FIPS180] + return this.sha512(data); + case 11: + // - SHA224 [FIPS180] + return this.sha224(data); + default: + throw new Error('Invalid hash function.'); + } + }, + + /** + * Returns the hash size in bytes of the specified hash algorithm type + * @param {Integer} algo Hash algorithm type (See RFC4880 9.4) + * @return {Integer} Size in bytes of the resulting hash + */ + getHashByteLength: function(algo) { + switch (algo) { + case 1: + // - MD5 [HAC] + return 16; + case 2: + // - SHA-1 [FIPS180] + case 3: + // - RIPE-MD/160 [HAC] + return 20; + case 8: + // - SHA256 [FIPS180] + return 32; + case 9: + // - SHA384 [FIPS180] + return 48 + case 10: + // - SHA512 [FIPS180] + return 64; + case 11: + // - SHA224 [FIPS180] + return 28; + default: + throw new Error('Invalid hash algorithm.'); + } + } +} + +},{"./md5.js":13,"./ripe-md.js":14,"./sha.js":15}],13:[function(require,module,exports){ +/** + * A fast MD5 JavaScript implementation + * Copyright (c) 2012 Joseph Myers + * http://www.myersdaily.org/joseph/javascript/md5-text.html + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for any purposes and without + * fee is hereby granted provided that this copyright notice + * appears in all copies. + * + * Of course, this soft is provided "as is" without express or implied + * warranty of any kind. + */ + +/** + * @requires util + * @module crypto/hash/md5 + */ + +var util = require('../../util'); + +/** + * MD5 hash + * @param {String} entree string to hash + */ +module.exports = function (entree) { + var hex = md5(entree); + var bin = util.hex2bin(hex); + return bin; +} + +function md5cycle(x, k) { + var a = x[0], + b = x[1], + c = x[2], + d = x[3]; + + a = ff(a, b, c, d, k[0], 7, -680876936); + d = ff(d, a, b, c, k[1], 12, -389564586); + c = ff(c, d, a, b, k[2], 17, 606105819); + b = ff(b, c, d, a, k[3], 22, -1044525330); + a = ff(a, b, c, d, k[4], 7, -176418897); + d = ff(d, a, b, c, k[5], 12, 1200080426); + c = ff(c, d, a, b, k[6], 17, -1473231341); + b = ff(b, c, d, a, k[7], 22, -45705983); + a = ff(a, b, c, d, k[8], 7, 1770035416); + d = ff(d, a, b, c, k[9], 12, -1958414417); + c = ff(c, d, a, b, k[10], 17, -42063); + b = ff(b, c, d, a, k[11], 22, -1990404162); + a = ff(a, b, c, d, k[12], 7, 1804603682); + d = ff(d, a, b, c, k[13], 12, -40341101); + c = ff(c, d, a, b, k[14], 17, -1502002290); + b = ff(b, c, d, a, k[15], 22, 1236535329); + + a = gg(a, b, c, d, k[1], 5, -165796510); + d = gg(d, a, b, c, k[6], 9, -1069501632); + c = gg(c, d, a, b, k[11], 14, 643717713); + b = gg(b, c, d, a, k[0], 20, -373897302); + a = gg(a, b, c, d, k[5], 5, -701558691); + d = gg(d, a, b, c, k[10], 9, 38016083); + c = gg(c, d, a, b, k[15], 14, -660478335); + b = gg(b, c, d, a, k[4], 20, -405537848); + a = gg(a, b, c, d, k[9], 5, 568446438); + d = gg(d, a, b, c, k[14], 9, -1019803690); + c = gg(c, d, a, b, k[3], 14, -187363961); + b = gg(b, c, d, a, k[8], 20, 1163531501); + a = gg(a, b, c, d, k[13], 5, -1444681467); + d = gg(d, a, b, c, k[2], 9, -51403784); + c = gg(c, d, a, b, k[7], 14, 1735328473); + b = gg(b, c, d, a, k[12], 20, -1926607734); + + a = hh(a, b, c, d, k[5], 4, -378558); + d = hh(d, a, b, c, k[8], 11, -2022574463); + c = hh(c, d, a, b, k[11], 16, 1839030562); + b = hh(b, c, d, a, k[14], 23, -35309556); + a = hh(a, b, c, d, k[1], 4, -1530992060); + d = hh(d, a, b, c, k[4], 11, 1272893353); + c = hh(c, d, a, b, k[7], 16, -155497632); + b = hh(b, c, d, a, k[10], 23, -1094730640); + a = hh(a, b, c, d, k[13], 4, 681279174); + d = hh(d, a, b, c, k[0], 11, -358537222); + c = hh(c, d, a, b, k[3], 16, -722521979); + b = hh(b, c, d, a, k[6], 23, 76029189); + a = hh(a, b, c, d, k[9], 4, -640364487); + d = hh(d, a, b, c, k[12], 11, -421815835); + c = hh(c, d, a, b, k[15], 16, 530742520); + b = hh(b, c, d, a, k[2], 23, -995338651); + + a = ii(a, b, c, d, k[0], 6, -198630844); + d = ii(d, a, b, c, k[7], 10, 1126891415); + c = ii(c, d, a, b, k[14], 15, -1416354905); + b = ii(b, c, d, a, k[5], 21, -57434055); + a = ii(a, b, c, d, k[12], 6, 1700485571); + d = ii(d, a, b, c, k[3], 10, -1894986606); + c = ii(c, d, a, b, k[10], 15, -1051523); + b = ii(b, c, d, a, k[1], 21, -2054922799); + a = ii(a, b, c, d, k[8], 6, 1873313359); + d = ii(d, a, b, c, k[15], 10, -30611744); + c = ii(c, d, a, b, k[6], 15, -1560198380); + b = ii(b, c, d, a, k[13], 21, 1309151649); + a = ii(a, b, c, d, k[4], 6, -145523070); + d = ii(d, a, b, c, k[11], 10, -1120210379); + c = ii(c, d, a, b, k[2], 15, 718787259); + b = ii(b, c, d, a, k[9], 21, -343485551); + + x[0] = add32(a, x[0]); + x[1] = add32(b, x[1]); + x[2] = add32(c, x[2]); + x[3] = add32(d, x[3]); + +} + +function cmn(q, a, b, x, s, t) { + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); +} + +function ff(a, b, c, d, x, s, t) { + return cmn((b & c) | ((~b) & d), a, b, x, s, t); +} + +function gg(a, b, c, d, x, s, t) { + return cmn((b & d) | (c & (~d)), a, b, x, s, t); +} + +function hh(a, b, c, d, x, s, t) { + return cmn(b ^ c ^ d, a, b, x, s, t); +} + +function ii(a, b, c, d, x, s, t) { + return cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +function md51(s) { + txt = ''; + var n = s.length, + state = [1732584193, -271733879, -1732584194, 271733878], + i; + for (i = 64; i <= s.length; i += 64) { + md5cycle(state, md5blk(s.substring(i - 64, i))); + } + s = s.substring(i - 64); + var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < s.length; i++) + tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3); + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i++) tail[i] = 0; + } + tail[14] = n * 8; + md5cycle(state, tail); + return state; +} + +/* there needs to be support for Unicode here, + * unless we pretend that we can redefine the MD-5 + * algorithm for multi-byte characters (perhaps + * by adding every four 16-bit characters and + * shortening the sum to 32 bits). Otherwise + * I suggest performing MD-5 as if every character + * was two bytes--e.g., 0040 0025 = @%--but then + * how will an ordinary MD-5 sum be matched? + * There is no way to standardize text to something + * like UTF-8 before transformation; speed cost is + * utterly prohibitive. The JavaScript standard + * itself needs to look at this: it should start + * providing access to strings as preformed UTF-8 + * 8-bit unsigned value arrays. + */ +function md5blk(s) { /* I figured global was faster. */ + var md5blks = [], + i; /* Andy King said do it this way. */ + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << + 24); + } + return md5blks; +} + +var hex_chr = '0123456789abcdef'.split(''); + +function rhex(n) { + var s = '', + j = 0; + for (; j < 4; j++) + s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F]; + return s; +} + +function hex(x) { + for (var i = 0; i < x.length; i++) + x[i] = rhex(x[i]); + return x.join(''); +} + +function md5(s) { + return hex(md51(s)); +} + +/* this function is much faster, +so if possible we use it. Some IEs +are the only ones I know of that +need the idiotic second function, +generated by an if clause. */ + +function add32(a, b) { + return (a + b) & 0xFFFFFFFF; +} + +if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') { + function add32(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } +} + +},{"../../util":56}],14:[function(require,module,exports){ +/* + * CryptoMX Tools + * Copyright (C) 2004 - 2006 Derek Buitenhuis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified by Recurity Labs GmbH + */ + +/** + * @module crypto/hash/ripe-md + */ + +var RMDsize = 160; +var X = new Array(); + +function ROL(x, n) { + return new Number((x << n) | (x >>> (32 - n))); +} + +function F(x, y, z) { + return new Number(x ^ y ^ z); +} + +function G(x, y, z) { + return new Number((x & y) | (~x & z)); +} + +function H(x, y, z) { + return new Number((x | ~y) ^ z); +} + +function I(x, y, z) { + return new Number((x & z) | (y & ~z)); +} + +function J(x, y, z) { + return new Number(x ^ (y | ~z)); +} + +function mixOneRound(a, b, c, d, e, x, s, roundNumber) { + switch (roundNumber) { + case 0: + a += F(b, c, d) + x + 0x00000000; + break; + case 1: + a += G(b, c, d) + x + 0x5a827999; + break; + case 2: + a += H(b, c, d) + x + 0x6ed9eba1; + break; + case 3: + a += I(b, c, d) + x + 0x8f1bbcdc; + break; + case 4: + a += J(b, c, d) + x + 0xa953fd4e; + break; + case 5: + a += J(b, c, d) + x + 0x50a28be6; + break; + case 6: + a += I(b, c, d) + x + 0x5c4dd124; + break; + case 7: + a += H(b, c, d) + x + 0x6d703ef3; + break; + case 8: + a += G(b, c, d) + x + 0x7a6d76e9; + break; + case 9: + a += F(b, c, d) + x + 0x00000000; + break; + + default: + document.write("Bogus round number"); + break; + } + + a = ROL(a, s) + e; + c = ROL(c, 10); + + a &= 0xffffffff; + b &= 0xffffffff; + c &= 0xffffffff; + d &= 0xffffffff; + e &= 0xffffffff; + + var retBlock = new Array(); + retBlock[0] = a; + retBlock[1] = b; + retBlock[2] = c; + retBlock[3] = d; + retBlock[4] = e; + retBlock[5] = x; + retBlock[6] = s; + + return retBlock; +} + +function MDinit(MDbuf) { + MDbuf[0] = 0x67452301; + MDbuf[1] = 0xefcdab89; + MDbuf[2] = 0x98badcfe; + MDbuf[3] = 0x10325476; + MDbuf[4] = 0xc3d2e1f0; +} + +var ROLs = [ + [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8], + [7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12], + [11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5], + [11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12], + [9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6], + [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6], + [9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11], + [9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5], + [15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8], + [8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11] +]; + +var indexes = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8], + [3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12], + [1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2], + [4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], + [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12], + [6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2], + [15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13], + [8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14], + [12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11] +]; + +function compress(MDbuf, X) { + blockA = new Array(); + blockB = new Array(); + + var retBlock; + + for (var i = 0; i < 5; i++) { + blockA[i] = new Number(MDbuf[i]); + blockB[i] = new Number(MDbuf[i]); + } + + var step = 0; + for (var j = 0; j < 5; j++) { + for (var i = 0; i < 16; i++) { + retBlock = mixOneRound( + blockA[(step + 0) % 5], + blockA[(step + 1) % 5], + blockA[(step + 2) % 5], + blockA[(step + 3) % 5], + blockA[(step + 4) % 5], + X[indexes[j][i]], + ROLs[j][i], + j); + + blockA[(step + 0) % 5] = retBlock[0]; + blockA[(step + 1) % 5] = retBlock[1]; + blockA[(step + 2) % 5] = retBlock[2]; + blockA[(step + 3) % 5] = retBlock[3]; + blockA[(step + 4) % 5] = retBlock[4]; + + step += 4; + } + } + + step = 0; + for (var j = 5; j < 10; j++) { + for (var i = 0; i < 16; i++) { + retBlock = mixOneRound( + blockB[(step + 0) % 5], + blockB[(step + 1) % 5], + blockB[(step + 2) % 5], + blockB[(step + 3) % 5], + blockB[(step + 4) % 5], + X[indexes[j][i]], + ROLs[j][i], + j); + + blockB[(step + 0) % 5] = retBlock[0]; + blockB[(step + 1) % 5] = retBlock[1]; + blockB[(step + 2) % 5] = retBlock[2]; + blockB[(step + 3) % 5] = retBlock[3]; + blockB[(step + 4) % 5] = retBlock[4]; + + step += 4; + } + } + + blockB[3] += blockA[2] + MDbuf[1]; + MDbuf[1] = MDbuf[2] + blockA[3] + blockB[4]; + MDbuf[2] = MDbuf[3] + blockA[4] + blockB[0]; + MDbuf[3] = MDbuf[4] + blockA[0] + blockB[1]; + MDbuf[4] = MDbuf[0] + blockA[1] + blockB[2]; + MDbuf[0] = blockB[3]; +} + +function zeroX(X) { + for (var i = 0; i < 16; i++) { + X[i] = 0; + } +} + +function MDfinish(MDbuf, strptr, lswlen, mswlen) { + var X = new Array(16); + zeroX(X); + + var j = 0; + for (var i = 0; i < (lswlen & 63); i++) { + X[i >>> 2] ^= (strptr.charCodeAt(j++) & 255) << (8 * (i & 3)); + } + + X[(lswlen >>> 2) & 15] ^= 1 << (8 * (lswlen & 3) + 7); + + if ((lswlen & 63) > 55) { + compress(MDbuf, X); + var X = new Array(16); + zeroX(X); + } + + X[14] = lswlen << 3; + X[15] = (lswlen >>> 29) | (mswlen << 3); + + compress(MDbuf, X); +} + +function BYTES_TO_DWORD(fourChars) { + var tmp = (fourChars.charCodeAt(3) & 255) << 24; + tmp |= (fourChars.charCodeAt(2) & 255) << 16; + tmp |= (fourChars.charCodeAt(1) & 255) << 8; + tmp |= (fourChars.charCodeAt(0) & 255); + + return tmp; +} + +function RMD(message) { + var MDbuf = new Array(RMDsize / 32); + var hashcode = new Array(RMDsize / 8); + var length; + var nbytes; + + MDinit(MDbuf); + length = message.length; + + var X = new Array(16); + zeroX(X); + + var j = 0; + for (var nbytes = length; nbytes > 63; nbytes -= 64) { + for (var i = 0; i < 16; i++) { + X[i] = BYTES_TO_DWORD(message.substr(j, 4)); + j += 4; + } + compress(MDbuf, X); + } + + MDfinish(MDbuf, message.substr(j), length, 0); + + for (var i = 0; i < RMDsize / 8; i += 4) { + hashcode[i] = MDbuf[i >>> 2] & 255; + hashcode[i + 1] = (MDbuf[i >>> 2] >>> 8) & 255; + hashcode[i + 2] = (MDbuf[i >>> 2] >>> 16) & 255; + hashcode[i + 3] = (MDbuf[i >>> 2] >>> 24) & 255; + } + + return hashcode; +} + + +function RMDstring(message) { + var hashcode = RMD(message); + var retString = ""; + + for (var i = 0; i < RMDsize / 8; i++) { + retString += String.fromCharCode(hashcode[i]); + } + + return retString; +} + +module.exports = RMDstring; + +},{}],15:[function(require,module,exports){ +/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS + * PUB 180-2 as well as the corresponding HMAC implementation as defined in + * FIPS PUB 198a + * + * Version 1.3 Copyright Brian Turek 2008-2010 + * Distributed under the BSD License + * See http://jssha.sourceforge.net/ for more information + * + * Several functions taken from Paul Johnson + */ + +/* Modified by Recurity Labs GmbH + * + * This code has been slightly modified direct string output: + * - bin2bstr has been added + * - following wrappers of this library have been added: + * - str_sha1 + * - str_sha256 + * - str_sha224 + * - str_sha384 + * - str_sha512 + */ + +/** + * @module crypto/hash/sha + */ + +var jsSHA = (function() { + + /* + * Configurable variables. Defaults typically work + */ + /* Number of Bits Per character (8 for ASCII, 16 for Unicode) */ + var charSize = 8, + /* base-64 pad character. "=" for strict RFC compliance */ + b64pad = "", + /* hex output format. 0 - lowercase; 1 - uppercase */ + hexCase = 0, + + /* + * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number + * + * @constructor + * @param {Number} msint_32 The most significant 32-bits of a 64-bit number + * @param {Number} lsint_32 The least significant 32-bits of a 64-bit number + */ + Int_64 = function(msint_32, lsint_32) { + this.highOrder = msint_32; + this.lowOrder = lsint_32; + }, + + /* + * Convert a string to an array of big-endian words + * If charSize is ASCII, characters >255 have their hi-byte silently + * ignored. + * + * @param {String} str String to be converted to binary representation + * @return Integer array representation of the parameter + */ + str2binb = function(str) { + var bin = [], + mask = (1 << charSize) - 1, + length = str.length * charSize, + i; + + for (i = 0; i < length; i += charSize) { + bin[i >> 5] |= (str.charCodeAt(i / charSize) & mask) << + (32 - charSize - (i % 32)); + } + + return bin; + }, + + /* + * Convert a hex string to an array of big-endian words + * + * @param {String} str String to be converted to binary representation + * @return Integer array representation of the parameter + */ + hex2binb = function(str) { + var bin = [], + length = str.length, + i, num; + + for (i = 0; i < length; i += 2) { + num = parseInt(str.substr(i, 2), 16); + if (!isNaN(num)) { + bin[i >> 3] |= num << (24 - (4 * (i % 8))); + } else { + return "INVALID HEX STRING"; + } + } + + return bin; + }, + + /* + * Convert an array of big-endian words to a hex string. + * + * @private + * @param {Array} binarray Array of integers to be converted to hexidecimal + * representation + * @return Hexidecimal representation of the parameter in String form + */ + binb2hex = function(binarray) { + var hex_tab = (hexCase) ? "0123456789ABCDEF" : "0123456789abcdef", + str = "", + length = binarray.length * 4, + i, srcByte; + + for (i = 0; i < length; i += 1) { + srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); + str += hex_tab.charAt((srcByte >> 4) & 0xF) + + hex_tab.charAt(srcByte & 0xF); + } + + return str; + }, + + /* + * Convert an array of big-endian words to a base-64 string + * + * @private + * @param {Array} binarray Array of integers to be converted to base-64 + * representation + * @return Base-64 encoded representation of the parameter in String form + */ + binb2b64 = function(binarray) { + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + + "0123456789+/", + str = "", + length = binarray.length * 4, + i, j, + triplet; + + for (i = 0; i < length; i += 3) { + triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | + (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | + ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); + for (j = 0; j < 4; j += 1) { + if (i * 8 + j * 6 <= binarray.length * 32) { + str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); + } else { + str += b64pad; + } + } + } + return str; + }, + + /* + * Convert an array of big-endian words to a string + */ + binb2str = function(bin) { + var str = ""; + var mask = (1 << 8) - 1; + for (var i = 0; i < bin.length * 32; i += 8) + str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask); + return str; + }, + /* + * The 32-bit implementation of circular rotate left + * + * @private + * @param {Number} x The 32-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted circularly by n bits + */ + rotl_32 = function(x, n) { + return (x << n) | (x >>> (32 - n)); + }, + + /* + * The 32-bit implementation of circular rotate right + * + * @private + * @param {Number} x The 32-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted circularly by n bits + */ + rotr_32 = function(x, n) { + return (x >>> n) | (x << (32 - n)); + }, + + /* + * The 64-bit implementation of circular rotate right + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted circularly by n bits + */ + rotr_64 = function(x, n) { + if (n <= 32) { + return new Int_64( + (x.highOrder >>> n) | (x.lowOrder << (32 - n)), (x.lowOrder >>> n) | (x.highOrder << (32 - n))); + } else { + return new Int_64( + (x.lowOrder >>> n) | (x.highOrder << (32 - n)), (x.highOrder >>> n) | (x.lowOrder << (32 - n))); + } + }, + + /* + * The 32-bit implementation of shift right + * + * @private + * @param {Number} x The 32-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted by n bits + */ + shr_32 = function(x, n) { + return x >>> n; + }, + + /* + * The 64-bit implementation of shift right + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted by n bits + */ + shr_64 = function(x, n) { + if (n <= 32) { + return new Int_64( + x.highOrder >>> n, + x.lowOrder >>> n | (x.highOrder << (32 - n))); + } else { + return new Int_64( + 0, + x.highOrder << (32 - n)); + } + }, + + /* + * The 32-bit implementation of the NIST specified Parity function + * + * @private + * @param {Number} x The first 32-bit integer argument + * @param {Number} y The second 32-bit integer argument + * @param {Number} z The third 32-bit integer argument + * @return The NIST specified output of the function + */ + parity_32 = function(x, y, z) { + return x ^ y ^ z; + }, + + /* + * The 32-bit implementation of the NIST specified Ch function + * + * @private + * @param {Number} x The first 32-bit integer argument + * @param {Number} y The second 32-bit integer argument + * @param {Number} z The third 32-bit integer argument + * @return The NIST specified output of the function + */ + ch_32 = function(x, y, z) { + return (x & y) ^ (~x & z); + }, + + /* + * The 64-bit implementation of the NIST specified Ch function + * + * @private + * @param {Int_64} x The first 64-bit integer argument + * @param {Int_64} y The second 64-bit integer argument + * @param {Int_64} z The third 64-bit integer argument + * @return The NIST specified output of the function + */ + ch_64 = function(x, y, z) { + return new Int_64( + (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder)); + }, + + /* + * The 32-bit implementation of the NIST specified Maj function + * + * @private + * @param {Number} x The first 32-bit integer argument + * @param {Number} y The second 32-bit integer argument + * @param {Number} z The third 32-bit integer argument + * @return The NIST specified output of the function + */ + maj_32 = function(x, y, z) { + return (x & y) ^ (x & z) ^ (y & z); + }, + + /* + * The 64-bit implementation of the NIST specified Maj function + * + * @private + * @param {Int_64} x The first 64-bit integer argument + * @param {Int_64} y The second 64-bit integer argument + * @param {Int_64} z The third 64-bit integer argument + * @return The NIST specified output of the function + */ + maj_64 = function(x, y, z) { + return new Int_64( + (x.highOrder & y.highOrder) ^ + (x.highOrder & z.highOrder) ^ + (y.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ + (x.lowOrder & z.lowOrder) ^ + (y.lowOrder & z.lowOrder)); + }, + + /* + * The 32-bit implementation of the NIST specified Sigma0 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + sigma0_32 = function(x) { + return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22); + }, + + /* + * The 64-bit implementation of the NIST specified Sigma0 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + sigma0_64 = function(x) { + var rotr28 = rotr_64(x, 28), + rotr34 = rotr_64(x, 34), + rotr39 = rotr_64(x, 39); + + return new Int_64( + rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, + rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder); + }, + + /* + * The 32-bit implementation of the NIST specified Sigma1 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + sigma1_32 = function(x) { + return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25); + }, + + /* + * The 64-bit implementation of the NIST specified Sigma1 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + sigma1_64 = function(x) { + var rotr14 = rotr_64(x, 14), + rotr18 = rotr_64(x, 18), + rotr41 = rotr_64(x, 41); + + return new Int_64( + rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, + rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder); + }, + + /* + * The 32-bit implementation of the NIST specified Gamma0 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + gamma0_32 = function(x) { + return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3); + }, + + /* + * The 64-bit implementation of the NIST specified Gamma0 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + gamma0_64 = function(x) { + var rotr1 = rotr_64(x, 1), + rotr8 = rotr_64(x, 8), + shr7 = shr_64(x, 7); + + return new Int_64( + rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, + rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder); + }, + + /* + * The 32-bit implementation of the NIST specified Gamma1 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + gamma1_32 = function(x) { + return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10); + }, + + /* + * The 64-bit implementation of the NIST specified Gamma1 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + gamma1_64 = function(x) { + var rotr19 = rotr_64(x, 19), + rotr61 = rotr_64(x, 61), + shr6 = shr_64(x, 6); + + return new Int_64( + rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, + rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder); + }, + + /* + * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Number} x The first 32-bit integer argument to be added + * @param {Number} y The second 32-bit integer argument to be added + * @return The sum of x + y + */ + safeAdd_32_2 = function(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + }, + + /* + * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Number} a The first 32-bit integer argument to be added + * @param {Number} b The second 32-bit integer argument to be added + * @param {Number} c The third 32-bit integer argument to be added + * @param {Number} d The fourth 32-bit integer argument to be added + * @return The sum of a + b + c + d + */ + safeAdd_32_4 = function(a, b, c, d) { + var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF), + msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + }, + + /* + * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Number} a The first 32-bit integer argument to be added + * @param {Number} b The second 32-bit integer argument to be added + * @param {Number} c The third 32-bit integer argument to be added + * @param {Number} d The fourth 32-bit integer argument to be added + * @param {Number} e The fifth 32-bit integer argument to be added + * @return The sum of a + b + c + d + e + */ + safeAdd_32_5 = function(a, b, c, d, e) { + var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) + + (e & 0xFFFF), + msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + + (e >>> 16) + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + }, + + /* + * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} x The first 64-bit integer argument to be added + * @param {Int_64} y The second 64-bit integer argument to be added + * @return The sum of x + y + */ + safeAdd_64_2 = function(x, y) { + var lsw, msw, lowOrder, highOrder; + + lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF); + msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16); + msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + }, + + /* + * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} a The first 64-bit integer argument to be added + * @param {Int_64} b The second 64-bit integer argument to be added + * @param {Int_64} c The third 64-bit integer argument to be added + * @param {Int_64} d The fouth 64-bit integer argument to be added + * @return The sum of a + b + c + d + */ + safeAdd_64_4 = function(a, b, c, d) { + var lsw, msw, lowOrder, highOrder; + + lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF); + msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16); + msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + }, + + /* + * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} a The first 64-bit integer argument to be added + * @param {Int_64} b The second 64-bit integer argument to be added + * @param {Int_64} c The third 64-bit integer argument to be added + * @param {Int_64} d The fouth 64-bit integer argument to be added + * @param {Int_64} e The fouth 64-bit integer argument to be added + * @return The sum of a + b + c + d + e + */ + safeAdd_64_5 = function(a, b, c, d, e) { + var lsw, msw, lowOrder, highOrder; + + lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + + (e.lowOrder & 0xFFFF); + msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + + (e.highOrder & 0xFFFF) + (msw >>> 16); + msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + (d.highOrder >>> 16) + + (e.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + }, + + /* + * Calculates the SHA-1 hash of the string set at instantiation + * + * @private + * @param {Array} message The binary array representation of the string to + * hash + * @param {Number} messageLen The number of bits in the message + * @return The array of integers representing the SHA-1 hash of message + */ + coreSHA1 = function(message, messageLen) { + var W = [], + a, b, c, d, e, T, ch = ch_32, + parity = parity_32, + maj = maj_32, + rotl = rotl_32, + safeAdd_2 = safeAdd_32_2, + i, t, + safeAdd_5 = safeAdd_32_5, + appendedMessageLength, + H = [ + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 + ], + K = [ + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 + ]; + + /* Append '1' at the end of the binary string */ + message[messageLen >> 5] |= 0x80 << (24 - (messageLen % 32)); + /* Append length of binary string in the position such that the new + length is a multiple of 512. Logic does not work for even multiples + of 512 but there can never be even multiples of 512 */ + message[(((messageLen + 65) >> 9) << 4) + 15] = messageLen; + + appendedMessageLength = message.length; + + for (i = 0; i < appendedMessageLength; i += 16) { + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + + for (t = 0; t < 80; t += 1) { + if (t < 16) { + W[t] = message[t + i]; + } else { + W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + } + + if (t < 20) { + T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, K[t], W[t]); + } else if (t < 40) { + T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); + } else if (t < 60) { + T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, K[t], W[t]); + } else { + T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); + } + + e = d; + d = c; + c = rotl(b, 30); + b = a; + a = T; + } + + H[0] = safeAdd_2(a, H[0]); + H[1] = safeAdd_2(b, H[1]); + H[2] = safeAdd_2(c, H[2]); + H[3] = safeAdd_2(d, H[3]); + H[4] = safeAdd_2(e, H[4]); + } + + return H; + }, + + /* + * Calculates the desired SHA-2 hash of the string set at instantiation + * + * @private + * @param {Array} The binary array representation of the string to hash + * @param {Number} The number of bits in message + * @param {String} variant The desired SHA-2 variant + * @return The array of integers representing the SHA-2 hash of message + */ + coreSHA2 = function(message, messageLen, variant) { + var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t, + binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5, + gamma0, gamma1, sigma0, sigma1, ch, maj, Int, K, W = [], + appendedMessageLength; + + /* Set up the various function handles and variable for the specific + * variant */ + if (variant === "SHA-224" || variant === "SHA-256") { + /* 32-bit variant */ + numRounds = 64; + lengthPosition = (((messageLen + 65) >> 9) << 4) + 15; + binaryStringInc = 16; + binaryStringMult = 1; + Int = Number; + safeAdd_2 = safeAdd_32_2; + safeAdd_4 = safeAdd_32_4; + safeAdd_5 = safeAdd_32_5; + gamma0 = gamma0_32; + gamma1 = gamma1_32; + sigma0 = sigma0_32; + sigma1 = sigma1_32; + maj = maj_32; + ch = ch_32; + K = [ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 + ]; + + if (variant === "SHA-224") { + H = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]; + } else { + H = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 + ]; + } + } else if (variant === "SHA-384" || variant === "SHA-512") { + /* 64-bit variant */ + numRounds = 80; + lengthPosition = (((messageLen + 128) >> 10) << 5) + 31; + binaryStringInc = 32; + binaryStringMult = 2; + Int = Int_64; + safeAdd_2 = safeAdd_64_2; + safeAdd_4 = safeAdd_64_4; + safeAdd_5 = safeAdd_64_5; + gamma0 = gamma0_64; + gamma1 = gamma1_64; + sigma0 = sigma0_64; + sigma1 = sigma1_64; + maj = maj_64; + ch = ch_64; + + K = [ + new Int(0x428a2f98, 0xd728ae22), new Int(0x71374491, 0x23ef65cd), + new Int(0xb5c0fbcf, 0xec4d3b2f), new Int(0xe9b5dba5, 0x8189dbbc), + new Int(0x3956c25b, 0xf348b538), new Int(0x59f111f1, 0xb605d019), + new Int(0x923f82a4, 0xaf194f9b), new Int(0xab1c5ed5, 0xda6d8118), + new Int(0xd807aa98, 0xa3030242), new Int(0x12835b01, 0x45706fbe), + new Int(0x243185be, 0x4ee4b28c), new Int(0x550c7dc3, 0xd5ffb4e2), + new Int(0x72be5d74, 0xf27b896f), new Int(0x80deb1fe, 0x3b1696b1), + new Int(0x9bdc06a7, 0x25c71235), new Int(0xc19bf174, 0xcf692694), + new Int(0xe49b69c1, 0x9ef14ad2), new Int(0xefbe4786, 0x384f25e3), + new Int(0x0fc19dc6, 0x8b8cd5b5), new Int(0x240ca1cc, 0x77ac9c65), + new Int(0x2de92c6f, 0x592b0275), new Int(0x4a7484aa, 0x6ea6e483), + new Int(0x5cb0a9dc, 0xbd41fbd4), new Int(0x76f988da, 0x831153b5), + new Int(0x983e5152, 0xee66dfab), new Int(0xa831c66d, 0x2db43210), + new Int(0xb00327c8, 0x98fb213f), new Int(0xbf597fc7, 0xbeef0ee4), + new Int(0xc6e00bf3, 0x3da88fc2), new Int(0xd5a79147, 0x930aa725), + new Int(0x06ca6351, 0xe003826f), new Int(0x14292967, 0x0a0e6e70), + new Int(0x27b70a85, 0x46d22ffc), new Int(0x2e1b2138, 0x5c26c926), + new Int(0x4d2c6dfc, 0x5ac42aed), new Int(0x53380d13, 0x9d95b3df), + new Int(0x650a7354, 0x8baf63de), new Int(0x766a0abb, 0x3c77b2a8), + new Int(0x81c2c92e, 0x47edaee6), new Int(0x92722c85, 0x1482353b), + new Int(0xa2bfe8a1, 0x4cf10364), new Int(0xa81a664b, 0xbc423001), + new Int(0xc24b8b70, 0xd0f89791), new Int(0xc76c51a3, 0x0654be30), + new Int(0xd192e819, 0xd6ef5218), new Int(0xd6990624, 0x5565a910), + new Int(0xf40e3585, 0x5771202a), new Int(0x106aa070, 0x32bbd1b8), + new Int(0x19a4c116, 0xb8d2d0c8), new Int(0x1e376c08, 0x5141ab53), + new Int(0x2748774c, 0xdf8eeb99), new Int(0x34b0bcb5, 0xe19b48a8), + new Int(0x391c0cb3, 0xc5c95a63), new Int(0x4ed8aa4a, 0xe3418acb), + new Int(0x5b9cca4f, 0x7763e373), new Int(0x682e6ff3, 0xd6b2b8a3), + new Int(0x748f82ee, 0x5defb2fc), new Int(0x78a5636f, 0x43172f60), + new Int(0x84c87814, 0xa1f0ab72), new Int(0x8cc70208, 0x1a6439ec), + new Int(0x90befffa, 0x23631e28), new Int(0xa4506ceb, 0xde82bde9), + new Int(0xbef9a3f7, 0xb2c67915), new Int(0xc67178f2, 0xe372532b), + new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207), + new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178), + new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6), + new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b), + new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493), + new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c), + new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a), + new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817) + ]; + + if (variant === "SHA-384") { + H = [ + new Int(0xcbbb9d5d, 0xc1059ed8), new Int(0x0629a292a, 0x367cd507), + new Int(0x9159015a, 0x3070dd17), new Int(0x0152fecd8, 0xf70e5939), + new Int(0x67332667, 0xffc00b31), new Int(0x98eb44a87, 0x68581511), + new Int(0xdb0c2e0d, 0x64f98fa7), new Int(0x047b5481d, 0xbefa4fa4) + ]; + } else { + H = [ + new Int(0x6a09e667, 0xf3bcc908), new Int(0xbb67ae85, 0x84caa73b), + new Int(0x3c6ef372, 0xfe94f82b), new Int(0xa54ff53a, 0x5f1d36f1), + new Int(0x510e527f, 0xade682d1), new Int(0x9b05688c, 0x2b3e6c1f), + new Int(0x1f83d9ab, 0xfb41bd6b), new Int(0x5be0cd19, 0x137e2179) + ]; + } + } + + /* Append '1' at the end of the binary string */ + message[messageLen >> 5] |= 0x80 << (24 - messageLen % 32); + /* Append length of binary string in the position such that the new + * length is correct */ + message[lengthPosition] = messageLen; + + appendedMessageLength = message.length; + + for (i = 0; i < appendedMessageLength; i += binaryStringInc) { + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + + for (t = 0; t < numRounds; t += 1) { + if (t < 16) { + /* Bit of a hack - for 32-bit, the second term is ignored */ + W[t] = new Int(message[t * binaryStringMult + i], + message[t * binaryStringMult + i + 1]); + } else { + W[t] = safeAdd_4( + gamma1(W[t - 2]), W[t - 7], + gamma0(W[t - 15]), W[t - 16]); + } + + T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]); + T2 = safeAdd_2(sigma0(a), maj(a, b, c)); + h = g; + g = f; + f = e; + e = safeAdd_2(d, T1); + d = c; + c = b; + b = a; + a = safeAdd_2(T1, T2); + } + + H[0] = safeAdd_2(a, H[0]); + H[1] = safeAdd_2(b, H[1]); + H[2] = safeAdd_2(c, H[2]); + H[3] = safeAdd_2(d, H[3]); + H[4] = safeAdd_2(e, H[4]); + H[5] = safeAdd_2(f, H[5]); + H[6] = safeAdd_2(g, H[6]); + H[7] = safeAdd_2(h, H[7]); + } + + switch (variant) { + case "SHA-224": + return [ + H[0], H[1], H[2], H[3], + H[4], H[5], H[6]]; + case "SHA-256": + return H; + case "SHA-384": + return [ + H[0].highOrder, H[0].lowOrder, + H[1].highOrder, H[1].lowOrder, + H[2].highOrder, H[2].lowOrder, + H[3].highOrder, H[3].lowOrder, + H[4].highOrder, H[4].lowOrder, + H[5].highOrder, H[5].lowOrder]; + case "SHA-512": + return [ + H[0].highOrder, H[0].lowOrder, + H[1].highOrder, H[1].lowOrder, + H[2].highOrder, H[2].lowOrder, + H[3].highOrder, H[3].lowOrder, + H[4].highOrder, H[4].lowOrder, + H[5].highOrder, H[5].lowOrder, + H[6].highOrder, H[6].lowOrder, + H[7].highOrder, H[7].lowOrder]; + default: + /* This should never be reached */ + return []; + } + }, + + /* + * jsSHA is the workhorse of the library. Instantiate it with the string to + * be hashed as the parameter + * + * @constructor + * @param {String} srcString The string to be hashed + * @param {String} inputFormat The format of srcString, ASCII or HEX + */ + jsSHA = function(srcString, inputFormat) { + + this.sha1 = null; + this.sha224 = null; + this.sha256 = null; + this.sha384 = null; + this.sha512 = null; + + this.strBinLen = null; + this.strToHash = null; + + /* Convert the input string into the correct type */ + if ("HEX" === inputFormat) { + if (0 !== (srcString.length % 2)) { + return "TEXT MUST BE IN BYTE INCREMENTS"; + } + this.strBinLen = srcString.length * 4; + this.strToHash = hex2binb(srcString); + } else if (("ASCII" === inputFormat) || + ('undefined' === typeof(inputFormat))) { + this.strBinLen = srcString.length * charSize; + this.strToHash = str2binb(srcString); + } else { + return "UNKNOWN TEXT INPUT TYPE"; + } + }; + + jsSHA.prototype = { + /* + * Returns the desired SHA hash of the string specified at instantiation + * using the specified parameters + * + * @param {String} variant The desired SHA variant (SHA-1, SHA-224, + * SHA-256, SHA-384, or SHA-512) + * @param {String} format The desired output formatting (B64 or HEX) + * @return The string representation of the hash in the format specified + */ + getHash: function(variant, format) { + var formatFunc = null, + message = this.strToHash.slice(); + + switch (format) { + case "HEX": + formatFunc = binb2hex; + break; + case "B64": + formatFunc = binb2b64; + break; + case "ASCII": + formatFunc = binb2str; + break; + default: + return "FORMAT NOT RECOGNIZED"; + } + + switch (variant) { + case "SHA-1": + if (null === this.sha1) { + this.sha1 = coreSHA1(message, this.strBinLen); + } + return formatFunc(this.sha1); + case "SHA-224": + if (null === this.sha224) { + this.sha224 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha224); + case "SHA-256": + if (null === this.sha256) { + this.sha256 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha256); + case "SHA-384": + if (null === this.sha384) { + this.sha384 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha384); + case "SHA-512": + if (null === this.sha512) { + this.sha512 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha512); + default: + return "HASH NOT RECOGNIZED"; + } + }, + + /* + * Returns the desired HMAC of the string specified at instantiation + * using the key and variant param. + * + * @param {String} key The key used to calculate the HMAC + * @param {String} inputFormat The format of key, ASCII or HEX + * @param {String} variant The desired SHA variant (SHA-1, SHA-224, + * SHA-256, SHA-384, or SHA-512) + * @param {String} outputFormat The desired output formatting + * (B64 or HEX) + * @return The string representation of the hash in the format specified + */ + getHMAC: function(key, inputFormat, variant, outputFormat) { + var formatFunc, keyToUse, blockByteSize, blockBitSize, i, + retVal, lastArrayIndex, keyBinLen, hashBitSize, + keyWithIPad = [], + keyWithOPad = []; + + /* Validate the output format selection */ + switch (outputFormat) { + case "HEX": + formatFunc = binb2hex; + break; + case "B64": + formatFunc = binb2b64; + break; + case "ASCII": + formatFunc = binb2str; + break; + default: + return "FORMAT NOT RECOGNIZED"; + } + + /* Validate the hash variant selection and set needed variables */ + switch (variant) { + case "SHA-1": + blockByteSize = 64; + hashBitSize = 160; + break; + case "SHA-224": + blockByteSize = 64; + hashBitSize = 224; + break; + case "SHA-256": + blockByteSize = 64; + hashBitSize = 256; + break; + case "SHA-384": + blockByteSize = 128; + hashBitSize = 384; + break; + case "SHA-512": + blockByteSize = 128; + hashBitSize = 512; + break; + default: + return "HASH NOT RECOGNIZED"; + } + + /* Validate input format selection */ + if ("HEX" === inputFormat) { + /* Nibbles must come in pairs */ + if (0 !== (key.length % 2)) { + return "KEY MUST BE IN BYTE INCREMENTS"; + } + keyToUse = hex2binb(key); + keyBinLen = key.length * 4; + } else if ("ASCII" === inputFormat) { + keyToUse = str2binb(key); + keyBinLen = key.length * charSize; + } else { + return "UNKNOWN KEY INPUT TYPE"; + } + + /* These are used multiple times, calculate and store them */ + blockBitSize = blockByteSize * 8; + lastArrayIndex = (blockByteSize / 4) - 1; + + /* Figure out what to do with the key based on its size relative to + * the hash's block size */ + if (blockByteSize < (keyBinLen / 8)) { + if ("SHA-1" === variant) { + keyToUse = coreSHA1(keyToUse, keyBinLen); + } else { + keyToUse = coreSHA2(keyToUse, keyBinLen, variant); + } + /* For all variants, the block size is bigger than the output + * size so there will never be a useful byte at the end of the + * string */ + keyToUse[lastArrayIndex] &= 0xFFFFFF00; + } else if (blockByteSize > (keyBinLen / 8)) { + /* If the blockByteSize is greater than the key length, there + * will always be at LEAST one "useless" byte at the end of the + * string */ + keyToUse[lastArrayIndex] &= 0xFFFFFF00; + } + + /* Create ipad and opad */ + for (i = 0; i <= lastArrayIndex; i += 1) { + keyWithIPad[i] = keyToUse[i] ^ 0x36363636; + keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C; + } + + /* Calculate the HMAC */ + if ("SHA-1" === variant) { + retVal = coreSHA1( + keyWithIPad.concat(this.strToHash), + blockBitSize + this.strBinLen); + retVal = coreSHA1( + keyWithOPad.concat(retVal), + blockBitSize + hashBitSize); + } else { + retVal = coreSHA2( + keyWithIPad.concat(this.strToHash), + blockBitSize + this.strBinLen, variant); + retVal = coreSHA2( + keyWithOPad.concat(retVal), + blockBitSize + hashBitSize, variant); + } + + return (formatFunc(retVal)); + } + }; + + return jsSHA; +}()); + +module.exports = { + /** SHA1 hash */ + sha1: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-1", "ASCII"); + }, + /** SHA224 hash */ + sha224: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-224", "ASCII"); + }, + /** SHA256 hash */ + sha256: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-256", "ASCII"); + }, + /** SHA384 hash */ + sha384: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-384", "ASCII"); + + }, + /** SHA512 hash */ + sha512: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-512", "ASCII"); + } +} + +},{}],16:[function(require,module,exports){ +/** + * @see module:crypto/crypto + * @module crypto + */ +module.exports = { + /** @see module:crypto/cipher */ + cipher: require('./cipher'), + /** @see module:crypto/hash */ + hash: require('./hash'), + /** @see module:crypto/cfb */ + cfb: require('./cfb.js'), + /** @see module:crypto/public_key */ + publicKey: require('./public_key'), + /** @see module:crypto/signature */ + signature: require('./signature.js'), + /** @see module:crypto/random */ + random: require('./random.js'), + /** @see module:crypto/pkcs1 */ + pkcs1: require('./pkcs1.js') + +} + +var crypto = require('./crypto.js'); + +for (var i in crypto) + module.exports[i] = crypto[i]; + +},{"./cfb.js":4,"./cipher":9,"./crypto.js":11,"./hash":12,"./pkcs1.js":17,"./public_key":20,"./random.js":23,"./signature.js":24}],17:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * PKCS1 encoding + * @requires crypto/crypto + * @requires crypto/hash + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/pkcs1 + */ + +/** + * ASN1 object identifiers for hashes (See RFC4880 5.2.2) + */ +hash_headers = new Array(); +hash_headers[1] = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, + 0x10 +]; +hash_headers[2] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14]; +hash_headers[3] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14]; +hash_headers[8] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, + 0x04, 0x20 +]; +hash_headers[9] = [0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, + 0x04, 0x30 +]; +hash_headers[10] = [0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40 +]; +hash_headers[11] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, + 0x00, 0x04, 0x1C +]; + +var crypto = require('./crypto.js'), + random = require('./random.js'), + util = require('../util'), + BigInteger = require('./public_key/jsbn.js'), + hash = require('./hash'); + +module.exports = { + eme: { + /** + * create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1) + * @param {String} message message to be padded + * @param {Integer} length Length to the resulting message + * @return {String} EME-PKCS1 padded message + */ + encode: function(message, length) { + if (message.length > length - 11) + return -1; + var result = ""; + result += String.fromCharCode(0); + result += String.fromCharCode(2); + for (var i = 0; i < length - message.length - 3; i++) { + result += String.fromCharCode(random.getPseudoRandom(1, 255)); + } + result += String.fromCharCode(0); + result += message; + return result; + }, + + /** + * decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2) + * @param {String} message EME-PKCS1 padded message + * @return {String} decoded message + */ + decode: function(message, len) { + if (message.length < len) + message = String.fromCharCode(0) + message; + if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2) + return -1; + var i = 2; + while (message.charCodeAt(i) != 0 && message.length > i) + i++; + return message.substring(i + 1, message.length); + } + }, + + emsa: { + + /** + * create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3) + * @param {Integer} algo Hash algorithm type used + * @param {String} data Data to be hashed + * @param {Integer} keylength Key size of the public mpi in bytes + * @returns {String} Hashcode with pkcs1padding as string + */ + encode: function(algo, data, keylength) { + var data2 = ""; + data2 += String.fromCharCode(0x00); + data2 += String.fromCharCode(0x01); + for (var i = 0; i < (keylength - hash_headers[algo].length - 3 - + hash.getHashByteLength(algo)); i++) + + data2 += String.fromCharCode(0xff); + + data2 += String.fromCharCode(0x00); + + for (var i = 0; i < hash_headers[algo].length; i++) + data2 += String.fromCharCode(hash_headers[algo][i]); + + data2 += hash.digest(algo, data); + return new BigInteger(util.hexstrdump(data2), 16); + }, + + /** + * extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3) + * @param {String} data Hash in pkcs1 encoding + * @returns {String} The hash as string + */ + decode: function(algo, data) { + var i = 0; + if (data.charCodeAt(0) == 0) i++; + else if (data.charCodeAt(0) != 1) return -1; + else i++; + + while (data.charCodeAt(i) == 0xFF) i++; + if (data.charCodeAt(i++) != 0) return -1; + var j = 0; + for (j = 0; j < hash_headers[algo].length && j + i < data.length; j++) { + if (data.charCodeAt(j + i) != hash_headers[algo][j]) return -1; + } + i += j; + if (data.substring(i).length < hash.getHashByteLength(algo)) return -1; + return data.substring(i); + } + } +} + +},{"../util":56,"./crypto.js":11,"./hash":12,"./public_key/jsbn.js":21,"./random.js":23}],18:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -17,76 +6284,94 @@ // // A Digital signature algorithm implementation +/** + * @requires crypto/hash + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/public_key/dsa + */ + +var BigInteger = require('./jsbn.js'), + random = require('../random.js'), + hashModule = require('../hash'), + util = require('../../util'), + config = require('../../config'); + function DSA() { - // s1 = ((g**s) mod p) mod q - // s1 = ((s**-1)*(sha-1(m)+(s1*x) mod q) - function sign(hashalgo, m, g, p, q, x) { - // If the output size of the chosen hash is larger than the number of - // bits of q, the hash result is truncated to fit by taking the number - // of leftmost bits equal to the number of bits of q. This (possibly - // truncated) hash function result is treated as a number and used - // directly in the DSA signature algorithm. - var hashed_data = util.getLeftNBits(openpgp_crypto_hashData(hashalgo,m),q.bitLength()); - var hash = new BigInteger(util.hexstrdump(hashed_data), 16); - var k = openpgp_crypto_getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE)); - var s1 = (g.modPow(k,p)).mod(q); - var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q); - var result = new Array(); - result[0] = s1.toMPI(); - result[1] = s2.toMPI(); - return result; - } - function select_hash_algorithm(q) { - var usersetting = openpgp.config.config.prefer_hash_algorithm; - /* - * 1024-bit key, 160-bit q, SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512 hash - * 2048-bit key, 224-bit q, SHA-224, SHA-256, SHA-384, or SHA-512 hash - * 2048-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash - * 3072-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash - */ - switch (Math.round(q.bitLength() / 8)) { - case 20: // 1024 bit - if (usersetting != 2 && - usersetting > 11 && - usersetting != 10 && - usersetting < 8) - return 2; // prefer sha1 - return usersetting; - case 28: // 2048 bit - if (usersetting > 11 && - usersetting < 8) - return 11; - return usersetting; - case 32: // 4096 bit // prefer sha224 - if (usersetting > 10 && - usersetting < 8) - return 8; // prefer sha256 - return usersetting; - default: - util.print_debug("DSA select hash algorithm: returning null for an unknown length of q"); - return null; - - } - } - this.select_hash_algorithm = select_hash_algorithm; - - function verify(hashalgo, s1,s2,m,p,q,g,y) { - var hashed_data = util.getLeftNBits(openpgp_crypto_hashData(hashalgo,m),q.bitLength()); - var hash = new BigInteger(util.hexstrdump(hashed_data), 16); - if (BigInteger.ZERO.compareTo(s1) > 0 || - s1.compareTo(q) > 0 || - BigInteger.ZERO.compareTo(s2) > 0 || - s2.compareTo(q) > 0) { - util.print_error("invalid DSA Signature"); - return null; - } - var w = s2.modInverse(q); - var u1 = hash.multiply(w).mod(q); - var u2 = s1.multiply(w).mod(q); - return g.modPow(u1,p).multiply(y.modPow(u2,p)).mod(p).mod(q); - } - - /* + // s1 = ((g**s) mod p) mod q + // s1 = ((s**-1)*(sha-1(m)+(s1*x) mod q) + function sign(hashalgo, m, g, p, q, x) { + // If the output size of the chosen hash is larger than the number of + // bits of q, the hash result is truncated to fit by taking the number + // of leftmost bits equal to the number of bits of q. This (possibly + // truncated) hash function result is treated as a number and used + // directly in the DSA signature algorithm. + var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength()); + var hash = new BigInteger(util.hexstrdump(hashed_data), 16); + var k = random.getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE)); + var s1 = (g.modPow(k, p)).mod(q); + var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q); + var result = new Array(); + result[0] = s1.toMPI(); + result[1] = s2.toMPI(); + return result; + } + + function select_hash_algorithm(q) { + var usersetting = config.prefer_hash_algorithm; + /* + * 1024-bit key, 160-bit q, SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512 hash + * 2048-bit key, 224-bit q, SHA-224, SHA-256, SHA-384, or SHA-512 hash + * 2048-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash + * 3072-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash + */ + switch (Math.round(q.bitLength() / 8)) { + case 20: + // 1024 bit + if (usersetting != 2 && + usersetting > 11 && + usersetting != 10 && + usersetting < 8) + return 2; // prefer sha1 + return usersetting; + case 28: + // 2048 bit + if (usersetting > 11 && + usersetting < 8) + return 11; + return usersetting; + case 32: + // 4096 bit // prefer sha224 + if (usersetting > 10 && + usersetting < 8) + return 8; // prefer sha256 + return usersetting; + default: + util.print_debug("DSA select hash algorithm: returning null for an unknown length of q"); + return null; + + } + } + this.select_hash_algorithm = select_hash_algorithm; + + function verify(hashalgo, s1, s2, m, p, q, g, y) { + var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength()); + var hash = new BigInteger(util.hexstrdump(hashed_data), 16); + if (BigInteger.ZERO.compareTo(s1) > 0 || + s1.compareTo(q) > 0 || + BigInteger.ZERO.compareTo(s2) > 0 || + s2.compareTo(q) > 0) { + util.print_debug("invalid DSA Signature"); + return null; + } + var w = s2.modInverse(q); + var u1 = hash.multiply(w).mod(q); + var u2 = s1.multiply(w).mod(q); + return g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); + } + + /* * unused code. This can be used as a start to write a key generator * function. @@ -145,10 +6430,14 @@ function DSA() { s = (k.modInverse(q).multiply(hash.add(x.multiply(r)))).mod(q); return s; } */ - this.sign = sign; - this.verify = verify; - // this.generate = generateKey; + this.sign = sign; + this.verify = verify; + // this.generate = generateKey; } + +module.exports = DSA; + +},{"../../config":3,"../../util":56,"../hash":12,"../random.js":23,"./jsbn.js":21}],19:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -168,35 +6457,819 @@ function DSA() { // // ElGamal implementation +/** + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/public_key/elgamal + */ + +var BigInteger = require('./jsbn.js'), + random = require('../random.js'), + util = require('../../util'); + function Elgamal() { - - function encrypt(m,g,p,y) { - // choose k in {2,...,p-2} - var two = BigInteger.ONE.add(BigInteger.ONE); - var pMinus2 = p.subtract(two); - var k = openpgp_crypto_getRandomBigIntegerInRange(two, pMinus2); - var k = k.mod(pMinus2).add(BigInteger.ONE); - var c = new Array(); - c[0] = g.modPow(k, p); - c[1] = y.modPow(k, p).multiply(m).mod(p).toMPI(); - c[0] = c[0].toMPI(); - return c; - } - - function decrypt(c1,c2,p,x) { - util.print_debug("Elgamal Decrypt:\nc1:"+util.hexstrdump(c1.toMPI())+"\n"+ - "c2:"+util.hexstrdump(c2.toMPI())+"\n"+ - "p:"+util.hexstrdump(p.toMPI())+"\n"+ - "x:"+util.hexstrdump(x.toMPI())); - return (c1.modPow(x, p).modInverse(p)).multiply(c2).mod(p); - //var c = c1.pow(x).modInverse(p); // c0^-a mod p - //return c.multiply(c2).mod(p); - } - - // signing and signature verification using Elgamal is not required by OpenPGP. - this.encrypt = encrypt; - this.decrypt = decrypt; -}/* + + function encrypt(m, g, p, y) { + // choose k in {2,...,p-2} + var two = BigInteger.ONE.add(BigInteger.ONE); + var pMinus2 = p.subtract(two); + var k = random.getRandomBigIntegerInRange(two, pMinus2); + k = k.mod(pMinus2).add(BigInteger.ONE); + var c = []; + c[0] = g.modPow(k, p); + c[1] = y.modPow(k, p).multiply(m).mod(p); + return c; + } + + function decrypt(c1, c2, p, x) { + util.print_debug("Elgamal Decrypt:\nc1:" + util.hexstrdump(c1.toMPI()) + "\n" + + "c2:" + util.hexstrdump(c2.toMPI()) + "\n" + + "p:" + util.hexstrdump(p.toMPI()) + "\n" + + "x:" + util.hexstrdump(x.toMPI())); + return (c1.modPow(x, p).modInverse(p)).multiply(c2).mod(p); + //var c = c1.pow(x).modInverse(p); // c0^-a mod p + //return c.multiply(c2).mod(p); + } + + // signing and signature verification using Elgamal is not required by OpenPGP. + this.encrypt = encrypt; + this.decrypt = decrypt; +} + +module.exports = Elgamal; + +},{"../../util":56,"../random.js":23,"./jsbn.js":21}],20:[function(require,module,exports){ +/** + * @requires crypto/public_key/dsa + * @requires crypto/public_key/elgamal + * @requires crypto/public_key/rsa + * @module crypto/public_key + */ +module.exports = { + /** @see module:crypto/public_key/rsa */ + rsa: require('./rsa.js'), + /** @see module:crypto/public_key/elgamal */ + elgamal: require('./elgamal.js'), + /** @see module:crypto/public_key/dsa */ + dsa: require('./dsa.js') +} + +},{"./dsa.js":18,"./elgamal.js":19,"./rsa.js":22}],21:[function(require,module,exports){ +/* + * Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU) + * All Rights Reserved. + * + * Modified by Recurity Labs GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +/** + * @requires util + * @module crypto/public_key/jsbn + */ + +var util = require('../../util'); + +// Basic JavaScript BN library - subset useful for RSA encryption. + +// Bits per digit +var dbits; + +// JavaScript engine analysis +var canary = 0xdeadbeefcafe; +var j_lm = ((canary & 0xffffff) == 0xefcafe); + +// (public) Constructor + +function BigInteger(a, b, c) { + if (a != null) + if ("number" == typeof a) this.fromNumber(a, b, c); + else if (b == null && "string" != typeof a) this.fromString(a, 256); + else this.fromString(a, b); +} + +// return new, unset BigInteger + +function nbi() { + return new BigInteger(null); +} + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) + +function am1(i, x, w, j, c, n) { + while (--n >= 0) { + var v = x * this[i++] + w[j] + c; + c = Math.floor(v / 0x4000000); + w[j++] = v & 0x3ffffff; + } + return c; +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) + +function am2(i, x, w, j, c, n) { + var xl = x & 0x7fff, + xh = x >> 15; + while (--n >= 0) { + var l = this[i] & 0x7fff; + var h = this[i++] >> 15; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); + w[j++] = l & 0x3fffffff; + } + return c; +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. + +function am3(i, x, w, j, c, n) { + var xl = x & 0x3fff, + xh = x >> 14; + while (--n >= 0) { + var l = this[i] & 0x3fff; + var h = this[i++] >> 14; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; + c = (l >> 28) + (m >> 14) + xh * h; + w[j++] = l & 0xfffffff; + } + return c; +} +/*if(j_lm && (navigator != undefined && + navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; +} +else if(j_lm && (navigator != undefined && navigator.appName != "Netscape")) {*/ +BigInteger.prototype.am = am1; +dbits = 26; +/*} +else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; +}*/ + +BigInteger.prototype.DB = dbits; +BigInteger.prototype.DM = ((1 << dbits) - 1); +BigInteger.prototype.DV = (1 << dbits); + +var BI_FP = 52; +BigInteger.prototype.FV = Math.pow(2, BI_FP); +BigInteger.prototype.F1 = BI_FP - dbits; +BigInteger.prototype.F2 = 2 * dbits - BI_FP; + +// Digit conversions +var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; +var BI_RC = new Array(); +var rr, vv; +rr = "0".charCodeAt(0); +for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; +rr = "a".charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; +rr = "A".charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + +function int2char(n) { + return BI_RM.charAt(n); +} + +function intAt(s, i) { + var c = BI_RC[s.charCodeAt(i)]; + return (c == null) ? -1 : c; +} + +// (protected) copy this to r + +function bnpCopyTo(r) { + for (var i = this.t - 1; i >= 0; --i) r[i] = this[i]; + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV + +function bnpFromInt(x) { + this.t = 1; + this.s = (x < 0) ? -1 : 0; + if (x > 0) this[0] = x; + else if (x < -1) this[0] = x + DV; + else this.t = 0; +} + +// return bigint initialized to value + +function nbv(i) { + var r = nbi(); + r.fromInt(i); + return r; +} + +// (protected) set from string and radix + +function bnpFromString(s, b) { + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 256) k = 8; // byte array + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else { + this.fromRadix(s, b); + return; + } + this.t = 0; + this.s = 0; + var i = s.length, + mi = false, + sh = 0; + while (--i >= 0) { + var x = (k == 8) ? s[i] & 0xff : intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if (sh == 0) + this[this.t++] = x; + else if (sh + k > this.DB) { + this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; + this[this.t++] = (x >> (this.DB - sh)); + } else + this[this.t - 1] |= x << sh; + sh += k; + if (sh >= this.DB) sh -= this.DB; + } + if (k == 8 && (s[0] & 0x80) != 0) { + this.s = -1; + if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh; + } + this.clamp(); + if (mi) BigInteger.ZERO.subTo(this, this); +} + +// (protected) clamp off excess high words + +function bnpClamp() { + var c = this.s & this.DM; + while (this.t > 0 && this[this.t - 1] == c)--this.t; +} + +// (public) return string representation in given radix + +function bnToString(b) { + if (this.s < 0) return "-" + this.negate().toString(b); + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else return this.toRadix(b); + var km = (1 << k) - 1, + d, m = false, + r = "", + i = this.t; + var p = this.DB - (i * this.DB) % k; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) > 0) { + m = true; + r = int2char(d); + } + while (i >= 0) { + if (p < k) { + d = (this[i] & ((1 << p) - 1)) << (k - p); + d |= this[--i] >> (p += this.DB - k); + } else { + d = (this[i] >> (p -= k)) & km; + if (p <= 0) { + p += this.DB; + --i; + } + } + if (d > 0) m = true; + if (m) r += int2char(d); + } + } + return m ? r : "0"; +} + +// (public) -this + +function bnNegate() { + var r = nbi(); + BigInteger.ZERO.subTo(this, r); + return r; +} + +// (public) |this| + +function bnAbs() { + return (this.s < 0) ? this.negate() : this; +} + +// (public) return + if this > a, - if this < a, 0 if equal + +function bnCompareTo(a) { + var r = this.s - a.s; + if (r != 0) return r; + var i = this.t; + r = i - a.t; + if (r != 0) return r; + while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; + return 0; +} + +// returns bit length of the integer x + +function nbits(x) { + var r = 1, + t; + if ((t = x >>> 16) != 0) { + x = t; + r += 16; + } + if ((t = x >> 8) != 0) { + x = t; + r += 8; + } + if ((t = x >> 4) != 0) { + x = t; + r += 4; + } + if ((t = x >> 2) != 0) { + x = t; + r += 2; + } + if ((t = x >> 1) != 0) { + x = t; + r += 1; + } + return r; +} + +// (public) return the number of bits in "this" + +function bnBitLength() { + if (this.t <= 0) return 0; + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)); +} + +// (protected) r = this << n*DB + +function bnpDLShiftTo(n, r) { + var i; + for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i]; + for (i = n - 1; i >= 0; --i) r[i] = 0; + r.t = this.t + n; + r.s = this.s; +} + +// (protected) r = this >> n*DB + +function bnpDRShiftTo(n, r) { + for (var i = n; i < this.t; ++i) r[i - n] = this[i]; + r.t = Math.max(this.t - n, 0); + r.s = this.s; +} + +// (protected) r = this << n + +function bnpLShiftTo(n, r) { + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << cbs) - 1; + var ds = Math.floor(n / this.DB), + c = (this.s << bs) & this.DM, + i; + for (i = this.t - 1; i >= 0; --i) { + r[i + ds + 1] = (this[i] >> cbs) | c; + c = (this[i] & bm) << bs; + } + for (i = ds - 1; i >= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t + ds + 1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n + +function bnpRShiftTo(n, r) { + r.s = this.s; + var ds = Math.floor(n / this.DB); + if (ds >= this.t) { + r.t = 0; + return; + } + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << bs) - 1; + r[0] = this[ds] >> bs; + for (var i = ds + 1; i < this.t; ++i) { + r[i - ds - 1] |= (this[i] & bm) << cbs; + r[i - ds] = this[i] >> bs; + } + if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; + r.t = this.t - ds; + r.clamp(); +} + +// (protected) r = this - a + +function bnpSubTo(a, r) { + var i = 0, + c = 0, + m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] - a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c -= a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while (i < a.t) { + c -= a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c < -1) r[i++] = this.DV + c; + else if (c > 0) r[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. + +function bnpMultiplyTo(a, r) { + var x = this.abs(), + y = a.abs(); + var i = x.t; + r.t = i + y.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); + r.s = 0; + r.clamp(); + if (this.s != a.s) BigInteger.ZERO.subTo(r, r); +} + +// (protected) r = this^2, r != this (HAC 14.16) + +function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2 * x.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < x.t - 1; ++i) { + var c = x.am(i, x[i], r, 2 * i, 0, 1); + if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { + r[i + x.t] -= x.DV; + r[i + x.t + 1] = 1; + } + } + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. + +function bnpDivRemTo(m, q, r) { + var pm = m.abs(); + if (pm.t <= 0) return; + var pt = this.abs(); + if (pt.t < pm.t) { + if (q != null) q.fromInt(0); + if (r != null) this.copyTo(r); + return; + } + if (r == null) r = nbi(); + var y = nbi(), + ts = this.s, + ms = m.s; + var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus + if (nsh > 0) { + pm.lShiftTo(nsh, y); + pt.lShiftTo(nsh, r); + } else { + pm.copyTo(y); + pt.copyTo(r); + } + var ys = y.t; + var y0 = y[ys - 1]; + if (y0 == 0) return; + var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0); + var d1 = this.FV / yt, + d2 = (1 << this.F1) / yt, + e = 1 << this.F2; + var i = r.t, + j = i - ys, + t = (q == null) ? nbi() : q; + y.dlShiftTo(j, t); + if (r.compareTo(t) >= 0) { + r[r.t++] = 1; + r.subTo(t, r); + } + BigInteger.ONE.dlShiftTo(ys, t); + t.subTo(y, y); // "negative" y so we can replace sub with am later + while (y.t < ys) y[y.t++] = 0; + while (--j >= 0) { + // Estimate quotient digit + var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); + if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out + y.dlShiftTo(j, t); + r.subTo(t, r); + while (r[i] < --qd) r.subTo(t, r); + } + } + if (q != null) { + r.drShiftTo(ys, q); + if (ts != ms) BigInteger.ZERO.subTo(q, q); + } + r.t = ys; + r.clamp(); + if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder + if (ts < 0) BigInteger.ZERO.subTo(r, r); +} + +// (public) this mod a + +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a, null, r); + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); + return r; +} + +// Modular reduction using "classic" algorithm + +function Classic(m) { + this.m = m; +} + +function cConvert(x) { + if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} + +function cRevert(x) { + return x; +} + +function cReduce(x) { + x.divRemTo(this.m, null, x); +} + +function cMulTo(x, y, r) { + x.multiplyTo(y, r); + this.reduce(r); +} + +function cSqrTo(x, r) { + x.squareTo(r); + this.reduce(r); +} + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. + +function bnpInvDigit() { + if (this.t < 1) return 0; + var x = this[0]; + if ((x & 1) == 0) return 0; + var y = x & 3; // y == 1/x mod 2^2 + y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4 + y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y > 0) ? this.DV - y : -y; +} + +// Montgomery reduction + +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp & 0x7fff; + this.mph = this.mp >> 15; + this.um = (1 << (m.DB - 15)) - 1; + this.mt2 = 2 * m.t; +} + +// xR mod m + +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t, r); + r.divRemTo(this.m, null, r); + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); + return r; +} + +// x/R mod m + +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) + +function montReduce(x) { + while (x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for (var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i] & 0x7fff; + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; + // use am to combine the multiply-shift-add into one call + j = i + this.m.t; + x[j] += this.m.am(0, u0, x, i, 0, this.m.t); + // propagate carry + while (x[j] >= x.DV) { + x[j] -= x.DV; + x[++j]++; + } + } + x.clamp(); + x.drShiftTo(this.m.t, x); + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); +} + +// r = "x^2/R mod m"; x != r + +function montSqrTo(x, r) { + x.squareTo(r); + this.reduce(r); +} + +// r = "xy/R mod m"; x,y != r + +function montMulTo(x, y, r) { + x.multiplyTo(y, r); + this.reduce(r); +} + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even + +function bnpIsEven() { + return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; +} + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) + +function bnpExp(e, z) { + if (e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), + r2 = nbi(), + g = z.convert(this), + i = nbits(e) - 1; + g.copyTo(r); + while (--i >= 0) { + z.sqrTo(r, r2); + if ((e & (1 << i)) > 0) z.mulTo(r2, g, r); + else { + var t = r; + r = r2; + r2 = t; + } + } + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 + +function bnModPowInt(e, m) { + var z; + if (e < 256 || m.isEven()) z = new Classic(m); + else z = new Montgomery(m); + return this.exp(e, z); +} + +// protected +BigInteger.prototype.copyTo = bnpCopyTo; +BigInteger.prototype.fromInt = bnpFromInt; +BigInteger.prototype.fromString = bnpFromString; +BigInteger.prototype.clamp = bnpClamp; +BigInteger.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger.prototype.drShiftTo = bnpDRShiftTo; +BigInteger.prototype.lShiftTo = bnpLShiftTo; +BigInteger.prototype.rShiftTo = bnpRShiftTo; +BigInteger.prototype.subTo = bnpSubTo; +BigInteger.prototype.multiplyTo = bnpMultiplyTo; +BigInteger.prototype.squareTo = bnpSquareTo; +BigInteger.prototype.divRemTo = bnpDivRemTo; +BigInteger.prototype.invDigit = bnpInvDigit; +BigInteger.prototype.isEven = bnpIsEven; +BigInteger.prototype.exp = bnpExp; + +// public +BigInteger.prototype.toString = bnToString; +BigInteger.prototype.negate = bnNegate; +BigInteger.prototype.abs = bnAbs; +BigInteger.prototype.compareTo = bnCompareTo; +BigInteger.prototype.bitLength = bnBitLength; +BigInteger.prototype.mod = bnMod; +BigInteger.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); + +module.exports = BigInteger; + + + + + + + + + + + + + + + + + + + +/* * Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU) * All Rights Reserved. * @@ -228,335 +7301,488 @@ function Elgamal() { * All redistributions must retain an intact copy of this copyright notice * and disclaimer. */ + + // Extended JavaScript BN functions, required for RSA private ops. // Version 1.1: new BigInteger("0", 10) returns "proper" zero // Version 1.2: square() API, isProbablePrime fix // (public) -function bnClone() { var r = nbi(); this.copyTo(r); return r; } +function bnClone() { + var r = nbi(); + this.copyTo(r); + return r; +} // (public) return value as integer + function bnIntValue() { - if(this.s < 0) { - if(this.t == 1) return this[0]-this.DV; - else if(this.t == 0) return -1; - } - else if(this.t == 1) return this[0]; - else if(this.t == 0) return 0; + if (this.s < 0) { + if (this.t == 1) return this[0] - this.DV; + else if (this.t == 0) return -1; + } else if (this.t == 1) return this[0]; + else if (this.t == 0) return 0; // assumes 16 < DB < 32 - return ((this[1]&((1<<(32-this.DB))-1))<>24; } + +function bnByteValue() { + return (this.t == 0) ? this.s : (this[0] << 24) >> 24; +} // (public) return value as short (assumes DB>=16) -function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; } + +function bnShortValue() { + return (this.t == 0) ? this.s : (this[0] << 16) >> 16; +} // (protected) return x s.t. r^x < DV -function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } + +function bnpChunkSize(r) { + return Math.floor(Math.LN2 * this.DB / Math.log(r)); +} // (public) 0 if this == 0, 1 if this > 0 + function bnSigNum() { - if(this.s < 0) return -1; - else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; + if (this.s < 0) return -1; + else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; else return 1; } // (protected) convert to radix string + function bnpToRadix(b) { - if(b == null) b = 10; - if(this.signum() == 0 || b < 2 || b > 36) return "0"; + if (b == null) b = 10; + if (this.signum() == 0 || b < 2 || b > 36) return "0"; var cs = this.chunkSize(b); - var a = Math.pow(b,cs); - var d = nbv(a), y = nbi(), z = nbi(), r = ""; - this.divRemTo(d,y,z); - while(y.signum() > 0) { - r = (a+z.intValue()).toString(b).substr(1) + r; - y.divRemTo(d,y,z); + var a = Math.pow(b, cs); + var d = nbv(a), + y = nbi(), + z = nbi(), + r = ""; + this.divRemTo(d, y, z); + while (y.signum() > 0) { + r = (a + z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d, y, z); } return z.intValue().toString(b) + r; } // (protected) convert from radix string -function bnpFromRadix(s,b) { + +function bnpFromRadix(s, b) { this.fromInt(0); - if(b == null) b = 10; + if (b == null) b = 10; var cs = this.chunkSize(b); - var d = Math.pow(b,cs), mi = false, j = 0, w = 0; - for(var i = 0; i < s.length; ++i) { - var x = intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-" && this.signum() == 0) mi = true; + var d = Math.pow(b, cs), + mi = false, + j = 0, + w = 0; + for (var i = 0; i < s.length; ++i) { + var x = intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-" && this.signum() == 0) mi = true; continue; } - w = b*w+x; - if(++j >= cs) { + w = b * w + x; + if (++j >= cs) { this.dMultiply(d); - this.dAddOffset(w,0); + this.dAddOffset(w, 0); j = 0; w = 0; } } - if(j > 0) { - this.dMultiply(Math.pow(b,j)); - this.dAddOffset(w,0); + if (j > 0) { + this.dMultiply(Math.pow(b, j)); + this.dAddOffset(w, 0); } - if(mi) BigInteger.ZERO.subTo(this,this); + if (mi) BigInteger.ZERO.subTo(this, this); } // (protected) alternate constructor -function bnpFromNumber(a,b,c) { - if("number" == typeof b) { + +function bnpFromNumber(a, b, c) { + if ("number" == typeof b) { // new BigInteger(int,int,RNG) - if(a < 2) this.fromInt(1); + if (a < 2) this.fromInt(1); else { - this.fromNumber(a,c); - if(!this.testBit(a-1)) // force MSB set - this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); - if(this.isEven()) this.dAddOffset(1,0); // force odd - while(!this.isProbablePrime(b)) { - this.dAddOffset(2,0); - if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); + this.fromNumber(a, c); + if (!this.testBit(a - 1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this); + if (this.isEven()) this.dAddOffset(1, 0); // force odd + while (!this.isProbablePrime(b)) { + this.dAddOffset(2, 0); + if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this); } } - } - else { + } else { // new BigInteger(int,RNG) - var x = new Array(), t = a&7; - x.length = (a>>3)+1; + var x = new Array(), + t = a & 7; + x.length = (a >> 3) + 1; b.nextBytes(x); - if(t > 0) x[0] &= ((1< 0) x[0] &= ((1 << t) - 1); + else x[0] = 0; + this.fromString(x, 256); } } // (public) convert to bigendian byte array + function bnToByteArray() { - var i = this.t, r = new Array(); + var i = this.t, + r = new Array(); r[0] = this.s; - var p = this.DB-(i*this.DB)%8, d, k = 0; - if(i-- > 0) { - if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p) - r[k++] = d|(this.s<<(this.DB-p)); - while(i >= 0) { - if(p < 8) { - d = (this[i]&((1<>(p+=this.DB-8); - } - else { - d = (this[i]>>(p-=8))&0xff; - if(p <= 0) { p += this.DB; --i; } + var p = this.DB - (i * this.DB) % 8, + d, k = 0; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) + r[k++] = d | (this.s << (this.DB - p)); + while (i >= 0) { + if (p < 8) { + d = (this[i] & ((1 << p) - 1)) << (8 - p); + d |= this[--i] >> (p += this.DB - 8); + } else { + d = (this[i] >> (p -= 8)) & 0xff; + if (p <= 0) { + p += this.DB; + --i; + } } //if((d&0x80) != 0) d |= -256; //if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; - if(k > 0 || d != this.s) r[k++] = d; + if (k > 0 || d != this.s) r[k++] = d; } } return r; } -function bnEquals(a) { return(this.compareTo(a)==0); } -function bnMin(a) { return(this.compareTo(a)<0)?this:a; } -function bnMax(a) { return(this.compareTo(a)>0)?this:a; } +function bnEquals(a) { + return (this.compareTo(a) == 0); +} + +function bnMin(a) { + return (this.compareTo(a) < 0) ? this : a; +} + +function bnMax(a) { + return (this.compareTo(a) > 0) ? this : a; +} // (protected) r = this op a (bitwise) -function bnpBitwiseTo(a,op,r) { - var i, f, m = Math.min(a.t,this.t); - for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]); - if(a.t < this.t) { - f = a.s&this.DM; - for(i = m; i < this.t; ++i) r[i] = op(this[i],f); + +function bnpBitwiseTo(a, op, r) { + var i, f, m = Math.min(a.t, this.t); + for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]); + if (a.t < this.t) { + f = a.s & this.DM; + for (i = m; i < this.t; ++i) r[i] = op(this[i], f); r.t = this.t; - } - else { - f = this.s&this.DM; - for(i = m; i < a.t; ++i) r[i] = op(f,a[i]); + } else { + f = this.s & this.DM; + for (i = m; i < a.t; ++i) r[i] = op(f, a[i]); r.t = a.t; } - r.s = op(this.s,a.s); + r.s = op(this.s, a.s); r.clamp(); } // (public) this & a -function op_and(x,y) { return x&y; } -function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } + +function op_and(x, y) { + return x & y; +} + +function bnAnd(a) { + var r = nbi(); + this.bitwiseTo(a, op_and, r); + return r; +} // (public) this | a -function op_or(x,y) { return x|y; } -function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } + +function op_or(x, y) { + return x | y; +} + +function bnOr(a) { + var r = nbi(); + this.bitwiseTo(a, op_or, r); + return r; +} // (public) this ^ a -function op_xor(x,y) { return x^y; } -function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } + +function op_xor(x, y) { + return x ^ y; +} + +function bnXor(a) { + var r = nbi(); + this.bitwiseTo(a, op_xor, r); + return r; +} // (public) this & ~a -function op_andnot(x,y) { return x&~y; } -function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } + +function op_andnot(x, y) { + return x & ~y; +} + +function bnAndNot(a) { + var r = nbi(); + this.bitwiseTo(a, op_andnot, r); + return r; +} // (public) ~this + function bnNot() { var r = nbi(); - for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i]; + for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i]; r.t = this.t; r.s = ~this.s; return r; } // (public) this << n + function bnShiftLeft(n) { var r = nbi(); - if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); + if (n < 0) this.rShiftTo(-n, r); + else this.lShiftTo(n, r); return r; } // (public) this >> n + function bnShiftRight(n) { var r = nbi(); - if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); + if (n < 0) this.lShiftTo(-n, r); + else this.rShiftTo(n, r); return r; } // return index of lowest 1-bit in x, x < 2^31 + function lbit(x) { - if(x == 0) return -1; + if (x == 0) return -1; var r = 0; - if((x&0xffff) == 0) { x >>= 16; r += 16; } - if((x&0xff) == 0) { x >>= 8; r += 8; } - if((x&0xf) == 0) { x >>= 4; r += 4; } - if((x&3) == 0) { x >>= 2; r += 2; } - if((x&1) == 0) ++r; + if ((x & 0xffff) == 0) { + x >>= 16; + r += 16; + } + if ((x & 0xff) == 0) { + x >>= 8; + r += 8; + } + if ((x & 0xf) == 0) { + x >>= 4; + r += 4; + } + if ((x & 3) == 0) { + x >>= 2; + r += 2; + } + if ((x & 1) == 0)++r; return r; } // (public) returns index of lowest 1-bit (or -1 if none) + function bnGetLowestSetBit() { - for(var i = 0; i < this.t; ++i) - if(this[i] != 0) return i*this.DB+lbit(this[i]); - if(this.s < 0) return this.t*this.DB; + for (var i = 0; i < this.t; ++i) + if (this[i] != 0) return i * this.DB + lbit(this[i]); + if (this.s < 0) return this.t * this.DB; return -1; } // return number of 1 bits in x + function cbit(x) { var r = 0; - while(x != 0) { x &= x-1; ++r; } + while (x != 0) { + x &= x - 1; + ++r; + } return r; } // (public) return number of set bits + function bnBitCount() { - var r = 0, x = this.s&this.DM; - for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x); + var r = 0, + x = this.s & this.DM; + for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x); return r; } // (public) true iff nth bit is set + function bnTestBit(n) { - var j = Math.floor(n/this.DB); - if(j >= this.t) return(this.s!=0); - return((this[j]&(1<<(n%this.DB)))!=0); + var j = Math.floor(n / this.DB); + if (j >= this.t) return (this.s != 0); + return ((this[j] & (1 << (n % this.DB))) != 0); } // (protected) this op (1<>= this.DB; } - if(a.t < this.t) { + if (a.t < this.t) { c += a.s; - while(i < this.t) { + while (i < this.t) { c += this[i]; - r[i++] = c&this.DM; + r[i++] = c & this.DM; c >>= this.DB; } c += this.s; - } - else { + } else { c += this.s; - while(i < a.t) { + while (i < a.t) { c += a[i]; - r[i++] = c&this.DM; + r[i++] = c & this.DM; c >>= this.DB; } c += a.s; } - r.s = (c<0)?-1:0; - if(c > 0) r[i++] = c; - else if(c < -1) r[i++] = this.DV+c; + r.s = (c < 0) ? -1 : 0; + if (c > 0) r[i++] = c; + else if (c < -1) r[i++] = this.DV + c; r.t = i; r.clamp(); } // (public) this + a -function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } + +function bnAdd(a) { + var r = nbi(); + this.addTo(a, r); + return r; +} // (public) this - a -function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } + +function bnSubtract(a) { + var r = nbi(); + this.subTo(a, r); + return r; +} // (public) this * a -function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } + +function bnMultiply(a) { + var r = nbi(); + this.multiplyTo(a, r); + return r; +} // (public) this^2 -function bnSquare() { var r = nbi(); this.squareTo(r); return r; } + +function bnSquare() { + var r = nbi(); + this.squareTo(r); + return r; +} // (public) this / a -function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } + +function bnDivide(a) { + var r = nbi(); + this.divRemTo(a, r, null); + return r; +} // (public) this % a -function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } + +function bnRemainder(a) { + var r = nbi(); + this.divRemTo(a, null, r); + return r; +} // (public) [this/a,this%a] + function bnDivideAndRemainder(a) { - var q = nbi(), r = nbi(); - this.divRemTo(a,q,r); - return new Array(q,r); + var q = nbi(), + r = nbi(); + this.divRemTo(a, q, r); + return new Array(q, r); } // (protected) this *= n, this >= 0, 1 < n < DV + function bnpDMultiply(n) { - this[this.t] = this.am(0,n-1,this,0,0,this.t); + this[this.t] = this.am(0, n - 1, this, 0, 0, this.t); ++this.t; this.clamp(); } // (protected) this += n << w words, this >= 0 -function bnpDAddOffset(n,w) { - if(n == 0) return; - while(this.t <= w) this[this.t++] = 0; + +function bnpDAddOffset(n, w) { + if (n == 0) return; + while (this.t <= w) this[this.t++] = 0; this[w] += n; - while(this[w] >= this.DV) { + while (this[w] >= this.DV) { this[w] -= this.DV; - if(++w >= this.t) this[this.t++] = 0; + if (++w >= this.t) this[this.t++] = 0; ++this[w]; } } // A "null" reducer + function NullExp() {} -function nNop(x) { return x; } -function nMulTo(x,y,r) { x.multiplyTo(y,r); } -function nSqrTo(x,r) { x.squareTo(r); } + +function nNop(x) { + return x; +} + +function nMulTo(x, y, r) { + x.multiplyTo(y, r); +} + +function nSqrTo(x, r) { + x.squareTo(r); +} NullExp.prototype.convert = nNop; NullExp.prototype.revert = nNop; @@ -564,68 +7790,93 @@ NullExp.prototype.mulTo = nMulTo; NullExp.prototype.sqrTo = nSqrTo; // (public) this^e -function bnPow(e) { return this.exp(e,new NullExp()); } + +function bnPow(e) { + return this.exp(e, new NullExp()); +} // (protected) r = lower n words of "this * a", a.t <= n // "this" should be the larger one if appropriate. -function bnpMultiplyLowerTo(a,n,r) { - var i = Math.min(this.t+a.t,n); + +function bnpMultiplyLowerTo(a, n, r) { + var i = Math.min(this.t + a.t, n); r.s = 0; // assumes a,this >= 0 r.t = i; - while(i > 0) r[--i] = 0; + while (i > 0) r[--i] = 0; var j; - for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t); - for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i); + for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t); + for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i); r.clamp(); } // (protected) r = "this * a" without lower n words, n > 0 // "this" should be the larger one if appropriate. -function bnpMultiplyUpperTo(a,n,r) { + +function bnpMultiplyUpperTo(a, n, r) { --n; - var i = r.t = this.t+a.t-n; + var i = r.t = this.t + a.t - n; r.s = 0; // assumes a,this >= 0 - while(--i >= 0) r[i] = 0; - for(i = Math.max(n-this.t,0); i < a.t; ++i) - r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n); + while (--i >= 0) r[i] = 0; + for (i = Math.max(n - this.t, 0); i < a.t; ++i) + r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n); r.clamp(); - r.drShiftTo(1,r); + r.drShiftTo(1, r); } // Barrett modular reduction + function Barrett(m) { // setup Barrett this.r2 = nbi(); this.q3 = nbi(); - BigInteger.ONE.dlShiftTo(2*m.t,this.r2); + BigInteger.ONE.dlShiftTo(2 * m.t, this.r2); this.mu = this.r2.divide(m); this.m = m; } function barrettConvert(x) { - if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); - else if(x.compareTo(this.m) < 0) return x; - else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } + if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m); + else if (x.compareTo(this.m) < 0) return x; + else { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; + } } -function barrettRevert(x) { return x; } +function barrettRevert(x) { + return x; +} // x = x mod m (HAC 14.42) + function barrettReduce(x) { - x.drShiftTo(this.m.t-1,this.r2); - if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } - this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); - this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); - while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); - x.subTo(this.r2,x); - while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); + x.drShiftTo(this.m.t - 1, this.r2); + if (x.t > this.m.t + 1) { + x.t = this.m.t + 1; + x.clamp(); + } + this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3); + this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); + while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1); + x.subTo(this.r2, x); + while (x.compareTo(this.m) >= 0) x.subTo(this.m, x); } // r = x^2 mod m; x != r -function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +function barrettSqrTo(x, r) { + x.squareTo(r); + this.reduce(r); +} // r = x*y mod m; x,y != r -function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +function barrettMulTo(x, y, r) { + x.multiplyTo(y, r); + this.reduce(r); +} Barrett.prototype.convert = barrettConvert; Barrett.prototype.revert = barrettRevert; @@ -634,162 +7885,218 @@ Barrett.prototype.mulTo = barrettMulTo; Barrett.prototype.sqrTo = barrettSqrTo; // (public) this^e % m (HAC 14.85) -function bnModPow(e,m) { - var i = e.bitLength(), k, r = nbv(1), z; - if(i <= 0) return r; - else if(i < 18) k = 1; - else if(i < 48) k = 3; - else if(i < 144) k = 4; - else if(i < 768) k = 5; + +function bnModPow(e, m) { + var i = e.bitLength(), + k, r = nbv(1), + z; + if (i <= 0) return r; + else if (i < 18) k = 1; + else if (i < 48) k = 3; + else if (i < 144) k = 4; + else if (i < 768) k = 5; else k = 6; - if(i < 8) + if (i < 8) z = new Classic(m); - else if(m.isEven()) + else if (m.isEven()) z = new Barrett(m); else z = new Montgomery(m); // precomputation - var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { + if (k > 1) { var g2 = nbi(); - z.sqrTo(g[1],g2); - while(n <= km) { + z.sqrTo(g[1], g2); + while (n <= km) { g[n] = nbi(); - z.mulTo(g2,g[n-2],g[n]); + z.mulTo(g2, g[n - 2], g[n]); n += 2; } } - var j = e.t-1, w, is1 = true, r2 = nbi(), t; - i = nbits(e[j])-1; - while(j >= 0) { - if(i >= k1) w = (e[j]>>(i-k1))&km; + var j = e.t - 1, + w, is1 = true, + r2 = nbi(), + t; + i = nbits(e[j]) - 1; + while (j >= 0) { + if (i >= k1) w = (e[j] >> (i - k1)) & km; else { - w = (e[j]&((1<<(i+1))-1))<<(k1-i); - if(j > 0) w |= e[j-1]>>(this.DB+i-k1); + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1); } n = k; - while((w&1) == 0) { w >>= 1; --n; } - if((i -= n) < 0) { i += this.DB; --j; } - if(is1) { // ret == 1, don't bother squaring or multiplying it + while ((w & 1) == 0) { + w >>= 1; + --n; + } + if ((i -= n) < 0) { + i += this.DB; + --j; + } + if (is1) { // ret == 1, don't bother squaring or multiplying it g[w].copyTo(r); is1 = false; - } - else { - while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } - if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } - z.mulTo(r2,g[w],r); + } else { + while (n > 1) { + z.sqrTo(r, r2); + z.sqrTo(r2, r); + n -= 2; + } + if (n > 0) z.sqrTo(r, r2); + else { + t = r; + r = r2; + r2 = t; + } + z.mulTo(r2, g[w], r); } - while(j >= 0 && (e[j]&(1<= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2); + t = r; + r = r2; + r2 = t; + if (--i < 0) { + i = this.DB - 1; + --j; + } } } return z.revert(r); } // (public) gcd(this,a) (HAC 14.54) + function bnGCD(a) { - var x = (this.s<0)?this.negate():this.clone(); - var y = (a.s<0)?a.negate():a.clone(); - if(x.compareTo(y) < 0) { var t = x; x = y; y = t; } - var i = x.getLowestSetBit(), g = y.getLowestSetBit(); - if(g < 0) return x; - if(i < g) g = i; - if(g > 0) { - x.rShiftTo(g,x); - y.rShiftTo(g,y); + var x = (this.s < 0) ? this.negate() : this.clone(); + var y = (a.s < 0) ? a.negate() : a.clone(); + if (x.compareTo(y) < 0) { + var t = x; + x = y; + y = t; } - while(x.signum() > 0) { - if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); - if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); - if(x.compareTo(y) >= 0) { - x.subTo(y,x); - x.rShiftTo(1,x); - } - else { - y.subTo(x,y); - y.rShiftTo(1,y); + var i = x.getLowestSetBit(), + g = y.getLowestSetBit(); + if (g < 0) return x; + if (i < g) g = i; + if (g > 0) { + x.rShiftTo(g, x); + y.rShiftTo(g, y); + } + while (x.signum() > 0) { + if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x); + if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y); + if (x.compareTo(y) >= 0) { + x.subTo(y, x); + x.rShiftTo(1, x); + } else { + y.subTo(x, y); + y.rShiftTo(1, y); } } - if(g > 0) y.lShiftTo(g,y); + if (g > 0) y.lShiftTo(g, y); return y; } // (protected) this % n, n < 2^26 + function bnpModInt(n) { - if(n <= 0) return 0; - var d = this.DV%n, r = (this.s<0)?n-1:0; - if(this.t > 0) - if(d == 0) r = this[0]%n; - else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n; + if (n <= 0) return 0; + var d = this.DV % n, + r = (this.s < 0) ? n - 1 : 0; + if (this.t > 0) + if (d == 0) r = this[0] % n; + else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n; return r; } // (public) 1/this % m (HAC 14.61) + function bnModInverse(m) { var ac = m.isEven(); - if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; - var u = m.clone(), v = this.clone(); - var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); - while(u.signum() != 0) { - while(u.isEven()) { - u.rShiftTo(1,u); - if(ac) { - if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } - a.rShiftTo(1,a); - } - else if(!b.isEven()) b.subTo(m,b); - b.rShiftTo(1,b); + if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), + v = this.clone(); + var a = nbv(1), + b = nbv(0), + c = nbv(0), + d = nbv(1); + while (u.signum() != 0) { + while (u.isEven()) { + u.rShiftTo(1, u); + if (ac) { + if (!a.isEven() || !b.isEven()) { + a.addTo(this, a); + b.subTo(m, b); + } + a.rShiftTo(1, a); + } else if (!b.isEven()) b.subTo(m, b); + b.rShiftTo(1, b); } - while(v.isEven()) { - v.rShiftTo(1,v); - if(ac) { - if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } - c.rShiftTo(1,c); - } - else if(!d.isEven()) d.subTo(m,d); - d.rShiftTo(1,d); + while (v.isEven()) { + v.rShiftTo(1, v); + if (ac) { + if (!c.isEven() || !d.isEven()) { + c.addTo(this, c); + d.subTo(m, d); + } + c.rShiftTo(1, c); + } else if (!d.isEven()) d.subTo(m, d); + d.rShiftTo(1, d); } - if(u.compareTo(v) >= 0) { - u.subTo(v,u); - if(ac) a.subTo(c,a); - b.subTo(d,b); - } - else { - v.subTo(u,v); - if(ac) c.subTo(a,c); - d.subTo(b,d); + if (u.compareTo(v) >= 0) { + u.subTo(v, u); + if (ac) a.subTo(c, a); + b.subTo(d, b); + } else { + v.subTo(u, v); + if (ac) c.subTo(a, c); + d.subTo(b, d); } } - if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; - if(d.compareTo(m) >= 0) return d.subtract(m); - if(d.signum() < 0) d.addTo(m,d); else return d; - if(d.signum() < 0) return d.add(m); else return d; + if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if (d.compareTo(m) >= 0) return d.subtract(m); + if (d.signum() < 0) d.addTo(m, d); + else return d; + if (d.signum() < 0) return d.add(m); + else return d; } -var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]; -var lplim = (1<<26)/lowprimes[lowprimes.length-1]; +var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, + 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, + 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, + 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, + 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, + 977, 983, 991, 997 +]; +var lplim = (1 << 26) / lowprimes[lowprimes.length - 1]; // (public) test primality with certainty >= 1-.5^t + function bnIsProbablePrime(t) { var i, x = this.abs(); - if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) { - for(i = 0; i < lowprimes.length; ++i) - if(x[0] == lowprimes[i]) return true; + if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) { + for (i = 0; i < lowprimes.length; ++i) + if (x[0] == lowprimes[i]) return true; return false; } - if(x.isEven()) return false; + if (x.isEven()) return false; i = 1; - while(i < lowprimes.length) { - var m = lowprimes[i], j = i+1; - while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + while (i < lowprimes.length) { + var m = lowprimes[i], + j = i + 1; + while (j < lowprimes.length && m < lplim) m *= lowprimes[j++]; m = x.modInt(m); - while(i < j) if(m%lowprimes[i++] == 0) return false; + while (i < j) if (m % lowprimes[i++] == 0) return false; } return x.millerRabin(t); } @@ -797,38 +8104,39 @@ function bnIsProbablePrime(t) { /* added by Recurity Labs */ function nbits(x) { - var n = 1, t; - if ((t = x >>> 16) != 0) { - x = t; - n += 16; - } - if ((t = x >> 8) != 0) { - x = t; - n += 8; - } - if ((t = x >> 4) != 0) { - x = t; - n += 4; - } - if ((t = x >> 2) != 0) { - x = t; - n += 2; - } - if ((t = x >> 1) != 0) { - x = t; - n += 1; - } - return n; + var n = 1, + t; + if ((t = x >>> 16) != 0) { + x = t; + n += 16; + } + if ((t = x >> 8) != 0) { + x = t; + n += 8; + } + if ((t = x >> 4) != 0) { + x = t; + n += 4; + } + if ((t = x >> 2) != 0) { + x = t; + n += 2; + } + if ((t = x >> 1) != 0) { + x = t; + n += 1; + } + return n; } -function bnToMPI () { - var ba = this.toByteArray(); - var size = (ba.length-1)*8+nbits(ba[0]); - var result = ""; - result += String.fromCharCode((size & 0xFF00) >> 8); - result += String.fromCharCode(size & 0xFF); - result += util.bin2str(ba); - return result; +function bnToMPI() { + var ba = this.toByteArray(); + var size = (ba.length - 1) * 8 + nbits(ba[0]); + var result = ""; + result += String.fromCharCode((size & 0xFF00) >> 8); + result += String.fromCharCode(size & 0xFF); + result += util.bin2str(ba); + return result; } /* END of addition */ @@ -836,13 +8144,13 @@ function bnToMPI () { function bnpMillerRabin(t) { var n1 = this.subtract(BigInteger.ONE); var k = n1.getLowestSetBit(); - if(k <= 0) return false; + if (k <= 0) return false; var r = n1.shiftRight(k); - t = (t+1)>>1; - if(t > lowprimes.length) t = lowprimes.length; + t = (t + 1) >> 1; + if (t > lowprimes.length) t = lowprimes.length; var a = nbi(); var j, bases = []; - for(var i = 0; i < t; ++i) { + for (var i = 0; i < t; ++i) { //Pick bases at random, instead of starting at 2 for (;;) { j = lowprimes[Math.floor(Math.random() * lowprimes.length)]; @@ -850,19 +8158,21 @@ function bnpMillerRabin(t) { } bases.push(j); a.fromInt(j); - var y = a.modPow(r,this); - if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var y = a.modPow(r, this); + if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { var j = 1; - while(j++ < k && y.compareTo(n1) != 0) { - y = y.modPowInt(2,this); - if(y.compareTo(BigInteger.ONE) == 0) return false; + while (j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2, this); + if (y.compareTo(BigInteger.ONE) == 0) return false; } - if(y.compareTo(n1) != 0) return false; + if (y.compareTo(n1) != 0) return false; } } return true; } +var BigInteger = require('./jsbn.js'); + // protected BigInteger.prototype.chunkSize = bnpChunkSize; BigInteger.prototype.toRadix = bnpToRadix; @@ -916,595 +8226,8 @@ BigInteger.prototype.toMPI = bnToMPI; // JSBN-specific extension BigInteger.prototype.square = bnSquare; -/* - * Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU) - * All Rights Reserved. - * - * Modified by Recurity Labs GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - -// Basic JavaScript BN library - subset useful for RSA encryption. - -// Bits per digit -var dbits; - -// JavaScript engine analysis -var canary = 0xdeadbeefcafe; -var j_lm = ((canary&0xffffff)==0xefcafe); - -// (public) Constructor -function BigInteger(a,b,c) { - if(a != null) - if("number" == typeof a) this.fromNumber(a,b,c); - else if(b == null && "string" != typeof a) this.fromString(a,256); - else this.fromString(a,b); -} - -// return new, unset BigInteger -function nbi() { return new BigInteger(null); } - -// am: Compute w_j += (x*this_i), propagate carries, -// c is initial carry, returns final carry. -// c < 3*dvalue, x < 2*dvalue, this_i < dvalue -// We need to select the fastest one that works in this environment. - -// am1: use a single mult and divide to get the high bits, -// max digit bits should be 26 because -// max internal value = 2*dvalue^2-2*dvalue (< 2^53) -function am1(i,x,w,j,c,n) { - while(--n >= 0) { - var v = x*this[i++]+w[j]+c; - c = Math.floor(v/0x4000000); - w[j++] = v&0x3ffffff; - } - return c; -} -// am2 avoids a big mult-and-extract completely. -// Max digit bits should be <= 30 because we do bitwise ops -// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) -function am2(i,x,w,j,c,n) { - var xl = x&0x7fff, xh = x>>15; - while(--n >= 0) { - var l = this[i]&0x7fff; - var h = this[i++]>>15; - var m = xh*l+h*xl; - l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); - c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); - w[j++] = l&0x3fffffff; - } - return c; -} -// Alternately, set max digit bits to 28 since some -// browsers slow down when dealing with 32-bit numbers. -function am3(i,x,w,j,c,n) { - var xl = x&0x3fff, xh = x>>14; - while(--n >= 0) { - var l = this[i]&0x3fff; - var h = this[i++]>>14; - var m = xh*l+h*xl; - l = xl*l+((m&0x3fff)<<14)+w[j]+c; - c = (l>>28)+(m>>14)+xh*h; - w[j++] = l&0xfffffff; - } - return c; -} -if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { - BigInteger.prototype.am = am2; - dbits = 30; -} -else if(j_lm && (navigator.appName != "Netscape")) { - BigInteger.prototype.am = am1; - dbits = 26; -} -else { // Mozilla/Netscape seems to prefer am3 - BigInteger.prototype.am = am3; - dbits = 28; -} - -BigInteger.prototype.DB = dbits; -BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i]; - r.t = this.t; - r.s = this.s; -} - -// (protected) set from integer value x, -DV <= x < DV -function bnpFromInt(x) { - this.t = 1; - this.s = (x<0)?-1:0; - if(x > 0) this[0] = x; - else if(x < -1) this[0] = x+DV; - else this.t = 0; -} - -// return bigint initialized to value -function nbv(i) { var r = nbi(); r.fromInt(i); return r; } - -// (protected) set from string and radix -function bnpFromString(s,b) { - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 256) k = 8; // byte array - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else { this.fromRadix(s,b); return; } - this.t = 0; - this.s = 0; - var i = s.length, mi = false, sh = 0; - while(--i >= 0) { - var x = (k==8)?s[i]&0xff:intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-") mi = true; - continue; - } - mi = false; - if(sh == 0) - this[this.t++] = x; - else if(sh+k > this.DB) { - this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); - } - else - this[this.t-1] |= x<= this.DB) sh -= this.DB; - } - if(k == 8 && (s[0]&0x80) != 0) { - this.s = -1; - if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t; -} - -// (public) return string representation in given radix -function bnToString(b) { - if(this.s < 0) return "-"+this.negate().toString(b); - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else return this.toRadix(b); - var km = (1< 0) { - if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } - while(i >= 0) { - if(p < k) { - d = (this[i]&((1<>(p+=this.DB-k); - } - else { - d = (this[i]>>(p-=k))&km; - if(p <= 0) { p += this.DB; --i; } - } - if(d > 0) m = true; - if(m) r += int2char(d); - } - } - return m?r:"0"; -} - -// (public) -this -function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } - -// (public) |this| -function bnAbs() { return (this.s<0)?this.negate():this; } - -// (public) return + if this > a, - if this < a, 0 if equal -function bnCompareTo(a) { - var r = this.s-a.s; - if(r != 0) return r; - var i = this.t; - r = i-a.t; - if(r != 0) return r; - while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; - return 0; -} - -// returns bit length of the integer x -function nbits(x) { - var r = 1, t; - if((t=x>>>16) != 0) { x = t; r += 16; } - if((t=x>>8) != 0) { x = t; r += 8; } - if((t=x>>4) != 0) { x = t; r += 4; } - if((t=x>>2) != 0) { x = t; r += 2; } - if((t=x>>1) != 0) { x = t; r += 1; } - return r; -} - -// (public) return the number of bits in "this" -function bnBitLength() { - if(this.t <= 0) return 0; - return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); -} - -// (protected) r = this << n*DB -function bnpDLShiftTo(n,r) { - var i; - for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; - for(i = n-1; i >= 0; --i) r[i] = 0; - r.t = this.t+n; - r.s = this.s; -} - -// (protected) r = this >> n*DB -function bnpDRShiftTo(n,r) { - for(var i = n; i < this.t; ++i) r[i-n] = this[i]; - r.t = Math.max(this.t-n,0); - r.s = this.s; -} - -// (protected) r = this << n -function bnpLShiftTo(n,r) { - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<= 0; --i) { - r[i+ds+1] = (this[i]>>cbs)|c; - c = (this[i]&bm)<= 0; --i) r[i] = 0; - r[ds] = c; - r.t = this.t+ds+1; - r.s = this.s; - r.clamp(); -} - -// (protected) r = this >> n -function bnpRShiftTo(n,r) { - r.s = this.s; - var ds = Math.floor(n/this.DB); - if(ds >= this.t) { r.t = 0; return; } - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<>bs; - for(var i = ds+1; i < this.t; ++i) { - r[i-ds-1] |= (this[i]&bm)<>bs; - } - if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB; - } - if(a.t < this.t) { - c -= a.s; - while(i < this.t) { - c += this[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c += this.s; - } - else { - c += this.s; - while(i < a.t) { - c -= a[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c -= a.s; - } - r.s = (c<0)?-1:0; - if(c < -1) r[i++] = this.DV+c; - else if(c > 0) r[i++] = c; - r.t = i; - r.clamp(); -} - -// (protected) r = this * a, r != this,a (HAC 14.12) -// "this" should be the larger one if appropriate. -function bnpMultiplyTo(a,r) { - var x = this.abs(), y = a.abs(); - var i = x.t; - r.t = i+y.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); - r.s = 0; - r.clamp(); - if(this.s != a.s) BigInteger.ZERO.subTo(r,r); -} - -// (protected) r = this^2, r != this (HAC 14.16) -function bnpSquareTo(r) { - var x = this.abs(); - var i = r.t = 2*x.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < x.t-1; ++i) { - var c = x.am(i,x[i],r,2*i,0,1); - if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { - r[i+x.t] -= x.DV; - r[i+x.t+1] = 1; - } - } - if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); - r.s = 0; - r.clamp(); -} - -// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) -// r != q, this != m. q or r may be null. -function bnpDivRemTo(m,q,r) { - var pm = m.abs(); - if(pm.t <= 0) return; - var pt = this.abs(); - if(pt.t < pm.t) { - if(q != null) q.fromInt(0); - if(r != null) this.copyTo(r); - return; - } - if(r == null) r = nbi(); - var y = nbi(), ts = this.s, ms = m.s; - var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus - if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } - else { pm.copyTo(y); pt.copyTo(r); } - var ys = y.t; - var y0 = y[ys-1]; - if(y0 == 0) return; - var yt = y0*(1<1)?y[ys-2]>>this.F2:0); - var d1 = this.FV/yt, d2 = (1<= 0) { - r[r.t++] = 1; - r.subTo(t,r); - } - BigInteger.ONE.dlShiftTo(ys,t); - t.subTo(y,y); // "negative" y so we can replace sub with am later - while(y.t < ys) y[y.t++] = 0; - while(--j >= 0) { - // Estimate quotient digit - var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); - if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out - y.dlShiftTo(j,t); - r.subTo(t,r); - while(r[i] < --qd) r.subTo(t,r); - } - } - if(q != null) { - r.drShiftTo(ys,q); - if(ts != ms) BigInteger.ZERO.subTo(q,q); - } - r.t = ys; - r.clamp(); - if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder - if(ts < 0) BigInteger.ZERO.subTo(r,r); -} - -// (public) this mod a -function bnMod(a) { - var r = nbi(); - this.abs().divRemTo(a,null,r); - if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); - return r; -} - -// Modular reduction using "classic" algorithm -function Classic(m) { this.m = m; } -function cConvert(x) { - if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); - else return x; -} -function cRevert(x) { return x; } -function cReduce(x) { x.divRemTo(this.m,null,x); } -function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } -function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -Classic.prototype.convert = cConvert; -Classic.prototype.revert = cRevert; -Classic.prototype.reduce = cReduce; -Classic.prototype.mulTo = cMulTo; -Classic.prototype.sqrTo = cSqrTo; - -// (protected) return "-1/this % 2^DB"; useful for Mont. reduction -// justification: -// xy == 1 (mod m) -// xy = 1+km -// xy(2-xy) = (1+km)(1-km) -// x[y(2-xy)] = 1-k^2m^2 -// x[y(2-xy)] == 1 (mod m^2) -// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 -// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. -// JS multiply "overflows" differently from C/C++, so care is needed here. -function bnpInvDigit() { - if(this.t < 1) return 0; - var x = this[0]; - if((x&1) == 0) return 0; - var y = x&3; // y == 1/x mod 2^2 - y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 - y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 - y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 - // last step - calculate inverse mod DV directly; - // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints - y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits - // we really want the negative inverse, and -DV < y < DV - return (y>0)?this.DV-y:-y; -} - -// Montgomery reduction -function Montgomery(m) { - this.m = m; - this.mp = m.invDigit(); - this.mpl = this.mp&0x7fff; - this.mph = this.mp>>15; - this.um = (1<<(m.DB-15))-1; - this.mt2 = 2*m.t; -} - -// xR mod m -function montConvert(x) { - var r = nbi(); - x.abs().dlShiftTo(this.m.t,r); - r.divRemTo(this.m,null,r); - if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); - return r; -} - -// x/R mod m -function montRevert(x) { - var r = nbi(); - x.copyTo(r); - this.reduce(r); - return r; -} - -// x = x/R mod m (HAC 14.32) -function montReduce(x) { - while(x.t <= this.mt2) // pad x so am has enough room later - x[x.t++] = 0; - for(var i = 0; i < this.m.t; ++i) { - // faster way of calculating u0 = x[i]*mp mod DV - var j = x[i]&0x7fff; - var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; - // use am to combine the multiply-shift-add into one call - j = i+this.m.t; - x[j] += this.m.am(0,u0,x,i,0,this.m.t); - // propagate carry - while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } - } - x.clamp(); - x.drShiftTo(this.m.t,x); - if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); -} - -// r = "x^2/R mod m"; x != r -function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -// r = "xy/R mod m"; x,y != r -function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - -Montgomery.prototype.convert = montConvert; -Montgomery.prototype.revert = montRevert; -Montgomery.prototype.reduce = montReduce; -Montgomery.prototype.mulTo = montMulTo; -Montgomery.prototype.sqrTo = montSqrTo; - -// (protected) true iff this is even -function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } - -// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) -function bnpExp(e,z) { - if(e > 0xffffffff || e < 1) return BigInteger.ONE; - var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; - g.copyTo(r); - while(--i >= 0) { - z.sqrTo(r,r2); - if((e&(1< 0) z.mulTo(r2,g,r); - else { var t = r; r = r2; r2 = t; } - } - return z.revert(r); -} - -// (public) this^e % m, 0 <= e < 2^32 -function bnModPowInt(e,m) { - var z; - if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); - return this.exp(e,z); -} - -// protected -BigInteger.prototype.copyTo = bnpCopyTo; -BigInteger.prototype.fromInt = bnpFromInt; -BigInteger.prototype.fromString = bnpFromString; -BigInteger.prototype.clamp = bnpClamp; -BigInteger.prototype.dlShiftTo = bnpDLShiftTo; -BigInteger.prototype.drShiftTo = bnpDRShiftTo; -BigInteger.prototype.lShiftTo = bnpLShiftTo; -BigInteger.prototype.rShiftTo = bnpRShiftTo; -BigInteger.prototype.subTo = bnpSubTo; -BigInteger.prototype.multiplyTo = bnpMultiplyTo; -BigInteger.prototype.squareTo = bnpSquareTo; -BigInteger.prototype.divRemTo = bnpDivRemTo; -BigInteger.prototype.invDigit = bnpInvDigit; -BigInteger.prototype.isEven = bnpIsEven; -BigInteger.prototype.exp = bnpExp; - -// public -BigInteger.prototype.toString = bnToString; -BigInteger.prototype.negate = bnNegate; -BigInteger.prototype.abs = bnAbs; -BigInteger.prototype.compareTo = bnCompareTo; -BigInteger.prototype.bitLength = bnBitLength; -BigInteger.prototype.mod = bnMod; -BigInteger.prototype.modPowInt = bnModPowInt; - -// "constants" -BigInteger.ZERO = nbv(0); -BigInteger.ONE = nbv(1); +},{"../../util":56,"./jsbn.js":21}],22:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -1524,2129 +8247,141 @@ BigInteger.ONE = nbv(1); // // RSA implementation -function SecureRandom(){ - function nextBytes(byteArray){ - for(var n = 0; n < byteArray.length;n++){ - byteArray[n] = openpgp_crypto_getSecureRandomOctet(); - } +/** + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/public_key/rsa + */ + +var BigInteger = require('./jsbn.js'), + util = require('../../util'), + random = require('../random.js'); + +function SecureRandom() { + function nextBytes(byteArray) { + for (var n = 0; n < byteArray.length; n++) { + byteArray[n] = random.getSecureRandomOctet(); } - this.nextBytes = nextBytes; + } + this.nextBytes = nextBytes; } function RSA() { - /** - * This function uses jsbn Big Num library to decrypt RSA - * @param m - * message - * @param d - * RSA d as BigInteger - * @param p - * RSA p as BigInteger - * @param q - * RSA q as BigInteger - * @param u - * RSA u as BigInteger - * @return {BigInteger} The decrypted value of the message - */ - function decrypt(m, d, p, q, u) { - var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); - var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); - util.print_debug("rsa.js decrypt\nxpn:"+util.hexstrdump(xp.toMPI())+"\nxqn:"+util.hexstrdump(xq.toMPI())); + /** + * This function uses jsbn Big Num library to decrypt RSA + * @param m + * message + * @param d + * RSA d as BigInteger + * @param p + * RSA p as BigInteger + * @param q + * RSA q as BigInteger + * @param u + * RSA u as BigInteger + * @return {BigInteger} The decrypted value of the message + */ + function decrypt(m, d, p, q, u) { + var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); + var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); + util.print_debug("rsa.js decrypt\nxpn:" + util.hexstrdump(xp.toMPI()) + "\nxqn:" + util.hexstrdump(xq.toMPI())); - var t = xq.subtract(xp); - if (t[0] == 0) { - t = xp.subtract(xq); - t = t.multiply(u).mod(q); - t = q.subtract(t); - } else { - t = t.multiply(u).mod(q); - } - return t.multiply(p).add(xp); - } - - /** - * encrypt message - * @param m message as BigInteger - * @param e public MPI part as BigInteger - * @param n public MPI part as BigInteger - * @return BigInteger - */ - function encrypt(m,e,n) { - return m.modPowInt(e, n); - } - - /* Sign and Verify */ - function sign(m,d,n) { - return m.modPow(d, n); - } - - function verify(x,e,n) { - return x.modPowInt(e, n); - } - - // "empty" RSA key constructor - function keyObject() { - this.n = null; - this.e = 0; - this.ee = null; - this.d = null; - this.p = null; - this.q = null; - this.dmp1 = null; - this.dmq1 = null; - this.u = null; + var t = xq.subtract(xp); + if (t[0] == 0) { + t = xp.subtract(xq); + t = t.multiply(u).mod(q); + t = q.subtract(t); + } else { + t = t.multiply(u).mod(q); } - - // Generate a new random private key B bits long, using public expt E - function generate(B,E) { - var key = new keyObject(); - var rng = new SecureRandom(); - var qs = B>>1; - key.e = parseInt(E,16); - key.ee = new BigInteger(E,16); - for(;;) { - for(;;) { - key.p = new BigInteger(B-qs,1,rng); - if(key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) break; - } - for(;;) { - key.q = new BigInteger(qs,1,rng); - if(key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) break; - } - if(key.p.compareTo(key.q) <= 0) { - var t = key.p; - key.p = key.q; - key.q = t; - } - var p1 = key.p.subtract(BigInteger.ONE); - var q1 = key.q.subtract(BigInteger.ONE); - var phi = p1.multiply(q1); - if(phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) { - key.n = key.p.multiply(key.q); - key.d = key.ee.modInverse(phi); - key.dmp1 = key.d.mod(p1); - key.dmq1 = key.d.mod(q1); - key.u = key.p.modInverse(key.q); - break; - } - } - return key; + return t.multiply(p).add(xp); + } + + /** + * encrypt message + * @param m message as BigInteger + * @param e public MPI part as BigInteger + * @param n public MPI part as BigInteger + * @return BigInteger + */ + function encrypt(m, e, n) { + return m.modPowInt(e, n); + } + + /* Sign and Verify */ + function sign(m, d, n) { + return m.modPow(d, n); + } + + function verify(x, e, n) { + return x.modPowInt(e, n); + } + + // "empty" RSA key constructor + + function keyObject() { + this.n = null; + this.e = 0; + this.ee = null; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.u = null; + } + + // Generate a new random private key B bits long, using public expt E + + function generate(B, E) { + var key = new keyObject(); + var rng = new SecureRandom(); + var qs = B >> 1; + key.e = parseInt(E, 16); + key.ee = new BigInteger(E, 16); + for (;;) { + for (;;) { + key.p = new BigInteger(B - qs, 1, rng); + if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) + break; + } + for (;;) { + key.q = new BigInteger(qs, 1, rng); + if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) + break; + } + if (key.p.compareTo(key.q) <= 0) { + var t = key.p; + key.p = key.q; + key.q = t; + } + var p1 = key.p.subtract(BigInteger.ONE); + var q1 = key.q.subtract(BigInteger.ONE); + var phi = p1.multiply(q1); + if (phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) { + key.n = key.p.multiply(key.q); + key.d = key.ee.modInverse(phi); + key.dmp1 = key.d.mod(p1); + key.dmq1 = key.d.mod(q1); + key.u = key.p.modInverse(key.q); + break; + } } - - this.encrypt = encrypt; - this.decrypt = decrypt; - this.verify = verify; - this.sign = sign; - this.generate = generate; - this.keyObject = keyObject; -} -/** - * A fast MD5 JavaScript implementation - * Copyright (c) 2012 Joseph Myers - * http://www.myersdaily.org/joseph/javascript/md5-text.html - * - * Permission to use, copy, modify, and distribute this software - * and its documentation for any purposes and without - * fee is hereby granted provided that this copyright notice - * appears in all copies. - * - * Of course, this soft is provided "as is" without express or implied - * warranty of any kind. - */ - -function MD5(entree) { - var hex = md5(entree); - var bin = util.hex2bin(hex); - return bin; -} - -function md5cycle(x, k) { -var a = x[0], b = x[1], c = x[2], d = x[3]; - -a = ff(a, b, c, d, k[0], 7, -680876936); -d = ff(d, a, b, c, k[1], 12, -389564586); -c = ff(c, d, a, b, k[2], 17, 606105819); -b = ff(b, c, d, a, k[3], 22, -1044525330); -a = ff(a, b, c, d, k[4], 7, -176418897); -d = ff(d, a, b, c, k[5], 12, 1200080426); -c = ff(c, d, a, b, k[6], 17, -1473231341); -b = ff(b, c, d, a, k[7], 22, -45705983); -a = ff(a, b, c, d, k[8], 7, 1770035416); -d = ff(d, a, b, c, k[9], 12, -1958414417); -c = ff(c, d, a, b, k[10], 17, -42063); -b = ff(b, c, d, a, k[11], 22, -1990404162); -a = ff(a, b, c, d, k[12], 7, 1804603682); -d = ff(d, a, b, c, k[13], 12, -40341101); -c = ff(c, d, a, b, k[14], 17, -1502002290); -b = ff(b, c, d, a, k[15], 22, 1236535329); - -a = gg(a, b, c, d, k[1], 5, -165796510); -d = gg(d, a, b, c, k[6], 9, -1069501632); -c = gg(c, d, a, b, k[11], 14, 643717713); -b = gg(b, c, d, a, k[0], 20, -373897302); -a = gg(a, b, c, d, k[5], 5, -701558691); -d = gg(d, a, b, c, k[10], 9, 38016083); -c = gg(c, d, a, b, k[15], 14, -660478335); -b = gg(b, c, d, a, k[4], 20, -405537848); -a = gg(a, b, c, d, k[9], 5, 568446438); -d = gg(d, a, b, c, k[14], 9, -1019803690); -c = gg(c, d, a, b, k[3], 14, -187363961); -b = gg(b, c, d, a, k[8], 20, 1163531501); -a = gg(a, b, c, d, k[13], 5, -1444681467); -d = gg(d, a, b, c, k[2], 9, -51403784); -c = gg(c, d, a, b, k[7], 14, 1735328473); -b = gg(b, c, d, a, k[12], 20, -1926607734); - -a = hh(a, b, c, d, k[5], 4, -378558); -d = hh(d, a, b, c, k[8], 11, -2022574463); -c = hh(c, d, a, b, k[11], 16, 1839030562); -b = hh(b, c, d, a, k[14], 23, -35309556); -a = hh(a, b, c, d, k[1], 4, -1530992060); -d = hh(d, a, b, c, k[4], 11, 1272893353); -c = hh(c, d, a, b, k[7], 16, -155497632); -b = hh(b, c, d, a, k[10], 23, -1094730640); -a = hh(a, b, c, d, k[13], 4, 681279174); -d = hh(d, a, b, c, k[0], 11, -358537222); -c = hh(c, d, a, b, k[3], 16, -722521979); -b = hh(b, c, d, a, k[6], 23, 76029189); -a = hh(a, b, c, d, k[9], 4, -640364487); -d = hh(d, a, b, c, k[12], 11, -421815835); -c = hh(c, d, a, b, k[15], 16, 530742520); -b = hh(b, c, d, a, k[2], 23, -995338651); - -a = ii(a, b, c, d, k[0], 6, -198630844); -d = ii(d, a, b, c, k[7], 10, 1126891415); -c = ii(c, d, a, b, k[14], 15, -1416354905); -b = ii(b, c, d, a, k[5], 21, -57434055); -a = ii(a, b, c, d, k[12], 6, 1700485571); -d = ii(d, a, b, c, k[3], 10, -1894986606); -c = ii(c, d, a, b, k[10], 15, -1051523); -b = ii(b, c, d, a, k[1], 21, -2054922799); -a = ii(a, b, c, d, k[8], 6, 1873313359); -d = ii(d, a, b, c, k[15], 10, -30611744); -c = ii(c, d, a, b, k[6], 15, -1560198380); -b = ii(b, c, d, a, k[13], 21, 1309151649); -a = ii(a, b, c, d, k[4], 6, -145523070); -d = ii(d, a, b, c, k[11], 10, -1120210379); -c = ii(c, d, a, b, k[2], 15, 718787259); -b = ii(b, c, d, a, k[9], 21, -343485551); - -x[0] = add32(a, x[0]); -x[1] = add32(b, x[1]); -x[2] = add32(c, x[2]); -x[3] = add32(d, x[3]); - -} - -function cmn(q, a, b, x, s, t) { -a = add32(add32(a, q), add32(x, t)); -return add32((a << s) | (a >>> (32 - s)), b); -} - -function ff(a, b, c, d, x, s, t) { -return cmn((b & c) | ((~b) & d), a, b, x, s, t); -} - -function gg(a, b, c, d, x, s, t) { -return cmn((b & d) | (c & (~d)), a, b, x, s, t); -} - -function hh(a, b, c, d, x, s, t) { -return cmn(b ^ c ^ d, a, b, x, s, t); -} - -function ii(a, b, c, d, x, s, t) { -return cmn(c ^ (b | (~d)), a, b, x, s, t); -} - -function md51(s) { -txt = ''; -var n = s.length, -state = [1732584193, -271733879, -1732584194, 271733878], i; -for (i=64; i<=s.length; i+=64) { -md5cycle(state, md5blk(s.substring(i-64, i))); -} -s = s.substring(i-64); -var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; -for (i=0; i>2] |= s.charCodeAt(i) << ((i%4) << 3); -tail[i>>2] |= 0x80 << ((i%4) << 3); -if (i > 55) { -md5cycle(state, tail); -for (i=0; i<16; i++) tail[i] = 0; -} -tail[14] = n*8; -md5cycle(state, tail); -return state; -} - -/* there needs to be support for Unicode here, - * unless we pretend that we can redefine the MD-5 - * algorithm for multi-byte characters (perhaps - * by adding every four 16-bit characters and - * shortening the sum to 32 bits). Otherwise - * I suggest performing MD-5 as if every character - * was two bytes--e.g., 0040 0025 = @%--but then - * how will an ordinary MD-5 sum be matched? - * There is no way to standardize text to something - * like UTF-8 before transformation; speed cost is - * utterly prohibitive. The JavaScript standard - * itself needs to look at this: it should start - * providing access to strings as preformed UTF-8 - * 8-bit unsigned value arrays. - */ -function md5blk(s) { /* I figured global was faster. */ -var md5blks = [], i; /* Andy King said do it this way. */ -for (i=0; i<64; i+=4) { -md5blks[i>>2] = s.charCodeAt(i) -+ (s.charCodeAt(i+1) << 8) -+ (s.charCodeAt(i+2) << 16) -+ (s.charCodeAt(i+3) << 24); -} -return md5blks; -} - -var hex_chr = '0123456789abcdef'.split(''); - -function rhex(n) -{ -var s='', j=0; -for(; j<4; j++) -s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] -+ hex_chr[(n >> (j * 8)) & 0x0F]; -return s; -} - -function hex(x) { -for (var i=0; i> 16) + (y >> 16) + (lsw >> 16); -return (msw << 16) | (lsw & 0xFFFF); -} -} -/* - * CryptoMX Tools - * Copyright (C) 2004 - 2006 Derek Buitenhuis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Modified by Recurity Labs GmbH - */ - -var RMDsize = 160; -var X = new Array(); - -function ROL(x, n) -{ - return new Number ((x << n) | ( x >>> (32 - n))); -} - -function F(x, y, z) -{ - return new Number(x ^ y ^ z); -} - -function G(x, y, z) -{ - return new Number((x & y) | (~x & z)); -} - -function H(x, y, z) -{ - return new Number((x | ~y) ^ z); -} - -function I(x, y, z) -{ - return new Number((x & z) | (y & ~z)); -} - -function J(x, y, z) -{ - return new Number(x ^ (y | ~z)); -} - -function mixOneRound(a, b, c, d, e, x, s, roundNumber) -{ - switch (roundNumber) - { - case 0 : a += F(b, c, d) + x + 0x00000000; break; - case 1 : a += G(b, c, d) + x + 0x5a827999; break; - case 2 : a += H(b, c, d) + x + 0x6ed9eba1; break; - case 3 : a += I(b, c, d) + x + 0x8f1bbcdc; break; - case 4 : a += J(b, c, d) + x + 0xa953fd4e; break; - case 5 : a += J(b, c, d) + x + 0x50a28be6; break; - case 6 : a += I(b, c, d) + x + 0x5c4dd124; break; - case 7 : a += H(b, c, d) + x + 0x6d703ef3; break; - case 8 : a += G(b, c, d) + x + 0x7a6d76e9; break; - case 9 : a += F(b, c, d) + x + 0x00000000; break; - - default : document.write("Bogus round number"); break; - } - - a = ROL(a, s) + e; - c = ROL(c, 10); - - a &= 0xffffffff; - b &= 0xffffffff; - c &= 0xffffffff; - d &= 0xffffffff; - e &= 0xffffffff; - - var retBlock = new Array(); - retBlock[0] = a; - retBlock[1] = b; - retBlock[2] = c; - retBlock[3] = d; - retBlock[4] = e; - retBlock[5] = x; - retBlock[6] = s; - - return retBlock; -} - -function MDinit (MDbuf) -{ - MDbuf[0] = 0x67452301; - MDbuf[1] = 0xefcdab89; - MDbuf[2] = 0x98badcfe; - MDbuf[3] = 0x10325476; - MDbuf[4] = 0xc3d2e1f0; -} - -var ROLs = [ - [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8], - [ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12], - [11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5], - [11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12], - [ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6], - [ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6], - [ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11], - [ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5], - [15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8], - [ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11] -]; - -var indexes = [ - [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - [ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8], - [ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12], - [ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2], - [ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], - [ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12], - [ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2], - [15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13], - [ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14], - [12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11] -]; - -function compress (MDbuf, X) -{ - blockA = new Array(); - blockB = new Array(); - - var retBlock; - - for (var i=0; i < 5; i++) - { - blockA[i] = new Number(MDbuf[i]); - blockB[i] = new Number(MDbuf[i]); + return key; } - var step = 0; - for (var j = 0; j < 5; j++) - { - for (var i = 0; i < 16; i++) - { - retBlock = mixOneRound( - blockA[(step+0) % 5], - blockA[(step+1) % 5], - blockA[(step+2) % 5], - blockA[(step+3) % 5], - blockA[(step+4) % 5], - X[indexes[j][i]], - ROLs[j][i], - j - ); - - blockA[(step+0) % 5] = retBlock[0]; - blockA[(step+1) % 5] = retBlock[1]; - blockA[(step+2) % 5] = retBlock[2]; - blockA[(step+3) % 5] = retBlock[3]; - blockA[(step+4) % 5] = retBlock[4]; - - step += 4; - } - } - - step = 0; - for (var j = 5; j < 10; j++) - { - for (var i = 0; i < 16; i++) - { - retBlock = mixOneRound( - blockB[(step+0) % 5], - blockB[(step+1) % 5], - blockB[(step+2) % 5], - blockB[(step+3) % 5], - blockB[(step+4) % 5], - X[indexes[j][i]], - ROLs[j][i], - j - ); - - blockB[(step+0) % 5] = retBlock[0]; - blockB[(step+1) % 5] = retBlock[1]; - blockB[(step+2) % 5] = retBlock[2]; - blockB[(step+3) % 5] = retBlock[3]; - blockB[(step+4) % 5] = retBlock[4]; - - step += 4; - } - } - - blockB[3] += blockA[2] + MDbuf[1]; - MDbuf[1] = MDbuf[2] + blockA[3] + blockB[4]; - MDbuf[2] = MDbuf[3] + blockA[4] + blockB[0]; - MDbuf[3] = MDbuf[4] + blockA[0] + blockB[1]; - MDbuf[4] = MDbuf[0] + blockA[1] + blockB[2]; - MDbuf[0] = blockB[3]; + this.encrypt = encrypt; + this.decrypt = decrypt; + this.verify = verify; + this.sign = sign; + this.generate = generate; + this.keyObject = keyObject; } -function zeroX(X) -{ - for (var i = 0; i < 16; i++) { X[i] = 0; } -} +module.exports = RSA; -function MDfinish (MDbuf, strptr, lswlen, mswlen) -{ - var X = new Array(16); - zeroX(X); - - var j = 0; - for (var i=0; i < (lswlen & 63); i++) - { - X[i >>> 2] ^= (strptr.charCodeAt(j++) & 255) << (8 * (i & 3)); - } - - X[(lswlen >>> 2) & 15] ^= 1 << (8 * (lswlen & 3) + 7); - - if ((lswlen & 63) > 55) - { - compress(MDbuf, X); - var X = new Array(16); - zeroX(X); - } - - X[14] = lswlen << 3; - X[15] = (lswlen >>> 29) | (mswlen << 3); - - compress(MDbuf, X); -} - -function BYTES_TO_DWORD(fourChars) -{ - var tmp = (fourChars.charCodeAt(3) & 255) << 24; - tmp |= (fourChars.charCodeAt(2) & 255) << 16; - tmp |= (fourChars.charCodeAt(1) & 255) << 8; - tmp |= (fourChars.charCodeAt(0) & 255); - - return tmp; -} - -function RMD(message) -{ - var MDbuf = new Array(RMDsize / 32); - var hashcode = new Array(RMDsize / 8); - var length; - var nbytes; - - MDinit(MDbuf); - length = message.length; - - var X = new Array(16); - zeroX(X); - - var j=0; - for (var nbytes=length; nbytes > 63; nbytes -= 64) - { - for (var i=0; i < 16; i++) - { - X[i] = BYTES_TO_DWORD(message.substr(j, 4)); - j += 4; - } - compress(MDbuf, X); - } - - MDfinish(MDbuf, message.substr(j), length, 0); - - for (var i=0; i < RMDsize / 8; i += 4) - { - hashcode[i] = MDbuf[i >>> 2] & 255; - hashcode[i+1] = (MDbuf[i >>> 2] >>> 8) & 255; - hashcode[i+2] = (MDbuf[i >>> 2] >>> 16) & 255; - hashcode[i+3] = (MDbuf[i >>> 2] >>> 24) & 255; - } - - return hashcode; -} - - -function RMDstring(message) -{ - var hashcode = RMD(message); - var retString = ""; - - for (var i=0; i < RMDsize/8; i++) - { - retString += String.fromCharCode(hashcode[i]); - } - - return retString; -}/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS - * PUB 180-2 as well as the corresponding HMAC implementation as defined in - * FIPS PUB 198a - * - * Version 1.3 Copyright Brian Turek 2008-2010 - * Distributed under the BSD License - * See http://jssha.sourceforge.net/ for more information - * - * Several functions taken from Paul Johnson - */ - -/* Modified by Recurity Labs GmbH - * - * This code has been slightly modified direct string output: - * - bin2bstr has been added - * - following wrappers of this library have been added: - * - str_sha1 - * - str_sha256 - * - str_sha224 - * - str_sha384 - * - str_sha512 - */ - -var jsSHA = (function () { - - /* - * Configurable variables. Defaults typically work - */ - /* Number of Bits Per character (8 for ASCII, 16 for Unicode) */ - var charSize = 8, - /* base-64 pad character. "=" for strict RFC compliance */ - b64pad = "", - /* hex output format. 0 - lowercase; 1 - uppercase */ - hexCase = 0, - - /* - * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number - * - * @constructor - * @param {Number} msint_32 The most significant 32-bits of a 64-bit number - * @param {Number} lsint_32 The least significant 32-bits of a 64-bit number - */ - Int_64 = function (msint_32, lsint_32) - { - this.highOrder = msint_32; - this.lowOrder = lsint_32; - }, - - /* - * Convert a string to an array of big-endian words - * If charSize is ASCII, characters >255 have their hi-byte silently - * ignored. - * - * @param {String} str String to be converted to binary representation - * @return Integer array representation of the parameter - */ - str2binb = function (str) - { - var bin = [], mask = (1 << charSize) - 1, - length = str.length * charSize, i; - - for (i = 0; i < length; i += charSize) - { - bin[i >> 5] |= (str.charCodeAt(i / charSize) & mask) << - (32 - charSize - (i % 32)); - } - - return bin; - }, - - /* - * Convert a hex string to an array of big-endian words - * - * @param {String} str String to be converted to binary representation - * @return Integer array representation of the parameter - */ - hex2binb = function (str) - { - var bin = [], length = str.length, i, num; - - for (i = 0; i < length; i += 2) - { - num = parseInt(str.substr(i, 2), 16); - if (!isNaN(num)) - { - bin[i >> 3] |= num << (24 - (4 * (i % 8))); - } - else - { - return "INVALID HEX STRING"; - } - } - - return bin; - }, - - /* - * Convert an array of big-endian words to a hex string. - * - * @private - * @param {Array} binarray Array of integers to be converted to hexidecimal - * representation - * @return Hexidecimal representation of the parameter in String form - */ - binb2hex = function (binarray) - { - var hex_tab = (hexCase) ? "0123456789ABCDEF" : "0123456789abcdef", - str = "", length = binarray.length * 4, i, srcByte; - - for (i = 0; i < length; i += 1) - { - srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); - str += hex_tab.charAt((srcByte >> 4) & 0xF) + - hex_tab.charAt(srcByte & 0xF); - } - - return str; - }, - - /* - * Convert an array of big-endian words to a base-64 string - * - * @private - * @param {Array} binarray Array of integers to be converted to base-64 - * representation - * @return Base-64 encoded representation of the parameter in String form - */ - binb2b64 = function (binarray) - { - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + - "0123456789+/", str = "", length = binarray.length * 4, i, j, - triplet; - - for (i = 0; i < length; i += 3) - { - triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | - (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | - ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); - for (j = 0; j < 4; j += 1) - { - if (i * 8 + j * 6 <= binarray.length * 32) - { - str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); - } - else - { - str += b64pad; - } - } - } - return str; - }, - - /* - * Convert an array of big-endian words to a string - */ - binb2str = function (bin) - { - var str = ""; - var mask = (1 << 8) - 1; - for(var i = 0; i < bin.length * 32; i += 8) - str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask); - return str; - }, - /* - * The 32-bit implementation of circular rotate left - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotl_32 = function (x, n) - { - return (x << n) | (x >>> (32 - n)); - }, - - /* - * The 32-bit implementation of circular rotate right - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotr_32 = function (x, n) - { - return (x >>> n) | (x << (32 - n)); - }, - - /* - * The 64-bit implementation of circular rotate right - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotr_64 = function (x, n) - { - if (n <= 32) - { - return new Int_64( - (x.highOrder >>> n) | (x.lowOrder << (32 - n)), - (x.lowOrder >>> n) | (x.highOrder << (32 - n)) - ); - } - else - { - return new Int_64( - (x.lowOrder >>> n) | (x.highOrder << (32 - n)), - (x.highOrder >>> n) | (x.lowOrder << (32 - n)) - ); - } - }, - - /* - * The 32-bit implementation of shift right - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted by n bits - */ - shr_32 = function (x, n) - { - return x >>> n; - }, - - /* - * The 64-bit implementation of shift right - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted by n bits - */ - shr_64 = function (x, n) - { - if (n <= 32) - { - return new Int_64( - x.highOrder >>> n, - x.lowOrder >>> n | (x.highOrder << (32 - n)) - ); - } - else - { - return new Int_64( - 0, - x.highOrder << (32 - n) - ); - } - }, - - /* - * The 32-bit implementation of the NIST specified Parity function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - parity_32 = function (x, y, z) - { - return x ^ y ^ z; - }, - - /* - * The 32-bit implementation of the NIST specified Ch function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - ch_32 = function (x, y, z) - { - return (x & y) ^ (~x & z); - }, - - /* - * The 64-bit implementation of the NIST specified Ch function - * - * @private - * @param {Int_64} x The first 64-bit integer argument - * @param {Int_64} y The second 64-bit integer argument - * @param {Int_64} z The third 64-bit integer argument - * @return The NIST specified output of the function - */ - ch_64 = function (x, y, z) - { - return new Int_64( - (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), - (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder) - ); - }, - - /* - * The 32-bit implementation of the NIST specified Maj function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - maj_32 = function (x, y, z) - { - return (x & y) ^ (x & z) ^ (y & z); - }, - - /* - * The 64-bit implementation of the NIST specified Maj function - * - * @private - * @param {Int_64} x The first 64-bit integer argument - * @param {Int_64} y The second 64-bit integer argument - * @param {Int_64} z The third 64-bit integer argument - * @return The NIST specified output of the function - */ - maj_64 = function (x, y, z) - { - return new Int_64( - (x.highOrder & y.highOrder) ^ - (x.highOrder & z.highOrder) ^ - (y.highOrder & z.highOrder), - (x.lowOrder & y.lowOrder) ^ - (x.lowOrder & z.lowOrder) ^ - (y.lowOrder & z.lowOrder) - ); - }, - - /* - * The 32-bit implementation of the NIST specified Sigma0 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - sigma0_32 = function (x) - { - return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22); - }, - - /* - * The 64-bit implementation of the NIST specified Sigma0 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - sigma0_64 = function (x) - { - var rotr28 = rotr_64(x, 28), rotr34 = rotr_64(x, 34), - rotr39 = rotr_64(x, 39); - - return new Int_64( - rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, - rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder); - }, - - /* - * The 32-bit implementation of the NIST specified Sigma1 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - sigma1_32 = function (x) - { - return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25); - }, - - /* - * The 64-bit implementation of the NIST specified Sigma1 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - sigma1_64 = function (x) - { - var rotr14 = rotr_64(x, 14), rotr18 = rotr_64(x, 18), - rotr41 = rotr_64(x, 41); - - return new Int_64( - rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, - rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder); - }, - - /* - * The 32-bit implementation of the NIST specified Gamma0 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - gamma0_32 = function (x) - { - return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3); - }, - - /* - * The 64-bit implementation of the NIST specified Gamma0 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - gamma0_64 = function (x) - { - var rotr1 = rotr_64(x, 1), rotr8 = rotr_64(x, 8), shr7 = shr_64(x, 7); - - return new Int_64( - rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, - rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder - ); - }, - - /* - * The 32-bit implementation of the NIST specified Gamma1 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - gamma1_32 = function (x) - { - return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10); - }, - - /* - * The 64-bit implementation of the NIST specified Gamma1 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - gamma1_64 = function (x) - { - var rotr19 = rotr_64(x, 19), rotr61 = rotr_64(x, 61), - shr6 = shr_64(x, 6); - - return new Int_64( - rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, - rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder - ); - }, - - /* - * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} x The first 32-bit integer argument to be added - * @param {Number} y The second 32-bit integer argument to be added - * @return The sum of x + y - */ - safeAdd_32_2 = function (x, y) - { - var lsw = (x & 0xFFFF) + (y & 0xFFFF), - msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16); - - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, - - /* - * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} a The first 32-bit integer argument to be added - * @param {Number} b The second 32-bit integer argument to be added - * @param {Number} c The third 32-bit integer argument to be added - * @param {Number} d The fourth 32-bit integer argument to be added - * @return The sum of a + b + c + d - */ - safeAdd_32_4 = function (a, b, c, d) - { - var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF), - msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + - (lsw >>> 16); - - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, - - /* - * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} a The first 32-bit integer argument to be added - * @param {Number} b The second 32-bit integer argument to be added - * @param {Number} c The third 32-bit integer argument to be added - * @param {Number} d The fourth 32-bit integer argument to be added - * @param {Number} e The fifth 32-bit integer argument to be added - * @return The sum of a + b + c + d + e - */ - safeAdd_32_5 = function (a, b, c, d, e) - { - var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) + - (e & 0xFFFF), - msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + - (e >>> 16) + (lsw >>> 16); - - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, - - /* - * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} x The first 64-bit integer argument to be added - * @param {Int_64} y The second 64-bit integer argument to be added - * @return The sum of x + y - */ - safeAdd_64_2 = function (x, y) - { - var lsw, msw, lowOrder, highOrder; - - lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF); - msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16); - msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - return new Int_64(highOrder, lowOrder); - }, - - /* - * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} a The first 64-bit integer argument to be added - * @param {Int_64} b The second 64-bit integer argument to be added - * @param {Int_64} c The third 64-bit integer argument to be added - * @param {Int_64} d The fouth 64-bit integer argument to be added - * @return The sum of a + b + c + d - */ - safeAdd_64_4 = function (a, b, c, d) - { - var lsw, msw, lowOrder, highOrder; - - lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + - (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF); - msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + - (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16); - msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + - (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - return new Int_64(highOrder, lowOrder); - }, - - /* - * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} a The first 64-bit integer argument to be added - * @param {Int_64} b The second 64-bit integer argument to be added - * @param {Int_64} c The third 64-bit integer argument to be added - * @param {Int_64} d The fouth 64-bit integer argument to be added - * @param {Int_64} e The fouth 64-bit integer argument to be added - * @return The sum of a + b + c + d + e - */ - safeAdd_64_5 = function (a, b, c, d, e) - { - var lsw, msw, lowOrder, highOrder; - - lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + - (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + - (e.lowOrder & 0xFFFF); - msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + - (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + - (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + - (e.highOrder & 0xFFFF) + (msw >>> 16); - msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + - (c.highOrder >>> 16) + (d.highOrder >>> 16) + - (e.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - return new Int_64(highOrder, lowOrder); - }, - - /* - * Calculates the SHA-1 hash of the string set at instantiation - * - * @private - * @param {Array} message The binary array representation of the string to - * hash - * @param {Number} messageLen The number of bits in the message - * @return The array of integers representing the SHA-1 hash of message - */ - coreSHA1 = function (message, messageLen) - { - var W = [], a, b, c, d, e, T, ch = ch_32, parity = parity_32, - maj = maj_32, rotl = rotl_32, safeAdd_2 = safeAdd_32_2, i, t, - safeAdd_5 = safeAdd_32_5, appendedMessageLength, - H = [ - 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 - ], - K = [ - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 - ]; - - /* Append '1' at the end of the binary string */ - message[messageLen >> 5] |= 0x80 << (24 - (messageLen % 32)); - /* Append length of binary string in the position such that the new - length is a multiple of 512. Logic does not work for even multiples - of 512 but there can never be even multiples of 512 */ - message[(((messageLen + 65) >> 9) << 4) + 15] = messageLen; - - appendedMessageLength = message.length; - - for (i = 0; i < appendedMessageLength; i += 16) - { - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - - for (t = 0; t < 80; t += 1) - { - if (t < 16) - { - W[t] = message[t + i]; - } - else - { - W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); - } - - if (t < 20) - { - T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, K[t], W[t]); - } - else if (t < 40) - { - T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); - } - else if (t < 60) - { - T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, K[t], W[t]); - } else { - T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); - } - - e = d; - d = c; - c = rotl(b, 30); - b = a; - a = T; - } - - H[0] = safeAdd_2(a, H[0]); - H[1] = safeAdd_2(b, H[1]); - H[2] = safeAdd_2(c, H[2]); - H[3] = safeAdd_2(d, H[3]); - H[4] = safeAdd_2(e, H[4]); - } - - return H; - }, - - /* - * Calculates the desired SHA-2 hash of the string set at instantiation - * - * @private - * @param {Array} The binary array representation of the string to hash - * @param {Number} The number of bits in message - * @param {String} variant The desired SHA-2 variant - * @return The array of integers representing the SHA-2 hash of message - */ - coreSHA2 = function (message, messageLen, variant) - { - var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t, - binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5, - gamma0, gamma1, sigma0, sigma1, ch, maj, Int, K, W = [], - appendedMessageLength; - - /* Set up the various function handles and variable for the specific - * variant */ - if (variant === "SHA-224" || variant === "SHA-256") - { - /* 32-bit variant */ - numRounds = 64; - lengthPosition = (((messageLen + 65) >> 9) << 4) + 15; - binaryStringInc = 16; - binaryStringMult = 1; - Int = Number; - safeAdd_2 = safeAdd_32_2; - safeAdd_4 = safeAdd_32_4; - safeAdd_5 = safeAdd_32_5; - gamma0 = gamma0_32; - gamma1 = gamma1_32; - sigma0 = sigma0_32; - sigma1 = sigma1_32; - maj = maj_32; - ch = ch_32; - K = [ - 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, - 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, - 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, - 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, - 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, - 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, - 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, - 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, - 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, - 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, - 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, - 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, - 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, - 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, - 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, - 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 - ]; - - if (variant === "SHA-224") - { - H = [ - 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, - 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 - ]; - } - else - { - H = [ - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 - ]; - } - } - else if (variant === "SHA-384" || variant === "SHA-512") - { - /* 64-bit variant */ - numRounds = 80; - lengthPosition = (((messageLen + 128) >> 10) << 5) + 31; - binaryStringInc = 32; - binaryStringMult = 2; - Int = Int_64; - safeAdd_2 = safeAdd_64_2; - safeAdd_4 = safeAdd_64_4; - safeAdd_5 = safeAdd_64_5; - gamma0 = gamma0_64; - gamma1 = gamma1_64; - sigma0 = sigma0_64; - sigma1 = sigma1_64; - maj = maj_64; - ch = ch_64; - - K = [ - new Int(0x428a2f98, 0xd728ae22), new Int(0x71374491, 0x23ef65cd), - new Int(0xb5c0fbcf, 0xec4d3b2f), new Int(0xe9b5dba5, 0x8189dbbc), - new Int(0x3956c25b, 0xf348b538), new Int(0x59f111f1, 0xb605d019), - new Int(0x923f82a4, 0xaf194f9b), new Int(0xab1c5ed5, 0xda6d8118), - new Int(0xd807aa98, 0xa3030242), new Int(0x12835b01, 0x45706fbe), - new Int(0x243185be, 0x4ee4b28c), new Int(0x550c7dc3, 0xd5ffb4e2), - new Int(0x72be5d74, 0xf27b896f), new Int(0x80deb1fe, 0x3b1696b1), - new Int(0x9bdc06a7, 0x25c71235), new Int(0xc19bf174, 0xcf692694), - new Int(0xe49b69c1, 0x9ef14ad2), new Int(0xefbe4786, 0x384f25e3), - new Int(0x0fc19dc6, 0x8b8cd5b5), new Int(0x240ca1cc, 0x77ac9c65), - new Int(0x2de92c6f, 0x592b0275), new Int(0x4a7484aa, 0x6ea6e483), - new Int(0x5cb0a9dc, 0xbd41fbd4), new Int(0x76f988da, 0x831153b5), - new Int(0x983e5152, 0xee66dfab), new Int(0xa831c66d, 0x2db43210), - new Int(0xb00327c8, 0x98fb213f), new Int(0xbf597fc7, 0xbeef0ee4), - new Int(0xc6e00bf3, 0x3da88fc2), new Int(0xd5a79147, 0x930aa725), - new Int(0x06ca6351, 0xe003826f), new Int(0x14292967, 0x0a0e6e70), - new Int(0x27b70a85, 0x46d22ffc), new Int(0x2e1b2138, 0x5c26c926), - new Int(0x4d2c6dfc, 0x5ac42aed), new Int(0x53380d13, 0x9d95b3df), - new Int(0x650a7354, 0x8baf63de), new Int(0x766a0abb, 0x3c77b2a8), - new Int(0x81c2c92e, 0x47edaee6), new Int(0x92722c85, 0x1482353b), - new Int(0xa2bfe8a1, 0x4cf10364), new Int(0xa81a664b, 0xbc423001), - new Int(0xc24b8b70, 0xd0f89791), new Int(0xc76c51a3, 0x0654be30), - new Int(0xd192e819, 0xd6ef5218), new Int(0xd6990624, 0x5565a910), - new Int(0xf40e3585, 0x5771202a), new Int(0x106aa070, 0x32bbd1b8), - new Int(0x19a4c116, 0xb8d2d0c8), new Int(0x1e376c08, 0x5141ab53), - new Int(0x2748774c, 0xdf8eeb99), new Int(0x34b0bcb5, 0xe19b48a8), - new Int(0x391c0cb3, 0xc5c95a63), new Int(0x4ed8aa4a, 0xe3418acb), - new Int(0x5b9cca4f, 0x7763e373), new Int(0x682e6ff3, 0xd6b2b8a3), - new Int(0x748f82ee, 0x5defb2fc), new Int(0x78a5636f, 0x43172f60), - new Int(0x84c87814, 0xa1f0ab72), new Int(0x8cc70208, 0x1a6439ec), - new Int(0x90befffa, 0x23631e28), new Int(0xa4506ceb, 0xde82bde9), - new Int(0xbef9a3f7, 0xb2c67915), new Int(0xc67178f2, 0xe372532b), - new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207), - new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178), - new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6), - new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b), - new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493), - new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c), - new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a), - new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817) - ]; - - if (variant === "SHA-384") - { - H = [ - new Int(0xcbbb9d5d, 0xc1059ed8), new Int(0x0629a292a, 0x367cd507), - new Int(0x9159015a, 0x3070dd17), new Int(0x0152fecd8, 0xf70e5939), - new Int(0x67332667, 0xffc00b31), new Int(0x98eb44a87, 0x68581511), - new Int(0xdb0c2e0d, 0x64f98fa7), new Int(0x047b5481d, 0xbefa4fa4) - ]; - } - else - { - H = [ - new Int(0x6a09e667, 0xf3bcc908), new Int(0xbb67ae85, 0x84caa73b), - new Int(0x3c6ef372, 0xfe94f82b), new Int(0xa54ff53a, 0x5f1d36f1), - new Int(0x510e527f, 0xade682d1), new Int(0x9b05688c, 0x2b3e6c1f), - new Int(0x1f83d9ab, 0xfb41bd6b), new Int(0x5be0cd19, 0x137e2179) - ]; - } - } - - /* Append '1' at the end of the binary string */ - message[messageLen >> 5] |= 0x80 << (24 - messageLen % 32); - /* Append length of binary string in the position such that the new - * length is correct */ - message[lengthPosition] = messageLen; - - appendedMessageLength = message.length; - - for (i = 0; i < appendedMessageLength; i += binaryStringInc) - { - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - f = H[5]; - g = H[6]; - h = H[7]; - - for (t = 0; t < numRounds; t += 1) - { - if (t < 16) - { - /* Bit of a hack - for 32-bit, the second term is ignored */ - W[t] = new Int(message[t * binaryStringMult + i], - message[t * binaryStringMult + i + 1]); - } - else - { - W[t] = safeAdd_4( - gamma1(W[t - 2]), W[t - 7], - gamma0(W[t - 15]), W[t - 16] - ); - } - - T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]); - T2 = safeAdd_2(sigma0(a), maj(a, b, c)); - h = g; - g = f; - f = e; - e = safeAdd_2(d, T1); - d = c; - c = b; - b = a; - a = safeAdd_2(T1, T2); - } - - H[0] = safeAdd_2(a, H[0]); - H[1] = safeAdd_2(b, H[1]); - H[2] = safeAdd_2(c, H[2]); - H[3] = safeAdd_2(d, H[3]); - H[4] = safeAdd_2(e, H[4]); - H[5] = safeAdd_2(f, H[5]); - H[6] = safeAdd_2(g, H[6]); - H[7] = safeAdd_2(h, H[7]); - } - - switch (variant) - { - case "SHA-224": - return [ - H[0], H[1], H[2], H[3], - H[4], H[5], H[6] - ]; - case "SHA-256": - return H; - case "SHA-384": - return [ - H[0].highOrder, H[0].lowOrder, - H[1].highOrder, H[1].lowOrder, - H[2].highOrder, H[2].lowOrder, - H[3].highOrder, H[3].lowOrder, - H[4].highOrder, H[4].lowOrder, - H[5].highOrder, H[5].lowOrder - ]; - case "SHA-512": - return [ - H[0].highOrder, H[0].lowOrder, - H[1].highOrder, H[1].lowOrder, - H[2].highOrder, H[2].lowOrder, - H[3].highOrder, H[3].lowOrder, - H[4].highOrder, H[4].lowOrder, - H[5].highOrder, H[5].lowOrder, - H[6].highOrder, H[6].lowOrder, - H[7].highOrder, H[7].lowOrder - ]; - default: - /* This should never be reached */ - return []; - } - }, - - /* - * jsSHA is the workhorse of the library. Instantiate it with the string to - * be hashed as the parameter - * - * @constructor - * @param {String} srcString The string to be hashed - * @param {String} inputFormat The format of srcString, ASCII or HEX - */ - jsSHA = function (srcString, inputFormat) - { - - this.sha1 = null; - this.sha224 = null; - this.sha256 = null; - this.sha384 = null; - this.sha512 = null; - - this.strBinLen = null; - this.strToHash = null; - - /* Convert the input string into the correct type */ - if ("HEX" === inputFormat) - { - if (0 !== (srcString.length % 2)) - { - return "TEXT MUST BE IN BYTE INCREMENTS"; - } - this.strBinLen = srcString.length * 4; - this.strToHash = hex2binb(srcString); - } - else if (("ASCII" === inputFormat) || - ('undefined' === typeof(inputFormat))) - { - this.strBinLen = srcString.length * charSize; - this.strToHash = str2binb(srcString); - } - else - { - return "UNKNOWN TEXT INPUT TYPE"; - } - }; - - jsSHA.prototype = { - /* - * Returns the desired SHA hash of the string specified at instantiation - * using the specified parameters - * - * @param {String} variant The desired SHA variant (SHA-1, SHA-224, - * SHA-256, SHA-384, or SHA-512) - * @param {String} format The desired output formatting (B64 or HEX) - * @return The string representation of the hash in the format specified - */ - getHash : function (variant, format) - { - var formatFunc = null, message = this.strToHash.slice(); - - switch (format) - { - case "HEX": - formatFunc = binb2hex; - break; - case "B64": - formatFunc = binb2b64; - break; - case "ASCII": - formatFunc = binb2str; - break; - default: - return "FORMAT NOT RECOGNIZED"; - } - - switch (variant) - { - case "SHA-1": - if (null === this.sha1) - { - this.sha1 = coreSHA1(message, this.strBinLen); - } - return formatFunc(this.sha1); - case "SHA-224": - if (null === this.sha224) - { - this.sha224 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha224); - case "SHA-256": - if (null === this.sha256) - { - this.sha256 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha256); - case "SHA-384": - if (null === this.sha384) - { - this.sha384 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha384); - case "SHA-512": - if (null === this.sha512) - { - this.sha512 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha512); - default: - return "HASH NOT RECOGNIZED"; - } - }, - - /* - * Returns the desired HMAC of the string specified at instantiation - * using the key and variant param. - * - * @param {String} key The key used to calculate the HMAC - * @param {String} inputFormat The format of key, ASCII or HEX - * @param {String} variant The desired SHA variant (SHA-1, SHA-224, - * SHA-256, SHA-384, or SHA-512) - * @param {String} outputFormat The desired output formatting - * (B64 or HEX) - * @return The string representation of the hash in the format specified - */ - getHMAC : function (key, inputFormat, variant, outputFormat) - { - var formatFunc, keyToUse, blockByteSize, blockBitSize, i, - retVal, lastArrayIndex, keyBinLen, hashBitSize, - keyWithIPad = [], keyWithOPad = []; - - /* Validate the output format selection */ - switch (outputFormat) - { - case "HEX": - formatFunc = binb2hex; - break; - case "B64": - formatFunc = binb2b64; - break; - case "ASCII": - formatFunc = binb2str; - break; - default: - return "FORMAT NOT RECOGNIZED"; - } - - /* Validate the hash variant selection and set needed variables */ - switch (variant) - { - case "SHA-1": - blockByteSize = 64; - hashBitSize = 160; - break; - case "SHA-224": - blockByteSize = 64; - hashBitSize = 224; - break; - case "SHA-256": - blockByteSize = 64; - hashBitSize = 256; - break; - case "SHA-384": - blockByteSize = 128; - hashBitSize = 384; - break; - case "SHA-512": - blockByteSize = 128; - hashBitSize = 512; - break; - default: - return "HASH NOT RECOGNIZED"; - } - - /* Validate input format selection */ - if ("HEX" === inputFormat) - { - /* Nibbles must come in pairs */ - if (0 !== (key.length % 2)) - { - return "KEY MUST BE IN BYTE INCREMENTS"; - } - keyToUse = hex2binb(key); - keyBinLen = key.length * 4; - } - else if ("ASCII" === inputFormat) - { - keyToUse = str2binb(key); - keyBinLen = key.length * charSize; - } - else - { - return "UNKNOWN KEY INPUT TYPE"; - } - - /* These are used multiple times, calculate and store them */ - blockBitSize = blockByteSize * 8; - lastArrayIndex = (blockByteSize / 4) - 1; - - /* Figure out what to do with the key based on its size relative to - * the hash's block size */ - if (blockByteSize < (keyBinLen / 8)) - { - if ("SHA-1" === variant) - { - keyToUse = coreSHA1(keyToUse, keyBinLen); - } - else - { - keyToUse = coreSHA2(keyToUse, keyBinLen, variant); - } - /* For all variants, the block size is bigger than the output - * size so there will never be a useful byte at the end of the - * string */ - keyToUse[lastArrayIndex] &= 0xFFFFFF00; - } - else if (blockByteSize > (keyBinLen / 8)) - { - /* If the blockByteSize is greater than the key length, there - * will always be at LEAST one "useless" byte at the end of the - * string */ - keyToUse[lastArrayIndex] &= 0xFFFFFF00; - } - - /* Create ipad and opad */ - for (i = 0; i <= lastArrayIndex; i += 1) - { - keyWithIPad[i] = keyToUse[i] ^ 0x36363636; - keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C; - } - - /* Calculate the HMAC */ - if ("SHA-1" === variant) - { - retVal = coreSHA1( - keyWithIPad.concat(this.strToHash), - blockBitSize + this.strBinLen); - retVal = coreSHA1( - keyWithOPad.concat(retVal), - blockBitSize + hashBitSize); - } - else - { - retVal = coreSHA2( - keyWithIPad.concat(this.strToHash), - blockBitSize + this.strBinLen, variant); - retVal = coreSHA2( - keyWithOPad.concat(retVal), - blockBitSize + hashBitSize, variant); - } - - return (formatFunc(retVal)); - } - }; - - return jsSHA; -}()); - -function str_sha1(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-1", "ASCII"); -} - -function str_sha224(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-224", "ASCII"); -} - -function str_sha256(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-256", "ASCII"); -} - - -function str_sha384(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-384", "ASCII"); - -} - -function str_sha512(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-512", "ASCII"); -} -// Modified by Recurity Labs GmbH - -// modified version of http://www.hanewin.net/encrypt/PGdecode.js: - -/* OpenPGP encryption using RSA/AES - * Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de - * version 2.0, check www.haneWIN.de for the latest version - - * This software is provided as-is, without express or implied warranty. - * Permission to use, copy, modify, distribute or sell this software, with or - * without fee, for any purpose and by any individual or organization, is hereby - * granted, provided that the above copyright notice and this paragraph appear - * in all copies. Distribution as a part of an application or binary must - * include the above copyright notice in the documentation and/or other - * materials provided with the application or distribution. - */ - -/** - * An array of bytes, that is integers with values from 0 to 255 - * @typedef {(Array|Uint8Array)} openpgp_byte_array - */ - -/** - * Block cipher function - * @callback openpgp_cipher_block_fn - * @param {openpgp_byte_array} block A block to perform operations on - * @param {openpgp_byte_array} key to use in encryption/decryption - * @return {openpgp_byte_array} Encrypted/decrypted block - */ - - -// -------------------------------------- -/** - * This function encrypts a given with the specified prefixrandom - * using the specified blockcipher to encrypt a message - * @param {String} prefixrandom random bytes of block_size length provided - * as a string to be used in prefixing the data - * @param {openpgp_cipher_block_fn} blockcipherfn the algorithm encrypt function to encrypt - * data in one block_size encryption. - * @param {Integer} block_size the block size in bytes of the algorithm used - * @param {String} plaintext data to be encrypted provided as a string - * @param {openpgp_byte_array} key key to be used to encrypt the data. This will be passed to the - * blockcipherfn - * @param {Boolean} resync a boolean value specifying if a resync of the - * IV should be used or not. The encrypteddatapacket uses the - * "old" style with a resync. Encryption within an - * encryptedintegrityprotecteddata packet is not resyncing the IV. - * @return {String} a string with the encrypted data - */ -function openpgp_cfb_encrypt(prefixrandom, blockcipherencryptfn, plaintext, block_size, key, resync) { - var FR = new Array(block_size); - var FRE = new Array(block_size); - - prefixrandom = prefixrandom + prefixrandom.charAt(block_size-2) +prefixrandom.charAt(block_size-1); - util.print_debug("prefixrandom:"+util.hexstrdump(prefixrandom)); - var ciphertext = ""; - // 1. The feedback register (FR) is set to the IV, which is all zeros. - for (var i = 0; i < block_size; i++) FR[i] = 0; - - // 2. FR is encrypted to produce FRE (FR Encrypted). This is the - // encryption of an all-zero value. - FRE = blockcipherencryptfn(FR, key); - // 3. FRE is xored with the first BS octets of random data prefixed to - // the plaintext to produce C[1] through C[BS], the first BS octets - // of ciphertext. - for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i)); - - // 4. FR is loaded with C[1] through C[BS]. - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); - - // 5. FR is encrypted to produce FRE, the encryption of the first BS - // octets of ciphertext. - FRE = blockcipherencryptfn(FR, key); - - // 6. The left two octets of FRE get xored with the next two octets of - // data that were prefixed to the plaintext. This produces C[BS+1] - // and C[BS+2], the next two octets of ciphertext. - ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size)); - ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size+1)); - - if (resync) { - // 7. (The resync step) FR is loaded with C3-C10. - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i+2); - } else { - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); - } - // 8. FR is encrypted to produce FRE. - FRE = blockcipherencryptfn(FR, key); - - if (resync) { - // 9. FRE is xored with the first 8 octets of the given plaintext, now - // that we have finished encrypting the 10 octets of prefixed data. - // This produces C11-C18, the next 8 octets of ciphertext. - for (var i = 0; i < block_size; i++) - ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); - for(n=block_size+2; n < plaintext.length; n+=block_size) { - // 10. FR is loaded with C11-C18 - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n+i); - - // 11. FR is encrypted to produce FRE. - FRE = blockcipherencryptfn(FR, key); - - // 12. FRE is xored with the next 8 octets of plaintext, to produce the - // next 8 octets of ciphertext. These are loaded into FR and the - // process is repeated until the plaintext is used up. - for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n-2)+i)); - } - } - else { - plaintext = " "+plaintext; - // 9. FRE is xored with the first 8 octets of the given plaintext, now - // that we have finished encrypting the 10 octets of prefixed data. - // This produces C11-C18, the next 8 octets of ciphertext. - for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); - var tempCiphertext = ciphertext.substring(0,2*block_size).split(''); - var tempCiphertextString = ciphertext.substring(block_size); - for(n=block_size; n block_size*pos) { - var encblock = blockcipherencryptfn(blockc, key); - blocki = plaintext.substring((pos*block_size),(pos*block_size)+block_size); - for (var i=0; i < blocki.length; i++) - tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i])); - blockc = tempBlock.join(''); - tempBlock = []; - cyphertext.push(blockc); - pos++; - } - return cyphertext.join(''); -} - -function normal_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, iv) { - var blockp =""; - var pos = 0; - var plaintext = []; - var offset = 0; - if (iv == null) - for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0); - else - blockp = iv.substring(0,block_size); - while (ciphertext.length > (block_size*pos)) { - var decblock = blockcipherencryptfn(blockp, key); - blockp = ciphertext.substring((pos*(block_size))+offset,(pos*(block_size))+(block_size)+offset); - for (var i=0; i < blockp.length; i++) { - plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i])); - } - pos++; - } - - return plaintext.join(''); -} +},{"../../util":56,"../random.js":23,"./jsbn.js":21}],23:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -3667,3703 +8402,210 @@ function normal_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, i // The GPG4Browsers crypto interface /** - * Encrypts data using the specified public key multiprecision integers - * and the specified algorithm. - * @param {Integer} algo Algorithm to be used (See RFC4880 9.1) - * @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers - * @param {openpgp_type_mpi} data Data to be encrypted as MPI - * @return {(openpgp_type_mpi|openpgp_type_mpi[])} if RSA an openpgp_type_mpi; - * if elgamal encryption an array of two openpgp_type_mpi is returned; otherwise null - */ -function openpgp_crypto_asymetricEncrypt(algo, publicMPIs, data) { - switch(algo) { - case 1: // RSA (Encrypt or Sign) [HAC] - case 2: // RSA Encrypt-Only [HAC] - case 3: // RSA Sign-Only [HAC] - var rsa = new RSA(); - var n = publicMPIs[0].toBigInteger(); - var e = publicMPIs[1].toBigInteger(); - var m = data.toBigInteger(); - return rsa.encrypt(m,e,n).toMPI(); - case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] - var elgamal = new Elgamal(); - var p = publicMPIs[0].toBigInteger(); - var g = publicMPIs[1].toBigInteger(); - var y = publicMPIs[2].toBigInteger(); - var m = data.toBigInteger(); - return elgamal.encrypt(m,g,p,y); - default: - return null; - } -} - -/** - * Decrypts data using the specified public key multiprecision integers of the private key, - * the specified secretMPIs of the private key and the specified algorithm. - * @param {Integer} algo Algorithm to be used (See RFC4880 9.1) - * @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers - * of the public key part of the private key - * @param {openpgp_type_mpi[]} secretMPIs Algorithm dependent multiprecision integers - * of the private key used - * @param {openpgp_type_mpi} data Data to be encrypted as MPI - * @return {BigInteger} returns a big integer containing the decrypted data; otherwise null + * @requires type/mpi + * @module crypto/random */ -function openpgp_crypto_asymetricDecrypt(algo, publicMPIs, secretMPIs, dataMPIs) { - switch(algo) { - case 1: // RSA (Encrypt or Sign) [HAC] - case 2: // RSA Encrypt-Only [HAC] - case 3: // RSA Sign-Only [HAC] - var rsa = new RSA(); - var d = secretMPIs[0].toBigInteger(); - var p = secretMPIs[1].toBigInteger(); - var q = secretMPIs[2].toBigInteger(); - var u = secretMPIs[3].toBigInteger(); - var m = dataMPIs[0].toBigInteger(); - return rsa.decrypt(m, d, p, q, u); - case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] - var elgamal = new Elgamal(); - var x = secretMPIs[0].toBigInteger(); - var c1 = dataMPIs[0].toBigInteger(); - var c2 = dataMPIs[1].toBigInteger(); - var p = publicMPIs[0].toBigInteger(); - return elgamal.decrypt(c1,c2,p,x); - default: - return null; - } - -} +var type_mpi = require('../type/mpi.js'); -/** - * generate random byte prefix as string for the specified algorithm - * @param {Integer} algo Algorithm to use (see RFC4880 9.2) - * @return {String} Random bytes with length equal to the block - * size of the cipher - */ -function openpgp_crypto_getPrefixRandom(algo) { - switch(algo) { - case 2: - case 3: - case 4: - return openpgp_crypto_getRandomBytes(8); - case 7: - case 8: - case 9: - case 10: - return openpgp_crypto_getRandomBytes(16); - default: - return null; - } -} - -/** - * retrieve the MDC prefixed bytes by decrypting them - * @param {Integer} algo Algorithm to use (see RFC4880 9.2) - * @param {String} key Key as string. length is depending on the algorithm used - * @param {String} data Encrypted data where the prefix is decrypted from - * @return {String} Plain text data of the prefixed data - */ -function openpgp_crypto_MDCSystemBytes(algo, key, data) { - util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nencrypteddata:",data); - switch(algo) { - case 0: // Plaintext or unencrypted data - return data; - case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - return openpgp_cfb_mdc(desede, 8, key, data, openpgp_cfb); - case 3: // CAST5 (128 bit key, as per [RFC2144]) - return openpgp_cfb_mdc(cast5_encrypt, 8, key, data); - case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH] - return openpgp_cfb_mdc(BFencrypt, 8, key, data); - case 7: // AES with 128-bit key [AES] - case 8: // AES with 192-bit key - case 9: // AES with 256-bit key - return openpgp_cfb_mdc(AESencrypt, 16, keyExpansion(key), data); - case 10: - return openpgp_cfb_mdc(TFencrypt, 16, key, data); - case 1: // IDEA [IDEA] - util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented")); - return null; - default: - } - return null; -} -/** - * Generating a session key for the specified symmetric algorithm - * @param {Integer} algo Algorithm to use (see RFC4880 9.2) - * @return {String} Random bytes as a string to be used as a key - */ -function openpgp_crypto_generateSessionKey(algo) { - switch (algo) { - case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - case 8: // AES with 192-bit key - return openpgp_crypto_getRandomBytes(24); - case 3: // CAST5 (128 bit key, as per [RFC2144]) - case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH] - case 7: // AES with 128-bit key [AES] - util.print_debug("length = 16:\n"+util.hexstrdump(openpgp_crypto_getRandomBytes(16))); - return openpgp_crypto_getRandomBytes(16); - case 9: // AES with 256-bit key - case 10:// Twofish with 256-bit key [TWOFISH] - return openpgp_crypto_getRandomBytes(32); - } - return null; -} - -/** - * - * @param {Integer} algo public Key algorithm - * @param {Integer} hash_algo Hash algorithm - * @param {openpgp_type_mpi[]} msg_MPIs Signature multiprecision integers - * @param {openpgp_type_mpi[]} publickey_MPIs Public key multiprecision integers - * @param {String} data Data on where the signature was computed on. - * @return {Boolean} true if signature (sig_data was equal to data over hash) - */ -function openpgp_crypto_verifySignature(algo, hash_algo, msg_MPIs, publickey_MPIs, data) { - var calc_hash = openpgp_crypto_hashData(hash_algo, data); - switch(algo) { - case 1: // RSA (Encrypt or Sign) [HAC] - case 2: // RSA Encrypt-Only [HAC] - case 3: // RSA Sign-Only [HAC] - var rsa = new RSA(); - var n = publickey_MPIs[0].toBigInteger(); - var e = publickey_MPIs[1].toBigInteger(); - var x = msg_MPIs[0].toBigInteger(); - var dopublic = rsa.verify(x,e,n); - var hash = openpgp_encoding_emsa_pkcs1_decode(hash_algo,dopublic.toMPI().substring(2)); - if (hash == -1) { - util.print_error("PKCS1 padding in message or key incorrect. Aborting..."); - return false; - } - util.print_debug('hash: '+util.hexdump(hash)); - util.print_debug('calc_hash: '+util.hexdump(calc_hash)); - return hash == calc_hash; - - case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] - util.print_error("signing with Elgamal is not defined in the OpenPGP standard."); - return null; - case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC] - var dsa = new DSA(); - var s1 = msg_MPIs[0].toBigInteger(); - var s2 = msg_MPIs[1].toBigInteger(); - var p = publickey_MPIs[0].toBigInteger(); - var q = publickey_MPIs[1].toBigInteger(); - var g = publickey_MPIs[2].toBigInteger(); - var y = publickey_MPIs[3].toBigInteger(); - var m = data; - var dopublic = dsa.verify(hash_algo,s1,s2,m,p,q,g,y); - return dopublic.compareTo(s1) == 0; - default: - return null; - } - -} - -/** - * Create a signature on data using the specified algorithm - * @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4) - * @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1) - * @param {openpgp_type_mpi[]} publicMPIs Public key multiprecision integers - * of the private key - * @param {openpgp_type_mpi[]} secretMPIs Private key multiprecision - * integers which is used to sign the data - * @param {String} data Data to be signed - * @return {(String|openpgp_type_mpi)} - */ -function openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, data) { - - switch(algo) { - case 1: // RSA (Encrypt or Sign) [HAC] - case 2: // RSA Encrypt-Only [HAC] - case 3: // RSA Sign-Only [HAC] - var rsa = new RSA(); - var d = secretMPIs[0].toBigInteger(); - var n = publicMPIs[0].toBigInteger(); - var m = openpgp_encoding_emsa_pkcs1_encode(hash_algo, data,publicMPIs[0].mpiByteLength); - util.print_debug("signing using RSA"); - return rsa.sign(m, d, n).toMPI(); - case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC] - var dsa = new DSA(); - util.print_debug("DSA Sign: q size in Bytes:"+publicMPIs[1].getByteLength()); - var p = publicMPIs[0].toBigInteger(); - var q = publicMPIs[1].toBigInteger(); - var g = publicMPIs[2].toBigInteger(); - var y = publicMPIs[3].toBigInteger(); - var x = secretMPIs[0].toBigInteger(); - var m = data; - var result = dsa.sign(hash_algo,m, g, p, q, x); - util.print_debug("signing using DSA\n result:"+util.hexstrdump(result[0])+"|"+util.hexstrdump(result[1])); - return result[0]+result[1]; - case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] - util.print_debug("signing with Elgamal is not defined in the OpenPGP standard."); - return null; - default: - return null; - } -} - -/** - * Create a hash on the specified data using the specified algorithm - * @param {Integer} algo Hash algorithm type (see RFC4880 9.4) - * @param {String} data Data to be hashed - * @return {String} hash value - */ -function openpgp_crypto_hashData(algo, data) { - var hash = null; - switch(algo) { - case 1: // - MD5 [HAC] - hash = MD5(data); - break; - case 2: // - SHA-1 [FIPS180] - hash = str_sha1(data); - break; - case 3: // - RIPE-MD/160 [HAC] - hash = RMDstring(data); - break; - case 8: // - SHA256 [FIPS180] - hash = str_sha256(data); - break; - case 9: // - SHA384 [FIPS180] - hash = str_sha384(data); - break; - case 10:// - SHA512 [FIPS180] - hash = str_sha512(data); - break; - case 11:// - SHA224 [FIPS180] - hash = str_sha224(data); - default: - break; - } - return hash; -} - -/** - * Returns the hash size in bytes of the specified hash algorithm type - * @param {Integer} algo Hash algorithm type (See RFC4880 9.4) - * @return {Integer} Size in bytes of the resulting hash - */ -function openpgp_crypto_getHashByteLength(algo) { - var hash = null; - switch(algo) { - case 1: // - MD5 [HAC] - return 16; - case 2: // - SHA-1 [FIPS180] - case 3: // - RIPE-MD/160 [HAC] - return 20; - case 8: // - SHA256 [FIPS180] - return 32; - case 9: // - SHA384 [FIPS180] - return 48 - case 10:// - SHA512 [FIPS180] - return 64; - case 11:// - SHA224 [FIPS180] - return 28; - } - return null; -} - -/** - * Retrieve secure random byte string of the specified length - * @param {Integer} length Length in bytes to generate - * @return {String} Random byte string - */ -function openpgp_crypto_getRandomBytes(length) { - var result = ''; - for (var i = 0; i < length; i++) { - result += String.fromCharCode(openpgp_crypto_getSecureRandomOctet()); - } - return result; -} - -/** - * Return a pseudo-random number in the specified range - * @param {Integer} from Min of the random number - * @param {Integer} to Max of the random number (max 32bit) - * @return {Integer} A pseudo random number - */ -function openpgp_crypto_getPseudoRandom(from, to) { - return Math.round(Math.random()*(to-from))+from; -} - -/** - * Return a secure random number in the specified range - * @param {Integer} from Min of the random number - * @param {Integer} to Max of the random number (max 32bit) - * @return {Integer} A secure random number - */ -function openpgp_crypto_getSecureRandom(from, to) { - var buf = new Uint32Array(1); - window.crypto.getRandomValues(buf); - var bits = ((to-from)).toString(2).length; - while ((buf[0] & (Math.pow(2, bits) -1)) > (to-from)) - window.crypto.getRandomValues(buf); - return from+(Math.abs(buf[0] & (Math.pow(2, bits) -1))); -} - -function openpgp_crypto_getSecureRandomOctet() { - var buf = new Uint32Array(1); - window.crypto.getRandomValues(buf); - return buf[0] & 0xFF; -} - -/** - * Create a secure random big integer of bits length - * @param {Integer} bits Bit length of the MPI to create - * @return {BigInteger} Resulting big integer - */ -function openpgp_crypto_getRandomBigInteger(bits) { - if (bits < 0) - return null; - var numBytes = Math.floor((bits+7)/8); - - var randomBits = openpgp_crypto_getRandomBytes(numBytes); - if (bits % 8 > 0) { - - randomBits = String.fromCharCode( - (Math.pow(2,bits % 8)-1) & - randomBits.charCodeAt(0)) + - randomBits.substring(1); - } - return new openpgp_type_mpi().create(randomBits).toBigInteger(); -} - -function openpgp_crypto_getRandomBigIntegerInRange(min, max) { - if (max.compareTo(min) <= 0) - return; - var range = max.subtract(min); - var r = openpgp_crypto_getRandomBigInteger(range.bitLength()); - while (r > range) { - r = openpgp_crypto_getRandomBigInteger(range.bitLength()); - } - return min.add(r); -} - - -//This is a test method to ensure that encryption/decryption with a given 1024bit RSAKey object functions as intended -function openpgp_crypto_testRSA(key){ - var rsa = new RSA(); - var mpi = new openpgp_type_mpi(); - mpi.create(openpgp_encoding_eme_pkcs1_encode('ABABABAB', 128)); - var msg = rsa.encrypt(mpi.toBigInteger(),key.ee,key.n); - var result = rsa.decrypt(msg, key.d, key.p, key.q, key.u); -} - -/** - * @typedef {Object} openpgp_keypair - * @property {openpgp_packet_keymaterial} privateKey - * @property {openpgp_packet_keymaterial} publicKey - */ - -/** - * Calls the necessary crypto functions to generate a keypair. - * Called directly by openpgp.js - * @param {Integer} keyType Follows OpenPGP algorithm convention. - * @param {Integer} numBits Number of bits to make the key to be generated - * @return {openpgp_keypair} - */ -function openpgp_crypto_generateKeyPair(keyType, numBits, passphrase, s2kHash, symmetricEncryptionAlgorithm){ - var privKeyPacket; - var publicKeyPacket; - var d = new Date(); - d = d.getTime()/1000; - var timePacket = String.fromCharCode(Math.floor(d/0x1000000%0x100)) + String.fromCharCode(Math.floor(d/0x10000%0x100)) + String.fromCharCode(Math.floor(d/0x100%0x100)) + String.fromCharCode(Math.floor(d%0x100)); - switch(keyType){ - case 1: - var rsa = new RSA(); - var key = rsa.generate(numBits,"10001"); - privKeyPacket = new openpgp_packet_keymaterial().write_private_key(keyType, key, passphrase, s2kHash, symmetricEncryptionAlgorithm, timePacket); - publicKeyPacket = new openpgp_packet_keymaterial().write_public_key(keyType, key, timePacket); - break; - default: - util.print_error("Unknown keytype "+keyType) - } - return {privateKey: privKeyPacket, publicKey: publicKeyPacket}; -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -// The GPG4Browsers symmetric crypto interface - -/** - * Symmetrically encrypts data using prefixedrandom, a key with length - * depending on the algorithm in openpgp_cfb mode with or without resync - * (MDC style) - * @param {String} prefixrandom Secure random bytes as string in - * length equal to the block size of the algorithm used (use - * openpgp_crypto_getPrefixRandom(algo) to retrieve that string - * @param {Integer} algo Algorithm to use (see RFC4880 9.2) - * @param {String} key Key as string. length is depending on the algorithm used - * @param {String} data Data to encrypt - * @param {Boolean} openpgp_cfb - * @return {String} Encrypted data - */ -function openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_cfb) { - switch(algo) { - case 0: // Plaintext or unencrypted data - return data; // blockcipherencryptfn, plaintext, block_size, key - case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - return openpgp_cfb_encrypt(prefixrandom, desede, data,8,key, openpgp_cfb).substring(0, data.length + 10); - case 3: // CAST5 (128 bit key, as per [RFC2144]) - return openpgp_cfb_encrypt(prefixrandom, cast5_encrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10); - case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH] - return openpgp_cfb_encrypt(prefixrandom, BFencrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10); - case 7: // AES with 128-bit key [AES] - case 8: // AES with 192-bit key - case 9: // AES with 256-bit key - return openpgp_cfb_encrypt(prefixrandom, AESencrypt, data, 16, keyExpansion(key), openpgp_cfb).substring(0, data.length + 18); - case 10: // Twofish with 256-bit key [TWOFISH] - return openpgp_cfb_encrypt(prefixrandom, TFencrypt, data,16, key, openpgp_cfb).substring(0, data.length + 18); - case 1: // IDEA [IDEA] - util.print_error("IDEA Algorithm not implemented"); - return null; - default: - return null; - } -} - -/** - * Symmetrically decrypts data using a key with length depending on the - * algorithm in openpgp_cfb mode with or without resync (MDC style) - * @param {Integer} algo Algorithm to use (see RFC4880 9.2) - * @param {String} key Key as string. length is depending on the algorithm used - * @param {String} data Data to be decrypted - * @param {Boolean} openpgp_cfb If true use the resync (for encrypteddata); - * otherwise use without the resync (for MDC encrypted data) - * @return {String} Plaintext data - */ -function openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) { - util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nalgo:"+algo+"\nencrypteddata:",data); - var n = 0; - if (!openpgp_cfb) - n = 2; - switch(algo) { - case 0: // Plaintext or unencrypted data - return data; - case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - return openpgp_cfb_decrypt(desede, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10); - case 3: // CAST5 (128 bit key, as per [RFC2144]) - return openpgp_cfb_decrypt(cast5_encrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10); - case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH] - return openpgp_cfb_decrypt(BFencrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10); - case 7: // AES with 128-bit key [AES] - case 8: // AES with 192-bit key - case 9: // AES with 256-bit key - return openpgp_cfb_decrypt(AESencrypt, 16, keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18); - case 10: // Twofish with 256-bit key [TWOFISH] - var result = openpgp_cfb_decrypt(TFencrypt, 16, key, data, openpgp_cfb).substring(n, (data.length+n)-18); - return result; - case 1: // IDEA [IDEA] - util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented")); - return null; - default: - } - return null; -} - -/* Rijndael (AES) Encryption - * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de - * version 1.1, check www.haneWIN.de for the latest version - - * This software is provided as-is, without express or implied warranty. - * Permission to use, copy, modify, distribute or sell this software, with or - * without fee, for any purpose and by any individual or organization, is hereby - * granted, provided that the above copyright notice and this paragraph appear - * in all copies. Distribution as a part of an application or binary must - * include the above copyright notice in the documentation and/or other - * materials provided with the application or distribution. - */ - -// The round constants used in subkey expansion -var Rcon = [ -0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, -0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, -0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]; - -// Precomputed lookup table for the SBox -var S = [ - 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, -118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, -114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, -216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, -235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, -179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, -190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, -249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, -188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, -23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, -144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, - 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, -141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, - 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, -181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, -248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, -140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, - 22 ]; - -var T1 = [ -0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, -0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, -0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, -0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, -0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, -0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, -0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, -0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, -0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, -0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, -0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, -0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, -0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, -0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, -0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, -0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, -0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, -0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, -0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, -0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, -0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, -0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, -0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, -0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, -0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, -0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, -0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, -0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, -0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, -0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, -0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, -0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, -0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, -0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, -0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, -0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, -0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, -0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, -0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, -0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, -0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, -0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, -0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, -0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, -0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, -0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, -0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, -0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, -0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, -0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, -0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, -0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, -0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, -0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, -0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, -0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, -0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, -0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, -0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, -0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, -0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, -0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, -0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, -0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c ]; - -var T2 = [ -0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, -0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, -0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, -0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, -0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, -0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, -0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, -0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, -0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, -0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, -0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, -0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, -0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, -0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, -0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, -0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, -0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, -0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, -0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, -0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, -0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, -0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, -0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, -0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, -0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, -0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, -0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, -0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, -0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, -0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, -0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, -0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, -0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, -0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, -0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, -0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, -0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, -0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, -0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, -0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, -0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, -0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, -0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, -0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, -0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, -0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, -0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, -0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, -0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, -0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, -0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, -0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, -0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, -0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, -0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, -0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, -0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, -0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, -0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, -0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, -0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, -0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, -0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, -0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a ]; - -var T3 = [ -0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, -0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, -0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, -0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, -0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, -0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, -0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, -0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, -0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, -0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, -0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, -0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, -0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, -0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, -0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, -0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, -0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, -0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, -0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, -0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, -0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, -0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, -0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, -0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, -0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, -0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, -0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, -0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, -0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, -0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, -0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, -0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, -0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, -0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, -0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, -0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, -0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, -0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, -0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, -0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, -0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, -0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, -0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, -0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, -0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, -0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, -0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, -0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, -0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, -0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, -0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, -0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, -0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, -0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, -0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, -0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, -0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, -0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, -0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, -0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, -0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, -0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, -0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, -0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16 ]; - -var T4 = [ -0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, -0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, -0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, -0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, -0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, -0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, -0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, -0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, -0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, -0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, -0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, -0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, -0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, -0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, -0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, -0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, -0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, -0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, -0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, -0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, -0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, -0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, -0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, -0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, -0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, -0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, -0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, -0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, -0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, -0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, -0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, -0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, -0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, -0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, -0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, -0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, -0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, -0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, -0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, -0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, -0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, -0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, -0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, -0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, -0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, -0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, -0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, -0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, -0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, -0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, -0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, -0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, -0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, -0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, -0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, -0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, -0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, -0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, -0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, -0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, -0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, -0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, -0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, -0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 ]; - -function B0(x) { return (x&255); } -function B1(x) { return ((x>>8)&255); } -function B2(x) { return ((x>>16)&255); } -function B3(x) { return ((x>>24)&255); } - -function F1(x0, x1, x2, x3) -{ - return B1(T1[x0&255]) | (B1(T1[(x1>>8)&255])<<8) - | (B1(T1[(x2>>16)&255])<<16) | (B1(T1[x3>>>24])<<24); -} - -function packBytes(octets) -{ - var i, j; - var len=octets.length; - var b=new Array(len/4); - - if (!octets || len % 4) return; - - for (i=0, j=0; j=0; j--) tk[j] = k[j]; - - r=0; - t=0; - for(j=0; (j>8)&255] ^ T3[(t2>>16)&255] ^ T4[t3>>>24]; - b1 = T1[t1&255] ^ T2[(t2>>8)&255] ^ T3[(t3>>16)&255] ^ T4[t0>>>24]; - b2 = T1[t2&255] ^ T2[(t3>>8)&255] ^ T3[(t0>>16)&255] ^ T4[t1>>>24]; - b3 = T1[t3&255] ^ T2[(t0>>8)&255] ^ T3[(t1>>16)&255] ^ T4[t2>>>24]; - } - - // last round is special - r = rounds-1; - - t0 = b0 ^ ctx.rk[r][0]; - t1 = b1 ^ ctx.rk[r][1]; - t2 = b2 ^ ctx.rk[r][2]; - t3 = b3 ^ ctx.rk[r][3]; - - b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0]; - b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1]; - b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2]; - b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3]; - - return unpackBytes(b); -} -/* Modified by Recurity Labs GmbH - * - * Originally written by nklein software (nklein.com) - */ - -/* - * Javascript implementation based on Bruce Schneier's reference implementation. - * - * - * The constructor doesn't do much of anything. It's just here - * so we can start defining properties and methods and such. - */ -function Blowfish() { -}; - -/* - * Declare the block size so that protocols know what size - * Initialization Vector (IV) they will need. - */ -Blowfish.prototype.BLOCKSIZE = 8; - -/* - * These are the default SBOXES. - */ -Blowfish.prototype.SBOXES = [ - [ - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, - 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, - 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, - 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, - 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, - 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, - 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, - 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, - 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, - 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, - 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, - 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, - 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, - 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, - 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, - 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, - 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, - 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, - 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, - 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, - 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, - 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a - ], [ - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, - 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, - 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, - 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, - 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, - 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, - 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, - 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, - 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, - 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, - 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, - 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, - 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, - 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, - 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, - 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, - 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, - 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, - 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, - 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, - 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, - 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 - ], [ - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, - 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, - 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, - 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, - 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, - 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, - 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, - 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, - 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, - 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, - 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, - 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, - 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, - 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, - 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, - 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, - 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, - 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, - 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, - 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, - 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, - 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 - ], [ - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, - 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, - 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, - 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, - 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, - 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, - 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, - 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, - 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, - 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, - 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, - 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, - 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, - 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, - 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, - 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, - 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, - 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, - 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, - 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, - 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, - 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 - ] -]; - -//* -//* This is the default PARRAY -//* -Blowfish.prototype.PARRAY = [ - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, - 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b -]; - -//* -//* This is the number of rounds the cipher will go -//* -Blowfish.prototype.NN = 16; - -//* -//* This function is needed to get rid of problems -//* with the high-bit getting set. If we don't do -//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not -//* equal to ( bb & 0x00FFFFFFFF ) even when they -//* agree bit-for-bit for the first 32 bits. -//* -Blowfish.prototype._clean = function( xx ) { - if ( xx < 0 ) { - var yy = xx & 0x7FFFFFFF; - xx = yy + 0x80000000; - } - return xx; -}; - -//* -//* This is the mixing function that uses the sboxes -//* -Blowfish.prototype._F = function ( xx ) { - var aa; - var bb; - var cc; - var dd; - var yy; - - dd = xx & 0x00FF; - xx >>>= 8; - cc = xx & 0x00FF; - xx >>>= 8; - bb = xx & 0x00FF; - xx >>>= 8; - aa = xx & 0x00FF; - - yy = this.sboxes[ 0 ][ aa ] + this.sboxes[ 1 ][ bb ]; - yy = yy ^ this.sboxes[ 2 ][ cc ]; - yy = yy + this.sboxes[ 3 ][ dd ]; - - return yy; -}; - -//* -//* This method takes an array with two values, left and right -//* and does NN rounds of Blowfish on them. -//* -Blowfish.prototype._encrypt_block = function ( vals ) { - var dataL = vals[ 0 ]; - var dataR = vals[ 1 ]; - - var ii; - - for ( ii=0; ii < this.NN; ++ii ) { - dataL = dataL ^ this.parray[ ii ]; - dataR = this._F( dataL ) ^ dataR; - - var tmp = dataL; - dataL = dataR; - dataR = tmp; - } - - dataL = dataL ^ this.parray[ this.NN + 0 ]; - dataR = dataR ^ this.parray[ this.NN + 1 ]; - - vals[ 0 ] = this._clean( dataR ); - vals[ 1 ] = this._clean( dataL ); -}; - -//* -//* This method takes a vector of numbers and turns them -//* into long words so that they can be processed by the -//* real algorithm. -//* -//* Maybe I should make the real algorithm above take a vector -//* instead. That will involve more looping, but it won't require -//* the F() method to deconstruct the vector. -//* -Blowfish.prototype.encrypt_block = function ( vector ) { - var ii; - var vals = [ 0, 0 ]; - var off = this.BLOCKSIZE/2; - for ( ii = 0; ii < this.BLOCKSIZE/2; ++ii ) { - vals[0] = ( vals[0] << 8 ) | ( vector[ ii + 0 ] & 0x00FF ); - vals[1] = ( vals[1] << 8 ) | ( vector[ ii + off ] & 0x00FF ); - } - - this._encrypt_block( vals ); - - var ret = [ ]; - for ( ii = 0; ii < this.BLOCKSIZE/2; ++ii ) { - ret[ ii + 0 ] = ( vals[ 0 ] >>> (24 - 8*(ii)) & 0x00FF ); - ret[ ii + off ] = ( vals[ 1 ] >>> (24 - 8*(ii)) & 0x00FF ); - // vals[ 0 ] = ( vals[ 0 ] >>> 8 ); - // vals[ 1 ] = ( vals[ 1 ] >>> 8 ); - } - - return ret; -}; - -//* -//* This method takes an array with two values, left and right -//* and undoes NN rounds of Blowfish on them. -//* -Blowfish.prototype._decrypt_block = function ( vals ) { - var dataL = vals[ 0 ]; - var dataR = vals[ 1 ]; - - var ii; - - for ( ii=this.NN+1; ii > 1; --ii ) { - dataL = dataL ^ this.parray[ ii ]; - dataR = this._F( dataL ) ^ dataR; - - var tmp = dataL; - dataL = dataR; - dataR = tmp; - } - - dataL = dataL ^ this.parray[ 1 ]; - dataR = dataR ^ this.parray[ 0 ]; - - vals[ 0 ] = this._clean( dataR ); - vals[ 1 ] = this._clean( dataL ); -}; - -//* -//* This method takes a key array and initializes the -//* sboxes and parray for this encryption. -//* -Blowfish.prototype.init = function ( key ) { - var ii; - var jj = 0; - - this.parray = []; - for ( ii=0; ii < this.NN + 2; ++ii ) { - var data = 0x00000000; - var kk; - for ( kk=0; kk < 4; ++kk ) { - data = ( data << 8 ) | ( key[ jj ] & 0x00FF ); - if ( ++jj >= key.length ) { - jj = 0; - } - } - this.parray[ ii ] = this.PARRAY[ ii ] ^ data; - } - - this.sboxes = []; - for ( ii=0; ii < 4; ++ii ) { - this.sboxes[ ii ] = []; - for ( jj=0; jj < 256; ++jj ) { - this.sboxes[ ii ][ jj ] = this.SBOXES[ ii ][ jj ]; - } - } - - var vals = [ 0x00000000, 0x00000000 ]; - - for ( ii=0; ii < this.NN+2; ii += 2 ) { - this._encrypt_block( vals ); - this.parray[ ii + 0 ] = vals[ 0 ]; - this.parray[ ii + 1 ] = vals[ 1 ]; - } - - for ( ii=0; ii < 4; ++ii ) { - for ( jj=0; jj < 256; jj += 2 ) { - this._encrypt_block( vals ); - this.sboxes[ ii ][ jj + 0 ] = vals[ 0 ]; - this.sboxes[ ii ][ jj + 1 ] = vals[ 1 ]; - } - } -}; - -// added by Recurity Labs -function BFencrypt(block,key) { - var bf = new Blowfish(); - bf.init(util.str2bin(key)); - return bf.encrypt_block(block); -} - -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Copyright 2010 pjacobs@xeekr.com . All rights reserved. - -// Modified by Recurity Labs GmbH - -// fixed/modified by Herbert Hanewinkel, www.haneWIN.de -// check www.haneWIN.de for the latest version - -// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144. -// CAST-128 is a common OpenPGP cipher. - - -// CAST5 constructor - -function cast5_encrypt(block, key) { - var cast5 = new openpgp_symenc_cast5(); - cast5.setKey(util.str2bin(key)); - return cast5.encrypt(block); -} - -function openpgp_symenc_cast5() { - this.BlockSize= 8; - this.KeySize = 16; - - this.setKey = function (key) { - this.masking = new Array(16); - this.rotate = new Array(16); - - this.reset(); - - if (key.length == this.KeySize) - { - this.keySchedule(key); - } - else - { - util.print_error('cast5.js: CAST-128: keys must be 16 bytes'); - return false; - } - return true; - }; - - this.reset = function() { - for (var i = 0; i < 16; i++) - { - this.masking[i] = 0; - this.rotate[i] = 0; - } - }; - - this.getBlockSize = function() { - return BlockSize; - }; - - this.encrypt = function(src) { - var dst = new Array(src.length); - - for(var i = 0; i < src.length; i+=8) - { - var l = src[i]<<24 | src[i+1]<<16 | src[i+2]<<8 | src[i+3]; - var r = src[i+4]<<24 | src[i+5]<<16 | src[i+6]<<8 | src[i+7]; - var t; - - t = r; r = l^f1(r, this.masking[0], this.rotate[0]); l = t; - t = r; r = l^f2(r, this.masking[1], this.rotate[1]); l = t; - t = r; r = l^f3(r, this.masking[2], this.rotate[2]); l = t; - t = r; r = l^f1(r, this.masking[3], this.rotate[3]); l = t; - - t = r; r = l^f2(r, this.masking[4], this.rotate[4]); l = t; - t = r; r = l^f3(r, this.masking[5], this.rotate[5]); l = t; - t = r; r = l^f1(r, this.masking[6], this.rotate[6]); l = t; - t = r; r = l^f2(r, this.masking[7], this.rotate[7]); l = t; - - t = r; r = l^f3(r, this.masking[8], this.rotate[8]); l = t; - t = r; r = l^f1(r, this.masking[9], this.rotate[9]); l = t; - t = r; r = l^f2(r, this.masking[10], this.rotate[10]); l = t; - t = r; r = l^f3(r, this.masking[11], this.rotate[11]); l = t; - - t = r; r = l^f1(r, this.masking[12], this.rotate[12]); l = t; - t = r; r = l^f2(r, this.masking[13], this.rotate[13]); l = t; - t = r; r = l^f3(r, this.masking[14], this.rotate[14]); l = t; - t = r; r = l^f1(r, this.masking[15], this.rotate[15]); l = t; - - dst[i] = (r >>> 24)&255; - dst[i+1] = (r >>> 16)&255; - dst[i+2] = (r >>> 8)&255; - dst[i+3] = r&255; - dst[i+4] = (l >>> 24)&255; - dst[i+5] = (l >>> 16)&255; - dst[i+6] = (l >>> 8)&255; - dst[i+7] = l&255; - } - - return dst; - }; - - this.decrypt = function(src) { - var dst = new Array(src.length); - - for(var i = 0; i < src.length; i+=8) - { - var l = src[i]<<24 | src[i+1]<<16 | src[i+2]<<8 | src[i+3]; - var r = src[i+4]<<24 | src[i+5]<<16 | src[i+6]<<8 | src[i+7]; - var t; - - t = r; r = l^f1(r, this.masking[15], this.rotate[15]); l = t; - t = r; r = l^f3(r, this.masking[14], this.rotate[14]); l = t; - t = r; r = l^f2(r, this.masking[13], this.rotate[13]); l = t; - t = r; r = l^f1(r, this.masking[12], this.rotate[12]); l = t; - - t = r; r = l^f3(r, this.masking[11], this.rotate[11]); l = t; - t = r; r = l^f2(r, this.masking[10], this.rotate[10]); l = t; - t = r; r = l^f1(r, this.masking[9], this.rotate[9]); l = t; - t = r; r = l^f3(r, this.masking[8], this.rotate[8]); l = t; - - t = r; r = l^f2(r, this.masking[7], this.rotate[7]); l = t; - t = r; r = l^f1(r, this.masking[6], this.rotate[6]); l = t; - t = r; r = l^f3(r, this.masking[5], this.rotate[5]); l = t; - t = r; r = l^f2(r, this.masking[4], this.rotate[4]); l = t; - - t = r; r = l^f1(r, this.masking[3], this.rotate[3]); l = t; - t = r; r = l^f3(r, this.masking[2], this.rotate[2]); l = t; - t = r; r = l^f2(r, this.masking[1], this.rotate[1]); l = t; - t = r; r = l^f1(r, this.masking[0], this.rotate[0]); l = t; - - dst[i] = (r >>> 24)&255; - dst[i+1] = (r >>> 16)&255; - dst[i+2] = (r >>> 8)&255; - dst[i+3] = r&255; - dst[i+4] = (l >>> 24)&255; - dst[i+5] = (l >> 16)&255; - dst[i+6] = (l >> 8)&255; - dst[i+7] = l&255; - } - - return dst; - }; - var scheduleA = new Array(4); - - scheduleA[0] = new Array(4); - scheduleA[0][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 0x8); - scheduleA[0][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); - scheduleA[0][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); - scheduleA[0][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); - - scheduleA[1] = new Array(4); - scheduleA[1][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); - scheduleA[1][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); - scheduleA[1][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); - scheduleA[1][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); - - scheduleA[2] = new Array(4); - scheduleA[2][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 8); - scheduleA[2][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); - scheduleA[2][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); - scheduleA[2][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); - - - scheduleA[3] = new Array(4); - scheduleA[3][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); - scheduleA[3][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); - scheduleA[3][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); - scheduleA[3][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); - - var scheduleB = new Array(4); - - scheduleB[0] = new Array(4); - scheduleB[0][0] = new Array(16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2); - scheduleB[0][1] = new Array(16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6); - scheduleB[0][2] = new Array(16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9); - scheduleB[0][3] = new Array(16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc); - - scheduleB[1] = new Array(4); - scheduleB[1][0] = new Array(3, 2, 0xc, 0xd, 8); - scheduleB[1][1] = new Array(1, 0, 0xe, 0xf, 0xd); - scheduleB[1][2] = new Array(7, 6, 8, 9, 3); - scheduleB[1][3] = new Array(5, 4, 0xa, 0xb, 7); - - - scheduleB[2] = new Array(4); - scheduleB[2][0] = new Array(16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9); - scheduleB[2][1] = new Array(16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc); - scheduleB[2][2] = new Array(16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2); - scheduleB[2][3] = new Array(16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6); - - - scheduleB[3] = new Array(4); - scheduleB[3][0] = new Array(8, 9, 7, 6, 3); - scheduleB[3][1] = new Array(0xa, 0xb, 5, 4, 7); - scheduleB[3][2] = new Array(0xc, 0xd, 3, 2, 8); - scheduleB[3][3] = new Array(0xe, 0xf, 1, 0, 0xd); - - // changed 'in' to 'inn' (in javascript 'in' is a reserved word) - this.keySchedule = function(inn) - { - var t = new Array(8); - var k = new Array(32); - - for (var i = 0; i < 4; i++) - { - var j = i * 4; - t[i] = inn[j]<<24 | inn[j+1]<<16 | inn[j+2]<<8 | inn[j+3]; - } - - var x = [6, 7, 4, 5]; - var ki = 0; - - for (var half = 0; half < 2; half++) - { - for (var round = 0; round < 4; round++) - { - for (var j = 0; j < 4; j++) - { - var a = scheduleA[round][j]; - var w = t[a[1]]; - - w ^= sBox[4][(t[a[2]>>>2]>>>(24-8*(a[2]&3)))&0xff]; - w ^= sBox[5][(t[a[3]>>>2]>>>(24-8*(a[3]&3)))&0xff]; - w ^= sBox[6][(t[a[4]>>>2]>>>(24-8*(a[4]&3)))&0xff]; - w ^= sBox[7][(t[a[5]>>>2]>>>(24-8*(a[5]&3)))&0xff]; - w ^= sBox[x[j]][(t[a[6]>>>2]>>>(24-8*(a[6]&3)))&0xff]; - t[a[0]] = w; - } - - for (var j = 0; j < 4; j++) - { - var b = scheduleB[round][j]; - var w = sBox[4][(t[b[0]>>>2]>>>(24-8*(b[0]&3)))&0xff]; - - w ^= sBox[5][(t[b[1]>>>2]>>>(24-8*(b[1]&3)))&0xff]; - w ^= sBox[6][(t[b[2]>>>2]>>>(24-8*(b[2]&3)))&0xff]; - w ^= sBox[7][(t[b[3]>>>2]>>>(24-8*(b[3]&3)))&0xff]; - w ^= sBox[4+j][(t[b[4]>>>2]>>>(24-8*(b[4]&3)))&0xff]; - k[ki] = w; - ki++; - } - } - } - - for (var i = 0; i < 16; i++) - { - this.masking[i] = k[i]; - this.rotate[i] = k[16+i] & 0x1f; - } - }; - - // These are the three 'f' functions. See RFC 2144, section 2.2. - - function f1(d, m, r) - { - var t = m + d; - var I = (t << r) | (t >>> (32 - r)); - return ((sBox[0][I>>>24] ^ sBox[1][(I>>>16)&255]) - sBox[2][(I>>>8)&255]) + sBox[3][I&255]; - } - - function f2(d, m, r) - { - var t = m ^ d; - var I = (t << r) | (t >>> (32 - r)); - return ((sBox[0][I>>>24] - sBox[1][(I>>>16)&255]) + sBox[2][(I>>>8)&255]) ^ sBox[3][I&255]; - } - - function f3(d, m, r) - { - var t = m - d; - var I = (t << r) | (t >>> (32 - r)); - return ((sBox[0][I>>>24] + sBox[1][(I>>>16)&255]) ^ sBox[2][(I>>>8)&255]) - sBox[3][I&255]; - } - - var sBox = new Array(8); - sBox[0] = new Array( - 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, - 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, - 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, - 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, - 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, - 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, - 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, - 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, - 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, - 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, - 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, - 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, - 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, - 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, - 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, - 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, - 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, - 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, - 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, - 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, - 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, - 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, - 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, - 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, - 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, - 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, - 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, - 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, - 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, - 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, - 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, - 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf); - - sBox[1] = new Array( - 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, - 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, - 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, - 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, - 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, - 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, - 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, - 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, - 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, - 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, - 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, - 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, - 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, - 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, - 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, - 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, - 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, - 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, - 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, - 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, - 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, - 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, - 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, - 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, - 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, - 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, - 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, - 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, - 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, - 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, - 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, - 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1); - - sBox[2] = new Array( - 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, - 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, - 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, - 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, - 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, - 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, - 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, - 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, - 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, - 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, - 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, - 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, - 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, - 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, - 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, - 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, - 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, - 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, - 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, - 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, - 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, - 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, - 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, - 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, - 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, - 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, - 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, - 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, - 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, - 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, - 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, - 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783); - - sBox[3] = new Array( - 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, - 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, - 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, - 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, - 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, - 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, - 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, - 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, - 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, - 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, - 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, - 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, - 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, - 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, - 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, - 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, - 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, - 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, - 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, - 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, - 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, - 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, - 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, - 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, - 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, - 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, - 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, - 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, - 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, - 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, - 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, - 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2); - - sBox[4] = new Array( - 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, - 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, - 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, - 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, - 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, - 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, - 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, - 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, - 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, - 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, - 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, - 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, - 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, - 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, - 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, - 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, - 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, - 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, - 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, - 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, - 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, - 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, - 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, - 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, - 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, - 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, - 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, - 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, - 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, - 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, - 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, - 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4); - - sBox[5] = new Array( - 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, - 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, - 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, - 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, - 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, - 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, - 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, - 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, - 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, - 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, - 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, - 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, - 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, - 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, - 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, - 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, - 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, - 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, - 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, - 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, - 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, - 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, - 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, - 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, - 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, - 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, - 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, - 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, - 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, - 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, - 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, - 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f); - - sBox[6] = new Array( - 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, - 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, - 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, - 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, - 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, - 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, - 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, - 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, - 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, - 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, - 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, - 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, - 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, - 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, - 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, - 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, - 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, - 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, - 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, - 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, - 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, - 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, - 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, - 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, - 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, - 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, - 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, - 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, - 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, - 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, - 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, - 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3); - - sBox[7] = new Array( - 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, - 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, - 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, - 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, - 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, - 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, - 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, - 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, - 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, - 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, - 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, - 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, - 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, - 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, - 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, - 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, - 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, - 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, - 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, - 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, - 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, - 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, - 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, - 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, - 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, - 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, - 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, - 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, - 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, - 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, - 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, - 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e); - -}; - -//Paul Tero, July 2001 -//http://www.tero.co.uk/des/ -// -//Optimised for performance with large blocks by Michael Hayworth, November 2001 -//http://www.netdealing.com -// -// Modified by Recurity Labs GmbH - -//THIS SOFTWARE IS PROVIDED "AS IS" AND -//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -//SUCH DAMAGE. - -//des -//this takes the key, the message, and whether to encrypt or decrypt - -// added by Recurity Labs -function desede(block,key) { - var key1 = key.substring(0,8); - var key2 = key.substring(8,16); - var key3 = key.substring(16,24); - return util.str2bin(des(des_createKeys(key3),des(des_createKeys(key2),des(des_createKeys(key1),util.bin2str(block), true, 0,null,null), false, 0,null,null), true, 0,null,null)); -} - - -function des (keys, message, encrypt, mode, iv, padding) { - //declaring this locally speeds things up a bit - var spfunction1 = new Array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004); - var spfunction2 = new Array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000); - var spfunction3 = new Array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200); - var spfunction4 = new Array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080); - var spfunction5 = new Array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100); - var spfunction6 = new Array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010); - var spfunction7 = new Array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002); - var spfunction8 = new Array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000); - - //create the 16 or 48 subkeys we will need - var m=0, i, j, temp, temp2, right1, right2, left, right, looping; - var cbcleft, cbcleft2, cbcright, cbcright2 - var endloop, loopinc; - var len = message.length; - var chunk = 0; - //set up the loops for single and triple des - var iterations = keys.length == 32 ? 3 : 9; //single or triple des - if (iterations == 3) {looping = encrypt ? new Array (0, 32, 2) : new Array (30, -2, -2);} - else {looping = encrypt ? new Array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array (94, 62, -2, 32, 64, 2, 30, -2, -2);} - - //pad the message depending on the padding parameter - //only add padding if encrypting - note that you need to use the same padding option for both encrypt and decrypt - if (encrypt) { - message = des_addPadding(message, padding); - len = message.length; - } - - //store the result here - result = ""; - tempresult = ""; - - if (mode == 1) { //CBC mode - cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); - cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); - m=0; - } - - //loop through each 64 bit chunk of the message - while (m < len) { - left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++); - right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++); - - //for Cipher Block Chaining mode, xor the message with the previous result - if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}} - - //first each 64 but chunk of the message must be permuted according to IP - temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4); - temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16); - temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2); - temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8); - temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1); - - left = ((left << 1) | (left >>> 31)); - right = ((right << 1) | (right >>> 31)); - - //do this either 1 or 3 times for each chunk of the message - for (j=0; j>> 4) | (right << 28)) ^ keys[i+1]; - //the result is attained by passing these bytes through the S selection functions - temp = left; - left = right; - right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f] - | spfunction6[(right1 >>> 8) & 0x3f] | spfunction8[right1 & 0x3f] - | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f] - | spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]); - } - temp = left; left = right; right = temp; //unreverse left and right - } //for either 1 or 3 iterations - - //move then each one bit to the right - left = ((left >>> 1) | (left << 31)); - right = ((right >>> 1) | (right << 31)); - - //now perform IP-1, which is IP in the opposite direction - temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1); - temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8); - temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2); - temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16); - temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4); - - //for Cipher Block Chaining mode, xor the message with the previous result - if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}} - tempresult += String.fromCharCode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff)); - - chunk += 8; - if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;} - } //for every 8 characters, or 64 bits in the message - - //return the result as an array - result += tempresult; - - //only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt - if (!encrypt) { - result = des_removePadding(result, padding); - } - return result; -} //end of des + }, + /** + * Return a pseudo-random number in the specified range + * @param {Integer} from Min of the random number + * @param {Integer} to Max of the random number (max 32bit) + * @return {Integer} A pseudo random number + */ + getPseudoRandom: function(from, to) { + return Math.round(Math.random() * (to - from)) + from; + }, + /** + * Return a secure random number in the specified range + * @param {Integer} from Min of the random number + * @param {Integer} to Max of the random number (max 32bit) + * @return {Integer} A secure random number + */ + getSecureRandom: function(from, to) { + var buf = new Uint32Array(1); + window.crypto.getRandomValues(buf); + var bits = ((to - from)).toString(2).length; + while ((buf[0] & (Math.pow(2, bits) - 1)) > (to - from)) + window.crypto.getRandomValues(buf); + return from + (Math.abs(buf[0] & (Math.pow(2, bits) - 1))); + }, -//des_createKeys -//this takes as input a 64 bit key (even though only 56 bits are used) -//as an array of 2 integers, and returns 16 48 bit keys -function des_createKeys (key) { - //declaring this locally speeds things up a bit - pc2bytes0 = new Array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204); - pc2bytes1 = new Array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101); - pc2bytes2 = new Array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808); - pc2bytes3 = new Array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000); - pc2bytes4 = new Array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010); - pc2bytes5 = new Array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420); - pc2bytes6 = new Array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002); - pc2bytes7 = new Array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800); - pc2bytes8 = new Array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002); - pc2bytes9 = new Array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408); - pc2bytes10 = new Array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020); - pc2bytes11 = new Array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200); - pc2bytes12 = new Array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010); - pc2bytes13 = new Array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105); + getSecureRandomOctet: function() { + var buf = new Uint32Array(1); + window.crypto.getRandomValues(buf); + return buf[0] & 0xFF; + }, - //how many iterations (1 for des, 3 for triple des) - var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys - //stores the return keys - var keys = new Array (32 * iterations); - //now define the left shifts which need to be done - var shifts = new Array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0); - //other variables - var lefttemp, righttemp, m=0, n=0, temp; - - for (var j=0; j>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4); - temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16); - temp = ((left >>> 2) ^ right) & 0x33333333; right ^= temp; left ^= (temp << 2); - temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16); - temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1); - temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8); - temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1); - - //the right side needs to be shifted and to get the last four bits of the left side - temp = (left << 8) | ((right >>> 20) & 0x000000f0); - //left needs to be put upside down - left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0); - right = temp; - - //now go through and perform these shifts on the left and right keys - for (i=0; i < shifts.length; i++) { - //shift the keys either one or two bits to the left - if (shifts[i]) {left = (left << 2) | (left >>> 26); right = (right << 2) | (right >>> 26);} - else {left = (left << 1) | (left >>> 27); right = (right << 1) | (right >>> 27);} - left &= -0xf; right &= -0xf; - - //now apply PC-2, in such a way that E is easier when encrypting or decrypting - //this conversion will look like PC-2 except only the last 6 bits of each byte are used - //rather than 48 consecutive bits and the order of lines will be according to - //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 - lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] - | pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf] - | pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] - | pc2bytes6[(left >>> 4) & 0xf]; - righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] - | pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf] - | pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] - | pc2bytes13[(right >>> 4) & 0xf]; - temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff; - keys[n++] = lefttemp ^ temp; keys[n++] = righttemp ^ (temp << 16); + /** + * Create a secure random big integer of bits length + * @param {Integer} bits Bit length of the MPI to create + * @return {BigInteger} Resulting big integer + */ + getRandomBigInteger: function(bits) { + if (bits < 0) { + return null; } - } //for each iterations - //return the keys we've created - return keys; -} //end of des_createKeys + var numBytes = Math.floor((bits + 7) / 8); + var randomBits = this.getRandomBytes(numBytes); + if (bits % 8 > 0) { -function des_addPadding(message, padding) { - var padLength = 8 - (message.length % 8); - if ((padding == 2) && (padLength < 8)) { //pad the message with spaces - message += " ".substr(0, padLength); - } - else if (padding == 1) { //PKCS7 padding - message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength, padLength).substr(0, padLength); - } - else if (!padding && (padLength < 8)) { //pad the message out with null bytes - message += "\0\0\0\0\0\0\0\0".substr(0, padLength); - } - return message; -} - -function des_removePadding(message, padding) { - if (padding == 2) { // space padded - message = message.replace(/ *$/g, ""); - } - else if (padding == 1) { // PKCS7 - var padCount = message.charCodeAt(message.length - 1); - message = message.substr(0, message.length - padCount); - } - else if (!padding) { // null padding - message = message.replace(/\0*$/g, ""); - } - return message; -} - -/* Modified by Recurity Labs GmbH - * - * Cipher.js - * A block-cipher algorithm implementation on JavaScript - * See Cipher.readme.txt for further information. - * - * Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ] - * This script file is distributed under the LGPL - * - * ACKNOWLEDGMENT - * - * The main subroutines are written by Michiel van Everdingen. - * - * Michiel van Everdingen - * http://home.versatel.nl/MAvanEverdingen/index.html - * - * All rights for these routines are reserved to Michiel van Everdingen. - * - */ - -// added by Recurity Labs -function TFencrypt(block, key) { - var block_copy = [].concat(block); - var tf = createTwofish(); - tf.open(util.str2bin(key),0); - var result = tf.encrypt(block_copy, 0); - tf.close(); - return result; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Math -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -var MAXINT = 0xFFFFFFFF; - -function rotb(b,n){ return ( b<>>( 8-n) ) & 0xFF; } -function rotw(w,n){ return ( w<>>(32-n) ) & MAXINT; } -function getW(a,i){ return a[i]|a[i+1]<<8|a[i+2]<<16|a[i+3]<<24; } -function setW(a,i,w){ a.splice(i,4,w&0xFF,(w>>>8)&0xFF,(w>>>16)&0xFF,(w>>>24)&0xFF); } -function setWInv(a,i,w){ a.splice(i,4,(w>>>24)&0xFF,(w>>>16)&0xFF,(w>>>8)&0xFF,w&0xFF); } -function getB(x,n){ return (x>>>(n*8))&0xFF; } - -function getNrBits(i){ var n=0; while (i>0){ n++; i>>>=1; } return n; } -function getMask(n){ return (1<> 2) ^ [ 0, 90, 180, 238 ][x & 3]; - } - function ffmEf(x) { - return x ^ (x >> 1) ^ (x >> 2) ^ [ 0, 238, 180, 90 ][x & 3]; - } - - function mdsRem(p, q) { - var i, t, u; - for (i = 0; i < 8; i++) { - t = q >>> 24; - q = ((q << 8) & MAXINT) | p >>> 24; - p = (p << 8) & MAXINT; - u = t << 1; - if (t & 128) { - u ^= 333; - } - q ^= t ^ (u << 16); - u ^= t >>> 1; - if (t & 1) { - u ^= 166; - } - q ^= u << 24 | u << 8; - } - return q; - } - - function qp(n, x) { - var a, b, c, d; - a = x >> 4; - b = x & 15; - c = q0[n][a ^ b]; - d = q1[n][ror4[b] ^ ashx[a]]; - return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d]; - } - - function hFun(x, key) { - var a = getB(x, 0), b = getB(x, 1), c = getB(x, 2), d = getB(x, 3); - switch (kLen) { - case 4: - a = q[1][a] ^ getB(key[3], 0); - b = q[0][b] ^ getB(key[3], 1); - c = q[0][c] ^ getB(key[3], 2); - d = q[1][d] ^ getB(key[3], 3); - case 3: - a = q[1][a] ^ getB(key[2], 0); - b = q[1][b] ^ getB(key[2], 1); - c = q[0][c] ^ getB(key[2], 2); - d = q[0][d] ^ getB(key[2], 3); - case 2: - a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0); - b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1); - c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2); - d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3); - } - return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d]; - } - - keyBytes = keyBytes.slice(0, 32); - i = keyBytes.length; - while (i != 16 && i != 24 && i != 32) - keyBytes[i++] = 0; - - for (i = 0; i < keyBytes.length; i += 4) { - inKey[i >> 2] = getW(keyBytes, i); - } - for (i = 0; i < 256; i++) { - q[0][i] = qp(0, i); - q[1][i] = qp(1, i); - } - for (i = 0; i < 256; i++) { - f01 = q[1][i]; - f5b = ffm5b(f01); - fef = ffmEf(f01); - m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24); - m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24); - f01 = q[0][i]; - f5b = ffm5b(f01); - fef = ffmEf(f01); - m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24); - m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24); - } - - kLen = inKey.length / 2; - for (i = 0; i < kLen; i++) { - a = inKey[i + i]; - meKey[i] = a; - b = inKey[i + i + 1]; - moKey[i] = b; - sKey[kLen - i - 1] = mdsRem(a, b); - } - for (i = 0; i < 40; i += 2) { - a = 0x1010101 * i; - b = a + 0x1010101; - a = hFun(a, meKey); - b = rotw(hFun(b, moKey), 8); - tfsKey[i] = (a + b) & MAXINT; - tfsKey[i + 1] = rotw(a + 2 * b, 9); - } - for (i = 0; i < 256; i++) { - a = b = c = d = i; - switch (kLen) { - case 4: - a = q[1][a] ^ getB(sKey[3], 0); - b = q[0][b] ^ getB(sKey[3], 1); - c = q[0][c] ^ getB(sKey[3], 2); - d = q[1][d] ^ getB(sKey[3], 3); - case 3: - a = q[1][a] ^ getB(sKey[2], 0); - b = q[1][b] ^ getB(sKey[2], 1); - c = q[0][c] ^ getB(sKey[2], 2); - d = q[0][d] ^ getB(sKey[2], 3); - case 2: - tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)] - ^ getB(sKey[0], 0)]; - tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)] - ^ getB(sKey[0], 1)]; - tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)] - ^ getB(sKey[0], 2)]; - tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)] - ^ getB(sKey[0], 3)]; - } - } - } - - function tfsG0(x) { - return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)] - ^ tfsM[3][getB(x, 3)]; - } - function tfsG1(x) { - return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)] - ^ tfsM[3][getB(x, 2)]; - } - - function tfsFrnd(r, blk) { - var a = tfsG0(blk[0]); - var b = tfsG1(blk[1]); - blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31); - blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT; - a = tfsG0(blk[2]); - b = tfsG1(blk[3]); - blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31); - blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT; - } - - function tfsIrnd(i, blk) { - var a = tfsG0(blk[0]); - var b = tfsG1(blk[1]); - blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT; - blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31); - a = tfsG0(blk[2]); - b = tfsG1(blk[3]); - blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT; - blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31); - } - - function tfsClose() { - tfsKey = []; - tfsM = [ [], [], [], [] ]; - } - - function tfsEncrypt(data, offset) { - dataBytes = data; - dataOffset = offset; - var blk = [ getW(dataBytes, dataOffset) ^ tfsKey[0], - getW(dataBytes, dataOffset + 4) ^ tfsKey[1], - getW(dataBytes, dataOffset + 8) ^ tfsKey[2], - getW(dataBytes, dataOffset + 12) ^ tfsKey[3] ]; - for ( var j = 0; j < 8; j++) { - tfsFrnd(j, blk); - } - setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]); - setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]); - setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]); - setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]); - dataOffset += 16; - return dataBytes; - } - - function tfsDecrypt(data, offset) { - dataBytes = data; - dataOffset = offset; - var blk = [ getW(dataBytes, dataOffset) ^ tfsKey[4], - getW(dataBytes, dataOffset + 4) ^ tfsKey[5], - getW(dataBytes, dataOffset + 8) ^ tfsKey[6], - getW(dataBytes, dataOffset + 12) ^ tfsKey[7] ]; - for ( var j = 7; j >= 0; j--) { - tfsIrnd(j, blk); - } - setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]); - setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]); - setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]); - setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]); - dataOffset += 16; - } - - // added by Recurity Labs - function tfsFinal() { - return dataBytes; - } - - return { - name : "twofish", - blocksize : 128 / 8, - open : tfsInit, - close : tfsClose, - encrypt : tfsEncrypt, - decrypt : tfsDecrypt, - // added by Recurity Labs - finalize: tfsFinal - }; -} - -JXG = {exists: (function(undefined){return function(v){return !(v===undefined || v===null);}})()}; -JXG.decompress = function(str) {return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip()[0][0]);}; -/* - Copyright 2008-2012 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt - - This file is part of JSXGraph. - - Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses. - - You should have received a copy of the GNU Lesser General Public License - along with JSXCompressor. If not, see . - - You should have received a copy of the Apache License along with JSXCompressor. - If not, see . - -*/ - -/** - * @class Util class - * @classdesc Utilities for uncompressing and base64 decoding - * Class for gunzipping, unzipping and base64 decoding of files. - * It is used for reading GEONExT, Geogebra and Intergeo files. - * - * Only Huffman codes are decoded in gunzip. - * The code is based on the source code for gunzip.c by Pasi Ojala - * {@link http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c} - * {@link http://www.cs.tut.fi/~albert} - */ -JXG.Util = {}; - -/** - * Unzip zip files - */ -JXG.Util.Unzip = function (barray){ - var outputArr = [], - output = "", - debug = false, - gpflags, - files = 0, - unzipped = [], - crc, - buf32k = new Array(32768), - bIdx = 0, - modeZIP=false, - - CRC, SIZE, - - bitReverse = [ - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff - ], - - cplens = [ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 - ], - - cplext = [ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 - ], /* 99==invalid */ - - cpdist = [ - 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, - 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, - 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01, - 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001 - ], - - cpdext = [ - 0, 0, 0, 0, 1, 1, 2, 2, - 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, - 11, 11, 12, 12, 13, 13 - ], - - border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], - - bA = barray, - - bytepos=0, - bitpos=0, - bb = 1, - bits=0, - - NAMEMAX = 256, - - nameBuf = [], - - fileout; - - function readByte(){ - bits+=8; - if (bytepos"); - return bA[bytepos++]; - } else - return -1; - }; - - function byteAlign(){ - bb = 1; - }; - - function readBit(){ - var carry; - bits++; - carry = (bb & 1); - bb >>= 1; - if (bb==0){ - bb = readByte(); - carry = (bb & 1); - bb = (bb>>1) | 0x80; - } - return carry; - }; - - function readBits(a) { - var res = 0, - i = a; - - while(i--) { - res = (res<<1) | readBit(); - } - if(a) { - res = bitReverse[res]>>(8-a); - } - return res; - }; - - function flushBuffer(){ - //document.write('FLUSHBUFFER:'+buf32k); - bIdx = 0; - }; - function addBuffer(a){ - SIZE++; - //CRC=updcrc(a,crc); - buf32k[bIdx++] = a; - outputArr.push(String.fromCharCode(a)); - //output+=String.fromCharCode(a); - if(bIdx==0x8000){ - //document.write('ADDBUFFER:'+buf32k); - bIdx=0; - } - }; - - function HufNode() { - this.b0=0; - this.b1=0; - this.jump = null; - this.jumppos = -1; - }; - - var LITERALS = 288; - - var literalTree = new Array(LITERALS); - var distanceTree = new Array(32); - var treepos=0; - var Places = null; - var Places2 = null; - - var impDistanceTree = new Array(64); - var impLengthTree = new Array(64); - - var len = 0; - var fpos = new Array(17); - fpos[0]=0; - var flens; - var fmax; - - function IsPat() { - while (1) { - if (fpos[len] >= fmax) - return -1; - if (flens[fpos[len]] == len) - return fpos[len]++; - fpos[len]++; - } - }; - - function Rec() { - var curplace = Places[treepos]; - var tmp; - if (debug) - document.write("
      len:"+len+" treepos:"+treepos); - if(len==17) { //war 17 - return -1; - } - treepos++; - len++; - - tmp = IsPat(); - if (debug) - document.write("
      IsPat "+tmp); - if(tmp >= 0) { - curplace.b0 = tmp; /* leaf cell for 0-bit */ - if (debug) - document.write("
      b0 "+curplace.b0); - } else { - /* Not a Leaf cell */ - curplace.b0 = 0x8000; - if (debug) - document.write("
      b0 "+curplace.b0); - if(Rec()) - return -1; - } - tmp = IsPat(); - if(tmp >= 0) { - curplace.b1 = tmp; /* leaf cell for 1-bit */ - if (debug) - document.write("
      b1 "+curplace.b1); - curplace.jump = null; /* Just for the display routine */ - } else { - /* Not a Leaf cell */ - curplace.b1 = 0x8000; - if (debug) - document.write("
      b1 "+curplace.b1); - curplace.jump = Places[treepos]; - curplace.jumppos = treepos; - if(Rec()) - return -1; - } - len--; - return 0; - }; - - function CreateTree(currentTree, numval, lengths, show) { - var i; - /* Create the Huffman decode tree/table */ - //document.write("
      createtree
      "); - if (debug) - document.write("currentTree "+currentTree+" numval "+numval+" lengths "+lengths+" show "+show); - Places = currentTree; - treepos=0; - flens = lengths; - fmax = numval; - for (i=0;i<17;i++) - fpos[i] = 0; - len = 0; - if(Rec()) { - //fprintf(stderr, "invalid huffman tree\n"); - if (debug) - alert("invalid huffman tree\n"); - return -1; - } - if (debug){ - document.write('
      Tree: '+Places.length); - for (var a=0;a<32;a++){ - document.write("Places["+a+"].b0="+Places[a].b0+"
      "); - document.write("Places["+a+"].b1="+Places[a].b1+"
      "); - } - } - - /*if(show) { - var tmp; - for(tmp=currentTree;tmpjump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0); - if(!(tmp.b0 & 0x8000)) { - //fprintf(stdout, " 0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�'); - } - if(!(tmp.b1 & 0x8000)) { - if((tmp.b0 & 0x8000)) - fprintf(stdout, " "); - fprintf(stdout, " 0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�'); - } - fprintf(stdout, "\n"); - } - }*/ - return 0; - }; - - function DecodeValue(currentTree) { - var len, i, - xtreepos=0, - X = currentTree[xtreepos], - b; - - /* decode one symbol of the data */ - while(1) { - b=readBit(); - if (debug) - document.write("b="+b); - if(b) { - if(!(X.b1 & 0x8000)){ - if (debug) - document.write("ret1"); - return X.b1; /* If leaf node, return data */ - } - X = X.jump; - len = currentTree.length; - for (i=0;i>1); - if(j > 23) { - j = (j<<1) | readBit(); /* 48..255 */ - - if(j > 199) { /* 200..255 */ - j -= 128; /* 72..127 */ - j = (j<<1) | readBit(); /* 144..255 << */ - } else { /* 48..199 */ - j -= 48; /* 0..151 */ - if(j > 143) { - j = j+136; /* 280..287 << */ - /* 0..143 << */ - } - } - } else { /* 0..23 */ - j += 256; /* 256..279 << */ - } - if(j < 256) { - addBuffer(j); - //document.write("out:"+String.fromCharCode(j)); - /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/ - } else if(j == 256) { - /* EOF */ - break; - } else { - var len, dist; - - j -= 256 + 1; /* bytes + EOF */ - len = readBits(cplext[j]) + cplens[j]; - - j = bitReverse[readBits(5)]>>3; - if(cpdext[j] > 8) { - dist = readBits(8); - dist |= (readBits(cpdext[j]-8)<<8); - } else { - dist = readBits(cpdext[j]); - } - dist += cpdist[j]; - - /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/ - for(j=0;jparam: "+literalCodes+" "+distCodes+" "+lenCodes+"
      "); - for(j=0; j<19; j++) { - ll[j] = 0; - } - - // Get the decode tree code lengths - - //document.write("
      "); - for(j=0; jll:'+ll); - len = distanceTree.length; - for (i=0; idistanceTree"); - for(var a=0;a"+distanceTree[a].b0+" "+distanceTree[a].b1+" "+distanceTree[a].jump+" "+distanceTree[a].jumppos); - /*if (distanceTree[a].jumppos!=-1) - document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1); - */ - } - } - //document.write('
      tree created'); - - //read in literal and distance code lengths - n = literalCodes + distCodes; - i = 0; - var z=-1; - if (debug) - document.write("
      n="+n+" bits: "+bits+"
      "); - while(i < n) { - z++; - j = DecodeValue(distanceTree); - if (debug) - document.write("
      "+z+" i:"+i+" decode: "+j+" bits "+bits+"
      "); - if(j<16) { // length of code in bits (0..15) - ll[i++] = j; - } else if(j==16) { // repeat last length 3 to 6 times - var l; - j = 3 + readBits(2); - if(i+j > n) { - flushBuffer(); - return 1; - } - l = i ? ll[i-1] : 0; - while(j--) { - ll[i++] = l; - } - } else { - if(j==17) { // 3 to 10 zero length codes - j = 3 + readBits(3); - } else { // j == 18: 11 to 138 zero length codes - j = 11 + readBits(7); - } - if(i+j > n) { - flushBuffer(); - return 1; - } - while(j--) { - ll[i++] = 0; - } - } - } - /*for(j=0; jliteralTree"); - outer: - while(1) { - j = DecodeValue(literalTree); - if(j >= 256) { // In C64: if carry set - var len, dist; - j -= 256; - if(j == 0) { - // EOF - break; - } - j--; - len = readBits(cplext[j]) + cplens[j]; - - j = DecodeValue(distanceTree); - if(cpdext[j] > 8) { - dist = readBits(8); - dist |= (readBits(cpdext[j]-8)<<8); - } else { - dist = readBits(cpdext[j]); - } - dist += cpdist[j]; - while(len--) { - if(bIdx - dist < 0) { - break outer; - } - var c = buf32k[(bIdx - dist) & 0x7fff]; - addBuffer(c); - } - } else { - addBuffer(j); - } - } - } - } while(!last); - flushBuffer(); - - byteAlign(); - return 0; -}; - -JXG.Util.Unzip.prototype.unzipFile = function(name) { - var i; - this.unzip(); - //alert(unzipped[0][1]); - for (i=0;i"); - } - */ - //alert(bA); - nextFile(); - return unzipped; - }; - - function nextFile(){ - if (debug) - alert("NEXTFILE"); - outputArr = []; - var tmp = []; - modeZIP = false; - tmp[0] = readByte(); - tmp[1] = readByte(); - if (debug) - alert("type: "+tmp[0]+" "+tmp[1]); - if (tmp[0] == parseInt("78",16) && tmp[1] == parseInt("da",16)){ //GZIP - if (debug) - alert("GEONExT-GZIP"); - DeflateLoop(); - if (debug) - alert(outputArr.join('')); - unzipped[files] = new Array(2); - unzipped[files][0] = outputArr.join(''); - unzipped[files][1] = "geonext.gxt"; - files++; - } - if (tmp[0] == parseInt("78",16) && tmp[1] == parseInt("9c",16)){ //ZLIB - if (debug) - alert("ZLIB"); - DeflateLoop(); - if (debug) - alert(outputArr.join('')); - unzipped[files] = new Array(2); - unzipped[files][0] = outputArr.join(''); - unzipped[files][1] = "ZLIB"; - files++; - } - if (tmp[0] == parseInt("1f",16) && tmp[1] == parseInt("8b",16)){ //GZIP - if (debug) - alert("GZIP"); - //DeflateLoop(); - skipdir(); - if (debug) - alert(outputArr.join('')); - unzipped[files] = new Array(2); - unzipped[files][0] = outputArr.join(''); - unzipped[files][1] = "file"; - files++; - } - if (tmp[0] == parseInt("50",16) && tmp[1] == parseInt("4b",16)){ //ZIP - modeZIP = true; - tmp[2] = readByte(); - tmp[3] = readByte(); - if (tmp[2] == parseInt("3",16) && tmp[3] == parseInt("4",16)){ - //MODE_ZIP - tmp[0] = readByte(); - tmp[1] = readByte(); - if (debug) - alert("ZIP-Version: "+tmp[1]+" "+tmp[0]/10+"."+tmp[0]%10); - - gpflags = readByte(); - gpflags |= (readByte()<<8); - if (debug) - alert("gpflags: "+gpflags); - - var method = readByte(); - method |= (readByte()<<8); - if (debug) - alert("method: "+method); - - readByte(); - readByte(); - readByte(); - readByte(); - - var crc = readByte(); - crc |= (readByte()<<8); - crc |= (readByte()<<16); - crc |= (readByte()<<24); - - var compSize = readByte(); - compSize |= (readByte()<<8); - compSize |= (readByte()<<16); - compSize |= (readByte()<<24); - - var size = readByte(); - size |= (readByte()<<8); - size |= (readByte()<<16); - size |= (readByte()<<24); - - if (debug) - alert("local CRC: "+crc+"\nlocal Size: "+size+"\nlocal CompSize: "+compSize); - - var filelen = readByte(); - filelen |= (readByte()<<8); - - var extralen = readByte(); - extralen |= (readByte()<<8); - - if (debug) - alert("filelen "+filelen); - i = 0; - nameBuf = []; - while (filelen--){ - var c = readByte(); - if (c == "/" | c ==":"){ - i = 0; - } else if (i < NAMEMAX-1) - nameBuf[i++] = String.fromCharCode(c); - } - if (debug) - alert("nameBuf: "+nameBuf); - - //nameBuf[i] = "\0"; - if (!fileout) - fileout = nameBuf; - - var i = 0; - while (i < extralen){ - c = readByte(); - i++; - } - - CRC = 0xffffffff; - SIZE = 0; - - if (size == 0 && fileOut.charAt(fileout.length-1)=="/"){ - //skipdir - if (debug) - alert("skipdir"); - } - if (method == 8){ - DeflateLoop(); - if (debug) - alert(outputArr.join('')); - unzipped[files] = new Array(2); - unzipped[files][0] = outputArr.join(''); - unzipped[files][1] = nameBuf.join(''); - files++; - //return outputArr.join(''); - } - skipdir(); - } - } - }; - -function skipdir(){ - var crc, - tmp = [], - compSize, size, os, i, c; - - if ((gpflags & 8)) { - tmp[0] = readByte(); - tmp[1] = readByte(); - tmp[2] = readByte(); - tmp[3] = readByte(); - - if (tmp[0] == parseInt("50",16) && - tmp[1] == parseInt("4b",16) && - tmp[2] == parseInt("07",16) && - tmp[3] == parseInt("08",16)) - { - crc = readByte(); - crc |= (readByte()<<8); - crc |= (readByte()<<16); - crc |= (readByte()<<24); - } else { - crc = tmp[0] | (tmp[1]<<8) | (tmp[2]<<16) | (tmp[3]<<24); - } - - compSize = readByte(); - compSize |= (readByte()<<8); - compSize |= (readByte()<<16); - compSize |= (readByte()<<24); - - size = readByte(); - size |= (readByte()<<8); - size |= (readByte()<<16); - size |= (readByte()<<24); - - if (debug) - alert("CRC:"); - } - - if (modeZIP) - nextFile(); - - tmp[0] = readByte(); - if (tmp[0] != 8) { - if (debug) - alert("Unknown compression method!"); - return 0; - } - - gpflags = readByte(); - if (debug){ - if ((gpflags & ~(parseInt("1f",16)))) - alert("Unknown flags set!"); - } - - readByte(); - readByte(); - readByte(); - readByte(); - - readByte(); - os = readByte(); - - if ((gpflags & 4)){ - tmp[0] = readByte(); - tmp[2] = readByte(); - len = tmp[0] + 256*tmp[1]; - if (debug) - alert("Extra field size: "+len); - for (i=0;i> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output.push([this._keyStr.charAt(enc1), - this._keyStr.charAt(enc2), - this._keyStr.charAt(enc3), - this._keyStr.charAt(enc4)].join('')); - } - - return output.join(''); - }, - - // public method for decoding - decode : function (input, utf8) { - var output = [], - chr1, chr2, chr3, - enc1, enc2, enc3, enc4, - i = 0; - - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - while (i < input.length) { - - enc1 = this._keyStr.indexOf(input.charAt(i++)); - enc2 = this._keyStr.indexOf(input.charAt(i++)); - enc3 = this._keyStr.indexOf(input.charAt(i++)); - enc4 = this._keyStr.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output.push(String.fromCharCode(chr1)); - - if (enc3 != 64) { - output.push(String.fromCharCode(chr2)); - } - if (enc4 != 64) { - output.push(String.fromCharCode(chr3)); - } - } - - output = output.join(''); - - if (utf8) { - output = JXG.Util.Base64._utf8_decode(output); - } - return output; - - }, - - // private method for UTF-8 encoding - _utf8_encode : function (string) { - string = string.replace(/\r\n/g,"\n"); - var utftext = ""; - - for (var n = 0; n < string.length; n++) { - - var c = string.charCodeAt(n); - - if (c < 128) { - utftext += String.fromCharCode(c); - } - else if((c > 127) && (c < 2048)) { - utftext += String.fromCharCode((c >> 6) | 192); - utftext += String.fromCharCode((c & 63) | 128); - } - else { - utftext += String.fromCharCode((c >> 12) | 224); - utftext += String.fromCharCode(((c >> 6) & 63) | 128); - utftext += String.fromCharCode((c & 63) | 128); - } - - } - - return utftext; - }, - - // private method for UTF-8 decoding - _utf8_decode : function (utftext) { - var string = [], - i = 0, - c = 0, c2 = 0, c3 = 0; - - while ( i < utftext.length ) { - c = utftext.charCodeAt(i); - if (c < 128) { - string.push(String.fromCharCode(c)); - i++; - } - else if((c > 191) && (c < 224)) { - c2 = utftext.charCodeAt(i+1); - string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63))); - i += 2; - } - else { - c2 = utftext.charCodeAt(i+1); - c3 = utftext.charCodeAt(i+2); - string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); - i += 3; - } - } - return string.join(''); - }, - - _destrip: function (stripped, wrap){ - var lines = [], lineno, i, - destripped = []; - - if (wrap==null) - wrap = 76; - - stripped.replace(/ /g, ""); - lineno = stripped.length / wrap; - for (i = 0; i < lineno; i++) - lines[i]=stripped.substr(i * wrap, wrap); - if (lineno != stripped.length / wrap) - lines[lines.length]=stripped.substr(lineno * wrap, stripped.length-(lineno * wrap)); - - for (i = 0; i < lines.length; i++) - destripped.push(lines[i]); - return destripped.join('\n'); - }, - - decodeAsArray: function (input){ - var dec = this.decode(input), - ar = [], i; - for (i=0;i255){ - switch (c) { - case 8364: c=128; - break; - case 8218: c=130; - break; - case 402: c=131; - break; - case 8222: c=132; - break; - case 8230: c=133; - break; - case 8224: c=134; - break; - case 8225: c=135; - break; - case 710: c=136; - break; - case 8240: c=137; - break; - case 352: c=138; - break; - case 8249: c=139; - break; - case 338: c=140; - break; - case 381: c=142; - break; - case 8216: c=145; - break; - case 8217: c=146; - break; - case 8220: c=147; - break; - case 8221: c=148; - break; - case 8226: c=149; - break; - case 8211: c=150; - break; - case 8212: c=151; - break; - case 732: c=152; - break; - case 8482: c=153; - break; - case 353: c=154; - break; - case 8250: c=155; - break; - case 339: c=156; - break; - case 382: c=158; - break; - case 376: c=159; - break; - default: - break; - } - } - return c; -}; - -/** - * Decoding string into utf-8 - * @param {String} string to decode - * @return {String} utf8 decoded string - */ -JXG.Util.utf8Decode = function(utftext) { - var string = []; - var i = 0; - var c = 0, c1 = 0, c2 = 0, c3; - if (!JXG.exists(utftext)) return ''; - - while ( i < utftext.length ) { - c = utftext.charCodeAt(i); - - if (c < 128) { - string.push(String.fromCharCode(c)); - i++; - } else if((c > 191) && (c < 224)) { - c2 = utftext.charCodeAt(i+1); - string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63))); - i += 2; - } else { - c2 = utftext.charCodeAt(i+1); - c3 = utftext.charCodeAt(i+2); - string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); - i += 3; - } - }; - return string.join(''); -}; - -/** - * Generate a random uuid. - * http://www.broofa.com - * mailto:robert@broofa.com - * - * Copyright (c) 2010 Robert Kieffer - * Dual licensed under the MIT and GPL licenses. - * - * EXAMPLES: - * >>> Math.uuid() - * "92329D39-6F5C-4520-ABFC-AAB64544E172" - */ -JXG.Util.genUUID = function() { - // Private array of chars to use - var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''), - uuid = new Array(36), rnd=0, r; - - for (var i = 0; i < 36; i++) { - if (i==8 || i==13 || i==18 || i==23) { - uuid[i] = '-'; - } else if (i==14) { - uuid[i] = '4'; - } else { - if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; - r = rnd & 0xf; - rnd = rnd >> 4; - uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; - } + getRandomBigIntegerInRange: function(min, max) { + if (max.compareTo(min) <= 0) { + return; } - return uuid.join(''); + var range = max.subtract(min); + var r = this.getRandomBigInteger(range.bitLength()); + while (r > range) { + r = this.getRandomBigInteger(range.bitLength()); + } + return min.add(r); + } + }; +},{"../type/mpi.js":54}],24:[function(require,module,exports){ +/** + * @requires crypto/hash + * @requires crypto/pkcs1 + * @requires crypto/public_key + * @module crypto/signature */ + +var publicKey = require('./public_key'), + pkcs1 = require('./pkcs1.js'), + hashModule = require('./hash'); + +module.exports = { + /** + * + * @param {Integer} algo public Key algorithm + * @param {Integer} hash_algo Hash algorithm + * @param {Array} msg_MPIs Signature multiprecision integers + * @param {Array} publickey_MPIs Public key multiprecision integers + * @param {String} data Data on where the signature was computed on. + * @return {Boolean} true if signature (sig_data was equal to data over hash) + */ + verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) { + var calc_hash = hashModule.digest(hash_algo, data); + + switch (algo) { + case 1: + // RSA (Encrypt or Sign) [HAC] + case 2: + // RSA Encrypt-Only [HAC] + case 3: + // RSA Sign-Only [HAC] + var rsa = new publicKey.rsa(); + var n = publickey_MPIs[0].toBigInteger(); + var e = publickey_MPIs[1].toBigInteger(); + var x = msg_MPIs[0].toBigInteger(); + var dopublic = rsa.verify(x, e, n); + var hash = pkcs1.emsa.decode(hash_algo, dopublic.toMPI().substring(2)); + if (hash == -1) { + throw new Error('PKCS1 padding in message or key incorrect. Aborting...'); + } + return hash == calc_hash; + + case 16: + // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] + throw new Error("signing with Elgamal is not defined in the OpenPGP standard."); + case 17: + // DSA (Digital Signature Algorithm) [FIPS186] [HAC] + var dsa = new publicKey.dsa(); + var s1 = msg_MPIs[0].toBigInteger(); + var s2 = msg_MPIs[1].toBigInteger(); + var p = publickey_MPIs[0].toBigInteger(); + var q = publickey_MPIs[1].toBigInteger(); + var g = publickey_MPIs[2].toBigInteger(); + var y = publickey_MPIs[3].toBigInteger(); + var m = data; + var dopublic = dsa.verify(hash_algo, s1, s2, m, p, q, g, y); + return dopublic.compareTo(s1) == 0; + default: + throw new Error('Invalid signature algorithm.'); + } + + }, + + /** + * Create a signature on data using the specified algorithm + * @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4) + * @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1) + * @param {Array} publicMPIs Public key multiprecision integers + * of the private key + * @param {Array} secretMPIs Private key multiprecision + * integers which is used to sign the data + * @param {String} data Data to be signed + * @return {Array} + */ + sign: function(hash_algo, algo, keyIntegers, data) { + + switch (algo) { + case 1: + // RSA (Encrypt or Sign) [HAC] + case 2: + // RSA Encrypt-Only [HAC] + case 3: + // RSA Sign-Only [HAC] + var rsa = new publicKey.rsa(); + var d = keyIntegers[2].toBigInteger(); + var n = keyIntegers[0].toBigInteger(); + var m = pkcs1.emsa.encode(hash_algo, + data, keyIntegers[0].byteLength()); + + return rsa.sign(m, d, n).toMPI(); + + case 17: + // DSA (Digital Signature Algorithm) [FIPS186] [HAC] + var dsa = new publicKey.dsa(); + + var p = keyIntegers[0].toBigInteger(); + var q = keyIntegers[1].toBigInteger(); + var g = keyIntegers[2].toBigInteger(); + var y = keyIntegers[3].toBigInteger(); + var x = keyIntegers[4].toBigInteger(); + var m = data; + var result = dsa.sign(hash_algo, m, g, p, q, x); + + return result[0].toString() + result[1].toString(); + case 16: + // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] + throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.'); + default: + throw new Error('Invalid signature algorithm.'); + } + } +} + +},{"./hash":12,"./pkcs1.js":17,"./public_key":20}],25:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -7382,283 +8624,15 @@ JXG.Util.genUUID = function() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * - * This object contains configuration values and implements - * storing and retrieving configuration them from HTML5 local storage. - * - * This object can be accessed after calling openpgp.init() - * using openpgp.config - * Stored config parameters can be accessed using - * openpgp.config.config - * @class - * @classdesc Implementation of the GPG4Browsers config object + * @requires encoding/base64 + * @requires enums + * @requires config + * @module encoding/armor */ -function openpgp_config() { - /** - * The variable with the actual configuration - * @property {Integer} prefer_hash_algorithm - * @property {Integer} encryption_cipher - * @property {Integer} compression - * @property {Boolean} show_version - * @property {Boolean} show_comment - * @property {Boolean} integrity_protect - * @property {Integer} composition_behavior - * @property {String} keyserver - */ - this.config = null; - /** - * The default config object which is used if no - * configuration was in place - */ - this.default_config = { - prefer_hash_algorithm: 8, - encryption_cipher: 9, - compression: 1, - show_version: true, - show_comment: true, - integrity_protect: true, - composition_behavior: 0, - keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371" - }; - - this.versionstring ="OpenPGP.js v.1.20131204"; - this.commentstring ="http://openpgpjs.org"; - /** - * Reads the config out of the HTML5 local storage - * and initializes the object config. - * if config is null the default config will be used - */ - function read() { - var cf = JSON.parse(window.localStorage.getItem("config")); - if (cf == null) { - this.config = this.default_config; - this.write(); - } - else - this.config = cf; - } - - /** - * If enabled, debug messages will be printed - */ - this.debug = false; - - /** - * Writes the config to HTML5 local storage - */ - function write() { - window.localStorage.setItem("config",JSON.stringify(this.config)); - } - - this.read = read; - this.write = write; -} -/* OpenPGP radix-64/base64 string encoding/decoding - * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de - * version 1.0, check www.haneWIN.de for the latest version - * - * This software is provided as-is, without express or implied warranty. - * Permission to use, copy, modify, distribute or sell this software, with or - * without fee, for any purpose and by any individual or organization, is hereby - * granted, provided that the above copyright notice and this paragraph appear - * in all copies. Distribution as a part of an application or binary must - * include the above copyright notice in the documentation and/or other materials - * provided with the application or distribution. - */ - -var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - -function s2r(t) { - var a, c, n; - var r = '', l = 0, s = 0; - var tl = t.length; - - for (n = 0; n < tl; n++) { - c = t.charCodeAt(n); - if (s == 0) { - r += b64s.charAt((c >> 2) & 63); - a = (c & 3) << 4; - } else if (s == 1) { - r += b64s.charAt((a | (c >> 4) & 15)); - a = (c & 15) << 2; - } else if (s == 2) { - r += b64s.charAt(a | ((c >> 6) & 3)); - l += 1; - if ((l % 60) == 0) - r += "\n"; - r += b64s.charAt(c & 63); - } - l += 1; - if ((l % 60) == 0) - r += "\n"; - - s += 1; - if (s == 3) - s = 0; - } - if (s > 0) { - r += b64s.charAt(a); - l += 1; - if ((l % 60) == 0) - r += "\n"; - r += '='; - l += 1; - } - if (s == 1) { - if ((l % 60) == 0) - r += "\n"; - r += '='; - } - if (r.charAt(r.length-1)==="\n") - r=r.slice(0,-1); - return r; -} - -function r2s(t) { - var c, n; - var r = '', s = 0, a = 0; - var tl = t.length; - - for (n = 0; n < tl; n++) { - c = b64s.indexOf(t.charAt(n)); - if (c >= 0) { - if (s) - r += String.fromCharCode(a | (c >> (6 - s)) & 255); - s = (s + 2) & 7; - a = (c << s) & 255; - } - } - return r; -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * DeArmor an OpenPGP armored message; verify the checksum and return - * the encoded bytes - * @param {String} text OpenPGP armored message - * @returns {(Boolean|Object)} Either false in case of an error - * or an object with attribute "text" containing the message text - * and an attribute "openpgp" containing the bytes. - */ -function openpgp_encoding_deArmor(text) { - var reSplit = /^-----[^-]+-----$\n/m; - - text = text.replace(/\r/g, ''); - - var type = openpgp_encoding_get_type(text); - - var splittedtext = text.split(reSplit); - - // IE has a bug in split with a re. If the pattern matches the beginning of the - // string it doesn't create an empty array element 0. So we need to detect this - // so we know the index of the data we are interested in. - var indexBase = 1; - - var result, checksum; - - if (text.search(reSplit) != splittedtext[0].length) { - indexBase = 0; - } - - if (type != 2) { - // splittedtext[indexBase] - the message and checksum - - // chunks separated by blank lines - var msg = openpgp_encoding_split_headers(splittedtext[indexBase].replace(/^- /mg, '')); - var msg_sum = openpgp_encoding_split_checksum(msg.body); - - result = { - openpgp: openpgp_encoding_base64_decode(msg_sum.body), - type: type - }; - checksum = msg_sum.checksum; - } else { - // splittedtext[indexBase] - the message - // splittedtext[indexBase + 1] - the signature and checksum - - var msg = openpgp_encoding_split_headers(splittedtext[indexBase].replace(/^- /mg, '')); - var sig = openpgp_encoding_split_headers(splittedtext[indexBase + 1].replace(/^- /mg, '')); - var sig_sum = openpgp_encoding_split_checksum(sig.body); - - result = { - text: msg.body.replace(/\n$/, "").replace(/\n/g, "\r\n"), - openpgp: openpgp_encoding_base64_decode(sig_sum.body), - type: type - }; - - checksum = sig_sum.checksum; - } - - if (!verifyCheckSum(result.openpgp, checksum)) { - util.print_error("Ascii armor integrity check on message failed: '" - + checksum - + "' should be '" - + getCheckSum(result) + "'"); - return false; - } else { - return result; - } -} - -/** - * Splits a message into two parts, the headers and the body. This is an internal function - * @param {String} text OpenPGP armored message part - * @returns {(Boolean|Object)} Either false in case of an error - * or an object with attribute "headers" containing the headers and - * and an attribute "body" containing the body. - */ -function openpgp_encoding_split_headers(text) { - var reEmptyLine = /^[\t ]*\n/m; - var headers = ""; - var body = text; - - var matchResult = reEmptyLine.exec(text); - - if (matchResult != null) { - headers = text.slice(0, matchResult.index); - body = text.slice(matchResult.index + matchResult[0].length); - } - - return { headers: headers, body: body }; -} - -/** - * Splits a message into two parts, the body and the checksum. This is an internal function - * @param {String} text OpenPGP armored message part - * @returns {(Boolean|Object)} Either false in case of an error - * or an object with attribute "body" containing the body - * and an attribute "checksum" containing the checksum. - */ -function openpgp_encoding_split_checksum(text) { - var reChecksumStart = /^=/m; - var body = text; - var checksum = ""; - - var matchResult = reChecksumStart.exec(text); - - if (matchResult != null) { - body = text.slice(0, matchResult.index); - checksum = text.slice(matchResult.index + 1); - } - - return { body: body, checksum: checksum }; -} +var base64 = require('./base64.js'), + enums = require('../enums.js'), + config = require('../config'); /** * Finds out which Ascii Armoring type is used. This is an internal function @@ -7671,49 +8645,50 @@ function openpgp_encoding_split_checksum(text) { * 5 = PRIVATE KEY BLOCK * null = unknown */ -function openpgp_encoding_get_type(text) { - var reHeader = /^-----([^-]+)-----$\n/m; +function getType(text) { + var reHeader = /^-----([^-]+)-----$\n/m; - var header = text.match(reHeader); - // BEGIN PGP MESSAGE, PART X/Y - // Used for multi-part messages, where the armor is split amongst Y - // parts, and this is the Xth part out of Y. - if (header[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) { - return 0; - } else - // BEGIN PGP MESSAGE, PART X - // Used for multi-part messages, where this is the Xth part of an - // unspecified number of parts. Requires the MESSAGE-ID Armor - // Header to be used. - if (header[1].match(/BEGIN PGP MESSAGE, PART \d+/)) { - return 1; + var header = text.match(reHeader); - } else - // BEGIN PGP SIGNED MESSAGE - // Used for detached signatures, OpenPGP/MIME signatures, and - // cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE - // for detached signatures. - if (header[1].match(/BEGIN PGP SIGNED MESSAGE/)) { - return 2; + // BEGIN PGP MESSAGE, PART X/Y + // Used for multi-part messages, where the armor is split amongst Y + // parts, and this is the Xth part out of Y. + if (header[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) { + return enums.armor.multipart_section; + } else + // BEGIN PGP MESSAGE, PART X + // Used for multi-part messages, where this is the Xth part of an + // unspecified number of parts. Requires the MESSAGE-ID Armor + // Header to be used. + if (header[1].match(/BEGIN PGP MESSAGE, PART \d+/)) { + return enums.armor.multipart_last; - } else - // BEGIN PGP MESSAGE - // Used for signed, encrypted, or compressed files. - if (header[1].match(/BEGIN PGP MESSAGE/)) { - return 3; + } else + // BEGIN PGP SIGNATURE + // Used for detached signatures, OpenPGP/MIME signatures, and + // cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE + // for detached signatures. + if (header[1].match(/BEGIN PGP SIGNED MESSAGE/)) { + return enums.armor.signed; - } else - // BEGIN PGP PUBLIC KEY BLOCK - // Used for armoring public keys. - if (header[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) { - return 4; + } else + // BEGIN PGP MESSAGE + // Used for signed, encrypted, or compressed files. + if (header[1].match(/BEGIN PGP MESSAGE/)) { + return enums.armor.message; - } else - // BEGIN PGP PRIVATE KEY BLOCK - // Used for armoring private keys. - if (header[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) { - return 5; - } + } else + // BEGIN PGP PUBLIC KEY BLOCK + // Used for armoring public keys. + if (header[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) { + return enums.armor.public_key; + + } else + // BEGIN PGP PRIVATE KEY BLOCK + // Used for armoring private keys. + if (header[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) { + return enums.armor.private_key; + } } /** @@ -7723,77 +8698,19 @@ function openpgp_encoding_get_type(text) { * @version 2011-12-16 * @returns {String} The header information */ -function openpgp_encoding_armor_addheader() { - var result = ""; - if (openpgp.config.config.show_version) { - result += "Version: "+openpgp.config.versionstring+'\r\n'; - } - if (openpgp.config.config.show_comment) { - result += "Comment: "+openpgp.config.commentstring+'\r\n'; - } - result += '\r\n'; - return result; +function addheader() { + var result = ""; + if (config.show_version) { + result += "Version: " + config.versionstring + '\r\n'; + } + if (config.show_comment) { + result += "Comment: " + config.commentstring + '\r\n'; + } + result += '\r\n'; + return result; } -/** - * Armor an OpenPGP binary packet block - * @param {Integer} messagetype type of the message - * @param data - * @param {Integer} partindex - * @param {Integer} parttotal - * @returns {String} Armored text - */ -function openpgp_encoding_armor(messagetype, data, partindex, parttotal) { - var result = ""; - switch(messagetype) { - case 0: - result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n"; - result += openpgp_encoding_armor_addheader(); - result += openpgp_encoding_base64_encode(data); - result += "\r\n="+getCheckSum(data)+"\r\n"; - result += "-----END PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n"; - break; - case 1: - result += "-----BEGIN PGP MESSAGE, PART "+partindex+"-----\r\n"; - result += openpgp_encoding_armor_addheader(); - result += openpgp_encoding_base64_encode(data); - result += "\r\n="+getCheckSum(data)+"\r\n"; - result += "-----END PGP MESSAGE, PART "+partindex+"-----\r\n"; - break; - case 2: - result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "+data.hash+"\r\n\r\n"; - result += data.text.replace(/\n-/g,"\n- -"); - result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n"; - result += openpgp_encoding_armor_addheader(); - result += openpgp_encoding_base64_encode(data.openpgp); - result += "\r\n="+getCheckSum(data.openpgp)+"\r\n"; - result += "-----END PGP SIGNATURE-----\r\n"; - break; - case 3: - result += "-----BEGIN PGP MESSAGE-----\r\n"; - result += openpgp_encoding_armor_addheader(); - result += openpgp_encoding_base64_encode(data); - result += "\r\n="+getCheckSum(data)+"\r\n"; - result += "-----END PGP MESSAGE-----\r\n"; - break; - case 4: - result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n"; - result += openpgp_encoding_armor_addheader(); - result += openpgp_encoding_base64_encode(data); - result += "\r\n="+getCheckSum(data)+"\r\n"; - result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n"; - break; - case 5: - result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n"; - result += openpgp_encoding_armor_addheader(); - result += openpgp_encoding_base64_encode(data); - result += "\r\n="+getCheckSum(data)+"\r\n"; - result += "-----END PGP PRIVATE KEY BLOCK-----\r\n"; - break; - } - return result; -} /** * Calculates a checksum over the given data and returns it base64 encoded @@ -7801,24 +8718,24 @@ function openpgp_encoding_armor(messagetype, data, partindex, parttotal) { * @return {String} Base64 encoded checksum */ function getCheckSum(data) { - var c = createcrc24(data); - var str = "" + String.fromCharCode(c >> 16)+ - String.fromCharCode((c >> 8) & 0xFF)+ - String.fromCharCode(c & 0xFF); - return openpgp_encoding_base64_encode(str); + var c = createcrc24(data); + var str = "" + String.fromCharCode(c >> 16) + + String.fromCharCode((c >> 8) & 0xFF) + + String.fromCharCode(c & 0xFF); + return base64.encode(str); } /** - * Calculates the checksum over the given data and compares it with the + * Calculates the checksum over the given data and compares it with the * given base64 encoded checksum * @param {String} data Data to create a CRC-24 checksum for * @param {String} checksum Base64 encoded checksum * @return {Boolean} True if the given checksum is correct; otherwise false */ function verifyCheckSum(data, checksum) { - var c = getCheckSum(data); - var d = checksum; - return c[0] == d[0] && c[1] == d[1] && c[2] == d[2]; + var c = getCheckSum(data); + var d = checksum; + return c[0] == d[0] && c[1] == d[1] && c[2] == d[2]; } /** * Internal function to calculate a CRC-24 checksum over a given string (data) @@ -7826,41 +8743,714 @@ function verifyCheckSum(data, checksum) { * @return {Integer} The CRC-24 checksum as number */ var crc_table = [ -0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, -0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340, 0x62330fbb, -0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c, -0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538]; + 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139, + 0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, + 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd, + 0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, + 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631, + 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, + 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5, + 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, + 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b, + 0x315aa1a0, + 0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f, + 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, + 0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3, + 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, + 0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67, + 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, + 0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d, + 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, + 0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340, + 0x62330fbb, + 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, + 0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de, + 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, + 0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61, + 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, + 0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d, + 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, + 0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50, + 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, + 0x51f6d10c, + 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3, + 0x57dd8538 +]; function createcrc24(input) { var crc = 0xB704CE; var index = 0; - while((input.length - index) > 16) { - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+1)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+2)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+3)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+4)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+5)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+6)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+7)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+8)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+9)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+10)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+11)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+12)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+13)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+14)) & 0xff]; - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+15)) & 0xff]; - index += 16; + while ((input.length - index) > 16) { + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 1)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 2)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 3)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 4)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 5)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 6)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 7)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 8)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 9)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 10)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 11)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 12)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 13)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 14)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 15)) & 0xff]; + index += 16; } - for(var j = index; j < input.length; j++) { - crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff] + for (var j = index; j < input.length; j++) { + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff]; } return crc & 0xffffff; } +/** + * Splits a message into two parts, the headers and the body. This is an internal function + * @param {String} text OpenPGP armored message part + * @returns {(Boolean|Object)} Either false in case of an error + * or an object with attribute "headers" containing the headers and + * and an attribute "body" containing the body. + */ +function splitHeaders(text) { + var reEmptyLine = /^[\t ]*\n/m; + var headers = ""; + var body = text; + + var matchResult = reEmptyLine.exec(text); + + if (matchResult != null) { + headers = text.slice(0, matchResult.index); + body = text.slice(matchResult.index + matchResult[0].length); + } + + return { headers: headers, body: body }; +} + +/** + * Splits a message into two parts, the body and the checksum. This is an internal function + * @param {String} text OpenPGP armored message part + * @returns {(Boolean|Object)} Either false in case of an error + * or an object with attribute "body" containing the body + * and an attribute "checksum" containing the checksum. + */ +function splitChecksum(text) { + var reChecksumStart = /^=/m; + var body = text; + var checksum = ""; + + var matchResult = reChecksumStart.exec(text); + + if (matchResult != null) { + body = text.slice(0, matchResult.index); + checksum = text.slice(matchResult.index + 1); + } + + return { body: body, checksum: checksum }; +} + +/** + * DeArmor an OpenPGP armored message; verify the checksum and return + * the encoded bytes + * @param {String} text OpenPGP armored message + * @returns {Object} An object with attribute "text" containing the message text, + * an attribute "data" containing the bytes and "type" for the ASCII armor type + * @static + */ +function dearmor(text) { + var reSplit = /^-----[^-]+-----$\n/m; + + text = text.replace(/\r/g, ''); + + var type = getType(text); + if (!type) { + throw new Error('Unknow ASCII armor type'); + } + + var splittext = text.split(reSplit); + + // IE has a bug in split with a re. If the pattern matches the beginning of the + // string it doesn't create an empty array element 0. So we need to detect this + // so we know the index of the data we are interested in. + var indexBase = 1; + + var result, checksum; + + if (text.search(reSplit) != splittext[0].length) { + indexBase = 0; + } + + if (type != 2) { + var msg = splitHeaders(splittext[indexBase]); + var msg_sum = splitChecksum(msg.body); + + result = { + data: base64.decode(msg_sum.body), + type: type + }; + + checksum = msg_sum.checksum; + } else { + // Reverse dash-escaping for msg and remove trailing whitespace at end of line + var msg = splitHeaders(splittext[indexBase].replace(/^- /mg, '').replace(/[\t ]+\n/g, "\n")); + var sig = splitHeaders(splittext[indexBase + 1].replace(/^- /mg, '')); + var sig_sum = splitChecksum(sig.body); + + result = { + text: msg.body.replace(/\n$/, '').replace(/\n/g, "\r\n"), + data: base64.decode(sig_sum.body), + type: type + }; + + checksum = sig_sum.checksum; + } + + if (!verifyCheckSum(result.data, checksum)) { + throw new Error("Ascii armor integrity check on message failed: '" + + checksum + + "' should be '" + + getCheckSum(result) + "'"); + } else { + return result; + } +} + + +/** + * Armor an OpenPGP binary packet block + * @param {Integer} messagetype type of the message + * @param body + * @param {Integer} partindex + * @param {Integer} parttotal + * @returns {String} Armored text + * @static + */ +function armor(messagetype, body, partindex, parttotal) { + var result = ""; + switch (messagetype) { + case enums.armor.multipart_section: + result += "-----BEGIN PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n"; + break; + case enums.armor.mutlipart_last: + result += "-----BEGIN PGP MESSAGE, PART " + partindex + "-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP MESSAGE, PART " + partindex + "-----\r\n"; + break; + case enums.armor.signed: + result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\n"; + result += "Hash: " + body.hash + "\r\n\r\n"; + result += body.text.replace(/\n-/g, "\n- -"); + result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n"; + result += addheader(); + result += base64.encode(body.data); + result += "\r\n=" + getCheckSum(body.data) + "\r\n"; + result += "-----END PGP SIGNATURE-----\r\n"; + break; + case enums.armor.message: + result += "-----BEGIN PGP MESSAGE-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP MESSAGE-----\r\n"; + break; + case enums.armor.public_key: + result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n"; + break; + case enums.armor.private_key: + result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP PRIVATE KEY BLOCK-----\r\n"; + break; + } + + return result; +} + +module.exports = { + encode: armor, + decode: dearmor +}; + +},{"../config":3,"../enums.js":27,"./base64.js":26}],26:[function(require,module,exports){ +/* OpenPGP radix-64/base64 string encoding/decoding + * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de + * version 1.0, check www.haneWIN.de for the latest version + * + * This software is provided as-is, without express or implied warranty. + * Permission to use, copy, modify, distribute or sell this software, with or + * without fee, for any purpose and by any individual or organization, is hereby + * granted, provided that the above copyright notice and this paragraph appear + * in all copies. Distribution as a part of an application or binary must + * include the above copyright notice in the documentation and/or other materials + * provided with the application or distribution. + */ + +/** + * @module encoding/base64 + */ + +var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +/** + * Convert binary string to radix-64 + * @param {String} t binary string to convert + * @returns {string} radix-64 version of input string + * @static + */ +function s2r(t) { + var a, c, n; + var r = '', + l = 0, + s = 0; + var tl = t.length; + + for (n = 0; n < tl; n++) { + c = t.charCodeAt(n); + if (s == 0) { + r += b64s.charAt((c >> 2) & 63); + a = (c & 3) << 4; + } else if (s == 1) { + r += b64s.charAt((a | (c >> 4) & 15)); + a = (c & 15) << 2; + } else if (s == 2) { + r += b64s.charAt(a | ((c >> 6) & 3)); + l += 1; + if ((l % 60) == 0) + r += "\n"; + r += b64s.charAt(c & 63); + } + l += 1; + if ((l % 60) == 0) + r += "\n"; + + s += 1; + if (s == 3) + s = 0; + } + if (s > 0) { + r += b64s.charAt(a); + l += 1; + if ((l % 60) == 0) + r += "\n"; + r += '='; + l += 1; + } + if (s == 1) { + if ((l % 60) == 0) + r += "\n"; + r += '='; + } + + return r; +} + +/** + * Convert radix-64 to binary string + * @param {String} t radix-64 string to convert + * @returns {string} binary version of input string + * @static + */ +function r2s(t) { + var c, n; + var r = '', + s = 0, + a = 0; + var tl = t.length; + + for (n = 0; n < tl; n++) { + c = b64s.indexOf(t.charAt(n)); + if (c >= 0) { + if (s) + r += String.fromCharCode(a | (c >> (6 - s)) & 255); + s = (s + 2) & 7; + a = (c << s) & 255; + } + } + return r; +} + +module.exports = { + encode: s2r, + decode: r2s +} + +},{}],27:[function(require,module,exports){ +/** + * @module enums + */ + +module.exports = { + + /** A string to key specifier type + * @enum {Integer} + * @readonly + */ + s2k: { + simple: 0, + salted: 1, + iterated: 3, + gnu: 101 + }, + + /** RFC4880, section 9.1 + * @enum {Integer} + * @readonly + */ + publicKey: { + rsa_encrypt_sign: 1, + rsa_encrypt: 2, + rsa_sign: 3, + elgamal: 16, + dsa: 17 + }, + + /** RFC4880, section 9.2 + * @enum {Integer} + * @readonly + */ + symmetric: { + plaintext: 0, + /** Not implemented! */ + idea: 1, + tripledes: 2, + cast5: 3, + blowfish: 4, + aes128: 7, + aes192: 8, + aes256: 9, + twofish: 10 + }, + + /** RFC4880, section 9.3 + * @enum {Integer} + * @readonly + */ + compression: { + uncompressed: 0, + /** RFC1951 */ + zip: 1, + /** RFC1950 */ + zlib: 2, + bzip2: 3 + }, + + /** RFC4880, section 9.4 + * @enum {Integer} + * @readonly + */ + hash: { + md5: 1, + sha1: 2, + ripemd: 3, + sha256: 8, + sha384: 9, + sha512: 10, + sha224: 11 + }, + + /** A list of packet types and numeric tags associated with them. + * @enum {Integer} + * @readonly + */ + packet: { + public_key_encrypted_session_key: 1, + signature: 2, + sym_encrypted_session_key: 3, + one_pass_signature: 4, + secret_key: 5, + public_key: 6, + secret_subkey: 7, + compressed: 8, + symmetrically_encrypted: 9, + marker: 10, + literal: 11, + trust: 12, + userid: 13, + public_subkey: 14, + user_attribute: 17, + sym_encrypted_integrity_protected: 18, + modification_detection_code: 19 + }, + + /** Data types in the literal packet + * @enum {Integer} + * @readonly + */ + literal: { + /** Binary data 'b' */ + binary: 'b'.charCodeAt(), + /** Text data 't' */ + text: 't'.charCodeAt(), + /** Utf8 data 'u' */ + utf8: 'u'.charCodeAt() + }, + + + /** One pass signature packet type + * @enum {Integer} + * @readonly + */ + signature: { + /** 0x00: Signature of a binary document. */ + binary: 0, + /** 0x01: Signature of a canonical text document.
      + * Canonicalyzing the document by converting line endings. */ + text: 1, + /** 0x02: Standalone signature.
      + * This signature is a signature of only its own subpacket contents. + * It is calculated identically to a signature over a zero-lengh + * binary document. Note that it doesn't make sense to have a V3 + * standalone signature. */ + standalone: 2, + /** 0x10: Generic certification of a User ID and Public-Key packet.
      + * The issuer of this certification does not make any particular + * assertion as to how well the certifier has checked that the owner + * of the key is in fact the person described by the User ID. */ + cert_generic: 16, + /** 0x11: Persona certification of a User ID and Public-Key packet.
      + * The issuer of this certification has not done any verification of + * the claim that the owner of this key is the User ID specified. */ + cert_persona: 17, + /** 0x12: Casual certification of a User ID and Public-Key packet.
      + * The issuer of this certification has done some casual + * verification of the claim of identity. */ + cert_casual: 18, + /** 0x13: Positive certification of a User ID and Public-Key packet.
      + * The issuer of this certification has done substantial + * verification of the claim of identity.
      + *
      + * Most OpenPGP implementations make their "key signatures" as 0x10 + * certifications. Some implementations can issue 0x11-0x13 + * certifications, but few differentiate between the types. */ + cert_positive: 19, + /** 0x30: Certification revocation signature
      + * This signature revokes an earlier User ID certification signature + * (signature class 0x10 through 0x13) or direct-key signature + * (0x1F). It should be issued by the same key that issued the + * revoked signature or an authorized revocation key. The signature + * is computed over the same data as the certificate that it + * revokes, and should have a later creation date than that + * certificate. */ + cert_revocation: 48, + /** 0x18: Subkey Binding Signature
      + * This signature is a statement by the top-level signing key that + * indicates that it owns the subkey. This signature is calculated + * directly on the primary key and subkey, and not on any User ID or + * other packets. A signature that binds a signing subkey MUST have + * an Embedded Signature subpacket in this binding signature that + * contains a 0x19 signature made by the signing subkey on the + * primary key and subkey. */ + subkey_binding: 24, + /** 0x19: Primary Key Binding Signature
      + * This signature is a statement by a signing subkey, indicating + * that it is owned by the primary key and subkey. This signature + * is calculated the same way as a 0x18 signature: directly on the + * primary key and subkey, and not on any User ID or other packets.
      + *
      + * When a signature is made over a key, the hash data starts with the + * octet 0x99, followed by a two-octet length of the key, and then body + * of the key packet. (Note that this is an old-style packet header for + * a key packet with two-octet length.) A subkey binding signature + * (type 0x18) or primary key binding signature (type 0x19) then hashes + * the subkey using the same format as the main key (also using 0x99 as + * the first octet). */ + key_binding: 25, + /** 0x1F: Signature directly on a key
      + * This signature is calculated directly on a key. It binds the + * information in the Signature subpackets to the key, and is + * appropriate to be used for subpackets that provide information + * about the key, such as the Revocation Key subpacket. It is also + * appropriate for statements that non-self certifiers want to make + * about the key itself, rather than the binding between a key and a + * name. */ + key: 31, + /** 0x20: Key revocation signature
      + * The signature is calculated directly on the key being revoked. A + * revoked key is not to be used. Only revocation signatures by the + * key being revoked, or by an authorized revocation key, should be + * considered valid revocation signatures.a */ + key_revocation: 32, + /** 0x28: Subkey revocation signature
      + * The signature is calculated directly on the subkey being revoked. + * A revoked subkey is not to be used. Only revocation signatures + * by the top-level signature key that is bound to this subkey, or + * by an authorized revocation key, should be considered valid + * revocation signatures.
      + *
      + * Key revocation signatures (types 0x20 and 0x28) + * hash only the key being revoked. */ + subkey_revocation: 40, + /** 0x40: Timestamp signature.
      + * This signature is only meaningful for the timestamp contained in + * it. */ + timestamp: 64, + /** 0x50: Third-Party Confirmation signature.
      + * This signature is a signature over some other OpenPGP Signature + * packet(s). It is analogous to a notary seal on the signed data. + * A third-party signature SHOULD include Signature Target + * subpacket(s) to give easy identification. Note that we really do + * mean SHOULD. There are plausible uses for this (such as a blind + * party that only sees the signature, not the key or source + * document) that cannot include a target subpacket. */ + third_party: 80 + }, + + /** Signature subpacket type + * @enum {Integer} + * @readonly + */ + signatureSubpacket: { + signature_creation_time: 2, + signature_expiration_time: 3, + exportable_certification: 4, + trust_signature: 5, + regular_expression: 6, + revocable: 7, + key_expiration_time: 9, + placeholder_backwards_compatibility: 10, + preferred_symmetric_algorithms: 11, + revocation_key: 12, + issuer: 16, + notation_data: 20, + preferred_hash_algorithms: 21, + preferred_compression_algorithms: 22, + key_server_preferences: 23, + preferred_key_server: 24, + primary_user_id: 25, + policy_uri: 26, + key_flags: 27, + signers_user_id: 28, + reason_for_revocation: 29, + features: 30, + signature_target: 31, + embedded_signature: 32 + }, + + /** Key flags + * @enum {Integer} + * @readonly + */ + keyFlags: { + /** 0x01 - This key may be used to certify other keys. */ + certify_keys: 1, + /** 0x02 - This key may be used to sign data. */ + sign_data: 2, + /** 0x04 - This key may be used to encrypt communications. */ + encrypt_communication: 4, + /** 0x08 - This key may be used to encrypt storage. */ + encrypt_storage: 8, + /** 0x10 - The private component of this key may have been split + * by a secret-sharing mechanism. */ + split_private_key: 16, + /** 0x20 - This key may be used for authentication. */ + authentication: 32, + /** 0x80 - The private component of this key may be in the + * possession of more than one person. */ + shared_private_key: 128 + }, + + /** Key status + * @enum {Integer} + * @readonly + */ + keyStatus: { + invalid: 0, + expired: 1, + revoked: 2, + valid: 3, + no_self_cert: 4 + }, + + /** Armor type + * @enum {Integer} + * @readonly + */ + armor: { + multipart_section: 0, + multipart_last: 1, + signed: 2, + message: 3, + public_key: 4, + private_key: 5 + }, + + /** Asserts validity and converts from string/integer to integer. */ + write: function(type, e) { + if (typeof e == 'number') { + e = this.read(type, e); + } + + if (type[e] !== undefined) { + return type[e]; + } else throw new Error('Invalid enum value.'); + }, + /** Converts from an integer to string. */ + read: function(type, e) { + for (var i in type) + if (type[i] == e) return i; + + throw new Error('Invalid enum value.'); + } +} + +},{}],"pr55Tj":[function(require,module,exports){ + +module.exports = require('./openpgp.js'); + +module.exports.key = require('./key.js'); +module.exports.message = require('./message.js'); +module.exports.cleartext = require('./cleartext.js'); +/** + * @see module:util/util + * @module util + */ +module.exports.util = require('./util/util.js'); +module.exports.packet = require('./packet'); +/** + * @see module:type/mpi + * @module mpi + */ +module.exports.mpi = require('./type/mpi.js'); +/** + * @see module:type/s2k + * @module s2k + */ +module.exports.s2k = require('./type/s2k.js'); +/** + * @see module:type/keyid + * @module keyid + */ +module.exports.keyid = require('./type/keyid.js'); +/** + * @see module:encoding/armor + * @module armor + */ +module.exports.armor = require('./encoding/armor.js'); +module.exports.enums = require('./enums.js'); +/** + * @see module:config/config + * @module config + */ +module.exports.config = require('./config/config.js'); +module.exports.crypto = require('./crypto'); + +},{"./cleartext.js":1,"./config/config.js":3,"./crypto":16,"./encoding/armor.js":25,"./enums.js":27,"./key.js":30,"./message.js":31,"./openpgp.js":32,"./packet":35,"./type/keyid.js":53,"./type/mpi.js":54,"./type/s2k.js":55,"./util/util.js":56}],"openpgp":[function(require,module,exports){ +module.exports=require('pr55Tj'); +},{}],30:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -7879,129 +9469,756 @@ function createcrc24(input) { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * Wrapper function for the base64 codec. - * This function encodes a String (message) in base64 (radix-64) - * @param {String} message The message to encode - * @return {String} The base64 encoded data + * @requires config + * @requires encoding/armor + * @requires enums + * @requires packet + * @module key */ -function openpgp_encoding_base64_encode(message) { - return s2r(message); -} +var packet = require('./packet'), + enums = require('./enums.js'), + armor = require('./encoding/armor.js'), + config = require('./config'); /** - * Wrapper function for the base64 codec. - * This function decodes a String(message) in base64 (radix-64) - * @param {String} message Base64 encoded data - * @return {String} Raw data after decoding + * @class + * @classdesc Class that represents an OpenPGP key. Must contain a primary key. + * Can contain additional subkeys, signatures, user ids, user attributes. + * @param {module:packet/packetlist} packetlist The packets that form this key */ -function openpgp_encoding_base64_decode(message) { - return r2s(message); + +function Key(packetlist) { + if (!(this instanceof Key)) { + return new Key(packetlist); + } + // same data as in packetlist but in structured form + this.primaryKey = null; + this.revocationSignature = null; + this.directSignatures = null; + this.users = null; + this.subKeys = null; + this.packetlist2structure(packetlist); + if (!this.primaryKey || !this.users) { + throw new Error('Invalid key: need at least key and user ID packet'); + } } /** - * Wrapper function for jquery library. - * This function escapes HTML characters within a string. This is used - * to prevent XSS. - * @param {String} message Message to escape - * @return {String} Html encoded string + * Transforms packetlist to structured key data + * @param {module:packet/packetlist} packetlist The packets that form a key */ -function openpgp_encoding_html_encode(message) { - if (message == null) - return ""; - return $('
      ').text(message).html(); +Key.prototype.packetlist2structure = function(packetlist) { + var user, primaryKeyId, subKey; + for (var i = 0; i < packetlist.length; i++) { + switch (packetlist[i].tag) { + case enums.packet.public_key: + case enums.packet.secret_key: + this.primaryKey = packetlist[i]; + primaryKeyId = this.primaryKey.getKeyId(); + break; + case enums.packet.userid: + case enums.packet.user_attribute: + user = new User(packetlist[i]); + if (!this.users) this.users = []; + this.users.push(user); + break; + case enums.packet.public_subkey: + case enums.packet.secret_subkey: + user = null; + if (!this.subKeys) this.subKeys = []; + subKey = new SubKey(packetlist[i]); + this.subKeys.push(subKey); + break; + case enums.packet.signature: + switch (packetlist[i].signatureType) { + case enums.signature.cert_generic: + case enums.signature.cert_persona: + case enums.signature.cert_casual: + case enums.signature.cert_positive: + if (packetlist[i].issuerKeyId.equals(primaryKeyId)) { + if (!user.selfCertifications) user.selfCertifications = []; + user.selfCertifications.push(packetlist[i]); + } else { + if (!user.otherCertifications) user.otherCertifications = []; + user.otherCertifications.push(packetlist[i]); + } + break; + case enums.signature.cert_revocation: + if (user) { + if (!user.revocationCertifications) user.revocationCertifications = []; + user.revocationCertifications.push(packetlist[i]); + } else { + if (!this.directSignatures) this.directSignatures = []; + this.directSignatures.push(packetlist[i]); + } + break; + case enums.signature.key: + if (!this.directSignatures) this.directSignatures = []; + this.directSignatures.push(packetlist[i]); + break; + case enums.signature.subkey_binding: + subKey.bindingSignature = packetlist[i]; + break; + case enums.signature.key_revocation: + this.revocationSignature = packetlist[i]; + break; + case enums.signature.subkey_revocation: + subKey.revocationSignature = packetlist[i]; + break; + } + break; + } + } +}; + +/** + * Transforms structured key data to packetlist + * @return {module:packet/packetlist} The packets that form a key + */ +Key.prototype.toPacketlist = function() { + var packetlist = new packet.list(); + packetlist.push(this.primaryKey); + packetlist.push(this.revocationSignature); + packetlist.concat(this.directSignatures); + for (var i = 0; i < this.users.length; i++) { + packetlist.concat(this.users[i].toPacketlist()); + } + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + packetlist.concat(this.subKeys[i].toPacketlist()); + } + } + return packetlist; +}; + +/** + * Returns the primary key packet (secret or public) + * @returns {(module:packet/secret_key|module:packet/public_key|null)} + */ +Key.prototype.getKeyPacket = function() { + return this.primaryKey; +}; + +/** + * Returns all the private and public subkey packets + * @returns {Array<(module:packet/public_subkey|module:packet/secret_subkey)>} + */ +Key.prototype.getSubkeyPackets = function() { + var subKeys = []; + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + subKeys.push(this.subKeys[i].subKey); + } + } + return subKeys; +}; + +/** + * Returns all the private and public key and subkey packets + * @returns {Array<(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key)>} + */ +Key.prototype.getAllKeyPackets = function() { + return [this.getKeyPacket()].concat(this.getSubkeyPackets()); +}; + +/** + * Returns key IDs of all key packets + * @returns {Array} + */ +Key.prototype.getKeyIds = function() { + var keyIds = []; + var keys = this.getAllKeyPackets(); + for (var i = 0; i < keys.length; i++) { + keyIds.push(keys[i].getKeyId()); + } + return keyIds; +}; + +function findKey(keys, keyIds) { + for (var i = 0; i < keys.length; i++) { + var keyId = keys[i].getKeyId(); + for (var j = 0; j < keyIds.length; j++) { + if (keyId.equals(keyIds[j])) { + return keys[i]; + } + } + } + return null; } /** - * create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1) - * @param {String} message message to be padded - * @param {Integer} length Length to the resulting message - * @return {String} EME-PKCS1 padded message + * Returns first public key packet for given array of key IDs + * @param {Array} keyIds + * @return {(module:packet/public_subkey|module:packet/public_key|null)} */ -function openpgp_encoding_eme_pkcs1_encode(message, length) { - if (message.length > length-11) - return -1; - var result = ""; - result += String.fromCharCode(0); - result += String.fromCharCode(2); - for (var i = 0; i < length - message.length - 3; i++) { - result += String.fromCharCode(openpgp_crypto_getPseudoRandom(1,255)); - } - result += String.fromCharCode(0); - result += message; - return result; +Key.prototype.getPublicKeyPacket = function(keyIds) { + if (this.primaryKey.tag == enums.packet.public_key) { + return findKey(this.getAllKeyPackets(), keyIds); + } else { + return null; + } +}; + +/** + * Returns first private key packet for given array of key IDs + * @param {Array} keyIds + * @return {(module:packet/secret_subkey|module:packet/secret_key|null)} + */ +Key.prototype.getPrivateKeyPacket = function(keyIds) { + if (this.primaryKey.tag == enums.packet.secret_key) { + return findKey(this.getAllKeyPackets(), keyIds); + } else { + return null; + } +}; + +/** + * Returns userids + * @return {Array} array of userids + */ +Key.prototype.getUserIds = function() { + var userids = []; + for (var i = 0; i < this.users.length; i++) { + if (this.users[i].userId) { + userids.push(this.users[i].userId.write()); + } + } + return userids; +}; + +/** + * Returns true if this is a public key + * @return {Boolean} + */ +Key.prototype.isPublic = function() { + return this.primaryKey.tag == enums.packet.public_key; +}; + +/** + * Returns true if this is a private key + * @return {Boolean} + */ +Key.prototype.isPrivate = function() { + return this.primaryKey.tag == enums.packet.secret_key; +}; + +/** + * Returns key as public key (shallow copy) + * @return {module:key~Key} new public Key + */ +Key.prototype.toPublic = function() { + var packetlist = new packet.list(); + var keyPackets = this.toPacketlist(); + for (var i = 0; i < keyPackets.length; i++) { + switch (keyPackets[i].tag) { + case enums.packet.secret_key: + var bytes = keyPackets[i].writePublicKey(); + var pubKeyPacket = new packet.public_key(); + pubKeyPacket.read(bytes); + packetlist.push(pubKeyPacket); + break; + case enums.packet.secret_subkey: + var bytes = keyPackets[i].writePublicKey(); + var pubSubkeyPacket = new packet.public_subkey(); + pubSubkeyPacket.read(bytes); + packetlist.push(pubSubkeyPacket); + break; + default: + packetlist.push(keyPackets[i]); + } + } + return new Key(packetlist); +}; + +/** + * Returns ASCII armored text of key + * @return {String} ASCII armor + */ +Key.prototype.armor = function() { + var type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key; + return armor.encode(type, this.toPacketlist().write()); +}; + +/** + * Returns first key packet that is available for signing + * @return {(module:packet/secret_subkey|module:packet/secret_key|null)} key packet or null if no signing key has been found + */ +Key.prototype.getSigningKeyPacket = function() { + if (this.isPublic()) { + throw new Error('Need private key for signing'); + } + var primaryUser = this.getPrimaryUser(); + if (primaryUser && + isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate)) { + return this.primaryKey; + } + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + if (this.subKeys[i].isValidSigningKey(this.primaryKey)) { + return this.subKeys[i].subKey; + } + } + } + return null; +}; + +/** + * Returns preferred signature hash algorithm of this key + * @return {String} + */ +Key.prototype.getPreferredHashAlgorithm = function() { + var primaryUser = this.getPrimaryUser(); + if (primaryUser && primaryUser.selfCertificate.preferredHashAlgorithms) { + return primaryUser.selfCertificate.preferredHashAlgorithms[0]; + } + return config.prefer_hash_algorithm; +}; + +function isValidEncryptionKeyPacket(keyPacket, signature) { + return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) && + keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_sign) && + ((signature.keyFlags & enums.keyFlags.encrypt_communication) !== 0 || + (signature.keyFlags & enums.keyFlags.encrypt_storage) !== 0 || + !signature.keyFlags); +}; + +function isValidSigningKeyPacket(keyPacket, signature) { + return (keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.dsa) || + keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.rsa_sign) || + keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.rsa_encrypt_sign)) && + ((signature.keyFlags & enums.keyFlags.sign_data) !== 0 || + !signature.keyFlags); +}; + +/** + * Returns the first valid encryption key packet for this key + * @returns {(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key|null)} key packet or null if no encryption key has been found + */ +Key.prototype.getEncryptionKeyPacket = function() { + // V4: by convention subkeys are prefered for encryption service + // V3: keys MUST NOT have subkeys + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + if (this.subKeys[i].isValidEncryptionKey(this.primaryKey)) { + return this.subKeys[i].subKey; + } + } + } + // if no valid subkey for encryption, evaluate primary key + var primaryUser = this.getPrimaryUser(); + if (primaryUser && + isValidEncryptionKeyPacket(this.primaryKey, primaryUser.selfCertificate)) { + return this.primaryKey; + } + return null; +}; + +/** + * Decrypts all secret key and subkey packets + * @param {String} passphrase + * @return {Boolean} true if all key and subkey packets decrypted successfully + */ +Key.prototype.decrypt = function(passphrase) { + if (this.isPrivate()) { + var keys = this.getAllKeyPackets(); + for (var i = 0; i < keys.length; i++) { + var success = keys[i].decrypt(passphrase); + if (!success) return false; + } + } else { + throw new Error("Nothing to decrypt in a public key"); + } + return true; +}; + +/** + * Decrypts specific key packets by key ID + * @param {Array} keyIds + * @param {String} passphrase + * @return {Boolean} true if all key packets decrypted successfully + */ +Key.prototype.decryptKeyPacket = function(keyIds, passphrase) { + if (this.isPrivate()) { + var keys = this.getAllKeyPackets(); + for (var i = 0; i < keys.length; i++) { + var keyId = keys[i].getKeyId(); + for (var j = 0; j < keyIds.length; j++) { + if (keyId.equals(keyIds[j])) { + var success = keys[i].decrypt(passphrase); + if (!success) return false; + } + } + } + } else { + throw new Error("Nothing to decrypt in a public key"); + } + return true; +}; + +/** + * Verify primary key. Checks for revocation signatures, expiration time + * and valid self signature + * @return {module:enums.keyStatus} The status of the primary key + */ +Key.prototype.verifyPrimaryKey = function() { + // check revocation signature + if (this.revocationSignature && !this.revocationSignature.isExpired() && + (this.revocationSignature.verified || + this.revocationSignature.verify(this.primaryKey, {key: this.primaryKey}))) { + return enums.keyStatus.revoked; + } + // check V3 expiration time + if (this.primaryKey.version == 3 && this.primaryKey.expirationTimeV3 !== 0 && + Date.now() > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) { + return enums.keyStatus.expired; + } + // check for at least one self signature. Self signature of user ID not mandatory + // See http://tools.ietf.org/html/rfc4880#section-11.1 + var selfSigned = false; + for (var i = 0; i < this.users.length; i++) { + if (this.users[i].userId && this.users[i].selfCertifications) { + selfSigned = true; + } + } + if (!selfSigned) { + return enums.keyStatus.no_self_cert; + } + // check for valid self signature + var primaryUser = this.getPrimaryUser(); + if (!primaryUser) { + return enums.keyStatus.invalid; + } + // check V4 expiration time + if (this.primaryKey.version == 4 && primaryUser.selfCertificate.keyNeverExpires === false && + Date.now() > (primaryUser.selfCertificate.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) { + return enums.keyStatus.expired; + } + return enums.keyStatus.valid; +}; + +/** + * Returns primary user and most significant (latest valid) self signature + * - if multiple users are marked as primary users returns the one with the latest self signature + * - if no primary user is found returns the user with the latest self signature + * @return {{user: Array, selfCertificate: Array}} The primary user and the self signature + */ +Key.prototype.getPrimaryUser = function() { + var user = null; + var userSelfCert; + for (var i = 0; i < this.users.length; i++) { + if (!this.users[i].userId) { + continue; + } + var selfCert = this.users[i].getValidSelfCertificate(this.primaryKey); + if (!selfCert) { + continue; + } + if (!user || + !userSelfCert.isPrimaryUserID && selfCert.isPrimaryUserID || + userSelfCert.created < selfCert.created) { + user = this.users[i]; + userSelfCert = selfCert; + } + } + return user ? {user: user, selfCertificate: userSelfCert} : null; +} + +// TODO +Key.prototype.revoke = function() { + +}; + +/** + * @class + * @classdesc Class that represents an user ID or attribute packet and the relevant signatures. + */ +function User(userPacket) { + if (!(this instanceof User)) { + return new User(userPacket); + } + this.userId = userPacket.tag == enums.packet.userid ? userPacket : null; + this.userAttribute = userPacket.tag == enums.packet.user_attribute ? userPacket : null + this.selfCertifications = null; + this.otherCertifications = null; + this.revocationCertifications = null; } /** - * decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2) - * @param {String} message EME-PKCS1 padded message - * @return {String} decoded message + * Transforms structured user data to packetlist + * @return {module:packet/packetlist} */ -function openpgp_encoding_eme_pkcs1_decode(message, len) { - if (message.length < len) - message = String.fromCharCode(0)+message; - if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2) - return -1; - var i = 2; - while (message.charCodeAt(i) != 0 && message.length > i) - i++; - return message.substring(i+1, message.length); -} -/** - * ASN1 object identifiers for hashes (See RFC4880 5.2.2) - */ -hash_headers = new Array(); -hash_headers[1] = [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10]; -hash_headers[3] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14]; -hash_headers[2] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14]; -hash_headers[8] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20]; -hash_headers[9] = [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30]; -hash_headers[10] = [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40]; -hash_headers[11] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1C]; +User.prototype.toPacketlist = function() { + var packetlist = new packet.list(); + packetlist.push(this.userId || this.userAttribute); + packetlist.concat(this.revocationCertifications); + packetlist.concat(this.selfCertifications); + packetlist.concat(this.otherCertifications); + return packetlist; +}; /** - * create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3) - * @param {Integer} algo Hash algorithm type used - * @param {String} data Data to be hashed - * @param {Integer} keylength Key size of the public mpi in bytes - * @returns {String} Hashcode with pkcs1padding as string + * Checks if a self signature of the user is revoked + * @param {module:packet/signature} certificate + * @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet + * @return {Boolean} True if the certificate is revoked */ -function openpgp_encoding_emsa_pkcs1_encode(algo, data, keylength) { - var data2 = ""; - data2 += String.fromCharCode(0x00); - data2 += String.fromCharCode(0x01); - for (var i = 0; i < (keylength - hash_headers[algo].length - 3 - openpgp_crypto_getHashByteLength(algo)); i++) - data2 += String.fromCharCode(0xff); - data2 += String.fromCharCode(0x00); - - for (var i = 0; i < hash_headers[algo].length; i++) - data2 += String.fromCharCode(hash_headers[algo][i]); - - data2 += openpgp_crypto_hashData(algo, data); - return new BigInteger(util.hexstrdump(data2),16); +User.prototype.isRevoked = function(certificate, primaryKey) { + if (this.revocationCertifications) { + var that = this; + return this.revocationCertifications.some(function(revCert) { + return revCert.issuerKeyId.equals(certificate.issuerKeyId) && + !revCert.isExpired() && + (revCert.verified || + revCert.verify(primaryKey, {userid: that.userId || that.userAttribute, key: primaryKey})); + }); + } else { + return false; + } +}; + +/** + * Returns the most significant (latest valid) self signature of the user + * @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet + * @return {module:packet/signature} The self signature + */ +User.prototype.getValidSelfCertificate = function(primaryKey) { + if (!this.selfCertifications) { + return null; + } + var validCert = []; + for (var i = 0; i < this.selfCertifications.length; i++) { + if (this.isRevoked(this.selfCertifications[i], primaryKey)) { + continue; + } + if (!this.selfCertifications[i].isExpired() && + (this.selfCertifications[i].verified || + this.selfCertifications[i].verify(primaryKey, {userid: this.userId || this.userAttribute, key: primaryKey}))) { + validCert.push(this.selfCertifications[i]); + } + } + // most recent first + validCert = validCert.sort(function(a, b) { + a = a.created; + b = b.created; + return a>b ? -1 : a (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) { + return enums.keyStatus.expired; + } + // check subkey binding signature + if (!this.bindingSignature) { + return enums.keyStatus.invalid; + } + if (this.bindingSignature.isExpired()) { + return enums.keyStatus.expired; + } + if (!(this.bindingSignature.verified || + this.bindingSignature.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) { + return enums.keyStatus.invalid; + } + // check V4 expiration time + if (this.subKey.version == 4 && + this.bindingSignature.keyNeverExpires === false && + Date.now() > (this.subKey.created.getTime() + this.bindingSignature.keyExpirationTime*1000)) { + return enums.keyStatus.expired; + } + return enums.keyStatus.valid; +}; + +/** + * Reads an OpenPGP armored text and returns one or multiple key objects + * @param {String} armoredText text to be parsed + * @return {{keys: Array, err: (Array|null)}} result object with key and error arrays + * @static + */ +function readArmored(armoredText) { + var result = {}; + result.keys = []; + try { + var input = armor.decode(armoredText); + if (!(input.type == enums.armor.public_key || input.type == enums.armor.private_key)) { + throw new Error('Armored text not of type key'); + } + var packetlist = new packet.list(); + packetlist.read(input.data); + var keyIndex = packetlist.indexOfTag(enums.packet.public_key, enums.packet.secret_key); + if (keyIndex.length == 0) { + throw new Error('No key packet found in armored text') + } + for (var i = 0; i < keyIndex.length; i++) { + var oneKeyList = packetlist.slice(keyIndex[i], keyIndex[i + 1]); + try { + var newKey = new Key(oneKeyList); + result.keys.push(newKey); + } catch (e) { + result.err = result.err || []; + result.err.push(e); + } + } + } catch (e) { + result.err = result.err || []; + result.err.push(e); + } + return result; } + +/** + * Generates a new OpenPGP key. Currently only supports RSA keys. + * Primary and subkey will be of same type. + * @param {Integer} keyType to indicate what type of key to make. + * RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1 + * @param {Integer} numBits number of bits for the key creation. + * @param {String} userId assumes already in form of "User Name " + * @param {String} passphrase The passphrase used to encrypt the resulting private key + * @return {module:key~Key} + * @static + */ +function generate(keyType, numBits, userId, passphrase) { + var packetlist = new packet.list(); + + var secretKeyPacket = new packet.secret_key(); + secretKeyPacket.algorithm = enums.read(enums.publicKey, keyType); + secretKeyPacket.generate(numBits); + secretKeyPacket.encrypt(passphrase); + + var userIdPacket = new packet.userid(); + userIdPacket.read(userId); + + var dataToSign = {}; + dataToSign.userid = userIdPacket; + dataToSign.key = secretKeyPacket; + var signaturePacket = new packet.signature(); + signaturePacket.signatureType = enums.signature.cert_generic; + signaturePacket.publicKeyAlgorithm = keyType; + //TODO we should load preferred hash from config, or as input to this function + signaturePacket.hashAlgorithm = enums.hash.sha256; + signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data]; + signaturePacket.sign(secretKeyPacket, dataToSign); + + var secretSubkeyPacket = new packet.secret_subkey(); + secretSubkeyPacket.algorithm = enums.read(enums.publicKey, keyType); + secretSubkeyPacket.generate(numBits); + secretSubkeyPacket.encrypt(passphrase); + + dataToSign = {}; + dataToSign.key = secretKeyPacket; + dataToSign.bind = secretSubkeyPacket; + var subkeySignaturePacket = new packet.signature(); + subkeySignaturePacket.signatureType = enums.signature.subkey_binding; + subkeySignaturePacket.publicKeyAlgorithm = keyType; + //TODO we should load preferred hash from config, or as input to this function + subkeySignaturePacket.hashAlgorithm = enums.hash.sha256; + subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage]; + subkeySignaturePacket.sign(secretKeyPacket, dataToSign); + + packetlist.push(secretKeyPacket); + packetlist.push(userIdPacket); + packetlist.push(signaturePacket); + packetlist.push(secretSubkeyPacket); + packetlist.push(subkeySignaturePacket); + + return new Key(packetlist); +} + +exports.Key = Key; +exports.readArmored = readArmored; +exports.generate = generate; + +},{"./config":3,"./encoding/armor.js":25,"./enums.js":27,"./packet":35}],31:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -8020,450 +10237,523 @@ function openpgp_encoding_emsa_pkcs1_decode(algo, data) { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @fileoverview The openpgp base class should provide all of the functionality + * @requires config + * @requires crypto + * @requires encoding/armor + * @requires enums + * @requires packet + * @module message + */ + +var packet = require('./packet'), + enums = require('./enums.js'), + armor = require('./encoding/armor.js'), + config = require('./config'), + crypto = require('./crypto'); + +/** + * @class + * @classdesc Class that represents an OpenPGP message. + * Can be an encrypted message, signed message, compressed message or literal message + * @param {module:packet/packetlist} packetlist The packets that form this message + * See http://tools.ietf.org/html/rfc4880#section-11.3 + */ + +function Message(packetlist) { + if (!(this instanceof Message)) { + return new Message(packetlist); + } + this.packets = packetlist || new packet.list(); +} + +/** + * Returns the key IDs of the keys to which the session key is encrypted + * @return {Array} array of keyid objects + */ +Message.prototype.getEncryptionKeyIds = function() { + var keyIds = []; + var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key); + pkESKeyPacketlist.forEach(function(packet) { + keyIds.push(packet.publicKeyId); + }); + return keyIds; +}; + +/** + * Returns the key IDs of the keys that signed the message + * @return {Array} array of keyid objects + */ +Message.prototype.getSigningKeyIds = function() { + var keyIds = []; + var msg = this.unwrapCompressed(); + // search for one pass signatures + var onePassSigList = msg.packets.filterByTag(enums.packet.one_pass_signature); + onePassSigList.forEach(function(packet) { + keyIds.push(packet.signingKeyId); + }); + // if nothing found look for signature packets + if (!keyIds.length) { + var signatureList = msg.packets.filterByTag(enums.packet.signature); + signatureList.forEach(function(packet) { + keyIds.push(packet.issuerKeyId); + }); + } + return keyIds; +}; + +/** + * Decrypt the message + * @param {module:key~Key} privateKey private key with decrypted secret data + * @return {Array} new message with decrypted content + */ +Message.prototype.decrypt = function(privateKey) { + var encryptionKeyIds = this.getEncryptionKeyIds(); + if (!encryptionKeyIds.length) { + // nothing to decrypt return unmodified message + return this; + } + var privateKeyPacket = privateKey.getPrivateKeyPacket(encryptionKeyIds); + if (!privateKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.'); + var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key); + var pkESKeyPacket; + for (var i = 0; i < pkESKeyPacketlist.length; i++) { + if (pkESKeyPacketlist[i].publicKeyId.equals(privateKeyPacket.getKeyId())) { + pkESKeyPacket = pkESKeyPacketlist[i]; + pkESKeyPacket.decrypt(privateKeyPacket); + break; + } + } + if (pkESKeyPacket) { + var symEncryptedPacketlist = this.packets.filterByTag(enums.packet.symmetrically_encrypted, enums.packet.sym_encrypted_integrity_protected); + if (symEncryptedPacketlist.length !== 0) { + var symEncryptedPacket = symEncryptedPacketlist[0]; + symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey); + return new Message(symEncryptedPacket.packets); + } + } +}; + +/** + * Get literal data that is the body of the message + * @return {(String|null)} literal body of the message as string + */ +Message.prototype.getLiteralData = function() { + var literal = this.packets.findPacket(enums.packet.literal); + return literal && literal.data || null; +}; + +/** + * Get literal data as text + * @return {(String|null)} literal body of the message interpreted as text + */ +Message.prototype.getText = function() { + var literal = this.packets.findPacket(enums.packet.literal); + if (literal) { + return literal.getText(); + } else { + return null; + } +}; + +/** + * Encrypt the message + * @param {Array} keys array of keys, used to encrypt the message + * @return {Array} new message with encrypted content + */ +Message.prototype.encrypt = function(keys) { + var packetlist = new packet.list(); + //TODO get preferred algo from signature + var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, config.encryption_cipher)); + keys.forEach(function(key) { + var encryptionKeyPacket = key.getEncryptionKeyPacket(); + if (encryptionKeyPacket) { + var pkESKeyPacket = new packet.public_key_encrypted_session_key(); + pkESKeyPacket.publicKeyId = encryptionKeyPacket.getKeyId(); + pkESKeyPacket.publicKeyAlgorithm = encryptionKeyPacket.algorithm; + pkESKeyPacket.sessionKey = sessionKey; + //TODO get preferred algo from signature + pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, config.encryption_cipher); + pkESKeyPacket.encrypt(encryptionKeyPacket); + packetlist.push(pkESKeyPacket); + } else { + throw new Error('Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex()); + } + }); + var symEncryptedPacket; + if (config.integrity_protect) { + symEncryptedPacket = new packet.sym_encrypted_integrity_protected(); + } else { + symEncryptedPacket = new packet.symmetrically_encrypted(); + } + symEncryptedPacket.packets = this.packets; + //TODO get preferred algo from signature + symEncryptedPacket.encrypt(enums.read(enums.symmetric, config.encryption_cipher), sessionKey); + packetlist.push(symEncryptedPacket); + return new Message(packetlist); +}; + +/** + * Sign the message (the literal data packet of the message) + * @param {Array} privateKey private keys with decrypted secret key data for signing + * @return {module:message~Message} new message with signed content + */ +Message.prototype.sign = function(privateKeys) { + + var packetlist = new packet.list(); + + var literalDataPacket = this.packets.findPacket(enums.packet.literal); + if (!literalDataPacket) throw new Error('No literal data packet to sign.'); + + var literalFormat = enums.write(enums.literal, literalDataPacket.format); + var signatureType = literalFormat == enums.literal.binary + ? enums.signature.binary : enums.signature.text; + + for (var i = 0; i < privateKeys.length; i++) { + var onePassSig = new packet.one_pass_signature(); + onePassSig.type = signatureType; + //TODO get preferred hashg algo from key signature + onePassSig.hashAlgorithm = config.prefer_hash_algorithm; + var signingKeyPacket = privateKeys[i].getSigningKeyPacket(); + if (!signingKeyPacket) { + throw new Error('Could not find valid key packet for signing in key ' + privateKeys[i].primaryKey.getKeyId().toHex()); + } + onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm; + onePassSig.signingKeyId = signingKeyPacket.getKeyId(); + packetlist.push(onePassSig); + } + + packetlist.push(literalDataPacket); + + for (var i = privateKeys.length - 1; i >= 0; i--) { + var signaturePacket = new packet.signature(); + signaturePacket.signatureType = signatureType; + signaturePacket.hashAlgorithm = config.prefer_hash_algorithm; + signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; + if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.'); + signaturePacket.sign(signingKeyPacket, literalDataPacket); + packetlist.push(signaturePacket); + } + + return new Message(packetlist); +}; + +/** + * Verify message signatures + * @param {Array} publicKeys public keys to verify signatures + * @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature + */ +Message.prototype.verify = function(publicKeys) { + var result = []; + var msg = this.unwrapCompressed(); + var literalDataList = msg.packets.filterByTag(enums.packet.literal); + if (literalDataList.length !== 1) throw new Error('Can only verify message with one literal data packet.'); + var signatureList = msg.packets.filterByTag(enums.packet.signature); + publicKeys.forEach(function(pubKey) { + for (var i = 0; i < signatureList.length; i++) { + var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]); + if (publicKeyPacket) { + var verifiedSig = {}; + verifiedSig.keyid = signatureList[i].issuerKeyId; + verifiedSig.valid = signatureList[i].verify(publicKeyPacket, literalDataList[0]); + result.push(verifiedSig); + break; + } + } + }); + return result; +}; + +/** + * Unwrap compressed message + * @return {module:message~Message} message Content of compressed message + */ +Message.prototype.unwrapCompressed = function() { + var compressed = this.packets.filterByTag(enums.packet.compressed); + if (compressed.length) { + return new Message(compressed[0].packets); + } else { + return this; + } +}; + +/** + * Returns ASCII armored text of message + * @return {String} ASCII armor + */ +Message.prototype.armor = function() { + return armor.encode(enums.armor.message, this.packets.write()); +}; + +/** + * reads an OpenPGP armored message and returns a message object + * @param {String} armoredText text to be parsed + * @return {module:message~Message} new message object + * @static + */ +function readArmored(armoredText) { + //TODO how do we want to handle bad text? Exception throwing + //TODO don't accept non-message armored texts + var input = armor.decode(armoredText).data; + var packetlist = new packet.list(); + packetlist.read(input); + var newMessage = new Message(packetlist); + return newMessage; +} + +/** + * creates new message object from text + * @param {String} text + * @return {module:message~Message} new message object + * @static + */ +function fromText(text) { + var literalDataPacket = new packet.literal(); + // text will be converted to UTF8 + literalDataPacket.setText(text); + var literalDataPacketlist = new packet.list(); + literalDataPacketlist.push(literalDataPacket); + var newMessage = new Message(literalDataPacketlist); + return newMessage; +} + +/** + * creates new message object from binary data + * @param {String} bytes + * @return {module:message~Message} new message object + * @static + */ +function fromBinary(bytes) { + var literalDataPacket = new packet.literal(); + literalDataPacket.setBytes(bytes, enums.read(enums.literal, enums.literal.binary)); + var literalDataPacketlist = new packet.list(); + literalDataPacketlist.push(literalDataPacket); + var newMessage = new Message(literalDataPacketlist); + return newMessage; +} + +exports.Message = Message; +exports.readArmored = readArmored; +exports.fromText = fromText; +exports.fromBinary = fromBinary; + +},{"./config":3,"./crypto":16,"./encoding/armor.js":25,"./enums.js":27,"./packet":35}],32:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @fileoverview The openpgp base module should provide all of the functionality * to consume the openpgp.js library. All additional classes are documented * for extending and developing on top of the base library. */ /** - * GPG4Browsers Core interface. A single instance is hold - * from the beginning. To use this library call "openpgp.init()" - * @alias openpgp - * @class - * @classdesc Main Openpgp.js class. Use this to initiate and make all calls to this library. + * @requires cleartext + * @requires config + * @requires encoding/armor + * @requires enums + * @requires message + * @requires packet + * @module openpgp */ -function _openpgp () { - this.tostring = ""; - - /** - * initializes the library: - * - reading the keyring from local storage - * - reading the config from local storage - */ - function init() { - this.config = new openpgp_config(); - this.config.read(); - this.keyring = new openpgp_keyring(); - this.keyring.init(); - } - - /** - * reads several publicKey objects from a ascii armored - * representation an returns openpgp_msg_publickey packets - * @param {String} armoredText OpenPGP armored text containing - * the public key(s) - * @return {openpgp_msg_publickey[]} on error the function - * returns null - */ - function read_publicKey(armoredText) { - var mypos = 0; - var publicKeys = new Array(); - var publicKeyCount = 0; - var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp; - var l = input.length; - while (mypos != input.length) { - var first_packet = openpgp_packet.read_packet(input, mypos, l); - // public key parser - if (input.charCodeAt(mypos) == 0x99 || first_packet.tagType == 6) { - publicKeys[publicKeyCount] = new openpgp_msg_publickey(); - publicKeys[publicKeyCount].header = input.substring(mypos,mypos+3); - if (input.charCodeAt(mypos) == 0x99) { - // parse the length and read a tag6 packet - mypos++; - var l = (input.charCodeAt(mypos++) << 8) - | input.charCodeAt(mypos++); - publicKeys[publicKeyCount].publicKeyPacket = new openpgp_packet_keymaterial(); - publicKeys[publicKeyCount].publicKeyPacket.header = publicKeys[publicKeyCount].header; - publicKeys[publicKeyCount].publicKeyPacket.read_tag6(input, mypos, l); - mypos += publicKeys[publicKeyCount].publicKeyPacket.packetLength; - mypos += publicKeys[publicKeyCount].read_nodes(publicKeys[publicKeyCount].publicKeyPacket, input, mypos, (input.length - mypos)); - } else { - publicKeys[publicKeyCount] = new openpgp_msg_publickey(); - publicKeys[publicKeyCount].publicKeyPacket = first_packet; - mypos += first_packet.headerLength+first_packet.packetLength; - mypos += publicKeys[publicKeyCount].read_nodes(first_packet, input, mypos, input.length -mypos); - } - } else { - util.print_error("no public key found!"); - return null; - } - publicKeys[publicKeyCount].data = input.substring(0,mypos); - publicKeyCount++; - } - return publicKeys; - } - - /** - * reads several privateKey objects from a ascii armored - * representation an returns openpgp_msg_privatekey objects - * @param {String} armoredText OpenPGP armored text containing - * the private key(s) - * @return {openpgp_msg_privatekey[]} on error the function - * returns null - */ - function read_privateKey(armoredText) { - var privateKeys = new Array(); - var privateKeyCount = 0; - var mypos = 0; - var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp; - var l = input.length; - while (mypos != input.length) { - var first_packet = openpgp_packet.read_packet(input, mypos, l); - if (first_packet.tagType == 5) { - privateKeys[privateKeys.length] = new openpgp_msg_privatekey(); - mypos += first_packet.headerLength+first_packet.packetLength; - mypos += privateKeys[privateKeyCount].read_nodes(first_packet, input, mypos, l); - // other blocks - } else { - util.print_error('no block packet found!'); - return null; - } - privateKeys[privateKeyCount].data = input.substring(0,mypos); - privateKeyCount++; - } - return privateKeys; - } - /** - * reads message packets out of an OpenPGP armored text and - * returns an array of message objects - * @param {String} armoredText text to be parsed - * @return {openpgp_msg_message[]} on error the function - * returns null - */ - function read_message(armoredText) { - var dearmored; - try{ - dearmored = openpgp_encoding_deArmor(armoredText); - } - catch(e){ - util.print_error('no message found!'); - return null; - } - return read_messages_dearmored(dearmored); - } - - /** - * reads message packets out of an OpenPGP armored text and - * returns an array of message objects. Can be called externally or internally. - * External call will parse a de-armored messaged and return messages found. - * Internal will be called to read packets wrapped in other packets (i.e. compressed) - * @param {String} input dearmored text of OpenPGP packets, to be parsed - * @return {openpgp_msg_message[]} on error the function - * returns null - */ - function read_messages_dearmored(input){ - var messageString = input.openpgp; - var signatureText = input.text; //text to verify signatures against. Modified by Tag11. - var messages = new Array(); - var messageCount = 0; - var mypos = 0; - var l = messageString.length; - while (mypos < messageString.length) { - var first_packet = openpgp_packet.read_packet(messageString, mypos, l); - if (!first_packet) { - break; - } - // public key parser (definition from the standard:) - // OpenPGP Message :- Encrypted Message | Signed Message | - // Compressed Message | Literal Message. - // Compressed Message :- Compressed Data Packet. - // - // Literal Message :- Literal Data Packet. - // - // ESK :- Public-Key Encrypted Session Key Packet | - // Symmetric-Key Encrypted Session Key Packet. - // - // ESK Sequence :- ESK | ESK Sequence, ESK. - // - // Encrypted Data :- Symmetrically Encrypted Data Packet | - // Symmetrically Encrypted Integrity Protected Data Packet - // - // Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data. - // - // One-Pass Signed Message :- One-Pass Signature Packet, - // OpenPGP Message, Corresponding Signature Packet. +var armor = require('./encoding/armor.js'), + packet = require('./packet'), + enums = require('./enums.js'), + config = require('./config'), + message = require('./message.js'), + cleartext = require('./cleartext.js'), + key = require('./key.js'); - // Signed Message :- Signature Packet, OpenPGP Message | - // One-Pass Signed Message. - if (first_packet.tagType == 1 || - (first_packet.tagType == 2 && first_packet.signatureType < 16) || - first_packet.tagType == 3 || - first_packet.tagType == 4 || - first_packet.tagType == 8 || - first_packet.tagType == 9 || - first_packet.tagType == 10 || - first_packet.tagType == 11 || - first_packet.tagType == 18 || - first_packet.tagType == 19) { - messages[messages.length] = new openpgp_msg_message(); - messages[messageCount].messagePacket = first_packet; - messages[messageCount].type = input.type; - // Encrypted Message - if (first_packet.tagType == 9 || - first_packet.tagType == 1 || - first_packet.tagType == 3 || - first_packet.tagType == 18) { - if (first_packet.tagType == 9) { - util.print_error("unexpected openpgp packet"); - break; - } else if (first_packet.tagType == 1) { - util.print_debug("session key found:\n "+first_packet.toString()); - var issessionkey = true; - messages[messageCount].sessionKeys = new Array(); - var sessionKeyCount = 0; - while (issessionkey) { - messages[messageCount].sessionKeys[sessionKeyCount] = first_packet; - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - first_packet = openpgp_packet.read_packet(messageString, mypos, l); - - if (first_packet.tagType != 1 && first_packet.tagType != 3) - issessionkey = false; - sessionKeyCount++; - } - if (first_packet.tagType == 18 || first_packet.tagType == 9) { - util.print_debug("encrypted data found:\n "+first_packet.toString()); - messages[messageCount].encryptedData = first_packet; - mypos += first_packet.packetLength+first_packet.headerLength; - l -= (first_packet.packetLength+first_packet.headerLength); - messageCount++; - - } else { - util.print_debug("something is wrong: "+first_packet.tagType); - } - - } else if (first_packet.tagType == 18) { - util.print_debug("symmetric encrypted data"); - break; - } - } else - if (first_packet.tagType == 2 && first_packet.signatureType < 3) { - // Signed Message - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - messages[messageCount].text = signatureText; - messages[messageCount].signature = first_packet; - messageCount++; - } else - // Signed Message - if (first_packet.tagType == 4) { - //TODO: Implement check - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } else - if (first_packet.tagType == 8) { - // Compressed Message - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - var decompressedText = first_packet.decompress(); - messages = messages.concat(openpgp.read_messages_dearmored({text: decompressedText, openpgp: decompressedText})); - } else - // Marker Packet (Obsolete Literal Packet) (Tag 10) - // "Such a packet MUST be ignored when received." see http://tools.ietf.org/html/rfc4880#section-5.8 - if (first_packet.tagType == 10) { - // reset messages - messages.length = 0; - // continue with next packet - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } else - if (first_packet.tagType == 11) { - // Literal Message -- work is already done in read_packet - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - signatureText = first_packet.data; - messages[messageCount].data = first_packet.data; - messageCount++; - } else - if (first_packet.tagType == 19) { - // Modification Detect Code - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } - } else { - util.print_error('no message found!'); - return null; - } - } - - return messages; - } - - /** - * creates a binary string representation of an encrypted and signed message. - * The message will be encrypted with the public keys specified and signed - * with the specified private key. - * @param {Object} privatekey {obj: [openpgp_msg_privatekey]} Private key - * to be used to sign the message - * @param {Object[]} publickeys An arraf of {obj: [openpgp_msg_publickey]} - * - public keys to be used to encrypt the message - * @param {String} messagetext message text to encrypt and sign - * @return {String} a binary string representation of the message which - * can be OpenPGP armored - */ - function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) { - var result = ""; - var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n")); - util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal); - for (var i = 0; i < publickeys.length; i++) { - var onepasssignature = new openpgp_packet_onepasssignature(); - var onepasssigstr = ""; - if (i == 0) - onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false); - else - onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false); - util.print_debug_hexstr_dump("onepasssigstr: |"+onepasssigstr+"|\n",onepasssigstr); - var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey); - util.print_debug_hexstr_dump("datasignature: |"+datasignature.openpgp+"|\n",datasignature.openpgp); - if (i == 0) { - result = onepasssigstr+literal+datasignature.openpgp; - } else { - result = onepasssigstr+result+datasignature.openpgp; - } - } - - util.print_debug_hexstr_dump("signed packet: |"+result+"|\n",result); - // signatures done.. now encryption - var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); - var result2 = ""; - - // creating session keys for each recipient - for (var i = 0; i < publickeys.length; i++) { - var pkey = publickeys[i].getEncryptionKey(); - if (pkey == null) { - util.print_error("no encryption key found! Key is for signing only."); - return null; - } - result2 += new openpgp_packet_encryptedsessionkey(). - write_pub_key_packet( - pkey.getKeyId(), - pkey.MPIs, - pkey.publicKeyAlgorithm, - openpgp.config.config.encryption_cipher, - sessionkey); - } - if (openpgp.config.config.integrity_protect) { - result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } else { - result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } - return openpgp_encoding_armor(3,result2,null,null); - } - /** - * creates a binary string representation of an encrypted message. - * The message will be encrypted with the public keys specified - * @param {Object[]} publickeys An array of {obj: [openpgp_msg_publickey]} - * -public keys to be used to encrypt the message - * @param {String} messagetext message text to encrypt - * @return {String} a binary string representation of the message - * which can be OpenPGP armored - */ - function write_encrypted_message(publickeys, messagetext) { - var result = ""; - var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n")); - util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal); - result = literal; - - // signatures done.. now encryption - var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); - var result2 = ""; - - // creating session keys for each recipient - for (var i = 0; i < publickeys.length; i++) { - var pkey = publickeys[i].getEncryptionKey(); - if (pkey == null) { - util.print_error("no encryption key found! Key is for signing only."); - return null; - } - result2 += new openpgp_packet_encryptedsessionkey(). - write_pub_key_packet( - pkey.getKeyId(), - pkey.MPIs, - pkey.publicKeyAlgorithm, - openpgp.config.config.encryption_cipher, - sessionkey); - } - if (openpgp.config.config.integrity_protect) { - result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } else { - result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } - return openpgp_encoding_armor(3,result2,null,null); - } - - /** - * creates a binary string representation a signed message. - * The message will be signed with the specified private key. - * @param {Object} privatekey {obj: [openpgp_msg_privatekey]} - * - the private key to be used to sign the message - * @param {String} messagetext message text to sign - * @return {Object} {Object: text [String]}, openpgp: {String} a binary - * string representation of the message which can be OpenPGP - * armored(openpgp) and a text representation of the message (text). - * This can be directly used to OpenPGP armor the message - */ - function write_signed_message(privatekey, messagetext) { - var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey); - var result = {text: messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), openpgp: sig.openpgp, hash: sig.hash}; - return openpgp_encoding_armor(2,result, null, null) - } - - /** - * generates a new key pair for openpgp. Beta stage. Currently only - * supports RSA keys, and no subkeys. - * @param {Integer} keyType to indicate what type of key to make. - * RSA is 1. Follows algorithms outlined in OpenPGP. - * @param {Integer} numBits number of bits for the key creation. (should - * be 1024+, generally) - * @param {String} userId assumes already in form of "User Name - * " - * @param {String} passphrase The passphrase used to encrypt the resulting private key - * @return {Object} {privateKey: [openpgp_msg_privatekey], - * privateKeyArmored: [string], publicKeyArmored: [string]} - */ - function generate_key_pair(keyType, numBits, userId, passphrase){ - var userIdPacket = new openpgp_packet_userid(); - var userIdString = userIdPacket.write_packet(userId); - - var keyPair = openpgp_crypto_generateKeyPair(keyType,numBits, passphrase, openpgp.config.config.prefer_hash_algorithm, 3); - var privKeyString = keyPair.privateKey; - var privKeyPacket = new openpgp_packet_keymaterial().read_priv_key(privKeyString.string,3,privKeyString.string.length); - if(!privKeyPacket.decryptSecretMPIs(passphrase)) - util.print_error('Issue creating key. Unable to read resulting private key'); - var privKey = new openpgp_msg_privatekey(); - privKey.privateKeyPacket = privKeyPacket; - privKey.getPreferredSignatureHashAlgorithm = function(){return openpgp.config.config.prefer_hash_algorithm};//need to override this to solve catch 22 to generate signature. 8 is value for SHA256 - - var publicKeyString = privKey.privateKeyPacket.publicKey.data; - userId = util.encode_utf8(userId); // needs same encoding as in userIdString - var hashData = String.fromCharCode(0x99)+ String.fromCharCode(((publicKeyString.length) >> 8) & 0xFF) - + String.fromCharCode((publicKeyString.length) & 0xFF) +publicKeyString+String.fromCharCode(0xB4) + - String.fromCharCode((userId.length) >> 24) +String.fromCharCode(((userId.length) >> 16) & 0xFF) - + String.fromCharCode(((userId.length) >> 8) & 0xFF) + String.fromCharCode((userId.length) & 0xFF) + userId - var signature = new openpgp_packet_signature(); - signature = signature.write_message_signature(16,hashData, privKey); - var publicArmored = openpgp_encoding_armor(4, keyPair.publicKey.string + userIdString + signature.openpgp ); - var privArmored = openpgp_encoding_armor(5,privKeyString.string+userIdString+signature.openpgp); - - return {privateKey : privKey, privateKeyArmored: privArmored, publicKeyArmored: publicArmored} - } - - this.generate_key_pair = generate_key_pair; - this.write_signed_message = write_signed_message; - this.write_signed_and_encrypted_message = write_signed_and_encrypted_message; - this.write_encrypted_message = write_encrypted_message; - this.read_message = read_message; - this.read_messages_dearmored = read_messages_dearmored; - this.read_publicKey = read_publicKey; - this.read_privateKey = read_privateKey; - this.init = init; +/** + * Encrypts message text with keys + * @param {Array} keys array of keys, used to encrypt the message + * @param {String} text message as native JavaScript string + * @return {String} encrypted ASCII armored message + * @static + */ +function encryptMessage(keys, text) { + var msg = message.fromText(text); + msg = msg.encrypt(keys); + var armored = armor.encode(enums.armor.message, msg.packets.write()); + return armored; } -var openpgp = new _openpgp(); +/** + * Signs message text and encrypts it + * @param {Array} publicKeys array of keys, used to encrypt the message + * @param {module:key~Key} privateKey private key with decrypted secret key data for signing + * @param {String} text message as native JavaScript string + * @return {String} encrypted ASCII armored message + * @static + */ +function signAndEncryptMessage(publicKeys, privateKey, text) { + var msg = message.fromText(text); + msg = msg.sign([privateKey]); + msg = msg.encrypt(publicKeys); + var armored = armor.encode(enums.armor.message, msg.packets.write()); + return armored; +} +/** + * Decrypts message + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {module:message~Message} message the message object with the encrypted data + * @return {(String|null)} decrypted message as as native JavaScript string + * or null if no literal data found + * @static + */ +function decryptMessage(privateKey, message) { + message = message.decrypt(privateKey); + return message.getText(); +} +/** + * Decrypts message and verifies signatures + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {Array} publicKeys public keys to verify signatures + * @param {module:message~Message} message the message object with signed and encrypted data + * @return {{text: String, signatures: Array<{keyid: module:type/keyid, valid: Boolean}>}} + * decrypted message as as native JavaScript string + * with verified signatures or null if no literal data found + * @static + */ +function decryptAndVerifyMessage(privateKey, publicKeys, message) { + var result = {}; + message = message.decrypt(privateKey); + result.text = message.getText(); + if (result.text) { + result.signatures = message.verify(publicKeys); + return result; + } + return null; +} + +/** + * Signs a cleartext message + * @param {Array} privateKeys private key with decrypted secret key data to sign cleartext + * @param {String} text cleartext + * @return {String} ASCII armored message + * @static + */ +function signClearMessage(privateKeys, text) { + var cleartextMessage = new cleartext.CleartextMessage(text); + cleartextMessage.sign(privateKeys); + return cleartextMessage.armor(); +} + +/** + * Verifies signatures of cleartext signed message + * @param {Array} publicKeys public keys to verify signatures + * @param {module:cleartext~CleartextMessage} message cleartext message object with signatures + * @return {{text: String, signatures: Array<{keyid: module:type/keyid, valid: Boolean}>}} + * cleartext with status of verified signatures + * @static + */ +function verifyClearSignedMessage(publicKeys, message) { + var result = {}; + if (!(message instanceof cleartext.CleartextMessage)) { + throw new Error('Parameter [message] needs to be of type CleartextMessage.'); + } + result.text = message.getText(); + result.signatures = message.verify(publicKeys); + return result; +} + +/** + * Generates a new OpenPGP key pair. Currently only supports RSA keys. + * Primary and subkey will be of same type. + * @param {Integer} keyType to indicate what type of key to make. + * RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1 + * @param {Integer} numBits number of bits for the key creation. (should be 1024+, generally) + * @param {String} userId assumes already in form of "User Name " + * @param {String} passphrase The passphrase used to encrypt the resulting private key + * @return {Object} {key: Array, privateKeyArmored: Array, publicKeyArmored: Array} + * @static + */ +function generateKeyPair(keyType, numBits, userId, passphrase) { + var result = {}; + var newKey = key.generate(keyType, numBits, userId, passphrase); + result.key = newKey; + result.privateKeyArmored = newKey.armor(); + result.publicKeyArmored = newKey.toPublic().armor(); + return result; +} + +exports.encryptMessage = encryptMessage; +exports.signAndEncryptMessage = signAndEncryptMessage; +exports.decryptMessage = decryptMessage; +exports.decryptAndVerifyMessage = decryptAndVerifyMessage +exports.signClearMessage = signClearMessage; +exports.verifyClearSignedMessage = verifyClearSignedMessage; +exports.generateKeyPair = generateKeyPair; + +},{"./cleartext.js":1,"./config":3,"./encoding/armor.js":25,"./enums.js":27,"./key.js":30,"./message.js":31,"./packet":35}],33:[function(require,module,exports){ +/** + * @requires enums + * @module packet + */ +var enums = require('../enums.js'); + +// This is pretty ugly, but browserify needs to have the requires explicitly written. + +module.exports = { + /** @see module:packet/compressed */ + compressed: require('./compressed.js'), + /** @see module:packet/sym_encrypted_integrity_protected */ + sym_encrypted_integrity_protected: require('./sym_encrypted_integrity_protected.js'), + /** @see module:packet/public_key_encrypted_session_key */ + public_key_encrypted_session_key: require('./public_key_encrypted_session_key.js'), + /** @see module:packet/sym_encrypted_session_key */ + sym_encrypted_session_key: require('./sym_encrypted_session_key.js'), + /** @see module:packet/literal */ + literal: require('./literal.js'), + /** @see module:packet/public_key */ + public_key: require('./public_key.js'), + /** @see module:packet/symmetrically_encrypted */ + symmetrically_encrypted: require('./symmetrically_encrypted.js'), + /** @see module:packet/marker */ + marker: require('./marker.js'), + /** @see module:packet/public_subkey */ + public_subkey: require('./public_subkey.js'), + /** @see module:packet/user_attribute */ + user_attribute: require('./user_attribute.js'), + /** @see module:packet/one_pass_signature */ + one_pass_signature: require('./one_pass_signature.js'), + /** @see module:packet/secret_key */ + secret_key: require('./secret_key.js'), + /** @see module:packet/userid */ + userid: require('./userid.js'), + /** @see module:packet/secret_subkey */ + secret_subkey: require('./secret_subkey.js'), + /** @see module:packet/signature */ + signature: require('./signature.js'), + /** @see module:packet/trust */ + trust: require('./trust.js') +} + +for (var i in enums.packet) { + var packetClass = module.exports[i]; + + if (packetClass != undefined) + packetClass.prototype.tag = enums.packet[i]; +} + +},{"../enums.js":27,"./compressed.js":34,"./literal.js":36,"./marker.js":37,"./one_pass_signature.js":38,"./public_key.js":41,"./public_key_encrypted_session_key.js":42,"./public_subkey.js":43,"./secret_key.js":44,"./secret_subkey.js":45,"./signature.js":46,"./sym_encrypted_integrity_protected.js":47,"./sym_encrypted_session_key.js":48,"./symmetrically_encrypted.js":49,"./trust.js":50,"./user_attribute.js":51,"./userid.js":52}],34:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -8482,1010 +10772,176 @@ var openpgp = new _openpgp(); // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. - */ -function openpgp_keyring() { - - /** - * Initialization routine for the keyring. This method reads the - * keyring from HTML5 local storage and initializes this instance. - * This method is called by openpgp.init(). - */ - function init() { - var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys")); - var spublickeys = JSON.parse(window.localStorage.getItem("publickeys")); - if (sprivatekeys == null || sprivatekeys.length == 0) { - sprivatekeys = new Array(); - } - - if (spublickeys == null || spublickeys.length == 0) { - spublickeys = new Array(); - } - this.publicKeys = new Array(); - this.privateKeys = new Array(); - var k = 0; - for (var i =0; i < sprivatekeys.length; i++) { - var r = openpgp.read_privateKey(sprivatekeys[i]); - this.privateKeys[k] = { armored: sprivatekeys[i], obj: r[0], keyId: r[0].getKeyId()}; - k++; - } - k = 0; - for (var i =0; i < spublickeys.length; i++) { - var r = openpgp.read_publicKey(spublickeys[i]); - if (r[0] != null) { - this.publicKeys[k] = { armored: spublickeys[i], obj: r[0], keyId: r[0].getKeyId()}; - k++; - } - } - } - this.init = init; - - /** - * Checks if at least one private key is in the keyring - * @return {Boolean} True if there are private keys, else false. - */ - function hasPrivateKey() { - return this.privateKeys.length > 0; - } - this.hasPrivateKey = hasPrivateKey; - - /** - * Saves the current state of the keyring to HTML5 local storage. - * The privateKeys array and publicKeys array gets Stringified using JSON - */ - function store() { - var priv = new Array(); - for (var i = 0; i < this.privateKeys.length; i++) { - priv[i] = this.privateKeys[i].armored; - } - var pub = new Array(); - for (var i = 0; i < this.publicKeys.length; i++) { - pub[i] = this.publicKeys[i].armored; - } - window.localStorage.setItem("privatekeys",JSON.stringify(priv)); - window.localStorage.setItem("publickeys",JSON.stringify(pub)); - } - this.store = store; - /** - * searches all public keys in the keyring matching the address or address part of the user ids - * @param {String} email_address - * @return {openpgp_msg_publickey[]} The public keys associated with provided email address. - */ - function getPublicKeyForAddress(email_address) { - var results = new Array(); - var spl = email_address.split("<"); - var email = ""; - if (spl.length > 1) { - email = spl[1].split(">")[0]; - } else { - email = email_address.trim(); - } - email = email.toLowerCase(); - if(!util.emailRegEx.test(email)){ - return results; - } - for (var i =0; i < this.publicKeys.length; i++) { - for (var j = 0; j < this.publicKeys[i].obj.userIds.length; j++) { - if (this.publicKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0) - results[results.length] = this.publicKeys[i]; - } - } - return results; - } - this.getPublicKeyForAddress = getPublicKeyForAddress; - - /** - * Searches the keyring for a private key containing the specified email address - * @param {String} email_address email address to search for - * @return {openpgp_msg_privatekey[]} private keys found - */ - function getPrivateKeyForAddress(email_address) { - var results = new Array(); - var spl = email_address.split("<"); - var email = ""; - if (spl.length > 1) { - email = spl[1].split(">")[0]; - } else { - email = email_address.trim(); - } - email = email.toLowerCase(); - if(!util.emailRegEx.test(email)){ - return results; - } - for (var i =0; i < this.privateKeys.length; i++) { - for (var j = 0; j < this.privateKeys[i].obj.userIds.length; j++) { - if (this.privateKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0) - results[results.length] = this.privateKeys[i]; - } - } - return results; - } - - this.getPrivateKeyForAddress = getPrivateKeyForAddress; - /** - * Searches the keyring for public keys having the specified key id - * @param {String} keyId provided as string of hex number (lowercase) - * @return {openpgp_msg_privatekey[]} public keys found - */ - function getPublicKeysForKeyId(keyId) { - var result = new Array(); - for (var i=0; i < this.publicKeys.length; i++) { - var key = this.publicKeys[i]; - if (keyId == key.obj.getKeyId()) - result[result.length] = key; - else if (key.obj.subKeys != null) { - for (var j=0; j < key.obj.subKeys.length; j++) { - var subkey = key.obj.subKeys[j]; - if (keyId == subkey.getKeyId()) { - result[result.length] = { - obj: key.obj.getSubKeyAsKey(j), - keyId: subkey.getKeyId() - } - } - } - } - } - return result; - } - this.getPublicKeysForKeyId = getPublicKeysForKeyId; - - /** - * Searches the keyring for private keys having the specified key id - * @param {String} keyId 8 bytes as string containing the key id to look for - * @return {openpgp_msg_privatekey[]} private keys found - */ - function getPrivateKeyForKeyId(keyId) { - var result = new Array(); - for (var i=0; i < this.privateKeys.length; i++) { - if (keyId == this.privateKeys[i].obj.getKeyId()) { - result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.privateKeyPacket}; - } - if (this.privateKeys[i].obj.subKeys != null) { - var subkeyids = this.privateKeys[i].obj.getSubKeyIds(); - for (var j=0; j < subkeyids.length; j++) - if (keyId == util.hexstrdump(subkeyids[j])) { - result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.subKeys[j]}; - } - } - } - return result; - } - this.getPrivateKeyForKeyId = getPrivateKeyForKeyId; - - /** - * Imports a public key from an exported ascii armored message - * @param {String} armored_text PUBLIC KEY BLOCK message to read the public key from - */ - function importPublicKey (armored_text) { - var result = openpgp.read_publicKey(armored_text); - for (var i = 0; i < result.length; i++) { - this.publicKeys[this.publicKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()}; - } - return true; - } - - /** - * Imports a private key from an exported ascii armored message - * @param {String} armored_text PRIVATE KEY BLOCK message to read the private key from - */ - function importPrivateKey (armored_text, password) { - var result = openpgp.read_privateKey(armored_text); - if(!result[0].decryptSecretMPIs(password)) - return false; - for (var i = 0; i < result.length; i++) { - this.privateKeys[this.privateKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()}; - } - return true; - } - - this.importPublicKey = importPublicKey; - this.importPrivateKey = importPrivateKey; - - /** - * returns the openpgp_msg_privatekey representation of the public key at public key ring index - * @param {Integer} index the index of the public key within the publicKeys array - * @return {openpgp_msg_privatekey} the public key object - */ - function exportPublicKey(index) { - return this.publicKey[index]; - } - this.exportPublicKey = exportPublicKey; - - - /** - * Removes a public key from the public key keyring at the specified index - * @param {Integer} index the index of the public key within the publicKeys array - * @return {openpgp_msg_privatekey} The public key object which has been removed - */ - function removePublicKey(index) { - var removed = this.publicKeys.splice(index,1); - this.store(); - return removed; - } - this.removePublicKey = removePublicKey; - - /** - * returns the openpgp_msg_privatekey representation of the private key at private key ring index - * @param {Integer} index the index of the private key within the privateKeys array - * @return {openpgp_msg_privatekey} the private key object - */ - function exportPrivateKey(index) { - return this.privateKeys[index]; - } - this.exportPrivateKey = exportPrivateKey; - - /** - * Removes a private key from the private key keyring at the specified index - * @param {Integer} index the index of the private key within the privateKeys array - * @return {openpgp_msg_privatekey} The private key object which has been removed - */ - function removePrivateKey(index) { - var removed = this.privateKeys.splice(index,1); - this.store(); - return removed; - } - this.removePrivateKey = removePrivateKey; - -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @protected - * @class - * @classdesc Top-level message object. Contains information from one or more packets + * Implementation of the Compressed Data Packet (Tag 8)
      + *
      + * RFC4880 5.6: The Compressed Data packet contains compressed data. Typically, + * this packet is found as the contents of an encrypted packet, or following + * a Signature or One-Pass Signature packet, and contains a literal data packet. + * @requires compression/jxg + * @requires encoding/base64 + * @requires enums + * @module packet/compressed */ -function openpgp_msg_message() { - - // -1 = no valid passphrase submitted - // -2 = no private key found - // -3 = decryption error - // text = valid decryption - this.text = ""; - this.messagePacket = null; - this.type = null; - - /** - * Decrypts a message and generates user interface message out of the found. - * MDC will be verified as well as message signatures - * @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key) - * @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message - * @return {String} plaintext of the message or null on error - */ - function decrypt(private_key, sessionkey) { - return this.decryptAndVerifySignature(private_key, sessionkey).text; - } - - /** - * Decrypts a message and generates user interface message out of the found. - * MDC will be verified as well as message signatures - * @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key) - * @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message - * @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore. - * @return {String} plaintext of the message or null on error - */ - function decryptAndVerifySignature(private_key, sessionkey, pubkey) { - if (private_key == null || sessionkey == null || sessionkey == "") - return null; - var decrypted = sessionkey.decrypt(this, private_key.keymaterial); - if (decrypted == null) - return null; - var packet; - var position = 0; - var len = decrypted.length; - var validSignatures = new Array(); - util.print_debug_hexstr_dump("openpgp.msg.messge decrypt:\n",decrypted); - - var messages = openpgp.read_messages_dearmored({text: decrypted, openpgp: decrypted}); - for(var m in messages){ - if(messages[m].data){ - this.text = messages[m].data; - } - if(messages[m].signature){ - validSignatures.push(messages[m].verifySignature(pubkey)); - } - } - return {text:this.text, validSignatures:validSignatures}; - } - - /** - * Verifies a message signature. This function can be called after read_message if the message was signed only. - * @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore. - * @return {boolean} true if the signature was correct; otherwise false - */ - function verifySignature(pubkey) { - var result = false; - if (this.signature.tagType == 2) { - if (!pubkey || pubkey.length == 0) { - var pubkey; - if (this.signature.version == 4) { - pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.issuerKeyId); - } else if (this.signature.version == 3) { - pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.keyId); - } else { - util.print_error("unknown signature type on message!"); - return false; - } - } - if (pubkey.length == 0) { - util.print_warning("Unable to verify signature of issuer: "+util.hexstrdump(this.signature.issuerKeyId)+". Public key not found in keyring."); - } else { - for (var i = 0 ; i < pubkey.length; i++) { - if (this.signature.verify(this.text, pubkey[i])) { - util.print_info("Found Good Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[i].obj.getKeyId()).substring(8)+")"); - result = true; - break; - } else { - util.print_error("Signature verification failed: Bad Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8)+")"); - } - } - } - } - return result; - } - - function toString() { - var result = "Session Keys:\n"; - if (this.sessionKeys !=null) - for (var i = 0; i < this.sessionKeys.length; i++) { - result += this.sessionKeys[i].toString(); - } - result += "\n\n EncryptedData:\n"; - if(this.encryptedData != null) - result += this.encryptedData.toString(); - - result += "\n\n Signature:\n"; - if(this.signature != null) - result += this.signature.toString(); - - result += "\n\n Text:\n" - if(this.signature != null) - result += this.text; - return result; - } - this.decrypt = decrypt; - this.decryptAndVerifySignature = decryptAndVerifySignature; - this.verifySignature = verifySignature; - this.toString = toString; -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +var enums = require('../enums.js'), + JXG = require('../compression/jxg.js'), + base64 = require('../encoding/base64.js'); /** - * @class - * @classdesc Class that represents a decoded private key for internal openpgp.js use + * @constructor */ +module.exports = function compressed() { + /** + * List of packets + * @type {module:packet/packetlist} + */ + this.packets = null; + /** + * Compression algorithm + * @type {compression} + */ + this.algorithm = 'uncompressed'; -function openpgp_msg_privatekey() { - this.subKeys = new Array(); - this.privateKeyPacket = null; - this.userIds = new Array(); - this.userAttributes = new Array(); - this.revocationSignatures = new Array(); - this.subKeys = new Array(); - - /** - * - * @return last position - */ - function read_nodes(parent_node, input, position, len) { - this.privateKeyPacket = parent_node; - - var pos = position; - while (input.length > pos) { - var result = openpgp_packet.read_packet(input, pos, input.length - pos); - if (result == null) { - util.print_error("openpgp.msg.messge decrypt:\n"+'[pub/priv_key]parsing ends here @:' + pos + " l:" + len); - break; - } else { - switch (result.tagType) { - case 2: // public key revocation signature - if (result.signatureType == 32) - this.revocationSignatures[this.revocationSignatures.length] = result; - else if (result.signatureType > 15 && result.signatureType < 20) { - if (this.certificationsignatures == null) - this.certificationSignatures = new Array(); - this.certificationSignatures[this.certificationSignatures.length] = result; - } else - util.print_error("openpgp.msg.messge decrypt:\n"+"unknown signature type directly on key "+result.signatureType+" @"+pos); - pos += result.packetLength + result.headerLength; - break; - case 7: // PrivateSubkey Packet - this.subKeys[this.subKeys.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos); - break; - case 17: // User Attribute Packet - this.userAttributes[this.userAttributes.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos); - break; - case 13: // User ID Packet - this.userIds[this.userIds.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.privateKeyPacket, input, pos, input.length - pos); - break; - default: - this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength; - this.len = pos - position; - return this.len; - } - } - } - this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength; - this.len = pos - position; - - return this.len; - } - - function getKeyId() { - return this.privateKeyPacket.publicKey.getKeyId(); - } - - - function getSubKeyIds() { - if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys. - var result = new Array(); - for (var i = 0; i < this.subKeys.length; i++) { - result[i] = str_sha1(this.subKeys[i].publicKey.header+this.subKeys[i].publicKey.data).substring(12,20); - } - return result; - } - - - function getSigningKey() { - if ((this.privateKeyPacket.publicKey.publicKeyAlgorithm == 17 || - this.privateKeyPacket.publicKey.publicKeyAlgorithm != 2) - && this.privateKeyPacket.publicKey.verifyKey() == 3) - return this.privateKeyPacket; - else if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys. - for (var j = 0; j < this.privateKeyPacket.subKeys.length; j++) { - if ((this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm == 17 || - this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm != 2) && - this.privateKeyPacket.subKeys[j].publicKey.verifyKey() == 3) - return this.privateKeyPacket.subKeys[j]; - } - return null; - } - - function getPreferredSignatureHashAlgorithm() { - var pkey = this.getSigningKey(); - if (pkey == null) { - util.print_error("private key is for encryption only! Cannot create a signature.") - return null; - } - if (pkey.publicKey.publicKeyAlgorithm == 17) { - var dsa = new DSA(); - return dsa.select_hash_algorithm(pkey.publicKey.MPIs[1].toBigInteger()); // q - } - //TODO implement: https://tools.ietf.org/html/rfc4880#section-5.2.3.8 - //separate private key preference from digest preferences - return openpgp.config.config.prefer_hash_algorithm; - - } - - function decryptSecretMPIs(str_passphrase) { - return this.privateKeyPacket.decryptSecretMPIs(str_passphrase); - } - - function getFingerprint() { - return this.privateKeyPacket.publicKey.getFingerprint(); - } - - // TODO need to implement this - function revoke() { - - } - - /** - * extracts the public key part - * @return {String} OpenPGP armored text containing the public key - * returns null if no sufficient data to extract public key - */ - function extractPublicKey() { - // add public key - var key = this.privateKeyPacket.publicKey.header + this.privateKeyPacket.publicKey.data; - for (var i = 0; i < this.userIds.length; i++) { - // verify userids - if (this.userIds[i].certificationSignatures.length === 0) { - util.print_error("extractPublicKey - missing certification signatures"); - return null; - } - var userIdPacket = new openpgp_packet_userid(); - // add userids - key += userIdPacket.write_packet(this.userIds[i].text); - for (var j = 0; j < this.userIds[i].certificationSignatures.length; j++) { - var certSig = this.userIds[i].certificationSignatures[j]; - // add signatures - key += openpgp_packet.write_packet_header(2, certSig.data.length) + certSig.data; - } - } - for (var k = 0; k < this.subKeys.length; k++) { - var pubSubKey = this.subKeys[k].publicKey; - // add public subkey package - key += openpgp_packet.write_old_packet_header(14, pubSubKey.data.length) + pubSubKey.data; - var subKeySig = this.subKeys[k].subKeySignature; - if (subKeySig !== null) { - // add subkey signature - key += openpgp_packet.write_packet_header(2, subKeySig.data.length) + subKeySig.data; - } else { - util.print_error("extractPublicKey - missing subkey signature"); - return null; - } - } - var publicArmored = openpgp_encoding_armor(4, key); - return publicArmored; - } - - this.extractPublicKey = extractPublicKey; - this.getSigningKey = getSigningKey; - this.getFingerprint = getFingerprint; - this.getPreferredSignatureHashAlgorithm = getPreferredSignatureHashAlgorithm; - this.read_nodes = read_nodes; - this.decryptSecretMPIs = decryptSecretMPIs; - this.getSubKeyIds = getSubKeyIds; - this.getKeyId = getKeyId; - -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Decoded public key object for internal openpgp.js use - */ -function openpgp_msg_publickey() { - this.tostring = "OPENPGP PUBLIC KEY\n"; - this.bindingSignature = null; - this.publicKeyPacket = null; - this.userIds = new Array(); - this.userAttributes = new Array(); - this.revocationSignatures = new Array(); - this.subKeys = new Array(); - this.arbitraryPacket = new Array(); - this.directSignatures = new Array(); - /** - * - * @return last position - */ - function read_nodes(parent_node, input, position, len) { - this.publicKeyPacket = parent_node; - var exit = false; - var pos = position; - var l = len; - while (input.length != pos) { - var result = openpgp_packet.read_packet(input, pos, input.length - pos); - if (result == null) { - util.print_error("openpgp.msg.publickey read_nodes:\n"+'[pub_key]parsing ends here @:' + pos + " l:" + l); - break; - } else { - switch (result.tagType) { - case 2: // public key revocation signature - if (result.signatureType == 32) - this.revocationSignatures[this.revocationSignatures.length] = result; - else if (result.signatureType == 16 || result.signatureType == 17 || result.signatureType == 18 || result.signatureType == 19) - this.certificationSignature = result; - else if (result.signatureType == 25) { - this.bindingSignature = result; - } else if (result.signatureType == 31) { - this.directSignatures[this.directSignatures.length] = result; - } else - util.print_error("openpgp.msg.publickey read_nodes:\n"+"unknown signature type directly on key "+result.signatureType); - pos += result.packetLength + result.headerLength; - break; - case 14: // Public-Subkey Packet - this.subKeys[this.subKeys.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos); - break; - case 17: // User Attribute Packet - this.userAttributes[this.userAttributes.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos); - break; - case 13: // User ID Packet - this.userIds[this.userIds.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.publicKeyPacket, input, pos, input.length - pos); - break; - default: - this.data = input; - this.position = position - this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength; - this.len = pos - position; - return this.len; - } - } - } - this.data = input; - this.position = position - (this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength); - this.len = pos - position; - return this.len; - } - - function write() { - - } - - function getKeyId() { - return this.publicKeyPacket.getKeyId(); - } - - function getFingerprint() { - return this.publicKeyPacket.getFingerprint(); - } + /** + * Compressed packet data + * @type {String} + */ + this.compressed = null; - - function validate() { - // check revocation keys - for (var i = 0; i < this.revocationSignatures.length; i++) { - var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data; - if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket)) - return false; - } - - if (this.subKeys.length != 0) { - // search for a valid subkey - var found = false; - for (var i = 0; i < this.subKeys.length; i++) - if (this.subKeys[i].verifyKey() == 3) { - found = true; - break; - } - if (!found) - return false; - } - // search for one valid userid - found = false; - for (var i = 0; i < this.userIds.length; i++) - if (this.userIds[i].verify(this.publicKeyPacket) == 0) { - found = true; - break; - } - if (!found) - return false; - return true; - } - - /** - * verifies all signatures - * @return a 2 dimensional array. the first dimension corresponds to the userids available - */ - function verifyCertificationSignatures() { - var result = new Array(); - for (var i = 0; i < this.userIds.length; i++) { - result[i] = this.userIds[i].verifyCertificationSignatures(this.publicKeyPacket); - } - return result; - } - this.verifyCertificationSignatures = verifyCertificationSignatures; - - /** - * verifies: - * - revocation certificates directly on key - * - self signatures - * - subkey binding and revocation certificates - * - * This is useful for validating the key - * @returns {Boolean} true if the basic signatures are all valid - */ - function verifyBasicSignatures() { - for (var i = 0; i < this.revocationSignatures.length; i++) { - var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data; - if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket)) - return false; - } - - if (this.subKeys.length != 0) { - // search for a valid subkey - var found = false; - for (var i = 0; i < this.subKeys.length; i++) { - if (this.subKeys[i] == null) - continue; - var result = this.subKeys[i].verifyKey(); - if (result == 3) { - found = true; - break; - } - } - if (!found) - return false; - } - var keyId = this.getKeyId(); - for (var i = 0; i < this.userIds.length; i++) { - for (var j = 0; j < this.userIds[i].certificationRevocationSignatures.length; j++) { - if (this.userIds[i].certificationSignatures[j].getIssuer == keyId && - this.userIds[i].certificationSignatures[j].verifyBasic(this.publicKeyPacket) != 4) - return false; - } - } - return true; - } - - function toString() { - var result = " OPENPGP Public Key\n length: "+this.len+"\n"; - result += " Revocation Signatures:\n" - for (var i=0; i < this.revocationSignatures.length; i++) { - result += " "+this.revocationSignatures[i].toString(); - } - result += " User Ids:\n"; - for (var i=0; i < this.userIds.length; i++) { - result += " "+this.userIds[i].toString(); - } - result += " User Attributes:\n"; - for (var i=0; i < this.userAttributes.length; i++) { - result += " "+this.userAttributes[i].toString(); - } - result += " Public Key SubKeys:\n"; - for (var i=0; i < this.subKeys.length; i++) { - result += " "+this.subKeys[i].toString(); - } - return result; - } - - /** - * finds an encryption key for this public key - * @returns null if no encryption key has been found - */ - function getEncryptionKey() { - // V4: by convention subkeys are prefered for encryption service - // V3: keys MUST NOT have subkeys - for (var j = 0; j < this.subKeys.length; j++) - if (this.subKeys[j].publicKeyAlgorithm != 17 && - this.subKeys[j].publicKeyAlgorithm != 3 && - this.subKeys[j].verifyKey()) { - return this.subKeys[j]; - } - // if no valid subkey for encryption, use primary key - if (this.publicKeyPacket.publicKeyAlgorithm != 17 && this.publicKeyPacket.publicKeyAlgorithm != 3 - && this.publicKeyPacket.verifyKey()) { - return this.publicKeyPacket; - } - return null; - } - - function getSigningKey() { - if ((this.publicKeyPacket.publicKeyAlgorithm == 17 || - this.publicKeyPacket.publicKeyAlgorithm != 2)) - return this.publicKeyPacket; - else if (this.publicKeyPacket.version == 4) // V3 keys MUST NOT have subkeys. - for (var j = 0; j < this.subKeys.length; j++) { - if ((this.subKeys[j].publicKeyAlgorithm == 17 || - this.subKeys[j].publicKeyAlgorithm != 2) && - this.subKeys[j].verifyKey()) - return this.subKeys[j]; - } - return null; - } + /** + * Parsing function for the packet. + * @param {String} bytes Payload of a tag 8 packet + */ + this.read = function(bytes) { + // One octet that gives the algorithm used to compress the packet. + this.algorithm = enums.read(enums.compression, bytes.charCodeAt(0)); - /* Returns the i-th subKey as a openpgp_msg_publickey object */ - function getSubKeyAsKey(i) { - var ret = new openpgp_msg_publickey(); - ret.userIds = this.userIds; - ret.userAttributes = this.userAttributes; - ret.publicKeyPacket = this.subKeys[i]; - return ret; - } + // Compressed data, which makes up the remainder of the packet. + this.compressed = bytes.substr(1); - this.getEncryptionKey = getEncryptionKey; - this.getSigningKey = getSigningKey; - this.read_nodes = read_nodes; - this.write = write; - this.toString = toString; - this.validate = validate; - this.getFingerprint = getFingerprint; - this.getKeyId = getKeyId; - this.verifyBasicSignatures = verifyBasicSignatures; - this.getSubKeyAsKey = getSubKeyAsKey; -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + this.decompress(); + } -/** - * @class - * @classdesc Implementation of the Compressed Data Packet (Tag 8) - * - * RFC4880 5.6: - * The Compressed Data packet contains compressed data. Typically, this - * packet is found as the contents of an encrypted packet, or following - * a Signature or One-Pass Signature packet, and contains a literal data - * packet. - */ -function openpgp_packet_compressed() { - this.tagType = 8; - this.decompressedData = null; - - /** - * Parsing function for the packet. - * @param {String} input Payload of a tag 8 packet - * @param {Integer} position Position to start reading from the input string - * @param {Integer} len Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_compressed} Object representation - */ - function read_packet (input, position, len) { - this.packetLength = len; - var mypos = position; - // One octet that gives the algorithm used to compress the packet. - this.type = input.charCodeAt(mypos++); - // Compressed data, which makes up the remainder of the packet. - this.compressedData = input.substring(position+1, position+len); - return this; - } - /** - * Decompression method for decompressing the compressed data - * read by read_packet - * @return {String} The decompressed data - */ - function decompress() { - if (this.decompressedData != null) - return this.decompressedData; - if (this.type == null) - return null; - switch (this.type) { - case 0: // - Uncompressed - this.decompressedData = this.compressedData; - break; - case 1: // - ZIP [RFC1951] - util.print_info('Decompressed packet [Type 1-ZIP]: ' + this.toString()); - var compData = this.compressedData; - var radix = s2r(compData).replace(/\n/g,""); - // no header in this case, directly call deflate - var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix)); - this.decompressedData = unescape(jxg_obj.deflate()[0][0]); - break; - case 2: // - ZLIB [RFC1950] - util.print_info('Decompressed packet [Type 2-ZLIB]: ' + this.toString()); - var compressionMethod = this.compressedData.charCodeAt(0) % 0x10; //RFC 1950. Bits 0-3 Compression Method - //Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size. - //2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary (how is this defined). Basic checksum, and compression level. - if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951 - // remove 4 bytes ADLER32 checksum from the end - var compData = this.compressedData.substring(0, this.compressedData.length - 4); - var radix = s2r(compData).replace(/\n/g,""); - //TODO check ADLER32 checksum - this.decompressedData = JXG.decompress(radix); - break; - } else { - util.print_error("Compression algorithm ZLIB only supports DEFLATE compression method."); - } - break; - case 3: // - BZip2 [BZ2] - // TODO: need to implement this - util.print_error("Compression algorithm BZip2 [BZ2] is not implemented."); - break; - default: - util.print_error("Compression algorithm unknown :"+this.type); - break; - } - util.print_debug("decompressed:"+util.hexstrdump(this.decompressedData)); - return this.decompressedData; - } + /** + * Return the compressed packet. + * @return {String} binary compressed packet + */ + this.write = function() { + if (this.compressed == null) + this.compress(); - /** - * Compress the packet data (member decompressedData) - * @param {Integer} type Algorithm to be used // See RFC 4880 9.3 - * @param {String} data Data to be compressed - * @return {String} The compressed data stored in attribute compressedData - */ - function compress(type, data) { - this.type = type; - this.decompressedData = data; - switch (this.type) { - case 0: // - Uncompressed - this.compressedData = this.decompressedData; - break; - case 1: // - ZIP [RFC1951] - util.print_error("Compression algorithm ZIP [RFC1951] is not implemented."); - break; - case 2: // - ZLIB [RFC1950] - // TODO: need to implement this - util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented."); - break; - case 3: // - BZip2 [BZ2] - // TODO: need to implement this - util.print_error("Compression algorithm BZip2 [BZ2] is not implemented."); - break; - default: - util.print_error("Compression algorithm unknown :"+this.type); - break; - } - this.packetLength = this.compressedData.length +1; - return this.compressedData; - } - - /** - * Creates a string representation of the packet - * @param {Integer} algorithm Algorithm to be used // See RFC 4880 9.3 - * @param {String} data Data to be compressed - * @return {String} String-representation of the packet - */ - function write_packet(algorithm, data) { - this.decompressedData = data; - if (algorithm == null) { - this.type = 1; - } - var result = String.fromCharCode(this.type)+this.compress(this.type); - return openpgp_packet.write_packet_header(8, result.length)+result; - } - - /** - * Pretty printing the packet (useful for debug purposes) - * @return {String} - */ - function toString() { - return '5.6. Compressed Data Packet (Tag 8)\n'+ - ' length: '+this.packetLength+'\n'+ - ' Compression Algorithm = '+this.type+'\n'+ - ' Compressed Data: Byte ['+util.hexstrdump(this.compressedData)+']\n'; - } - - this.read_packet = read_packet; - this.toString = toString; - this.compress = compress; - this.decompress = decompress; - this.write_packet = write_packet; + return String.fromCharCode(enums.write(enums.compression, this.algorithm)) + this.compressed; + } + + + /** + * Decompression method for decompressing the compressed data + * read by read_packet + */ + this.decompress = function() { + var decompressed; + + switch (this.algorithm) { + case 'uncompressed': + decompressed = this.compressed; + break; + + case 'zip': + var compData = this.compressed; + + var radix = base64.encode(compData).replace(/\n/g, ""); + // no header in this case, directly call deflate + var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix)); + + decompressed = unescape(jxg_obj.deflate()[0][0]); + break; + + case 'zlib': + //RFC 1950. Bits 0-3 Compression Method + var compressionMethod = this.compressed.charCodeAt(0) % 0x10; + + //Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size. + // 2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary + // (how is this defined). Basic checksum, and compression level. + + if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951 + // remove 4 bytes ADLER32 checksum from the end + var compData = this.compressed.substring(0, this.compressed.length - 4); + var radix = base64.encode(compData).replace(/\n/g, ""); + //TODO check ADLER32 checksum + decompressed = JXG.decompress(radix); + break; + + } else { + throw new Error("Compression algorithm ZLIB only supports " + + "DEFLATE compression method."); + } + break; + + case 'bzip2': + // TODO: need to implement this + throw new Error('Compression algorithm BZip2 [BZ2] is not implemented.'); + break; + + default: + throw new Error("Compression algorithm unknown :" + this.alogrithm); + break; + } + + this.packets.read(decompressed); + } + + /** + * Compress the packet data (member decompressedData) + */ + this.compress = function() { + switch (this.algorithm) { + + case 'uncompressed': + // - Uncompressed + this.compressed = this.packets.write(); + break; + + case 'zip': + // - ZIP [RFC1951] + throw new Error("Compression algorithm ZIP [RFC1951] is not implemented."); + break; + + case 'zlib': + // - ZLIB [RFC1950] + // TODO: need to implement this + throw new Error("Compression algorithm ZLIB [RFC1950] is not implemented."); + break; + + case 'bzip2': + // - BZip2 [BZ2] + // TODO: need to implement this + throw new Error("Compression algorithm BZip2 [BZ2] is not implemented."); + break; + + default: + throw new Error("Compression algorithm unknown :" + this.type); + break; + } + } }; + +},{"../compression/jxg.js":2,"../encoding/base64.js":26,"../enums.js":27}],35:[function(require,module,exports){ +var enums = require('../enums.js'); + +module.exports = { + list: require('./packetlist.js') +}; + +var packets = require('./all_packets.js'); + +for (var i in packets) + module.exports[i] = packets[i]; + +},{"../enums.js":27,"./all_packets.js":33,"./packetlist.js":40}],36:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -9504,87 +10960,119 @@ function openpgp_packet_compressed() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Implementation of the Symmetrically Encrypted Data Packet (Tag 9) - * - * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted - * with a symmetric-key algorithm. When it has been decrypted, it contains other - * packets (usually a literal data packet or compressed data packet, but in - * theory other Symmetrically Encrypted Data packets or sequences of packets - * that form whole OpenPGP messages). + * Implementation of the Literal Data Packet (Tag 11)
      + *
      + * RFC4880 5.9: A Literal Data packet contains the body of a message; data that + * is not to be further interpreted. + * @requires enums + * @requires util + * @module packet/literal */ -function openpgp_packet_encrypteddata() { - this.tagType = 9; - this.packetLength = null; - this.encryptedData = null; - this.decryptedData = null; +var util = require('../util'), + enums = require('../enums.js'); - /** - * Parsing function for the packet. - * - * @param {String} input Payload of a tag 9 packet - * @param {Integer} position Position to start reading from the input string - * @param {Integer} len Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} Object representation - */ - function read_packet(input, position, len) { - var mypos = position; - this.packetLength = len; - // - Encrypted data, the output of the selected symmetric-key cipher - // operating in OpenPGP's variant of Cipher Feedback (CFB) mode. - this.encryptedData = input.substring(position, position + len); - return this; - } +/** + * @constructor + */ +module.exports = function literal() { + this.format = 'utf8'; // default format for literal data packets + this.data = ''; // literal data representation as native JavaScript string or bytes + this.date = new Date(); - /** - * Symmetrically decrypt the packet data - * - * @param {Integer} symmetric_algorithm_type - * Symmetric key algorithm to use // See RFC4880 9.2 - * @param {String} key - * Key as string with the corresponding length to the - * algorithm - * @return The decrypted data; - */ - function decrypt_sym(symmetric_algorithm_type, key) { - this.decryptedData = openpgp_crypto_symmetricDecrypt( - symmetric_algorithm_type, key, this.encryptedData, true); - util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+ - "data: "+util.hexstrdump(this.decryptedData)); - return this.decryptedData; - } - /** - * Creates a string representation of the packet - * - * @param {Integer} algo Symmetric key algorithm to use // See RFC4880 9.2 - * @param {String} key Key as string with the corresponding length to the - * algorithm - * @param {String} data Data to be - * @return {String} String-representation of the packet - */ - function write_packet(algo, key, data) { - var result = ""; - result += openpgp_crypto_symmetricEncrypt( - openpgp_crypto_getPrefixRandom(algo), algo, key, data, true); - result = openpgp_packet.write_packet_header(9, result.length) + result; - return result; - } + /** + * Set the packet data to a javascript native string, end of line + * will be normalized to \r\n and by default text is converted to UTF8 + * @param {String} text Any native javascript string + */ + this.setText = function (text) { + // normalize EOL to \r\n + text = text.replace(/\r/g, '').replace(/\n/g, '\r\n'); + // encode UTF8 + this.data = this.format == 'utf8' ? util.encode_utf8(text) : text; + } - function toString() { - return '5.7. Symmetrically Encrypted Data Packet (Tag 9)\n' - + ' length: ' + this.packetLength + '\n' - + ' Used symmetric algorithm: ' + this.algorithmType + '\n' - + ' encrypted data: Bytes [' - + util.hexstrdump(this.encryptedData) + ']\n'; - } - this.decrypt_sym = decrypt_sym; - this.toString = toString; - this.read_packet = read_packet; - this.write_packet = write_packet; -}; + /** + * Returns literal data packets as native JavaScript string + * with normalized end of line to \n + * @return {String} literal data as text + */ + this.getText = function () { + // decode UTF8 + var text = util.decode_utf8(this.data); + // normalize EOL to \n + return text.replace(/\r\n/g, '\n'); + } + + /** + * Set the packet data to value represented by the provided string of bytes. + * @param {String} bytes The string of bytes + * @param {utf8|binary|text} format The format of the string of bytes + */ + this.setBytes = function (bytes, format) { + this.format = format; + this.data = bytes; + } + + + /** + * Get the byte sequence representing the literal packet data + * @returns {String} A sequence of bytes + */ + this.getBytes = function () { + return this.data; + } + + + /** + * Parsing function for a literal data packet (tag 11). + * + * @param {String} input Payload of a tag 11 packet + * @param {Integer} position + * Position to start reading from the input string + * @param {Integer} len + * Length of the packet or the remaining length of + * input at position + * @return {module:packet/literal} object representation + */ + this.read = function (bytes) { + // - A one-octet field that describes how the data is formatted. + + var format = enums.read(enums.literal, bytes.charCodeAt(0)); + + var filename_len = bytes.charCodeAt(1); + this.filename = util.decode_utf8(bytes.substr(2, filename_len)); + + this.date = util.readDate(bytes.substr(2 + filename_len, 4)); + + var data = bytes.substring(6 + filename_len); + + this.setBytes(data, format); + } + + /** + * Creates a string representation of the packet + * + * @param {String} data The data to be inserted as body + * @return {String} string-representation of the packet + */ + this.write = function () { + var filename = util.encode_utf8("msg.txt"); + + var data = this.getBytes(); + + var result = ''; + result += String.fromCharCode(enums.write(enums.literal, this.format)); + result += String.fromCharCode(filename.length); + result += filename; + result += util.writeDate(this.date); + result += data; + return result; + } +} + +},{"../enums.js":27,"../util":56}],37:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -9602,144 +11090,45 @@ function openpgp_packet_encrypteddata() { // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + /** - * @class - * @classdesc Implementation of the Sym. Encrypted Integrity Protected Data - * Packet (Tag 18) - * - * RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is - * a variant of the Symmetrically Encrypted Data packet. It is a new feature - * created for OpenPGP that addresses the problem of detecting a modification to - * encrypted data. It is used in combination with a Modification Detection Code - * packet. + * Implementation of the strange "Marker packet" (Tag 10)
      + *
      + * RFC4880 5.8: An experimental version of PGP used this packet as the Literal + * packet, but no released version of PGP generated Literal packets with this + * tag. With PGP 5.x, this packet has been reassigned and is reserved for use as + * the Marker packet.
      + *
      + * Such a packet MUST be ignored when received. + * @module packet/marker */ -function openpgp_packet_encryptedintegrityprotecteddata() { - this.tagType = 18; - this.version = null; // integer == 1 - this.packetLength = null; // integer - this.encryptedData = null; // string - this.decrytpedData = null; // string - this.hash = null; // string - /** - * Parsing function for the packet. - * - * @param {String} input Payload of a tag 18 packet - * @param {Integer} position - * position to start reading from the input string - * @param {Integer} len Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encryptedintegrityprotecteddata} object - * representation - */ - function read_packet(input, position, len) { - this.packetLength = len; - // - A one-octet version number. The only currently defined value is - // 1. - this.version = input.charCodeAt(position); - if (this.version != 1) { - util - .print_error('openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: ' - + this.version - + " , @ " - + position - + "hex:" - + util.hexstrdump(input)); - return null; - } - // - Encrypted data, the output of the selected symmetric-key cipher - // operating in Cipher Feedback mode with shift amount equal to the - // block size of the cipher (CFB-n where n is the block size). - this.encryptedData = input.substring(position + 1, position + 1 + len); - util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n" - + this.toString()); - return this; - } +/** + * @constructor + */ +module.exports = function marker() { + /** + * Parsing function for a literal data packet (tag 10). + * + * @param {String} input Payload of a tag 10 packet + * @param {Integer} position + * Position to start reading from the input string + * @param {Integer} len + * Length of the packet or the remaining length of + * input at position + * @return {module:packet/marker} Object representation + */ + this.read = function (bytes) { + if (bytes.charCodeAt(0) == 0x50 && // P + bytes.charCodeAt(1) == 0x47 && // G + bytes.charCodeAt(2) == 0x50) // P + return true; + // marker packet does not contain "PGP" + return false; + } +} - /** - * Creates a string representation of a Sym. Encrypted Integrity Protected - * Data Packet (tag 18) (see RFC4880 5.13) - * - * @param {Integer} symmetric_algorithm - * The selected symmetric encryption algorithm to be used - * @param {String} key The key of cipher blocksize length to be used - * @param {String} data - * Plaintext data to be encrypted within the packet - * @return {String} A string representation of the packet - */ - function write_packet(symmetric_algorithm, key, data) { - - var prefixrandom = openpgp_crypto_getPrefixRandom(symmetric_algorithm); - var prefix = prefixrandom - + prefixrandom.charAt(prefixrandom.length - 2) - + prefixrandom.charAt(prefixrandom.length - 1); - var tohash = data; - tohash += String.fromCharCode(0xD3); - tohash += String.fromCharCode(0x14); - util.print_debug_hexstr_dump("data to be hashed:" - , prefix + tohash); - tohash += str_sha1(prefix + tohash); - util.print_debug_hexstr_dump("hash:" - , tohash.substring(tohash.length - 20, - tohash.length)); - var result = openpgp_crypto_symmetricEncrypt(prefixrandom, - symmetric_algorithm, key, tohash, false).substring(0, - prefix.length + tohash.length); - var header = openpgp_packet.write_packet_header(18, result.length + 1) - + String.fromCharCode(1); - this.encryptedData = result; - return header + result; - } - - /** - * Decrypts the encrypted data contained in this object read_packet must - * have been called before - * - * @param {Integer} symmetric_algorithm_type - * The selected symmetric encryption algorithm to be used - * @param {String} key The key of cipher blocksize length to be used - * @return {String} The decrypted data of this packet - */ - function decrypt(symmetric_algorithm_type, key) { - this.decryptedData = openpgp_crypto_symmetricDecrypt( - symmetric_algorithm_type, key, this.encryptedData, false); - // there must be a modification detection code packet as the - // last packet and everything gets hashed except the hash itself - this.hash = str_sha1(openpgp_crypto_MDCSystemBytes( - symmetric_algorithm_type, key, this.encryptedData) - + this.decryptedData.substring(0, - this.decryptedData.length - 20)); - util.print_debug_hexstr_dump("calc hash = ", this.hash); - if (this.hash == this.decryptedData.substring( - this.decryptedData.length - 20, this.decryptedData.length)) - return this.decryptedData; - else - util - .print_error("Decryption stopped: discovered a modification of encrypted data."); - return null; - } - - function toString() { - var data = ''; - if(openpgp.config.debug) - data = ' data: Bytes [' - + util.hexstrdump(this.encryptedData) + ']'; - - return '5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n' - + ' length: ' - + this.packetLength - + '\n' - + ' version: ' - + this.version - + '\n' - + data; - } - - this.write_packet = write_packet; - this.read_packet = read_packet; - this.toString = toString; - this.decrypt = decrypt; -}; +},{}],38:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -9758,9 +11147,738 @@ function openpgp_packet_encryptedintegrityprotecteddata() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Public-Key Encrypted Session Key Packets (Tag 1) - * + * Implementation of the One-Pass Signature Packets (Tag 4)
      + *
      + * RFC4880 5.4: + * The One-Pass Signature packet precedes the signed data and contains + * enough information to allow the receiver to begin calculating any + * hashes needed to verify the signature. It allows the Signature + * packet to be placed at the end of the message, so that the signer + * can compute the entire signed message in one pass. + * @requires enums + * @requires type/keyid + * @module packet/one_pass_signature +*/ + +var enums = require('../enums.js'), + type_keyid = require('../type/keyid.js'); + +/** + * @constructor + */ +module.exports = function one_pass_signature() { + this.version = null; // A one-octet version number. The current version is 3. + this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1. + this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4) + this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1) + this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key. + this.flags = null; // A one-octet number holding a flag showing whether the signature is nested. A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data. + + /** + * parsing function for a one-pass signature packet (tag 4). + * @param {String} bytes payload of a tag 4 packet + * @return {module:packet/one_pass_signature} object representation + */ + this.read = function (bytes) { + var mypos = 0; + // A one-octet version number. The current version is 3. + this.version = bytes.charCodeAt(mypos++); + + // A one-octet signature type. Signature types are described in + // Section 5.2.1. + this.type = enums.read(enums.signature, bytes.charCodeAt(mypos++)); + + // A one-octet number describing the hash algorithm used. + this.hashAlgorithm = enums.read(enums.hash, bytes.charCodeAt(mypos++)); + + // A one-octet number describing the public-key algorithm used. + this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(mypos++)); + + // An eight-octet number holding the Key ID of the signing key. + this.signingKeyId = new type_keyid(); + this.signingKeyId.read(bytes.substr(mypos)); + mypos += 8; + + // A one-octet number holding a flag showing whether the signature + // is nested. A zero value indicates that the next packet is + // another One-Pass Signature packet that describes another + // signature to be applied to the same message data. + this.flags = bytes.charCodeAt(mypos++); + return this; + } + + /** + * creates a string representation of a one-pass signature packet + * @return {String} a string representation of a one-pass signature packet + */ + this.write = function () { + var result = ""; + + result += String.fromCharCode(3); + result += String.fromCharCode(enums.write(enums.signature, this.type)); + result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm)); + result += String.fromCharCode(enums.write(enums.publicKey, this.publicKeyAlgorithm)); + result += this.signingKeyId.write(); + result += String.fromCharCode(this.flags); + + return result; + } +}; + +},{"../enums.js":27,"../type/keyid.js":53}],39:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires enums + * @requires util + * @module packet/packet + */ + +var enums = require('../enums.js'), + util = require('../util'); + + +module.exports = { + readSimpleLength: function(bytes) { + var len = 0, + offset, + type = bytes.charCodeAt(0); + + + if (type < 192) { + len = bytes.charCodeAt(0); + offset = 1; + } else if (type < 255) { + len = ((bytes.charCodeAt(0) - 192) << 8) + (bytes.charCodeAt(1)) + 192; + offset = 2; + } else if (type == 255) { + len = util.readNumber(bytes.substr(1, 4)); + offset = 5; + } + + return { + len: len, + offset: offset + }; + }, + + /** + * Encodes a given integer of length to the openpgp length specifier to a + * string + * + * @param {Integer} length The length to encode + * @return {String} String with openpgp length representation + */ + writeSimpleLength: function(length) { + var result = ""; + if (length < 192) { + result += String.fromCharCode(length); + } else if (length > 191 && length < 8384) { + /* + * let a = (total data packet length) - 192 let bc = two octet + * representation of a let d = b + 192 + */ + result += String.fromCharCode(((length - 192) >> 8) + 192); + result += String.fromCharCode((length - 192) & 0xFF); + } else { + result += String.fromCharCode(255); + result += util.writeNumber(length, 4); + } + return result; + }, + + /** + * Writes a packet header version 4 with the given tag_type and length to a + * string + * + * @param {Integer} tag_type Tag type + * @param {Integer} length Length of the payload + * @return {String} String of the header + */ + writeHeader: function(tag_type, length) { + /* we're only generating v4 packet headers here */ + var result = ""; + result += String.fromCharCode(0xC0 | tag_type); + result += this.writeSimpleLength(length); + return result; + }, + + /** + * Writes a packet header Version 3 with the given tag_type and length to a + * string + * + * @param {Integer} tag_type Tag type + * @param {Integer} length Length of the payload + * @return {String} String of the header + */ + writeOldHeader: function(tag_type, length) { + var result = ""; + if (length < 256) { + result += String.fromCharCode(0x80 | (tag_type << 2)); + result += String.fromCharCode(length); + } else if (length < 65536) { + result += String.fromCharCode(0x80 | (tag_type << 2) | 1); + result += util.writeNumber(length, 2); + } else { + result += String.fromCharCode(0x80 | (tag_type << 2) | 2); + result += util.writeNumber(length, 4); + } + return result; + }, + + /** + * Generic static Packet Parser function + * + * @param {String} input Input stream as string + * @param {integer} position Position to start parsing + * @param {integer} len Length of the input from position on + * @return {Object} Returns a parsed module:packet/packet + */ + read: function(input, position, len) { + // some sanity checks + if (input == null || input.length <= position || input.substring(position).length < 2 || (input.charCodeAt(position) & + 0x80) == 0) { + throw new Error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."); + } + var mypos = position; + var tag = -1; + var format = -1; + var packet_length; + + format = 0; // 0 = old format; 1 = new format + if ((input.charCodeAt(mypos) & 0x40) != 0) { + format = 1; + } + + var packet_length_type; + if (format) { + // new format header + tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0 + } else { + // old format header + tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2 + packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0 + } + + // header octet parsing done + mypos++; + + // parsed length from length field + var bodydata = null; + + // used for partial body lengths + var real_packet_length = -1; + if (!format) { + // 4.2.1. Old Format Packet Lengths + switch (packet_length_type) { + case 0: + // The packet has a one-octet length. The header is 2 octets + // long. + packet_length = input.charCodeAt(mypos++); + break; + case 1: + // The packet has a two-octet length. The header is 3 octets + // long. + packet_length = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); + break; + case 2: + // The packet has a four-octet length. The header is 5 + // octets long. + packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << + 8) | input.charCodeAt(mypos++); + break; + default: + // 3 - The packet is of indeterminate length. The header is 1 + // octet long, and the implementation must determine how long + // the packet is. If the packet is in a file, this means that + // the packet extends until the end of the file. In general, + // an implementation SHOULD NOT use indeterminate-length + // packets except where the end of the data will be clear + // from the context, and even then it is better to use a + // definite length, or a new format header. The new format + // headers described below have a mechanism for precisely + // encoding data of indeterminate length. + packet_length = len; + break; + } + + } else // 4.2.2. New Format Packet Lengths + { + + // 4.2.2.1. One-Octet Lengths + if (input.charCodeAt(mypos) < 192) { + packet_length = input.charCodeAt(mypos++); + util.print_debug("1 byte length:" + packet_length); + // 4.2.2.2. Two-Octet Lengths + } else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) { + packet_length = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192; + util.print_debug("2 byte length:" + packet_length); + // 4.2.2.4. Partial Body Lengths + } else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) { + packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F); + util.print_debug("4 byte length:" + packet_length); + // EEEK, we're reading the full data here... + var mypos2 = mypos + packet_length; + bodydata = input.substring(mypos, mypos + packet_length); + while (true) { + if (input.charCodeAt(mypos2) < 192) { + var tmplen = input.charCodeAt(mypos2++); + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + break; + } else if (input.charCodeAt(mypos2) >= 192 && input.charCodeAt(mypos2) < 224) { + var tmplen = ((input.charCodeAt(mypos2++) - 192) << 8) + (input.charCodeAt(mypos2++)) + 192; + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + break; + } else if (input.charCodeAt(mypos2) > 223 && input.charCodeAt(mypos2) < 255) { + var tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F); + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + } else { + mypos2++; + var tmplen = (input.charCodeAt(mypos2++) << 24) | (input.charCodeAt(mypos2++) << 16) | (input[mypos2++] + .charCodeAt() << 8) | input.charCodeAt(mypos2++); + bodydata += input.substring(mypos2, mypos2 + tmplen); + packet_length += tmplen; + mypos2 += tmplen; + break; + } + } + real_packet_length = mypos2; + // 4.2.2.3. Five-Octet Lengths + } else { + mypos++; + packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << + 8) | input.charCodeAt(mypos++); + } + } + + // if there was'nt a partial body length: use the specified + // packet_length + if (real_packet_length == -1) { + real_packet_length = packet_length; + } + + if (bodydata == null) { + bodydata = input.substring(mypos, mypos + real_packet_length); + } + + return { + tag: tag, + packet: bodydata, + offset: mypos + real_packet_length + }; + } +} + +},{"../enums.js":27,"../util":56}],40:[function(require,module,exports){ +/** + * This class represents a list of openpgp packets. + * Take care when iterating over it - the packets themselves + * are stored as numerical indices. + * @requires enums + * @requires packet + * @requires packet/packet + * @module packet/packetlist + */ + +var packetParser = require('./packet.js'), + packets = require('./all_packets.js'), + enums = require('../enums.js'); + +/** + * @constructor + */ +module.exports = function packetlist() { + /** The number of packets contained within the list. + * @readonly + * @type {Integer} */ + this.length = 0; + + /** + * Reads a stream of binary data and interprents it as a list of packets. + * @param {String} A binary string of bytes. + */ + this.read = function (bytes) { + var i = 0; + + while (i < bytes.length) { + var parsed = packetParser.read(bytes, i, bytes.length - i); + i = parsed.offset; + + var tag = enums.read(enums.packet, parsed.tag); + var packet = new packets[tag](); + + this.push(packet); + + packet.read(parsed.packet); + } + } + + /** + * Creates a binary representation of openpgp objects contained within the + * class instance. + * @returns {String} A binary string of bytes containing valid openpgp packets. + */ + this.write = function () { + var bytes = ''; + + for (var i = 0; i < this.length; i++) { + var packetbytes = this[i].write(); + bytes += packetParser.writeHeader(this[i].tag, packetbytes.length); + bytes += packetbytes; + } + + return bytes; + } + + /** + * Adds a packet to the list. This is the only supported method of doing so; + * writing to packetlist[i] directly will result in an error. + */ + this.push = function (packet) { + if (!packet) return; + + packet.packets = packet.packets || new packetlist(); + + this[this.length] = packet; + this.length++; + } + + /** + * Creates a new packetList with all packets that pass the test implemented by the provided function. + */ + this.filter = function (callback) { + + var filtered = new packetlist(); + + for (var i = 0; i < this.length; i++) { + if (callback(this[i], i, this)) { + filtered.push(this[i]); + } + } + + return filtered; + } + + /** + * Creates a new packetList with all packets from the given types + */ + this.filterByTag = function () { + var args = Array.prototype.slice.call(arguments); + var filtered = new packetlist(); + var that = this; + + for (var i = 0; i < this.length; i++) { + if (args.some(function(packetType) {return that[i].tag == packetType})) { + filtered.push(this[i]); + } + } + + return filtered; + } + + /** + * Executes the provided callback once for each element + */ + this.forEach = function (callback) { + for (var i = 0; i < this.length; i++) { + callback(this[i]); + } + } + + /** + * Traverses packet tree and returns first matching packet + * @param {module:enums.packet} type The packet type + * @return {module:packet/packet|null} + */ + this.findPacket = function (type) { + var packetlist = this.filterByTag(type); + if (packetlist.length) { + return packetlist[0]; + } else { + var found = null; + for (var i = 0; i < this.length; i++) { + if (this[i].packets.length) { + found = this[i].packets.findPacket(type); + if (found) return found; + } + } + } + return null; + } + + /** + * Returns array of found indices by tag + */ + this.indexOfTag = function () { + var args = Array.prototype.slice.call(arguments); + var tagIndex = []; + var that = this; + for (var i = 0; i < this.length; i++) { + if (args.some(function(packetType) {return that[i].tag == packetType})) { + tagIndex.push(i); + } + } + return tagIndex; + } + + /** + * Returns slice of packetlist + */ + this.slice = function (begin, end) { + if (!end) { + end = this.length + } + var part = new packetlist(); + for (var i = begin; i < end; i++) { + part.push(this[i]); + } + return part; + } + + /** + * Concatenates packetlist or array of packets + */ + this.concat = function (packetlist) { + if (packetlist) { + for (var i = 0; i < packetlist.length; i++) { + this.push(packetlist[i]); + } + } + } + +} + +},{"../enums.js":27,"./all_packets.js":33,"./packet.js":39}],41:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Key Material Packet (Tag 5,6,7,14)
      + *
      + * RFC4480 5.5: + * A key material packet contains all the information about a public or + * private key. There are four variants of this packet type, and two + * major versions. Consequently, this section is complex. + * @requires crypto + * @requires enums + * @requires type/keyid + * @requires type/mpi + * @requires util + * @module packet/public_key + */ + +var util = require('../util'), + type_mpi = require('../type/mpi.js'), + type_keyid = require('../type/keyid.js'), + enums = require('../enums.js'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function public_key() { + this.version = 4; + /** Key creation date. + * @type {Date} */ + this.created = new Date(); + /** A list of multiprecision integers + * @type {module:type/mpi} */ + this.mpi = []; + /** Public key algorithm + * @type {module:enums.publicKey} */ + this.algorithm = 'rsa_sign'; + // time in days (V3 only) + this.expirationTimeV3 = 0; + + + /** + * Internal Parser for public keys as specified in RFC 4880 section + * 5.5.2 Public-Key Packet Formats + * called by read_tag<num> + * @param {String} input Input string to read the packet from + * @return {Object} This object with attributes set by the parser + */ + this.read = function (bytes) { + var pos = 0; + // A one-octet version number (3 or 4). + this.version = bytes.charCodeAt(pos++); + + if (this.version == 3 || this.version == 4) { + // - A four-octet number denoting the time that the key was created. + this.created = util.readDate(bytes.substr(pos, 4)); + pos += 4; + + if (this.version == 3) { + // - A two-octet number denoting the time in days that this key is + // valid. If this number is zero, then it does not expire. + this.expirationTimeV3 = util.readNumber(bytes.substr(pos, 2)); + pos += 2; + } + + // - A one-octet number denoting the public-key algorithm of this key. + this.algorithm = enums.read(enums.publicKey, bytes.charCodeAt(pos++)); + + var mpicount = crypto.getPublicMpiCount(this.algorithm); + this.mpi = []; + + var bmpi = bytes.substr(pos); + var p = 0; + + for (var i = 0; i < mpicount && p < bmpi.length; i++) { + + this.mpi[i] = new type_mpi(); + + p += this.mpi[i].read(bmpi.substr(p)) + + if (p > bmpi.length) { + throw new Error('Error reading MPI @:' + p); + } + } + + return p + 6; + } else { + throw new Error('Version ' + version + ' of the key packet is unsupported.'); + } + }; + + /** + * Alias of read() + * @function module:packet/public_key#readPublicKey + * @see module:packet/public_key#read + */ + this.readPublicKey = this.read; + + /** + * Same as write_private_key, but has less information because of + * public key. + * @return {Object} {body: [string]OpenPGP packet body contents, + * header: [string] OpenPGP packet header, string: [string] header+body} + */ + this.write = function () { + // Version + var result = String.fromCharCode(this.version); + result += util.writeDate(this.created); + if (this.version == 3) { + result += util.writeNumber(this.expirationTimeV3, 2); + } + result += String.fromCharCode(enums.write(enums.publicKey, this.algorithm)); + + var mpicount = crypto.getPublicMpiCount(this.algorithm); + + for (var i = 0; i < mpicount; i++) { + result += this.mpi[i].write(); + } + + return result; + }; + + /** + * Alias of write() + * @function module:packet/public_key#writePublicKey + * @see module:packet/public_key#write + */ + this.writePublicKey = this.write; + + /** + * Write an old version packet - it's used by some of the internal routines. + */ + this.writeOld = function () { + var bytes = this.writePublicKey(); + + return String.fromCharCode(0x99) + + util.writeNumber(bytes.length, 2) + + bytes; + }; + + /** + * Calculates the key id of the key + * @return {String} A 8 byte key id + */ + this.getKeyId = function () { + var keyid = new type_keyid(); + if (this.version == 4) { + keyid.read(this.getFingerprint().substr(12, 8)); + } else if (this.version == 3) { + keyid.read(this.mpi[0].write().substr(-8)); + } + return keyid; + }; + + /** + * Calculates the fingerprint of the key + * @return {String} A string containing the fingerprint + */ + this.getFingerprint = function () { + var toHash = ''; + if (this.version == 4) { + toHash = this.writeOld(); + return crypto.hash.sha1(toHash); + } else if (this.version == 3) { + var mpicount = crypto.getPublicMpiCount(this.algorithm); + for (var i = 0; i < mpicount; i++) { + toHash += this.mpi[i].toBytes(); + } + return crypto.hash.md5(toHash) + } + }; +}; + +},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56}],42:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Public-Key Encrypted Session Key Packets (Tag 1)
      + *
      * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key * used to encrypt a message. Zero or more Public-Key Encrypted Session Key * packets and/or Symmetric-Key Encrypted Session Key packets may precede a @@ -9772,200 +11890,159 @@ function openpgp_packet_encryptedintegrityprotecteddata() { * The recipient of the message finds a session key that is encrypted to their * public key, decrypts the session key, and then uses the session key to * decrypt the message. + * @requires crypto + * @requires enums + * @requires type/keyid + * @requires type/mpi + * @requires util + * @module packet/public_key_encrypted_session_key */ -function openpgp_packet_encryptedsessionkey() { - /** - * Parsing function for a publickey encrypted session key packet (tag 1). - * - * @param {String} input Payload of a tag 1 packet - * @param {Integer} position Position to start reading from the input string - * @param {Integer} len Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} Object representation - */ - function read_pub_key_packet(input, position, len) { - this.tagType = 1; - this.packetLength = len; - var mypos = position; - if (len < 10) { - util - .print_error("openpgp.packet.encryptedsessionkey.js\n" + 'invalid length'); - return null; - } +var type_keyid = require('../type/keyid.js'), + util = require('../util'), + type_mpi = require('../type/mpi.js'), + enums = require('../enums.js'), + crypto = require('../crypto'); - this.version = input.charCodeAt(mypos++); - this.keyId = new openpgp_type_keyid(); - this.keyId.read_packet(input, mypos); - mypos += 8; - this.publicKeyAlgorithmUsed = input.charCodeAt(mypos++); +/** + * @constructor + */ +module.exports = function public_key_encrypted_session_key() { + this.version = 3; - switch (this.publicKeyAlgorithmUsed) { - case 1: - case 2: // RSA - this.MPIs = new Array(); - this.MPIs[0] = new openpgp_type_mpi(); - this.MPIs[0].read(input, mypos, mypos - position); - break; - case 16: // Elgamal - this.MPIs = new Array(); - this.MPIs[0] = new openpgp_type_mpi(); - this.MPIs[0].read(input, mypos, mypos - position); - mypos += this.MPIs[0].packetLength; - this.MPIs[1] = new openpgp_type_mpi(); - this.MPIs[1].read(input, mypos, mypos - position); - break; - default: - util.print_error("openpgp.packet.encryptedsessionkey.js\n" - + "unknown public key packet algorithm type " - + this.publicKeyAlgorithmType); - break; - } - return this; - } + this.publicKeyId = new type_keyid(); + this.publicKeyAlgorithm = 'rsa_encrypt'; - /** - * Create a string representation of a tag 1 packet - * - * @param {String} publicKeyId - * The public key id corresponding to publicMPIs key as string - * @param {openpgp_type_mpi[]} publicMPIs - * Multiprecision integer objects describing the public key - * @param {Integer} pubalgo - * The corresponding public key algorithm // See RFC4880 9.1 - * @param {Integer} symmalgo - * The symmetric cipher algorithm used to encrypt the data - * within an encrypteddatapacket or encryptedintegrity- - * protecteddatapacket - * following this packet //See RFC4880 9.2 - * @param {String} sessionkey - * A string of randombytes representing the session key - * @return {String} The string representation - */ - function write_pub_key_packet(publicKeyId, publicMPIs, pubalgo, symmalgo, - sessionkey) { - var result = String.fromCharCode(3); - var data = String.fromCharCode(symmalgo); - data += sessionkey; - var checksum = util.calc_checksum(sessionkey); - data += String.fromCharCode((checksum >> 8) & 0xFF); - data += String.fromCharCode((checksum) & 0xFF); - result += publicKeyId; - result += String.fromCharCode(pubalgo); - var mpi = new openpgp_type_mpi(); - var mpiresult = openpgp_crypto_asymetricEncrypt(pubalgo, publicMPIs, - mpi.create(openpgp_encoding_eme_pkcs1_encode(data, - publicMPIs[0].mpiByteLength))); - for ( var i = 0; i < mpiresult.length; i++) { - result += mpiresult[i]; - } - result = openpgp_packet.write_packet_header(1, result.length) + result; - return result; - } + this.sessionKey = null; + this.sessionKeyAlgorithm = 'aes256'; - /** - * Parsing function for a symmetric encrypted session key packet (tag 3). - * - * @param {String} input Payload of a tag 1 packet - * @param {Integer} position Position to start reading from the input string - * @param {Integer} len - * Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} Object representation - */ - function read_symmetric_key_packet(input, position, len) { - this.tagType = 3; - var mypos = position; - // A one-octet version number. The only currently defined version is 4. - this.version = input[mypos++]; + /** @type {Array} */ + this.encrypted = []; - // A one-octet number describing the symmetric algorithm used. - this.symmetricKeyAlgorithmUsed = input[mypos++]; - // A string-to-key (S2K) specifier, length as defined above. - this.s2k = new openpgp_type_s2k(); - this.s2k.read(input, mypos); + /** + * Parsing function for a publickey encrypted session key packet (tag 1). + * + * @param {String} input Payload of a tag 1 packet + * @param {Integer} position Position to start reading from the input string + * @param {Integer} len Length of the packet or the remaining length of + * input at position + * @return {module:packet/public_key_encrypted_session_key} Object representation + */ + this.read = function (bytes) { - // Optionally, the encrypted session key itself, which is decrypted - // with the string-to-key object. - if ((s2k.s2kLength + mypos) < len) { - this.encryptedSessionKey = new Array(); - for ( var i = (mypos - position); i < len; i++) { - this.encryptedSessionKey[i] = input[mypos++]; - } - } - return this; - } - /** - * Decrypts the session key (only for public key encrypted session key - * packets (tag 1) - * - * @param {openpgp_msg_message} msg - * The message object (with member encryptedData - * @param {openpgp_msg_privatekey} key - * Private key with secMPIs unlocked - * @return {String} The unencrypted session key - */ - function decrypt(msg, key) { - if (this.tagType == 1) { - var result = openpgp_crypto_asymetricDecrypt( - this.publicKeyAlgorithmUsed, key.publicKey.MPIs, - key.secMPIs, this.MPIs).toMPI(); - var checksum = ((result.charCodeAt(result.length - 2) << 8) + result - .charCodeAt(result.length - 1)); - var decoded = openpgp_encoding_eme_pkcs1_decode(result.substring(2, result.length - 2), key.publicKey.MPIs[0].getByteLength()); - var sesskey = decoded.substring(1); - var algo = decoded.charCodeAt(0); - if (msg.encryptedData.tagType == 18) - return msg.encryptedData.decrypt(algo, sesskey); - else - return msg.encryptedData.decrypt_sym(algo, sesskey); - } else if (this.tagType == 3) { - util - .print_error("Symmetric encrypted sessionkey is not supported!"); - return null; - } - } + this.version = bytes.charCodeAt(0); + this.publicKeyId.read(bytes.substr(1)); + this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(9)); - /** - * Creates a string representation of this object (useful for debug - * purposes) - * - * @return {String} The string containing a openpgp description - */ - function toString() { - if (this.tagType == 1) { - var result = '5.1. Public-Key Encrypted Session Key Packets (Tag 1)\n' - + ' KeyId: ' - + this.keyId.toString() - + '\n' - + ' length: ' - + this.packetLength - + '\n' - + ' version:' - + this.version - + '\n' - + ' pubAlgUs:' - + this.publicKeyAlgorithmUsed + '\n'; - for ( var i = 0; i < this.MPIs.length; i++) { - result += this.MPIs[i].toString(); - } - return result; - } else - return '5.3 Symmetric-Key Encrypted Session Key Packets (Tag 3)\n' - + ' KeyId: ' + this.keyId.toString() + '\n' - + ' length: ' + this.packetLength + '\n' - + ' version:' + this.version + '\n' + ' symKeyA:' - + this.symmetricKeyAlgorithmUsed + '\n' + ' s2k: ' - + this.s2k + '\n'; - } + var i = 10; - this.read_pub_key_packet = read_pub_key_packet; - this.read_symmetric_key_packet = read_symmetric_key_packet; - this.write_pub_key_packet = write_pub_key_packet; - this.toString = toString; - this.decrypt = decrypt; + var integerCount = (function(algo) { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + return 1; + + case 'elgamal': + return 2; + + default: + throw new Error("Invalid algorithm."); + } + })(this.publicKeyAlgorithm); + + this.encrypted = []; + + for (var j = 0; j < integerCount; j++) { + var mpi = new type_mpi(); + i += mpi.read(bytes.substr(i)); + this.encrypted.push(mpi); + } + }; + + /** + * Create a string representation of a tag 1 packet + * + * @param {String} publicKeyId + * The public key id corresponding to publicMPIs key as string + * @param {Array} publicMPIs + * Multiprecision integer objects describing the public key + * @param {Integer} pubalgo + * The corresponding public key algorithm // See RFC4880 9.1 + * @param {Integer} symmalgo + * The symmetric cipher algorithm used to encrypt the data + * within an encrypteddatapacket or encryptedintegrity- + * protecteddatapacket + * following this packet //See RFC4880 9.2 + * @param {String} sessionkey + * A string of randombytes representing the session key + * @return {String} The string representation + */ + this.write = function () { + + var result = String.fromCharCode(this.version); + result += this.publicKeyId.write(); + result += String.fromCharCode( + enums.write(enums.publicKey, this.publicKeyAlgorithm)); + + for (var i = 0; i < this.encrypted.length; i++) { + result += this.encrypted[i].write() + } + + return result; + }; + + this.encrypt = function (key) { + var data = String.fromCharCode( + enums.write(enums.symmetric, this.sessionKeyAlgorithm)); + + data += this.sessionKey; + var checksum = util.calc_checksum(this.sessionKey); + data += util.writeNumber(checksum, 2); + + var mpi = new type_mpi(); + mpi.fromBytes(crypto.pkcs1.eme.encode( + data, + key.mpi[0].byteLength())); + + this.encrypted = crypto.publicKeyEncrypt( + this.publicKeyAlgorithm, + key.mpi, + mpi); + }; + + /** + * Decrypts the session key (only for public key encrypted session key + * packets (tag 1) + * + * @param {module:packet/secret_key} key + * Private key with secMPIs unlocked + * @return {String} The unencrypted session key + */ + this.decrypt = function (key) { + var result = crypto.publicKeyDecrypt( + this.publicKeyAlgorithm, + key.mpi, + this.encrypted).toBytes(); + + var checksum = util.readNumber(result.substr(result.length - 2)); + + var decoded = crypto.pkcs1.eme.decode( + result, + key.mpi[0].byteLength()); + + var key = decoded.substring(1, decoded.length - 2); + + if (checksum != util.calc_checksum(key)) { + throw new Error('Checksum mismatch'); + } else { + this.sessionKey = key; + this.sessionKeyAlgorithm = + enums.read(enums.symmetric, decoded.charCodeAt(0)); + } + }; }; +},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56}],43:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -9984,395 +12061,21 @@ function openpgp_packet_encryptedsessionkey() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Parent openpgp packet class. Operations focus on determining - * packet types and packet header. + * @requires packet/public_key + * @module packet/public_subkey */ -function _openpgp_packet() { - /** - * Encodes a given integer of length to the openpgp length specifier to a - * string - * - * @param {Integer} length The length to encode - * @return {String} String with openpgp length representation - */ - function encode_length(length) { - result = ""; - if (length < 192) { - result += String.fromCharCode(length); - } else if (length > 191 && length < 8384) { - /* - * let a = (total data packet length) - 192 let bc = two octet - * representation of a let d = b + 192 - */ - result += String.fromCharCode(((length - 192) >> 8) + 192); - result += String.fromCharCode((length - 192) & 0xFF); - } else { - result += String.fromCharCode(255); - result += String.fromCharCode((length >> 24) & 0xFF); - result += String.fromCharCode((length >> 16) & 0xFF); - result += String.fromCharCode((length >> 8) & 0xFF); - result += String.fromCharCode(length & 0xFF); - } - return result; - } - this.encode_length = encode_length; - /** - * Writes a packet header version 4 with the given tag_type and length to a - * string - * - * @param {Integer} tag_type Tag type - * @param {Integer} length Length of the payload - * @return {String} String of the header - */ - function write_packet_header(tag_type, length) { - /* we're only generating v4 packet headers here */ - var result = ""; - result += String.fromCharCode(0xC0 | tag_type); - result += encode_length(length); - return result; - } +var publicKey = require('./public_key.js'); - /** - * Writes a packet header Version 3 with the given tag_type and length to a - * string - * - * @param {Integer} tag_type Tag type - * @param {Integer} length Length of the payload - * @return {String} String of the header - */ - function write_old_packet_header(tag_type, length) { - var result = ""; - if (length < 256) { - result += String.fromCharCode(0x80 | (tag_type << 2)); - result += String.fromCharCode(length); - } else if (length < 65536) { - result += String.fromCharCode(0x80 | (tag_type << 2) | 1); - result += String.fromCharCode(length >> 8); - result += String.fromCharCode(length & 0xFF); - } else { - result += String.fromCharCode(0x80 | (tag_type << 2) | 2); - result += String.fromCharCode((length >> 24) & 0xFF); - result += String.fromCharCode((length >> 16) & 0xFF); - result += String.fromCharCode((length >> 8) & 0xFF); - result += String.fromCharCode(length & 0xFF); - } - return result; - } - this.write_old_packet_header = write_old_packet_header; - this.write_packet_header = write_packet_header; - /** - * Generic static Packet Parser function - * - * @param {String} input Input stream as string - * @param {integer} position Position to start parsing - * @param {integer} len Length of the input from position on - * @return {Object} Returns a parsed openpgp_packet - */ - function read_packet(input, position, len) { - // some sanity checks - if (input == null || input.length <= position - || input.substring(position).length < 2 - || (input.charCodeAt(position) & 0x80) == 0) { - util - .print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."); - return null; - } - var mypos = position; - var tag = -1; - var format = -1; - - format = 0; // 0 = old format; 1 = new format - if ((input.charCodeAt(mypos) & 0x40) != 0) { - format = 1; - } - - var packet_length_type; - if (format) { - // new format header - tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0 - } else { - // old format header - tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2 - packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0 - } - - // header octet parsing done - mypos++; - - // parsed length from length field - var bodydata = null; - - // used for partial body lengths - var real_packet_length = -1; - if (!format) { - // 4.2.1. Old Format Packet Lengths - switch (packet_length_type) { - case 0: // The packet has a one-octet length. The header is 2 octets - // long. - packet_length = input.charCodeAt(mypos++); - break; - case 1: // The packet has a two-octet length. The header is 3 octets - // long. - packet_length = (input.charCodeAt(mypos++) << 8) - | input.charCodeAt(mypos++); - break; - case 2: // The packet has a four-octet length. The header is 5 - // octets long. - packet_length = (input.charCodeAt(mypos++) << 24) - | (input.charCodeAt(mypos++) << 16) - | (input.charCodeAt(mypos++) << 8) - | input.charCodeAt(mypos++); - break; - default: - // 3 - The packet is of indeterminate length. The header is 1 - // octet long, and the implementation must determine how long - // the packet is. If the packet is in a file, this means that - // the packet extends until the end of the file. In general, - // an implementation SHOULD NOT use indeterminate-length - // packets except where the end of the data will be clear - // from the context, and even then it is better to use a - // definite length, or a new format header. The new format - // headers described below have a mechanism for precisely - // encoding data of indeterminate length. - packet_length = len; - break; - } - - } else // 4.2.2. New Format Packet Lengths - { - - // 4.2.2.1. One-Octet Lengths - if (input.charCodeAt(mypos) < 192) { - packet_length = input.charCodeAt(mypos++); - util.print_debug("1 byte length:" + packet_length); - // 4.2.2.2. Two-Octet Lengths - } else if (input.charCodeAt(mypos) >= 192 - && input.charCodeAt(mypos) < 224) { - packet_length = ((input.charCodeAt(mypos++) - 192) << 8) - + (input.charCodeAt(mypos++)) + 192; - util.print_debug("2 byte length:" + packet_length); - // 4.2.2.4. Partial Body Lengths - } else if (input.charCodeAt(mypos) > 223 - && input.charCodeAt(mypos) < 255) { - packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F); - util.print_debug("4 byte length:" + packet_length); - // EEEK, we're reading the full data here... - var mypos2 = mypos + packet_length; - bodydata = input.substring(mypos, mypos + packet_length); - while (true) { - if (input.charCodeAt(mypos2) < 192) { - var tmplen = input.charCodeAt(mypos2++); - packet_length += tmplen; - bodydata += input.substring(mypos2, mypos2 + tmplen); - mypos2 += tmplen; - break; - } else if (input.charCodeAt(mypos2) >= 192 - && input.charCodeAt(mypos2) < 224) { - var tmplen = ((input.charCodeAt(mypos2++) - 192) << 8) - + (input.charCodeAt(mypos2++)) + 192; - packet_length += tmplen; - bodydata += input.substring(mypos2, mypos2 + tmplen); - mypos2 += tmplen; - break; - } else if (input.charCodeAt(mypos2) > 223 - && input.charCodeAt(mypos2) < 255) { - var tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F); - packet_length += tmplen; - bodydata += input.substring(mypos2, mypos2 + tmplen); - mypos2 += tmplen; - } else { - mypos2++; - var tmplen = (input.charCodeAt(mypos2++) << 24) - | (input.charCodeAt(mypos2++) << 16) - | (input.charCodeAt(mypos2++) << 8) - | input.charCodeAt(mypos2++); - bodydata += input.substring(mypos2, mypos2 + tmplen); - packet_length += tmplen; - mypos2 += tmplen; - break; - } - } - real_packet_length = mypos2; - // 4.2.2.3. Five-Octet Lengths - } else { - mypos++; - packet_length = (input.charCodeAt(mypos++) << 24) - | (input.charCodeAt(mypos++) << 16) - | (input.charCodeAt(mypos++) << 8) - | input.charCodeAt(mypos++); - } - } - - // if there was'nt a partial body length: use the specified - // packet_length - if (real_packet_length == -1) { - real_packet_length = packet_length; - } - - if (bodydata == null) { - bodydata = input.substring(mypos, mypos + real_packet_length); - } - - // alert('tag type: '+this.tag+' length: '+packet_length); - var version = 1; // (old format; 2= new format) - // if (input.charCodeAt(mypos++) > 15) - // version = 2; - - switch (tag) { - case 0: // Reserved - a packet tag MUST NOT have this value - break; - case 1: // Public-Key Encrypted Session Key Packet - var result = new openpgp_packet_encryptedsessionkey(); - if (result.read_pub_key_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 2: // Signature Packet - var result = new openpgp_packet_signature(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 3: // Symmetric-Key Encrypted Session Key Packet - var result = new openpgp_packet_encryptedsessionkey(); - if (result.read_symmetric_key_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 4: // One-Pass Signature Packet - var result = new openpgp_packet_onepasssignature(); - if (result.read_packet(bodydata, 0, packet_length)) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 5: // Secret-Key Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag5(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 6: // Public-Key Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag6(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 7: // Secret-Subkey Packet - var result = new openpgp_packet_keymaterial(); - if (result.read_tag7(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 8: // Compressed Data Packet - var result = new openpgp_packet_compressed(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 9: // Symmetrically Encrypted Data Packet - var result = new openpgp_packet_encrypteddata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 10: // Marker Packet = PGP (0x50, 0x47, 0x50) - var result = new openpgp_packet_marker(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 11: // Literal Data Packet - var result = new openpgp_packet_literaldata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.header = input.substring(position, mypos); - result.packetLength = real_packet_length; - return result; - } - break; - case 12: // Trust Packet - // TODO: to be implemented - break; - case 13: // User ID Packet - var result = new openpgp_packet_userid(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 14: // Public-Subkey Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag14(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 17: // User Attribute Packet - var result = new openpgp_packet_userattribute(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 18: // Sym. Encrypted and Integrity Protected Data Packet - var result = new openpgp_packet_encryptedintegrityprotecteddata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 19: // Modification Detection Code Packet - var result = new openpgp_packet_modificationdetectioncode(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - default: - util.print_error("openpgp.packet.js\n" - + "[ERROR] openpgp_packet: failed to parse packet @:" - + mypos + "\nchar:'" - + util.hexstrdump(input.substring(mypos)) + "'\ninput:" - + util.hexstrdump(input)); - return null; - break; - } - } - - this.read_packet = read_packet; +/** + * @constructor + * @extends module:packet/public_key + */ +module.exports = function public_subkey() { + publicKey.call(this); } -var openpgp_packet = new _openpgp_packet(); +},{"./public_key.js":41}],44:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -10391,962 +12094,256 @@ var openpgp_packet = new _openpgp_packet(); // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14) - * + * Implementation of the Key Material Packet (Tag 5,6,7,14)
      + *
      * RFC4480 5.5: * A key material packet contains all the information about a public or * private key. There are four variants of this packet type, and two * major versions. Consequently, this section is complex. + * @requires crypto + * @requires enums + * @requires packet/public_key + * @requires type/mpi + * @requires type/s2k + * @requires util + * @module packet/secret_key */ -function openpgp_packet_keymaterial() { - // members: - this.publicKeyAlgorithm = null; - this.tagType = null; - this.creationTime = null; - this.version = null; - this.expiration = null;// V3 - this.MPIs = null; - this.secMPIs = null; - this.publicKey = null; - this.symmetricEncryptionAlgorithm = null; - this.s2kUsageConventions = null; - this.IVLength = null; - this.encryptedMPIData = null; - this.hasUnencryptedSecretKeyData = null; - this.checksum = null; - this.parentNode = null; - this.subKeySignature = null; - this.subKeyRevocationSignature = null; - // 5.5.1. Key Packet Variants - - // 5.5.1.3. Secret-Key Packet (Tag 5) - /** - * This function reads the payload of a secret key packet (Tag 5) - * and initializes the openpgp_packet_keymaterial - * @param {String} input Input string to read the packet from - * @param {Integer} position Start position for the parser - * @param {Intefer} len Length of the packet or remaining length of input - * @return {openpgp_packet_keymaterial} - */ - function read_tag5(input, position, len) { - this.tagType = 5; - this.read_priv_key(input, position, len); - return this; - } +var publicKey = require('./public_key.js'), + enums = require('../enums.js'), + util = require('../util'), + crypto = require('../crypto'), + type_mpi = require('../type/mpi.js'), + type_s2k = require('../type/s2k.js'); - // 5.5.1.1. Public-Key Packet (Tag 6) - /** - * This function reads the payload of a public key packet (Tag 6) - * and initializes the openpgp_packet_keymaterial - * @param {String} input Input string to read the packet from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet or remaining length of input - * @return {openpgp_packet_keymaterial} - */ - function read_tag6(input, position, len) { - // A Public-Key packet starts a series of packets that forms an OpenPGP - // key (sometimes called an OpenPGP certificate). - this.tagType = 6; - this.packetLength = len; - this.read_pub_key(input, position,len); - - return this; - } +/** + * @constructor + * @extends module:packet/public_key + */ +module.exports = function secret_key() { + publicKey.call(this); + // encrypted secret-key data + this.encrypted = null; + // indicator if secret-key data is available in decrypted form + this.isDecrypted = false; - // 5.5.1.4. Secret-Subkey Packet (Tag 7) - /** - * This function reads the payload of a secret key sub packet (Tag 7) - * and initializes the openpgp_packet_keymaterial - * @param {String} input Input string to read the packet from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet or remaining length of input - * @return {openpgp_packet_keymaterial} - */ - function read_tag7(input, position, len) { - this.tagType = 7; - this.packetLength = len; - return this.read_priv_key(input, position, len); - } - // 5.5.1.2. Public-Subkey Packet (Tag 14) - /** - * This function reads the payload of a public key sub packet (Tag 14) - * and initializes the openpgp_packet_keymaterial - * @param {String} input Input string to read the packet from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet or remaining length of input - * @return {openpgp_packet_keymaterial} - */ - function read_tag14(input, position, len) { - this.subKeySignature = null; - this.subKeyRevocationSignature = new Array(); - this.tagType = 14; - this.packetLength = len; - this.read_pub_key(input, position,len); - return this; - } - - /** - * Internal Parser for public keys as specified in RFC 4880 section - * 5.5.2 Public-Key Packet Formats - * called by read_tag<num> - * @param {String} input Input string to read the packet from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet or remaining length of input - * @return {Object} This object with attributes set by the parser - */ - function read_pub_key(input, position, len) { - var mypos = position; - // A one-octet version number (3 or 4). - this.version = input.charCodeAt(mypos++); - if (this.version == 3) { - // A four-octet number denoting the time that the key was created. - this.creationTime = new Date(((input.charCodeAt(mypos++) << 24) | - (input.charCodeAt(mypos++) << 16) | - (input.charCodeAt(mypos++) << 8) | - (input.charCodeAt(mypos++)))*1000); - - // - A two-octet number denoting the time in days that this key is - // valid. If this number is zero, then it does not expire. - this.expiration = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); - - // - A one-octet number denoting the public-key algorithm of this key. - this.publicKeyAlgorithm = input.charCodeAt(mypos++); - var mpicount = 0; - // - A series of multiprecision integers comprising the key material: - // Algorithm-Specific Fields for RSA public keys: - // - a multiprecision integer (MPI) of RSA public modulus n; - // - an MPI of RSA public encryption exponent e. - if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) - mpicount = 2; - // Algorithm-Specific Fields for Elgamal public keys: - // - MPI of Elgamal prime p; - // - MPI of Elgamal group generator g; - // - MPI of Elgamal public key value y (= g**x mod p where x is secret). + function get_hash_len(hash) { + if (hash == 'sha1') + return 20; + else + return 2; + } - else if (this.publicKeyAlgorithm == 16) - mpicount = 3; - // Algorithm-Specific Fields for DSA public keys: - // - MPI of DSA prime p; - // - MPI of DSA group order q (q is a prime divisor of p-1); - // - MPI of DSA group generator g; - // - MPI of DSA public-key value y (= g**x mod p where x is secret). - else if (this.publicKeyAlgorithm == 17) - mpicount = 4; + function get_hash_fn(hash) { + if (hash == 'sha1') + return crypto.hash.sha1; + else + return function(c) { + return util.writeNumber(util.calc_checksum(c), 2); + }; + } - this.MPIs = new Array(); - for (var i = 0; i < mpicount; i++) { - this.MPIs[i] = new openpgp_type_mpi(); - if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && - !this.packetLength < (mypos-position)) { - mypos += this.MPIs[i].packetLength; - } else { - util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos); - } - } - this.packetLength = mypos-position; - } else if (this.version == 4) { - // - A four-octet number denoting the time that the key was created. - this.creationTime = new Date(((input.charCodeAt(mypos++) << 24) | - (input.charCodeAt(mypos++) << 16) | - (input.charCodeAt(mypos++) << 8) | - (input.charCodeAt(mypos++)))*1000); - - // - A one-octet number denoting the public-key algorithm of this key. - this.publicKeyAlgorithm = input.charCodeAt(mypos++); - var mpicount = 0; - // - A series of multiprecision integers comprising the key material: - // Algorithm-Specific Fields for RSA public keys: - // - a multiprecision integer (MPI) of RSA public modulus n; - // - an MPI of RSA public encryption exponent e. - if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) - mpicount = 2; - // Algorithm-Specific Fields for Elgamal public keys: - // - MPI of Elgamal prime p; - // - MPI of Elgamal group generator g; - // - MPI of Elgamal public key value y (= g**x mod p where x is secret). - else if (this.publicKeyAlgorithm == 16) - mpicount = 3; + // Helper function - // Algorithm-Specific Fields for DSA public keys: - // - MPI of DSA prime p; - // - MPI of DSA group order q (q is a prime divisor of p-1); - // - MPI of DSA group generator g; - // - MPI of DSA public-key value y (= g**x mod p where x is secret). - else if (this.publicKeyAlgorithm == 17) - mpicount = 4; + function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) { + var hashlen = get_hash_len(hash_algorithm), + hashfn = get_hash_fn(hash_algorithm); - this.MPIs = new Array(); - var i = 0; - for (var i = 0; i < mpicount; i++) { - this.MPIs[i] = new openpgp_type_mpi(); - if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && - !this.packetLength < (mypos-position)) { - mypos += this.MPIs[i].packetLength; - } else { - util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos); - } - } - this.packetLength = mypos-position; - } else { - return null; - } - this.data = input.substring(position, mypos); - this.packetdata = input.substring(position, mypos); - return this; - } - - // 5.5.3. Secret-Key Packet Formats - - /** - * Internal parser for private keys as specified in RFC 4880 section 5.5.3 - * @param {String} input Input string to read the packet from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet or remaining length of input - * @return {Object} This object with attributes set by the parser - */ - function read_priv_key(input,position, len) { - // - A Public-Key or Public-Subkey packet, as described above. - this.publicKey = new openpgp_packet_keymaterial(); - if (this.publicKey.read_pub_key(input,position, len) == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+"Failed reading public key portion of a private key: "+input.charCodeAt(position)+" "+position+" "+len+"\n Aborting here..."); - return null; - } - this.publicKey.header = openpgp_packet.write_old_packet_header(6,this.publicKey.packetLength); - // this.publicKey.header = String.fromCharCode(0x99) + String.fromCharCode(this.publicKey.packetLength >> 8 & 0xFF)+String.fromCharCode(this.publicKey.packetLength & 0xFF); - var mypos = position + this.publicKey.data.length; - this.packetLength = len; - - // - One octet indicating string-to-key usage conventions. Zero - // indicates that the secret-key data is not encrypted. 255 or 254 - // indicates that a string-to-key specifier is being given. Any - // other value is a symmetric-key encryption algorithm identifier. - this.s2kUsageConventions = input.charCodeAt(mypos++); - - if (this.s2kUsageConventions == 0) - this.hasUnencryptedSecretKeyData = true; - - // - [Optional] If string-to-key usage octet was 255 or 254, a one- - // octet symmetric encryption algorithm. - if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) { - this.symmetricEncryptionAlgorithm = input.charCodeAt(mypos++); - } - - // - [Optional] If string-to-key usage octet was 255 or 254, a - // string-to-key specifier. The length of the string-to-key - // specifier is implied by its type, as described above. - if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) { - this.s2k = new openpgp_type_s2k(); - this.s2k.read(input, mypos); - mypos +=this.s2k.s2kLength; - } - - // - [Optional] If secret data is encrypted (string-to-key usage octet - // not zero), an Initial Vector (IV) of the same length as the - // cipher's block size. - this.symkeylength = 0; - if (this.s2kUsageConventions != 0 && this.s2kUsageConventions != 255 && - this.s2kUsageConventions != 254) { - this.symmetricEncryptionAlgorithm = this.s2kUsageConventions; - } - if (this.s2kUsageConventions != 0 && this.s2k.type != 1001) { - this.hasIV = true; - switch (this.symmetricEncryptionAlgorithm) { - case 1: // - IDEA [IDEA] - util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encrytryption algorithim: IDEA is not implemented"); - return null; - case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - case 3: // - CAST5 (128 bit key, as per [RFC2144]) - this.IVLength = 8; - break; - case 4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH] - case 7: // - AES with 128-bit key [AES] - case 8: // - AES with 192-bit key - case 9: // - AES with 256-bit key - this.IVLength = 16; - break; - case 10: // - Twofish with 256-bit key [TWOFISH] - this.IVLength = 32; - break; - case 5: // - Reserved - case 6: // - Reserved - default: - util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm); - return null; - } - mypos++; - this.IV = input.substring(mypos, mypos+this.IVLength); - mypos += this.IVLength; - } - // - Plain or encrypted multiprecision integers comprising the secret - // key data. These algorithm-specific fields are as described - // below. + var hashtext = cleartext.substr(cleartext.length - hashlen); + cleartext = cleartext.substr(0, cleartext.length - hashlen); - // s2k type 1001 corresponds to GPG specific extension without primary key secrets - // http://www.gnupg.org/faq/GnuPG-FAQ.html#how-can-i-use-gnupg-in-an-automated-environment - if (this.s2kUsageConventions != 0 && this.s2k.type == 1001) { - this.secMPIs = null; - this.encryptedMPIData = null; - } else if (!this.hasUnencryptedSecretKeyData) { - this.encryptedMPIData = input.substring(mypos, len); - mypos += this.encryptedMPIData.length; - } else { - if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) { - // Algorithm-Specific Fields for RSA secret keys: - // - multiprecision integer (MPI) of RSA secret exponent d. - // - MPI of RSA secret prime value p. - // - MPI of RSA secret prime value q (p < q). - // - MPI of u, the multiplicative inverse of p, mod q. - this.secMPIs = new Array(); - this.secMPIs[0] = new openpgp_type_mpi(); - this.secMPIs[0].read(input, mypos, len-2- (mypos - position)); - mypos += this.secMPIs[0].packetLength; - this.secMPIs[1] = new openpgp_type_mpi(); - this.secMPIs[1].read(input, mypos, len-2- (mypos - position)); - mypos += this.secMPIs[1].packetLength; - this.secMPIs[2] = new openpgp_type_mpi(); - this.secMPIs[2].read(input, mypos, len-2- (mypos - position)); - mypos += this.secMPIs[2].packetLength; - this.secMPIs[3] = new openpgp_type_mpi(); - this.secMPIs[3].read(input, mypos, len-2- (mypos - position)); - mypos += this.secMPIs[3].packetLength; - } else if (this.publicKey.publicKeyAlgorithm == 16) { - // Algorithm-Specific Fields for Elgamal secret keys: - // - MPI of Elgamal secret exponent x. - this.secMPIs = new Array(); - this.secMPIs[0] = new openpgp_type_mpi(); - this.secMPIs[0].read(input, mypos, len-2- (mypos - position)); - mypos += this.secMPIs[0].packetLength; - } else if (this.publicKey.publicKeyAlgorithm == 17) { - // Algorithm-Specific Fields for DSA secret keys: - // - MPI of DSA secret exponent x. - this.secMPIs = new Array(); - this.secMPIs[0] = new openpgp_type_mpi(); - this.secMPIs[0].read(input, mypos, len-2- (mypos - position)); - mypos += this.secMPIs[0].packetLength; - } - // checksum because s2k usage convention is 0 - this.checksum = new Array(); - this.checksum[0] = input.charCodeAt(mypos++); - this.checksum[1] = input.charCodeAt(mypos++); - } - return this; - } - + var hash = hashfn(cleartext); - /** - * Decrypts the private key MPIs which are needed to use the key. - * openpgp_packet_keymaterial.hasUnencryptedSecretKeyData should be - * false otherwise - * a call to this function is not needed - * - * @param {String} str_passphrase The passphrase for this private key - * as string - * @return {Boolean} True if the passphrase was correct; false if not - */ - function decryptSecretMPIs(str_passphrase) { - if (this.hasUnencryptedSecretKeyData) - return this.secMPIs; - // creating a key out of the passphrase - var key = this.s2k.produce_key(str_passphrase); - var cleartextMPIs = ""; - switch (this.symmetricEncryptionAlgorithm) { - case 1: // - IDEA [IDEA] - util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encryption algorithim: IDEA is not implemented"); - return false; - case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - cleartextMPIs = normal_cfb_decrypt(function(block, key) { - return des(key, block,1,null,0); - }, this.IVLength, key, this.encryptedMPIData, this.IV); - break; - case 3: // - CAST5 (128 bit key, as per [RFC2144]) - cleartextMPIs = normal_cfb_decrypt(function(block, key) { - var cast5 = new openpgp_symenc_cast5(); - cast5.setKey(key); - return cast5.encrypt(util.str2bin(block)); - }, this.IVLength, util.str2bin(key.substring(0,16)), this.encryptedMPIData, this.IV); - break; - case 4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH] - cleartextMPIs = normal_cfb_decrypt(function(block, key) { - var blowfish = new Blowfish(key); - return blowfish.encrypt(block); - }, this.IVLength, key, this.encryptedMPIData, this.IV); - break; - case 7: // - AES with 128-bit key [AES] - case 8: // - AES with 192-bit key - case 9: // - AES with 256-bit key - var numBytes = 16; - //This is a weird way to achieve this. If's within a switch is probably not ideal. - if(this.symmetricEncryptionAlgorithm == 8){ - numBytes = 24; - key = this.s2k.produce_key(str_passphrase,numBytes); - } - if(this.symmetricEncryptionAlgorithm == 9){ - numBytes = 32; - key = this.s2k.produce_key(str_passphrase,numBytes); - } - cleartextMPIs = normal_cfb_decrypt(function(block,key){ - return AESencrypt(util.str2bin(block),key); - }, - this.IVLength, keyExpansion(key.substring(0,numBytes)), this.encryptedMPIData, this.IV); - break; - case 10: // - Twofish with 256-bit key [TWOFISH] - util.print_error("openpgp.packet.keymaterial.js\n"+"Key material is encrypted with twofish: not implemented"); - return false; - case 5: // - Reserved - case 6: // - Reserved - default: - util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm); - return false; - } - - if (cleartextMPIs == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+"cleartextMPIs was null"); - return false; - } - - var cleartextMPIslength = cleartextMPIs.length; + if (hash != hashtext) + return new Error("Hash mismatch."); - if (this.s2kUsageConventions == 254 && - str_sha1(cleartextMPIs.substring(0,cleartextMPIs.length - 20)) == - cleartextMPIs.substring(cleartextMPIs.length - 20)) { - cleartextMPIslength -= 20; - } else if (this.s2kUsageConventions != 254 && util.calc_checksum(cleartextMPIs.substring(0,cleartextMPIs.length - 2)) == - (cleartextMPIs.charCodeAt(cleartextMPIs.length -2) << 8 | cleartextMPIs.charCodeAt(cleartextMPIs.length -1))) { - cleartextMPIslength -= 2; - } else { - return false; - } + var mpis = crypto.getPrivateMpiCount(algorithm); - if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) { - // Algorithm-Specific Fields for RSA secret keys: - // - multiprecision integer (MPI) of RSA secret exponent d. - // - MPI of RSA secret prime value p. - // - MPI of RSA secret prime value q (p < q). - // - MPI of u, the multiplicative inverse of p, mod q. - var mypos = 0; - this.secMPIs = new Array(); - this.secMPIs[0] = new openpgp_type_mpi(); - this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength); - mypos += this.secMPIs[0].packetLength; - this.secMPIs[1] = new openpgp_type_mpi(); - this.secMPIs[1].read(cleartextMPIs, mypos, cleartextMPIslength-mypos); - mypos += this.secMPIs[1].packetLength; - this.secMPIs[2] = new openpgp_type_mpi(); - this.secMPIs[2].read(cleartextMPIs, mypos, cleartextMPIslength-mypos); - mypos += this.secMPIs[2].packetLength; - this.secMPIs[3] = new openpgp_type_mpi(); - this.secMPIs[3].read(cleartextMPIs, mypos, cleartextMPIslength-mypos); - mypos += this.secMPIs[3].packetLength; - } else if (this.publicKey.publicKeyAlgorithm == 16) { - // Algorithm-Specific Fields for Elgamal secret keys: - // - MPI of Elgamal secret exponent x. - this.secMPIs = new Array(); - this.secMPIs[0] = new openpgp_type_mpi(); - this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIs); - } else if (this.publicKey.publicKeyAlgorithm == 17) { - // Algorithm-Specific Fields for DSA secret keys: - // - MPI of DSA secret exponent x. - this.secMPIs = new Array(); - this.secMPIs[0] = new openpgp_type_mpi(); - this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength); - } - return true; - } - - /** - * Generates Debug output - * @return String which gives some information about the keymaterial - */ - function toString() { - var result = ""; - switch (this.tagType) { - case 6: - result += '5.5.1.1. Public-Key Packet (Tag 6)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.version+'\n'+ - ' creation time: '+this.creationTime+'\n'+ - ' expiration time: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - case 14: - result += '5.5.1.2. Public-Subkey Packet (Tag 14)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.version+'\n'+ - ' creation time: '+this.creationTime+'\n'+ - ' expiration time: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - case 5: - result +='5.5.1.3. Secret-Key Packet (Tag 5)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.publicKey.version+'\n'+ - ' creation time: '+this.publicKey.creationTime+'\n'+ - ' expiration time: '+this.publicKey.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKey.publicKeyAlgorithm+'\n'; - break; - case 7: - result += '5.5.1.4. Secret-Subkey Packet (Tag 7)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version[1]: '+(this.version == 4)+'\n'+ - ' creationtime[4]: '+this.creationTime+'\n'+ - ' expiration[2]: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - default: - result += 'unknown key material packet\n'; - } - if (this.MPIs != null) { - result += "Public Key MPIs:\n"; - for (var i = 0; i < this.MPIs.length; i++) { - result += this.MPIs[i].toString(); - } - } - if (this.publicKey != null && this.publicKey.MPIs != null) { - result += "Public Key MPIs:\n"; - for (var i = 0; i < this.publicKey.MPIs.length; i++) { - result += this.publicKey.MPIs[i].toString(); - } - } - if (this.secMPIs != null) { - result += "Secret Key MPIs:\n"; - for (var i = 0; i < this.secMPIs.length; i++) { - result += this.secMPIs[i].toString(); - } - } - - if (this.subKeySignature != null) - result += "subKey Signature:\n"+this.subKeySignature.toString(); - - if (this.subKeyRevocationSignature != null ) - result += "subKey Revocation Signature:\n"+this.subKeyRevocationSignature.toString(); - return result; - } - - /** - * Continue parsing packets belonging to the key material such as signatures - * @param {Object} parent_node The parent object - * @param {String} input Input string to read the packet(s) from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet(s) or remaining length of input - * @return {Integer} Length of nodes read - */ - function read_nodes(parent_node, input, position, len) { - this.parentNode = parent_node; - if (this.tagType == 14) { // public sub-key packet - var pos = position; - var result = null; - while (input.length != pos) { - var l = input.length - pos; - result = openpgp_packet.read_packet(input, pos, l); - if (result == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_pub]parsing ends here @:' + pos + " l:" + l); - break; - } else { - - switch (result.tagType) { - case 2: // Signature Packet certification signature - if (result.signatureType == 24) { // subkey binding signature - this.subKeySignature = result; - pos += result.packetLength + result.headerLength; - break; - } else if (result.signatureType == 40) { // subkey revocation signature - this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result; - pos += result.packetLength + result.headerLength; - break; - } else { - util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+result.toString()); - } - - default: - this.data = input; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - break; - } - } - } - this.data = input; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } else if (this.tagType == 7) { // private sub-key packet - var pos = position; - while (input.length != pos) { - var result = openpgp_packet.read_packet(input, pos, len - (pos - position)); - if (result == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_priv] parsing ends here @:' + pos); - break; - } else { - switch (result.tagType) { - case 2: // Signature Packet certification signature - if (result.signatureType == 24) // subkey embedded signature - this.subKeySignature = result; - else if (result.signatureType == 40) // subkey revocation signature - this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result; - pos += result.packetLength + result.headerLength; - break; - default: - this.data = input; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } - } - } - this.data = input; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } else { - util.print_error("openpgp.packet.keymaterial.js\n"+"unknown parent node for a key material packet "+parent_node.tagType); - } - } + var j = 0; + var mpi = []; - /** - * Checks the validity for usage of this (sub)key - * @return {Integer} 0 = bad key, 1 = expired, 2 = revoked, 3 = valid - */ - function verifyKey() { - if (this.tagType == 14) { - if (this.subKeySignature == null) { - return 0; - } - if (this.subKeySignature.version == 4 && - this.subKeySignature.keyNeverExpires != null && - !this.subKeySignature.keyNeverExpires && - new Date((this.subKeySignature.keyExpirationTime*1000)+ this.creationTime.getTime()) < new Date()) { - return 1; - } - var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+ - String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata; - if (!this.subKeySignature.verify(hashdata,this.parentNode)) { - return 0; - } - for (var i = 0; i < this.subKeyRevocationSignature.length; i++) { - if (this.getKeyId() == this.subKeyRevocationSignature[i].keyId){ - return 2; - } - } - } - return 3; - } - - /** - * Calculates the key id of they key - * @return {String} A 8 byte key id - */ - function getKeyId() { - if (this.version == 4) { - var f = this.getFingerprint(); - return f.substring(12,20); - } else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) { - var key_id = this.MPIs[0].MPI.substring((this.MPIs[0].mpiByteLength-8)); - util.print_debug("openpgp.msg.publickey read_nodes:\n"+"V3 key ID: "+key_id); - return key_id; - } - } - - /** - * Calculates the fingerprint of the key - * @return {String} A string containing the fingerprint - */ - function getFingerprint() { - if (this.version == 4) { - tohash = String.fromCharCode(0x99)+ String.fromCharCode(((this.packetdata.length) >> 8) & 0xFF) - + String.fromCharCode((this.packetdata.length) & 0xFF)+this.packetdata; - util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm); - return str_sha1(tohash, tohash.length); - } else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) { - return MD5(this.MPIs[0].MPI); - } - } - - /* - * Creates an OpenPGP key packet for the given key. much - * TODO in regards to s2k, subkeys. - * @param {Integer} keyType Follows the OpenPGP algorithm standard, - * IE 1 corresponds to RSA. - * @param {RSA.keyObject} key - * @param password - * @param s2kHash - * @param symmetricEncryptionAlgorithm - * @param timePacket - * @return {Object} {body: [string]OpenPGP packet body contents, - header: [string] OpenPGP packet header, string: [string] header+body} - */ - function write_private_key(keyType, key, password, s2kHash, symmetricEncryptionAlgorithm, timePacket){ - this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm; - var tag = 5; - var body = String.fromCharCode(4); - body += timePacket; - switch(keyType){ - case 1: - body += String.fromCharCode(keyType);//public key algo - body += key.n.toMPI(); - body += key.ee.toMPI(); - var algorithmStart = body.length; - //below shows ske/s2k - if(password){ - body += String.fromCharCode(254); //octet of 254 indicates s2k with SHA1 - //if s2k == 255,254 then 1 octet symmetric encryption algo - body += String.fromCharCode(this.symmetricEncryptionAlgorithm); - //if s2k == 255,254 then s2k specifier - body += String.fromCharCode(3); //s2k salt+iter - body += String.fromCharCode(s2kHash); - //8 octet salt value - //1 octet count - var cleartextMPIs = key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI(); - var sha1Hash = str_sha1(cleartextMPIs); - util.print_debug_hexstr_dump('write_private_key sha1: ',sha1Hash); - var salt = openpgp_crypto_getRandomBytes(8); - util.print_debug_hexstr_dump('write_private_key Salt: ',salt); - body += salt; - var c = 96; //c of 96 translates to count of 65536 - body += String.fromCharCode(c); - util.print_debug('write_private_key c: '+ c); - var s2k = new openpgp_type_s2k(); - var hashKey = s2k.write(3, s2kHash, password, salt, c); - //if s2k, IV of same length as cipher's block - switch(this.symmetricEncryptionAlgorithm){ - case 3: - this.IVLength = 8; - this.IV = openpgp_crypto_getRandomBytes(this.IVLength); - ciphertextMPIs = normal_cfb_encrypt(function(block, key) { - var cast5 = new openpgp_symenc_cast5(); - cast5.setKey(key); - return cast5.encrypt(util.str2bin(block)); - }, this.IVLength, util.str2bin(hashKey.substring(0,16)), cleartextMPIs + sha1Hash, this.IV); - body += this.IV + ciphertextMPIs; - break; - case 7: - case 8: - case 9: - this.IVLength = 16; - this.IV = openpgp_crypto_getRandomBytes(this.IVLength); - ciphertextMPIs = normal_cfb_encrypt(AESencrypt, - this.IVLength, hashKey, cleartextMPIs + sha1Hash, this.IV); - body += this.IV + ciphertextMPIs; - break; - } - } - else{ - body += String.fromCharCode(0);//1 octet -- s2k, 0 for no s2k - body += key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI(); - var checksum = util.calc_checksum(key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI()); - body += String.fromCharCode(checksum/0x100) + String.fromCharCode(checksum%0x100);//DEPRECATED:s2k == 0, 255: 2 octet checksum, sum all octets%65536 - util.print_debug_hexstr_dump('write_private_key basic checksum: '+ checksum); - } - break; - default : - body = ""; - util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType); - } - var header = openpgp_packet.write_packet_header(tag,body.length); - return {string: header+body , header: header, body: body}; + for (var i = 0; i < mpis && j < cleartext.length; i++) { + mpi[i] = new type_mpi(); + j += mpi[i].read(cleartext.substr(j)); } - - /* - * Same as write_private_key, but has less information because of - * public key. - * @param {Integer} keyType Follows the OpenPGP algorithm standard, - * IE 1 corresponds to RSA. - * @param {RSA.keyObject} key - * @param timePacket - * @return {Object} {body: [string]OpenPGP packet body contents, - * header: [string] OpenPGP packet header, string: [string] header+body} - */ - function write_public_key(keyType, key, timePacket){ - var tag = 6; - var body = String.fromCharCode(4); - body += timePacket; - switch(keyType){ - case 1: - body += String.fromCharCode(1);//public key algo - body += key.n.toMPI(); - body += key.ee.toMPI(); - break; - default: - util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType); - } - var header = openpgp_packet.write_packet_header(tag,body.length); - return {string: header+body , header: header, body: body}; - } - - this.read_tag5 = read_tag5; - this.read_tag6 = read_tag6; - this.read_tag7 = read_tag7; - this.read_tag14 = read_tag14; - this.toString = toString; - this.read_pub_key = read_pub_key; - this.read_priv_key = read_priv_key; - this.decryptSecretMPIs = decryptSecretMPIs; - this.read_nodes = read_nodes; - this.verifyKey = verifyKey; - this.getKeyId = getKeyId; - this.getFingerprint = getFingerprint; - this.write_private_key = write_private_key; - this.write_public_key = write_public_key; -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + return mpi; + } -/** - * @class - * @classdesc Implementation of the Literal Data Packet (Tag 11) - * - * RFC4880 5.9: A Literal Data packet contains the body of a message; data that - * is not to be further interpreted. - */ -function openpgp_packet_literaldata() { - this.tagType = 11; + function write_cleartext_mpi(hash_algorithm, algorithm, mpi) { + var bytes = ''; + var discard = crypto.getPublicMpiCount(algorithm); - - /** - * Set the packet data to a javascript native string or a squence of - * bytes. Conversion to a proper utf8 encoding takes place when the - * packet is written. - * @param {String} str Any native javascript string - * @param {openpgp_packet_literaldata.formats} format - */ - this.set_data = function(str, format) { - this.format = format; - this.data = str; - } + for (var i = discard; i < mpi.length; i++) { + bytes += mpi[i].write(); + } - /** - * Set the packet data to value represented by the provided string - * of bytes together with the appropriate conversion format. - * @param {String} bytes The string of bytes - * @param {openpgp_packet_literaldata.formats} format - */ - this.set_data_bytes = function(bytes, format) { - this.format = format; - if(format == openpgp_packet_literaldata.formats.utf8) - bytes = util.decode_utf8(bytes); + bytes += get_hash_fn(hash_algorithm)(bytes); - this.data = bytes; - } + return bytes; + } - /** - * Get the byte sequence representing the literal packet data - * @returns {String} A sequence of bytes - */ - this.get_data_bytes = function() { - if(this.format == openpgp_packet_literaldata.formats.utf8) - return util.encode_utf8(this.data); - else - return this.data; - } - - - /** - * Parsing function for a literal data packet (tag 11). - * - * @param {String} input Payload of a tag 11 packet - * @param {Integer} position - * Position to start reading from the input string - * @param {Integer} len - * Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - this.read_packet = function(input, position, len) { - this.packetLength = len; - // - A one-octet field that describes how the data is formatted. + // 5.5.3. Secret-Key Packet Formats - var format = input[position]; + /** + * Internal parser for private keys as specified in RFC 4880 section 5.5.3 + * @param {String} bytes Input string to read the packet from + */ + this.read = function (bytes) { + // - A Public-Key or Public-Subkey packet, as described above. + var len = this.readPublicKey(bytes); - this.filename = util.decode_utf8(input.substr(position + 2, input - .charCodeAt(position + 1))); + bytes = bytes.substr(len); - this.date = new Date(parseInt(input.substr(position + 2 - + input.charCodeAt(position + 1), 4)) * 1000); - var bytes = input.substring(position + 6 - + input.charCodeAt(position + 1)); - - this.set_data_bytes(bytes, format); - return this; - } + // - One octet indicating string-to-key usage conventions. Zero + // indicates that the secret-key data is not encrypted. 255 or 254 + // indicates that a string-to-key specifier is being given. Any + // other value is a symmetric-key encryption algorithm identifier. + var isEncrypted = bytes.charCodeAt(0); - /** - * Creates a string representation of the packet - * - * @param {String} data The data to be inserted as body - * @return {String} string-representation of the packet - */ - this.write_packet = function(data) { - this.set_data(data, openpgp_packet_literaldata.formats.utf8); - this.filename = util.encode_utf8("msg.txt"); - this.date = new Date(); + if (isEncrypted) { + this.encrypted = bytes; + } else { - data = this.get_data_bytes(); + // - Plain or encrypted multiprecision integers comprising the secret + // key data. These algorithm-specific fields are as described + // below. + var parsedMPI = parse_cleartext_mpi('mod', bytes.substr(1), this.algorithm); + if (parsedMPI instanceof Error) + throw parsedMPI; + this.mpi = this.mpi.concat(parsedMPI); + this.isDecrypted = true; + } - var result = openpgp_packet.write_packet_header(11, data.length + 6 - + this.filename.length); - result += this.format; - result += String.fromCharCode(this.filename.length); - result += this.filename; - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 24) & 0xFF); - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 16) & 0xFF); - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 8) & 0xFF); - result += String - .fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF); - result += data; - return result; - } + }; + + /** Creates an OpenPGP key packet for the given key. + * @return {String} A string of bytes containing the secret key OpenPGP packet + */ + this.write = function () { + var bytes = this.writePublicKey(); + + if (!this.encrypted) { + bytes += String.fromCharCode(0); + + bytes += write_cleartext_mpi('mod', this.algorithm, this.mpi); + } else { + bytes += this.encrypted; + } + + return bytes; + }; + + + + + /** Encrypt the payload. By default, we use aes256 and iterated, salted string + * to key specifier + * @param {String} passphrase + */ + this.encrypt = function (passphrase) { + + var s2k = new type_s2k(), + symmetric = 'aes256', + cleartext = write_cleartext_mpi('sha1', this.algorithm, this.mpi), + key = produceEncryptionKey(s2k, passphrase, symmetric), + blockLen = crypto.cipher[symmetric].blockSize, + iv = crypto.random.getRandomBytes(blockLen); + + + this.encrypted = ''; + this.encrypted += String.fromCharCode(254); + this.encrypted += String.fromCharCode(enums.write(enums.symmetric, symmetric)); + this.encrypted += s2k.write(); + this.encrypted += iv; + + this.encrypted += crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv); + }; + + function produceEncryptionKey(s2k, passphrase, algorithm) { + return s2k.produce_key(passphrase, + crypto.cipher[algorithm].keySize); + } + + /** + * Decrypts the private key MPIs which are needed to use the key. + * @link module:packet/secret_key.isDecrypted should be + * false otherwise a call to this function is not needed + * + * @param {String} str_passphrase The passphrase for this private key + * as string + * @return {Boolean} True if the passphrase was correct or MPI already + * decrypted; false if not + */ + this.decrypt = function (passphrase) { + if (this.isDecrypted) + return true; + + var i = 0, + symmetric, + key; + + var s2k_usage = this.encrypted.charCodeAt(i++); + + // - [Optional] If string-to-key usage octet was 255 or 254, a one- + // octet symmetric encryption algorithm. + if (s2k_usage == 255 || s2k_usage == 254) { + symmetric = this.encrypted.charCodeAt(i++); + symmetric = enums.read(enums.symmetric, symmetric); + + // - [Optional] If string-to-key usage octet was 255 or 254, a + // string-to-key specifier. The length of the string-to-key + // specifier is implied by its type, as described above. + var s2k = new type_s2k(); + i += s2k.read(this.encrypted.substr(i)); + + key = produceEncryptionKey(s2k, passphrase, symmetric); + } else { + symmetric = s2k_usage; + symmetric = enums.read(enums.symmetric, symmetric); + key = crypto.hash.md5(passphrase); + } + + + // - [Optional] If secret data is encrypted (string-to-key usage octet + // not zero), an Initial Vector (IV) of the same length as the + // cipher's block size. + var iv = this.encrypted.substr(i, + crypto.cipher[symmetric].blockSize); + + i += iv.length; + + var cleartext, + ciphertext = this.encrypted.substr(i); + + cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv); + + var hash = s2k_usage == 254 ? + 'sha1' : + 'mod'; + + var parsedMPI = parse_cleartext_mpi(hash, cleartext, this.algorithm); + if (parsedMPI instanceof Error) + return false; + this.mpi = this.mpi.concat(parsedMPI); + this.isDecrypted = true; + return true; + }; + + this.generate = function (bits) { + this.mpi = crypto.generateMpi(this.algorithm, bits); + this.isDecrypted = true; + }; - /** - * Generates debug output (pretty print) - * - * @return {String} String which gives some information about the keymaterial - */ - this.toString = function() { - return '5.9. Literal Data Packet (Tag 11)\n' + ' length: ' - + this.packetLength + '\n' + ' format: ' + this.format - + '\n' + ' filename:' + this.filename + '\n' - + ' date: ' + this.date + '\n' + ' data: |' - + this.data + '|\n' + ' rdata: |' + this.real_data + '|\n'; - } } -/** - * Data types in the literal packet - * @readonly - * @enum {String} - */ -openpgp_packet_literaldata.formats = { - /** Binary data */ - binary: 'b', - /** Text data */ - text: 't', - /** Utf8 data */ - utf8: 'u' -}; +module.exports.prototype = new publicKey(); + +},{"../crypto":16,"../enums.js":27,"../type/mpi.js":54,"../type/s2k.js":55,"../util":56,"./public_key.js":41}],45:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -11365,53 +12362,21 @@ openpgp_packet_literaldata.formats = { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Implementation of the strange "Marker packet" (Tag 10) - * - * RFC4880 5.8: An experimental version of PGP used this packet as the Literal - * packet, but no released version of PGP generated Literal packets with this - * tag. With PGP 5.x, this packet has been reassigned and is reserved for use as - * the Marker packet. - * - * Such a packet MUST be ignored when received. + * @requires packet/secret_key + * @module packet/secret_subkey */ -function openpgp_packet_marker() { - this.tagType = 10; - /** - * Parsing function for a literal data packet (tag 10). - * - * @param {String} input Payload of a tag 10 packet - * @param {Integer} position - * Position to start reading from the input string - * @param {Integer} len - * Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} Object representation - */ - function read_packet(input, position, len) { - this.packetLength = 3; - if (input.charCodeAt(position) == 0x50 && // P - input.charCodeAt(position + 1) == 0x47 && // G - input.charCodeAt(position + 2) == 0x50) // P - return this; - // marker packet does not contain "PGP" - return null; - } - /** - * Generates Debug output - * - * @return {String} String which gives some information about the - * keymaterial - */ - function toString() { - return "5.8. Marker Packet (Obsolete Literal Packet) (Tag 10)\n" - + " packet reads: \"PGP\"\n"; - } +var secretKey = require('./secret_key.js'); - this.read_packet = read_packet; - this.toString = toString; +/** + * @constructor + * @extends module:packet/secret_key + */ +module.exports = function secret_subkey() { + secretKey.call(this); } + +},{"./secret_key.js":44}],46:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -11430,1088 +12395,630 @@ function openpgp_packet_marker() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Implementation of the Modification Detection Code Packet (Tag 19) - * - * RFC4880 5.14: The Modification Detection Code packet contains a SHA-1 hash of - * plaintext data, which is used to detect message modification. It is only used - * with a Symmetrically Encrypted Integrity Protected Data packet. The - * Modification Detection Code packet MUST be the last packet in the plaintext - * data that is encrypted in the Symmetrically Encrypted Integrity Protected - * Data packet, and MUST appear in no other place. - */ - -function openpgp_packet_modificationdetectioncode() { - this.tagType = 19; - this.hash = null; - /** - * parsing function for a modification detection code packet (tag 19). - * - * @param {String} input payload of a tag 19 packet - * @param {Integer} position - * position to start reading from the input string - * @param {Integer} len - * length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - function read_packet(input, position, len) { - this.packetLength = len; - - if (len != 20) { - util - .print_error("openpgp.packet.modificationdetectioncode.js\n" - + 'invalid length for a modification detection code packet!' - + len); - return null; - } - // - A 20-octet SHA-1 hash of the preceding plaintext data of the - // Symmetrically Encrypted Integrity Protected Data packet, - // including prefix data, the tag octet, and length octet of the - // Modification Detection Code packet. - this.hash = input.substring(position, position + 20); - return this; - } - - /* - * this packet is created within the encryptedintegrityprotected packet - * function write_packet(data) { } - */ - - /** - * generates debug output (pretty print) - * - * @return {String} String which gives some information about the - * modification detection code - */ - function toString() { - return '5.14 Modification detection code packet\n' + ' bytes (' - + this.hash.length + '): [' + util.hexstrdump(this.hash) + ']'; - } - this.read_packet = read_packet; - this.toString = toString; -}; -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the One-Pass Signature Packets (Tag 4) - * - * RFC4880 5.4: - * The One-Pass Signature packet precedes the signed data and contains - * enough information to allow the receiver to begin calculating any - * hashes needed to verify the signature. It allows the Signature - * packet to be placed at the end of the message, so that the signer - * can compute the entire signed message in one pass. - */ -function openpgp_packet_onepasssignature() { - this.tagType = 4; - this.version = null; // A one-octet version number. The current version is 3. - this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1. - this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4) - this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1) - this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key. - this.flags = null; // A one-octet number holding a flag showing whether the signature is nested. A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data. - - /** - * parsing function for a one-pass signature packet (tag 4). - * @param {String} input payload of a tag 4 packet - * @param {Integer} position position to start reading from the input string - * @param {Integer} len length of the packet or the remaining length of input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - function read_packet(input, position, len) { - this.packetLength = len; - var mypos = position; - // A one-octet version number. The current version is 3. - this.version = input.charCodeAt(mypos++); - - // A one-octet signature type. Signature types are described in - // Section 5.2.1. - this.type = input.charCodeAt(mypos++); - - // A one-octet number describing the hash algorithm used. - this.hashAlgorithm = input.charCodeAt(mypos++); - - // A one-octet number describing the public-key algorithm used. - this.publicKeyAlgorithm = input.charCodeAt(mypos++); - // An eight-octet number holding the Key ID of the signing key. - this.signingKeyId = new openpgp_type_keyid(); - this.signingKeyId.read_packet(input,mypos); - mypos += 8; - - // A one-octet number holding a flag showing whether the signature - // is nested. A zero value indicates that the next packet is - // another One-Pass Signature packet that describes another - // signature to be applied to the same message data. - this.flags = input.charCodeAt(mypos++); - return this; - } - - /** - * creates a string representation of a one-pass signature packet - * @param {Integer} type Signature types as described in RFC4880 Section 5.2.1. - * @param {Integer} hashalgorithm the hash algorithm used within the signature - * @param {openpgp_msg_privatekey} privatekey the private key used to generate the signature - * @param {Integer} length length of data to be signed - * @param {boolean} nested boolean showing whether the signature is nested. - * "true" indicates that the next packet is another One-Pass Signature packet - * that describes another signature to be applied to the same message data. - * @return {String} a string representation of a one-pass signature packet - */ - function write_packet(type, hashalgorithm, privatekey,length, nested) { - var result =""; - - result += openpgp_packet.write_packet_header(4,13); - result += String.fromCharCode(3); - result += String.fromCharCode(type); - result += String.fromCharCode(hashalgorithm); - result += String.fromCharCode(privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm); - result += privatekey.getKeyId(); - if (nested) - result += String.fromCharCode(0); - else - result += String.fromCharCode(1); - - return result; - } - - /** - * generates debug output (pretty print) - * @return {String} String which gives some information about the one-pass signature packet - */ - function toString() { - return '5.4. One-Pass Signature Packets (Tag 4)\n'+ - ' length: '+this.packetLength+'\n'+ - ' type: '+this.type+'\n'+ - ' keyID: '+this.signingKeyId.toString()+'\n'+ - ' hashA: '+this.hashAlgorithm+'\n'+ - ' pubKeyA:'+this.publicKeyAlgorithm+'\n'+ - ' flags: '+this.flags+'\n'+ - ' version:'+this.version+'\n'; - } - - this.read_packet = read_packet; - this.toString = toString; - this.write_packet = write_packet; -}; -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the Signature Packet (Tag 2) - * + * Implementation of the Signature Packet (Tag 2)
      + *
      * RFC4480 5.2: * A Signature packet describes a binding between some public key and * some data. The most common signatures are a signature of a file or a * block of text, and a signature that is a certification of a User ID. + * @requires crypto + * @requires enums + * @requires packet/packet + * @requires type/keyid + * @requires type/mpi + * @requires util + * @module packet/signature */ -function openpgp_packet_signature() { - this.tagType = 2; - this.signatureType = null; - this.creationTime = null; - this.keyId = null; - this.signatureData = null; - this.signatureExpirationTime = null; - this.signatureNeverExpires = null; - this.signedHashValue = null; - this.MPIs = null; - this.publicKeyAlgorithm = null; - this.hashAlgorithm = null; - this.exportable = null; - this.trustLevel = null; - this.trustAmount = null; - this.regular_expression = null; - this.revocable = null; - this.keyExpirationTime = null; - this.keyNeverExpires = null; - this.preferredSymmetricAlgorithms = null; - this.revocationKeyClass = null; - this.revocationKeyAlgorithm = null; - this.revocationKeyFingerprint = null; - this.issuerKeyId = null; - this.notationFlags = null; - this.notationName = null; - this.notationValue = null; - this.preferredHashAlgorithms = null; - this.preferredCompressionAlgorithms = null; - this.keyServerPreferences = null; - this.preferredKeyServer = null; - this.isPrimaryUserID = null; - this.policyURI = null; - this.keyFlags = null; - this.signersUserId = null; - this.reasonForRevocationFlag = null; - this.reasonForRevocationString = null; - this.signatureTargetPublicKeyAlgorithm = null; - this.signatureTargetHashAlgorithm = null; - this.signatureTargetHash = null; - this.embeddedSignature = null; - this.verified = false; - - /** - * parsing function for a signature packet (tag 2). - * @param {String} input payload of a tag 2 packet - * @param {Integer} position position to start reading from the input string - * @param {Integer} len length of the packet or the remaining length of input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - function read_packet(input, position, len) { - this.data = input.substring (position, position+len); - if (len < 0) { - util.print_debug("openpgp.packet.signature.js\n"+"openpgp_packet_signature read_packet length < 0 @:"+position); - return null; - } - var mypos = position; - this.packetLength = len; - // alert('starting parsing signature: '+position+' '+this.packetLength); - this.version = input.charCodeAt(mypos++); - // switch on version (3 and 4) - switch (this.version) { - case 3: - // One-octet length of following hashed material. MUST be 5. - if (input.charCodeAt(mypos++) != 5) - util.print_debug("openpgp.packet.signature.js\n"+'invalid One-octet length of following hashed material. MUST be 5. @:'+(mypos-1)); - var sigpos = mypos; - // One-octet signature type. - this.signatureType = input.charCodeAt(mypos++); +var util = require('../util'), + packet = require('./packet.js'), + enums = require('../enums.js'), + crypto = require('../crypto'), + type_mpi = require('../type/mpi.js'), + type_keyid = require('../type/keyid.js'); - // Four-octet creation time. - this.creationTime = new Date(((input.charCodeAt(mypos++)) << 24 | - (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << 8) | - input.charCodeAt(mypos++))* 1000); - - // storing data appended to data which gets verified - this.signatureData = input.substring(sigpos, mypos); - - // Eight-octet Key ID of signer. - this.keyId = input.substring(mypos, mypos +8); - mypos += 8; +/** + * @constructor + */ +module.exports = function signature() { - // One-octet public-key algorithm. - this.publicKeyAlgorithm = input.charCodeAt(mypos++); + this.version = 4; + this.signatureType = null; + this.hashAlgorithm = null; + this.publicKeyAlgorithm = null; - // One-octet hash algorithm. - this.hashAlgorithm = input.charCodeAt(mypos++); + this.signatureData = null; + this.signedHashValue = null; + this.mpi = null; - // Two-octet field holding left 16 bits of signed hash value. - this.signedHashValue = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); - var mpicount = 0; - // Algorithm-Specific Fields for RSA signatures: - // - multiprecision integer (MPI) of RSA signature value m**d mod n. - if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) - mpicount = 1; - // Algorithm-Specific Fields for DSA signatures: - // - MPI of DSA value r. - // - MPI of DSA value s. - else if (this.publicKeyAlgorithm == 17) - mpicount = 2; - - this.MPIs = new Array(); - for (var i = 0; i < mpicount; i++) { - this.MPIs[i] = new openpgp_type_mpi(); - if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && - !this.packetLength < (mypos-position)) { - mypos += this.MPIs[i].packetLength; - } else { - util.print_error('signature contains invalid MPI @:'+mypos); - } - } - break; - case 4: - this.signatureType = input.charCodeAt(mypos++); - this.publicKeyAlgorithm = input.charCodeAt(mypos++); - this.hashAlgorithm = input.charCodeAt(mypos++); + this.created = new Date(); + this.signatureExpirationTime = null; + this.signatureNeverExpires = true; + this.exportable = null; + this.trustLevel = null; + this.trustAmount = null; + this.regularExpression = null; + this.revocable = null; + this.keyExpirationTime = null; + this.keyNeverExpires = null; + this.preferredSymmetricAlgorithms = null; + this.revocationKeyClass = null; + this.revocationKeyAlgorithm = null; + this.revocationKeyFingerprint = null; + this.issuerKeyId = new type_keyid(); + this.notation = null; + this.preferredHashAlgorithms = null; + this.preferredCompressionAlgorithms = null; + this.keyServerPreferences = null; + this.preferredKeyServer = null; + this.isPrimaryUserID = null; + this.policyURI = null; + this.keyFlags = null; + this.signersUserId = null; + this.reasonForRevocationFlag = null; + this.reasonForRevocationString = null; + this.features = null; + this.signatureTargetPublicKeyAlgorithm = null; + this.signatureTargetHashAlgorithm = null; + this.signatureTargetHash = null; + this.embeddedSignature = null; - // Two-octet scalar octet count for following hashed subpacket - // data. - var hashed_subpacket_count = (input.charCodeAt(mypos++) << 8) + input.charCodeAt(mypos++); + this.verified = false; - // Hashed subpacket data set (zero or more subpackets) - var subpacket_length = 0; - while (hashed_subpacket_count != subpacket_length) { - if (hashed_subpacket_count < subpacket_length) { - util.print_debug("openpgp.packet.signature.js\n"+"hashed missed something: "+mypos+" c:"+hashed_subpacket_count+" l:"+subpacket_length); - } + /** + * parsing function for a signature packet (tag 2). + * @param {String} bytes payload of a tag 2 packet + * @param {Integer} position position to start reading from the bytes string + * @param {Integer} len length of the packet or the remaining length of bytes at position + * @return {module:packet/signature} object representation + */ + this.read = function (bytes) { + var i = 0; - subpacket_length += this._raw_read_signature_sub_packet(input, - mypos + subpacket_length, hashed_subpacket_count - - subpacket_length); - } - - mypos += hashed_subpacket_count; - this.signatureData = input.substring(position, mypos); + this.version = bytes.charCodeAt(i++); + // switch on version (3 and 4) + switch (this.version) { + case 3: + // One-octet length of following hashed material. MUST be 5. + if (bytes.charCodeAt(i++) != 5) + util.print_debug("packet/signature.js\n" + + 'invalid One-octet length of following hashed material.' + + 'MUST be 5. @:' + (i - 1)); - // alert("signatureData: "+util.hexstrdump(this.signatureData)); - - // Two-octet scalar octet count for the following unhashed subpacket - var subpacket_count = (input.charCodeAt(mypos++) << 8) + input.charCodeAt(mypos++); - - // Unhashed subpacket data set (zero or more subpackets). - subpacket_length = 0; - while (subpacket_count != subpacket_length) { - if (subpacket_count < subpacket_length) { - util.print_debug("openpgp.packet.signature.js\n"+"missed something: "+subpacket_length+" c:"+subpacket_count+" "+" l:"+subpacket_length); - } - subpacket_length += this._raw_read_signature_sub_packet(input, - mypos + subpacket_length, subpacket_count - - subpacket_length); + var sigpos = i; + // One-octet signature type. + this.signatureType = bytes.charCodeAt(i++); - } - mypos += subpacket_count; - // Two-octet field holding the left 16 bits of the signed hash - // value. - this.signedHashValue = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); - // One or more multiprecision integers comprising the signature. - // This portion is algorithm specific, as described above. - var mpicount = 0; - if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) - mpicount = 1; - else if (this.publicKeyAlgorithm == 17) - mpicount = 2; - - this.MPIs = new Array(); - for (var i = 0; i < mpicount; i++) { - this.MPIs[i] = new openpgp_type_mpi(); - if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && - !this.packetLength < (mypos-position)) { - mypos += this.MPIs[i].packetLength; - } else { - util.print_error('signature contains invalid MPI @:'+mypos); - } - } - break; - default: - util.print_error("openpgp.packet.signature.js\n"+'unknown signature packet version'+this.version); - break; - } - // util.print_message("openpgp.packet.signature.js\n"+"end signature: l: "+this.packetLength+"m: "+mypos+" m-p: "+(mypos-position)); - return this; - } - /** - * creates a string representation of a message signature packet (tag 2). - * This can be only used on text data - * @param {Integer} signature_type should be 1 (one) - * @param {String} data data to be signed - * @param {openpgp_msg_privatekey} privatekey private key used to sign the message. (secMPIs MUST be unlocked) - * @return {String} string representation of a signature packet - */ - function write_message_signature(signature_type, data, privatekey) { - var publickey = privatekey.privateKeyPacket.publicKey; - var hash_algo = privatekey.getPreferredSignatureHashAlgorithm(); - var result = String.fromCharCode(4); - result += String.fromCharCode(signature_type); - result += String.fromCharCode(publickey.publicKeyAlgorithm); - result += String.fromCharCode(hash_algo); - var d = Math.round(new Date().getTime() / 1000); - var datesubpacket = write_sub_signature_packet(2,""+ - String.fromCharCode((d >> 24) & 0xFF) + - String.fromCharCode((d >> 16) & 0xFF) + - String.fromCharCode((d >> 8) & 0xFF) + - String.fromCharCode(d & 0xFF)); - var issuersubpacket = write_sub_signature_packet(16, privatekey.getKeyId()); - result += String.fromCharCode(((datesubpacket.length + issuersubpacket.length) >> 8) & 0xFF); - result += String.fromCharCode ((datesubpacket.length + issuersubpacket.length) & 0xFF); - result += datesubpacket; - result += issuersubpacket; - var trailer = ''; - - trailer += String.fromCharCode(4); - trailer += String.fromCharCode(0xFF); - trailer += String.fromCharCode((result.length) >> 24); - trailer += String.fromCharCode(((result.length) >> 16) & 0xFF); - trailer += String.fromCharCode(((result.length) >> 8) & 0xFF); - trailer += String.fromCharCode((result.length) & 0xFF); - var result2 = String.fromCharCode(0); - result2 += String.fromCharCode(0); - var hash = openpgp_crypto_hashData(hash_algo, data+result+trailer); - util.print_debug("DSA Signature is calculated with:|"+data+result+trailer+"|\n"+util.hexstrdump(data+result+trailer)+"\n hash:"+util.hexstrdump(hash)); - result2 += hash.charAt(0); - result2 += hash.charAt(1); - result2 += openpgp_crypto_signData(hash_algo,privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm, - publickey.MPIs, - privatekey.privateKeyPacket.secMPIs, - data+result+trailer); - return {openpgp: (openpgp_packet.write_packet_header(2, (result+result2).length)+result + result2), - hash: util.get_hashAlgorithmString(hash_algo)}; - } - /** - * creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1) - * @param {Integer} type subpacket signature type. Signature types as described in RFC4880 Section 5.2.3.2 - * @param {String} data data to be included - * @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1) - */ - function write_sub_signature_packet(type, data) { - var result = ""; - result += openpgp_packet.encode_length(data.length+1); - result += String.fromCharCode(type); - result += data; - return result; - } - - // V4 signature sub packets - - this._raw_read_signature_sub_packet = function(input, position, len) { - if (len < 0) - util.print_debug("openpgp.packet.signature.js\n"+"_raw_read_signature_sub_packet length < 0 @:"+position); - var mypos = position; - var subplen = 0; - // alert('starting signature subpackage read at position:'+position+' length:'+len); - if (input.charCodeAt(mypos) < 192) { - subplen = input.charCodeAt(mypos++); - } else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) { - subplen = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192; - } else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) { - subplen = 1 << (input.charCodeAt(mypos++) & 0x1F); - } else if (input.charCodeAt(mypos) < 255) { - mypos++; - subplen = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) - | (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); - } - - var type = input.charCodeAt(mypos++) & 0x7F; - // alert('signature subpacket type '+type+" with length: "+subplen); - // subpacket type - switch (type) { - case 2: // Signature Creation Time - this.creationTime = new Date(((input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) - | (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++))*1000); - break; - case 3: // Signature Expiration Time - this.signatureExpirationTime = (input.charCodeAt(mypos++) << 24) - | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << 8) - | input.charCodeAt(mypos++); - this.signatureNeverExpires = (this.signature_expiration_time == 0); - - break; - case 4: // Exportable Certification - this.exportable = input.charCodeAt(mypos++) == 1; - break; - case 5: // Trust Signature - this.trustLevel = input.charCodeAt(mypos++); - this.trustAmount = input.charCodeAt(mypos++); - break; - case 6: // Regular Expression - this.regular_expression = new String(); - for (var i = 0; i < subplen - 1; i++) - this.regular_expression += (input[mypos++]); - break; - case 7: // Revocable - this.revocable = input.charCodeAt(mypos++) == 1; - break; - case 9: // Key Expiration Time - this.keyExpirationTime = (input.charCodeAt(mypos++) << 24) - | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << 8) - | input.charCodeAt(mypos++); - this.keyNeverExpires = (this.keyExpirationTime == 0); - break; - case 11: // Preferred Symmetric Algorithms - this.preferredSymmetricAlgorithms = new Array(); - for (var i = 0; i < subplen-1; i++) { - this.preferredSymmetricAlgorithms = input.charCodeAt(mypos++); - } - break; - case 12: // Revocation Key - // (1 octet of class, 1 octet of public-key algorithm ID, 20 - // octets of - // fingerprint) - this.revocationKeyClass = input.charCodeAt(mypos++); - this.revocationKeyAlgorithm = input.charCodeAt(mypos++); - this.revocationKeyFingerprint = new Array(); - for ( var i = 0; i < 20; i++) { - this.revocationKeyFingerprint = input.charCodeAt(mypos++); - } - break; - case 16: // Issuer - this.issuerKeyId = input.substring(mypos,mypos+8); - mypos += 8; - break; - case 20: // Notation Data - this.notationFlags = (input.charCodeAt(mypos++) << 24) | - (input.charCodeAt(mypos++) << 16) | - (input.charCodeAt(mypos++) << 8) | - (input.charCodeAt(mypos++)); - var nameLength = (input.charCodeAt(mypos++) << 8) | (input.charCodeAt(mypos++)); - var valueLength = (input.charCodeAt(mypos++) << 8) | (input.charCodeAt(mypos++)); - this.notationName = ""; - for (var i = 0; i < nameLength; i++) { - this.notationName += input[mypos++]; - } - this.notationValue = ""; - for (var i = 0; i < valueLength; i++) { - this.notationValue += input[mypos++]; - } - break; - case 21: // Preferred Hash Algorithms - this.preferredHashAlgorithms = new Array(); - for (var i = 0; i < subplen-1; i++) { - this.preferredHashAlgorithms = input.charCodeAt(mypos++); - } - break; - case 22: // Preferred Compression Algorithms - this.preferredCompressionAlgorithms = new Array(); - for ( var i = 0; i < subplen-1; i++) { - this.preferredCompressionAlgorithms = input.charCodeAt(mypos++); - } - break; - case 23: // Key Server Preferences - this.keyServerPreferences = new Array(); - for ( var i = 0; i < subplen-1; i++) { - this.keyServerPreferences = input.charCodeAt(mypos++); - } - break; - case 24: // Preferred Key Server - this.preferredKeyServer = new String(); - for ( var i = 0; i < subplen-1; i++) { - this.preferredKeyServer += input[mypos++]; - } - break; - case 25: // Primary User ID - this.isPrimaryUserID = input[mypos++] != 0; - break; - case 26: // Policy URI - this.policyURI = new String(); - for ( var i = 0; i < subplen-1; i++) { - this.policyURI += input[mypos++]; - } - break; - case 27: // Key Flags - this.keyFlags = new Array(); - for ( var i = 0; i < subplen-1; i++) { - this.keyFlags = input.charCodeAt(mypos++); - } - break; - case 28: // Signer's User ID - this.signersUserId = new String(); - for ( var i = 0; i < subplen-1; i++) { - this.signersUserId += input[mypos++]; - } - break; - case 29: // Reason for Revocation - this.reasonForRevocationFlag = input.charCodeAt(mypos++); - this.reasonForRevocationString = new String(); - for ( var i = 0; i < subplen -2; i++) { - this.reasonForRevocationString += input[mypos++]; - } - break; - case 30: // Features - // TODO: to be implemented - return subplen+1; - case 31: // Signature Target - // (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash) - this.signatureTargetPublicKeyAlgorithm = input.charCodeAt(mypos++); - this.signatureTargetHashAlgorithm = input.charCodeAt(mypos++); - var signatureTargetHashAlgorithmLength = 0; - switch(this.signatureTargetHashAlgorithm) { - case 1: // - MD5 [HAC] "MD5" - case 2: // - SHA-1 [FIPS180] "SHA1" - signatureTargetHashAlgorithmLength = 20; - break; - case 3: // - RIPE-MD/160 [HAC] "RIPEMD160" - case 8: // - SHA256 [FIPS180] "SHA256" - case 9: // - SHA384 [FIPS180] "SHA384" - case 10: // - SHA512 [FIPS180] "SHA512" - case 11: // - SHA224 [FIPS180] "SHA224" - break; - // 100 to 110 - Private/Experimental algorithm - default: - util.print_error("openpgp.packet.signature.js\n"+"unknown signature target hash algorithm:"+this.signatureTargetHashAlgorithm); - return null; - } - this.signatureTargetHash = new Array(); - for (var i = 0; i < signatureTargetHashAlgorithmLength; i++) { - this.signatureTargetHash[i] = input[mypos++]; - } - case 32: // Embedded Signature - this.embeddedSignature = new openpgp_packet_signature(); - this.embeddedSignature.read_packet(input, mypos, len -(mypos-position)); - return ((mypos+ this.embeddedSignature.packetLength) - position); - break; - case 100: // Private or experimental - case 101: // Private or experimental - case 102: // Private or experimental - case 103: // Private or experimental - case 104: // Private or experimental - case 105: // Private or experimental - case 106: // Private or experimental - case 107: // Private or experimental - case 108: // Private or experimental - case 109: // Private or experimental - case 110: // Private or experimental - util.print_error("openpgp.packet.signature.js\n"+'private or experimental signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len); - return subplen+1; - break; - case 0: // Reserved - case 1: // Reserved - case 8: // Reserved - case 10: // Placeholder for backward compatibility - case 13: // Reserved - case 14: // Reserved - case 15: // Reserved - case 17: // Reserved - case 18: // Reserved - case 19: // Reserved - default: - util.print_error("openpgp.packet.signature.js\n"+'unknown signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len); - return subplen+1; - break; - } - return mypos -position; - }; - /** - * verifys the signature packet. Note: not signature types are implemented - * @param {String} data data which on the signature applies - * @param {openpgp_msg_privatekey} key the public key to verify the signature - * @return {boolean} True if message is verified, else false. - */ - function verify(data, key) { - // calculating the trailer - var trailer = ''; - trailer += String.fromCharCode(this.version); - trailer += String.fromCharCode(0xFF); - trailer += String.fromCharCode(this.signatureData.length >> 24); - trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF); - trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF); - trailer += String.fromCharCode(this.signatureData.length & 0xFF); - switch(this.signatureType) { - case 0: // 0x00: Signature of a binary document. - if (this.version == 4) { - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer); - } else if (this.version == 3) { - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData); - } else { - this.verified = false; - } - break; + // Four-octet creation time. + this.created = util.readDate(bytes.substr(i, 4)); + i += 4; - case 1: // 0x01: Signature of a canonical text document. - var tohash = data - .replace(/\r\n/g,"\n") - .replace(/[\t ]+\n/g, "\n") - .replace(/\n/g,"\r\n"); - if (openpgp.config.debug) { - util.print_debug('tohash: '+util.hexdump(tohash)); - util.print_debug('signatureData: '+util.hexdump(this.signatureData)); - util.print_debug('trailer: '+util.hexdump(trailer)); - } - if (this.version == 4) { - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.obj.publicKeyPacket.MPIs, tohash+this.signatureData+trailer); - } else if (this.version == 3) { - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.obj.publicKeyPacket.MPIs, tohash+this.signatureData); - } else { - this.verified = false; - } - break; - - case 2: // 0x02: Standalone signature. - // This signature is a signature of only its own subpacket contents. - // It is calculated identically to a signature over a zero-length - // binary document. Note that it doesn't make sense to have a V3 - // standalone signature. - if (this.version == 4) { - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.obj.publicKeyPacket.MPIs, this.signatureData+trailer); - } else { - this.verified = false; - } - break; - case 16: - // 0x10: Generic certification of a User ID and Public-Key packet. - // The issuer of this certification does not make any particular - // assertion as to how well the certifier has checked that the owner - // of the key is in fact the person described by the User ID. - case 17: - // 0x11: Persona certification of a User ID and Public-Key packet. - // The issuer of this certification has not done any verification of - // the claim that the owner of this key is the User ID specified. - case 18: - // 0x12: Casual certification of a User ID and Public-Key packet. - // The issuer of this certification has done some casual - // verification of the claim of identity. - case 19: - // 0x13: Positive certification of a User ID and Public-Key packet. - // The issuer of this certification has done substantial - // verification of the claim of identity. - // - // Most OpenPGP implementations make their "key signatures" as 0x10 - // certifications. Some implementations can issue 0x11-0x13 - // certifications, but few differentiate between the types. - case 48: - // 0x30: Certification revocation signature - // This signature revokes an earlier User ID certification signature - // (signature class 0x10 through 0x13) or direct-key signature - // (0x1F). It should be issued by the same key that issued the - // revoked signature or an authorized revocation key. The signature - // is computed over the same data as the certificate that it - // revokes, and should have a later creation date than that - // certificate. + // storing data appended to data which gets verified + this.signatureData = bytes.substring(sigpos, i); - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.MPIs, data+this.signatureData+trailer); - break; - - case 24: - // 0x18: Subkey Binding Signature - // This signature is a statement by the top-level signing key that - // indicates that it owns the subkey. This signature is calculated - // directly on the primary key and subkey, and not on any User ID or - // other packets. A signature that binds a signing subkey MUST have - // an Embedded Signature subpacket in this binding signature that - // contains a 0x19 signature made by the signing subkey on the - // primary key and subkey. - if (this.version == 3) { - this.verified = false; - break; - } - - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.MPIs, data+this.signatureData+trailer); - break; - case 25: - // 0x19: Primary Key Binding Signature - // This signature is a statement by a signing subkey, indicating - // that it is owned by the primary key and subkey. This signature - // is calculated the same way as a 0x18 signature: directly on the - // primary key and subkey, and not on any User ID or other packets. - - // When a signature is made over a key, the hash data starts with the - // octet 0x99, followed by a two-octet length of the key, and then body - // of the key packet. (Note that this is an old-style packet header for - // a key packet with two-octet length.) A subkey binding signature - // (type 0x18) or primary key binding signature (type 0x19) then hashes - // the subkey using the same format as the main key (also using 0x99 as - // the first octet). - case 31: - // 0x1F: Signature directly on a key - // This signature is calculated directly on a key. It binds the - // information in the Signature subpackets to the key, and is - // appropriate to be used for subpackets that provide information - // about the key, such as the Revocation Key subpacket. It is also - // appropriate for statements that non-self certifiers want to make - // about the key itself, rather than the binding between a key and a - // name. - case 32: - // 0x20: Key revocation signature - // The signature is calculated directly on the key being revoked. A - // revoked key is not to be used. Only revocation signatures by the - // key being revoked, or by an authorized revocation key, should be - // considered valid revocation signatures. - case 40: - // 0x28: Subkey revocation signature - // The signature is calculated directly on the subkey being revoked. - // A revoked subkey is not to be used. Only revocation signatures - // by the top-level signature key that is bound to this subkey, or - // by an authorized revocation key, should be considered valid - // revocation signatures. - this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, - this.MPIs, key.MPIs, data+this.signatureData+trailer); - break; - - // Key revocation signatures (types 0x20 and 0x28) - // hash only the key being revoked. - case 64: - // 0x40: Timestamp signature. - // This signature is only meaningful for the timestamp contained in - // it. - case 80: - // 0x50: Third-Party Confirmation signature. - // This signature is a signature over some other OpenPGP Signature - // packet(s). It is analogous to a notary seal on the signed data. - // A third-party signature SHOULD include Signature Target - // subpacket(s) to give easy identification. Note that we really do - // mean SHOULD. There are plausible uses for this (such as a blind - // party that only sees the signature, not the key or source - // document) that cannot include a target subpacket. - default: - util.print_error("openpgp.packet.signature.js\n"+"signature verification for type"+ this.signatureType+" not implemented"); - this.verified = false; - break; - } - return this.verified; - } - /** - * generates debug output (pretty print) - * @return {String} String which gives some information about the signature packet - */ + // Eight-octet Key ID of signer. + this.issuerKeyId.read(bytes.substring(i, i + 8)); + i += 8; - function toString () { - if (this.version == 3) { - var result = '5.2. Signature Packet (Tag 2)\n'+ - "Packet Length: :"+this.packetLength+'\n'+ - "Packet version: :"+this.version+'\n'+ - "One-octet signature type :"+this.signatureType+'\n'+ - "Four-octet creation time. :"+this.creationTime+'\n'+ - "Eight-octet Key ID of signer. :"+util.hexidump(this.keyId)+'\n'+ - "One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+ - "One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+ - "Two-octet field holding left\n" + - " 16 bits of signed hash value. :"+this.signedHashValue+'\n'; - } else { - var result = '5.2. Signature Packet (Tag 2)\n'+ - "Packet Length: :"+this.packetLength+'\n'+ - "Packet version: :"+this.version+'\n'+ - "One-octet signature type :"+this.signatureType+'\n'+ - "One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+ - "One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+ - "Two-octet field holding left\n" + - " 16 bits of signed hash value. :"+this.signedHashValue+'\n'+ - "Signature Creation Time :"+this.creationTime+'\n'+ - "Signature Expiration Time :"+this.signatureExpirationTime+'\n'+ - "Signature Never Expires :"+this.signatureNeverExpires+'\n'+ - "Exportable Certification :"+this.exportable+'\n'+ - "Trust Signature level: :"+this.trustLevel+' amount'+this.trustAmount+'\n'+ - "Regular Expression :"+this.regular_expression+'\n'+ - "Revocable :"+this.revocable+'\n'+ - "Key Expiration Time :"+this.keyExpirationTime+" "+this.keyNeverExpires+'\n'+ - "Preferred Symmetric Algorithms :"+this.preferredSymmetricAlgorithms+'\n'+ - "Revocation Key"+'\n'+ - " ( 1 octet of class, :"+this.revocationKeyClass +'\n'+ - " 1 octet of public-key ID, :" +this.revocationKeyAlgorithm+'\n'+ - " 20 octets of fingerprint) :"+this.revocationKeyFingerprint+'\n'+ - "Issuer :"+util.hexstrdump(this.issuerKeyId)+'\n'+ - "Preferred Hash Algorithms :"+this.preferredHashAlgorithms+'\n'+ - "Preferred Compression Alg. :"+this.preferredCompressionAlgorithms+'\n'+ - "Key Server Preferences :"+this.keyServerPreferences+'\n'+ - "Preferred Key Server :"+this.preferredKeyServer+'\n'+ - "Primary User ID :"+this.isPrimaryUserID+'\n'+ - "Policy URI :"+this.policyURI+'\n'+ - "Key Flags :"+this.keyFlags+'\n'+ - "Signer's User ID :"+this.signersUserId+'\n'+ - "Notation :"+this.notationName+" = "+this.notationValue+"\n"+ - "Reason for Revocation\n"+ - " Flag :"+this.reasonForRevocationFlag+'\n'+ - " Reason :"+this.reasonForRevocationString+'\nMPI:\n'; - } - for (var i = 0; i < this.MPIs.length; i++) { - result += this.MPIs[i].toString(); + // One-octet public-key algorithm. + this.publicKeyAlgorithm = bytes.charCodeAt(i++); + + // One-octet hash algorithm. + this.hashAlgorithm = bytes.charCodeAt(i++); + break; + case 4: + this.signatureType = bytes.charCodeAt(i++); + this.publicKeyAlgorithm = bytes.charCodeAt(i++); + this.hashAlgorithm = bytes.charCodeAt(i++); + + function subpackets(bytes) { + // Two-octet scalar octet count for following subpacket data. + var subpacket_length = util.readNumber( + bytes.substr(0, 2)); + + var i = 2; + + // subpacket data set (zero or more subpackets) + var subpacked_read = 0; + while (i < 2 + subpacket_length) { + + var len = packet.readSimpleLength(bytes.substr(i)); + i += len.offset; + + this.read_sub_packet(bytes.substr(i, len.len)); + + i += len.len; } - return result; - } - /** - * gets the issuer key id of this signature - * @return {String} issuer key id as string (8bytes) - */ - function getIssuer() { - if (this.version == 4) - return this.issuerKeyId; - if (this.version == 3) - return this.keyId; - return null; - } + return i; + } - /** - * Tries to get the corresponding public key out of the public keyring for the issuer created this signature - * @return {Object} {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise - */ - function getIssuerKey() { - var result = null; - if (this.version == 4) { - result = openpgp.keyring.getPublicKeysForKeyId(this.issuerKeyId); - } else if (this.version == 3) { - result = openpgp.keyring.getPublicKeysForKeyId(this.keyId); - } else return null; - if (result.length == 0) - return null; - return result[0]; - } - this.getIssuerKey = getIssuerKey; - this.getIssuer = getIssuer; - this.write_message_signature = write_message_signature; - this.verify = verify; - this.read_packet = read_packet; - this.toString = toString; + // hashed subpackets + i += subpackets.call(this, bytes.substr(i), true); + + // A V4 signature hashes the packet body + // starting from its first field, the version number, through the end + // of the hashed subpacket data. Thus, the fields hashed are the + // signature version, the signature type, the public-key algorithm, the + // hash algorithm, the hashed subpacket length, and the hashed + // subpacket body. + this.signatureData = bytes.substr(0, i); + + // unhashed subpackets + i += subpackets.call(this, bytes.substr(i), false); + + break; + default: + throw new Error('Version ' + version + ' of the signature is unsupported.'); + break; + } + + // Two-octet field holding left 16 bits of signed hash value. + this.signedHashValue = bytes.substr(i, 2); + i += 2; + + this.signature = bytes.substr(i); + }; + + this.write = function () { + return this.signatureData + + util.writeNumber(0, 2) + // Number of unsigned subpackets. + this.signedHashValue + + this.signature; + }; + + /** + * Signs provided data. This needs to be done prior to serialization. + * @param {module:packet/secret_key} key private key used to sign the message. + * @param {Object} data Contains packets to be signed. + */ + this.sign = function (key, data) { + var signatureType = enums.write(enums.signature, this.signatureType), + publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm), + hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); + + var result = String.fromCharCode(4); + result += String.fromCharCode(signatureType); + result += String.fromCharCode(publicKeyAlgorithm); + result += String.fromCharCode(hashAlgorithm); + + this.issuerKeyId = key.getKeyId(); + + // Add hashed subpackets + result += this.write_all_sub_packets(); + + this.signatureData = result; + + var trailer = this.calculateTrailer(); + + var toHash = this.toSign(signatureType, data) + + this.signatureData + trailer; + + var hash = crypto.hash.digest(hashAlgorithm, toHash); + + this.signedHashValue = hash.substr(0, 2); + + this.signature = crypto.signature.sign(hashAlgorithm, + publicKeyAlgorithm, key.mpi, toHash); + }; + + /** + * Creates string of bytes with all subpacket data + * @return {String} a string-representation of a all subpacket data + */ + this.write_all_sub_packets = function () { + var sub = enums.signatureSubpacket; + var result = ''; + var bytes = ''; + if (this.created !== null) { + result += write_sub_packet(sub.signature_creation_time, util.writeDate(this.created)); + } + if (this.signatureExpirationTime !== null) { + result += write_sub_packet(sub.signature_expiration_time, util.writeNumber(this.signatureExpirationTime, 4)); + } + if (this.exportable !== null) { + result += write_sub_packet(sub.exportable_certification, String.fromCharCode(this.exportable ? 1 : 0)); + } + if (this.trustLevel !== null) { + bytes = String.fromCharCode(this.trustLevel) + String.fromCharCode(this.trustAmount); + result += write_sub_packet(sub.trust_signature, bytes); + } + if (this.regularExpression !== null) { + result += write_sub_packet(sub.regular_expression, this.regularExpression); + } + if (this.revocable !== null) { + result += write_sub_packet(sub.revocable, String.fromCharCode(this.revocable ? 1 : 0)); + } + if (this.keyExpirationTime !== null) { + result += write_sub_packet(sub.key_expiration_time, util.writeNumber(this.keyExpirationTime, 4)); + } + if (this.preferredSymmetricAlgorithms !== null) { + bytes = util.bin2str(this.preferredSymmetricAlgorithms); + result += write_sub_packet(sub.preferred_symmetric_algorithms, bytes); + } + if (this.revocationKeyClass !== null) { + bytes = String.fromCharCode(this.revocationKeyClass); + bytes += String.fromCharCode(this.revocationKeyAlgorithm); + bytes += this.revocationKeyFingerprint; + result += write_sub_packet(sub.revocation_key, bytes); + } + if (!this.issuerKeyId.isNull()) { + result += write_sub_packet(sub.issuer, this.issuerKeyId.write()); + } + if (this.notation !== null) { + for (var name in this.notation) { + if (this.notation.hasOwnProperty(name)) { + var value = this.notation[name]; + bytes = String.fromCharCode(0x80); + bytes += String.fromCharCode(0); + bytes += String.fromCharCode(0); + bytes += String.fromCharCode(0); + // 2 octets of name length + bytes += util.writeNumber(name.length, 2); + // 2 octets of value length + bytes += util.writeNumber(value.length, 2); + bytes += name + value; + result += write_sub_packet(sub.notation_data, bytes); + } + } + } + if (this.preferredHashAlgorithms !== null) { + bytes = util.bin2str(this.preferredHashAlgorithms); + result += write_sub_packet(sub.preferred_hash_algorithms, bytes); + } + if (this.preferredCompressionAlgorithms !== null) { + bytes = util.bin2str(this.preferredCompressionAlgorithms); + result += write_sub_packet(sub.preferred_hash_algorithms, bytes); + } + if (this.keyServerPreferences !== null) { + bytes = util.bin2str(this.keyServerPreferences); + result += write_sub_packet(sub.key_server_preferences, bytes); + } + if (this.preferredKeyServer !== null) { + result += write_sub_packet(sub.preferred_key_server, this.preferredKeyServer); + } + if (this.isPrimaryUserID !== null) { + result += write_sub_packet(sub.primary_user_id, String.fromCharCode(this.isPrimaryUserID ? 1 : 0)); + } + if (this.policyURI !== null) { + result += write_sub_packet(sub.policy_uri, this.policyURI); + } + if (this.keyFlags !== null) { + bytes = util.bin2str(this.keyFlags); + result += write_sub_packet(sub.key_flags, bytes); + } + if (this.signersUserId !== null) { + result += write_sub_packet(sub.signers_user_id, this.signersUserId); + } + if (this.reasonForRevocationFlag !== null) { + bytes = String.fromCharCode(this.reasonForRevocationFlag); + bytes += this.reasonForRevocationString; + result += write_sub_packet(sub.reason_for_revocation, bytes); + } + if (this.features !== null) { + bytes = util.bin2str(this.features); + result += write_sub_packet(sub.features, bytes); + } + if (this.signatureTargetPublicKeyAlgorithm !== null) { + bytes = String.fromCharCode(this.signatureTargetPublicKeyAlgorithm); + bytes += String.fromCharCode(this.signatureTargetHashAlgorithm); + bytes += this.signatureTargetHash; + result += write_sub_packet(sub.signature_target, bytes); + } + if (this.embeddedSignature !== null) { + result += write_sub_packet(sub.embedded_signature, this.embeddedSignature.write()); + } + result = util.writeNumber(result.length, 2) + result; + return result; + }; + + /** + * creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1) + * @param {Integer} type subpacket signature type. Signature types as described + * in RFC4880 Section 5.2.3.2 + * @param {String} data data to be included + * @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1) + */ + function write_sub_packet(type, data) { + var result = ""; + result += packet.writeSimpleLength(data.length + 1); + result += String.fromCharCode(type); + result += data; + return result; + } + + // V4 signature sub packets + + this.read_sub_packet = function (bytes) { + var mypos = 0; + + function read_array(prop, bytes) { + this[prop] = []; + + for (var i = 0; i < bytes.length; i++) { + this[prop].push(bytes.charCodeAt(i)); + } + } + + // The leftwost bit denotes a "critical" packet, but we ignore it. + var type = bytes.charCodeAt(mypos++) & 0x7F; + + // subpacket type + switch (type) { + case 2: + // Signature Creation Time + this.created = util.readDate(bytes.substr(mypos)); + break; + case 3: + // Signature Expiration Time in seconds + var seconds = util.readNumber(bytes.substr(mypos)); + + this.signatureNeverExpires = seconds == 0; + this.signatureExpirationTime = seconds; + + break; + case 4: + // Exportable Certification + this.exportable = bytes.charCodeAt(mypos++) == 1; + break; + case 5: + // Trust Signature + this.trustLevel = bytes.charCodeAt(mypos++); + this.trustAmount = bytes.charCodeAt(mypos++); + break; + case 6: + // Regular Expression + this.regularExpression = bytes.substr(mypos); + break; + case 7: + // Revocable + this.revocable = bytes.charCodeAt(mypos++) == 1; + break; + case 9: + // Key Expiration Time in seconds + var seconds = util.readNumber(bytes.substr(mypos)); + + this.keyExpirationTime = seconds; + this.keyNeverExpires = seconds == 0; + + break; + case 11: + // Preferred Symmetric Algorithms + this.preferredSymmetricAlgorithms = []; + + while (mypos != bytes.length) { + this.preferredSymmetricAlgorithms.push(bytes.charCodeAt(mypos++)); + } + + break; + case 12: + // Revocation Key + // (1 octet of class, 1 octet of public-key algorithm ID, 20 + // octets of + // fingerprint) + this.revocationKeyClass = bytes.charCodeAt(mypos++); + this.revocationKeyAlgorithm = bytes.charCodeAt(mypos++); + this.revocationKeyFingerprint = bytes.substr(mypos, 20); + break; + + case 16: + // Issuer + this.issuerKeyId.read(bytes.substr(mypos)); + break; + + case 20: + // Notation Data + // We don't know how to handle anything but a text flagged data. + if (bytes.charCodeAt(mypos) == 0x80) { + + // We extract key/value tuple from the byte stream. + mypos += 4; + var m = util.readNumber(bytes.substr(mypos, 2)); + mypos += 2 + var n = util.readNumber(bytes.substr(mypos, 2)); + mypos += 2 + + var name = bytes.substr(mypos, m), + value = bytes.substr(mypos + m, n); + + this.notation = this.notation || {}; + this.notation[name] = value; + } else throw new Error("Unsupported notation flag."); + break; + case 21: + // Preferred Hash Algorithms + read_array.call(this, 'preferredHashAlgorithms', bytes.substr(mypos)); + break; + case 22: + // Preferred Compression Algorithms + read_array.call(this, 'preferredCompressionAlgorithms ', bytes.substr(mypos)); + break; + case 23: + // Key Server Preferences + read_array.call(this, 'keyServerPreferencess', bytes.substr(mypos)); + break; + case 24: + // Preferred Key Server + this.preferredKeyServer = bytes.substr(mypos); + break; + case 25: + // Primary User ID + this.isPrimaryUserID = bytes[mypos++] != 0; + break; + case 26: + // Policy URI + this.policyURI = bytes.substr(mypos); + break; + case 27: + // Key Flags + read_array.call(this, 'keyFlags', bytes.substr(mypos)); + break; + case 28: + // Signer's User ID + this.signersUserId += bytes.substr(mypos); + break; + case 29: + // Reason for Revocation + this.reasonForRevocationFlag = bytes.charCodeAt(mypos++); + this.reasonForRevocationString = bytes.substr(mypos); + break; + case 30: + // Features + read_array.call(this, 'features', bytes.substr(mypos)); + break; + case 31: + // Signature Target + // (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash) + this.signatureTargetPublicKeyAlgorithm = bytes.charCodeAt(mypos++); + this.signatureTargetHashAlgorithm = bytes.charCodeAt(mypos++); + + var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm); + + this.signatureTargetHash = bytes.substr(mypos, len); + break; + case 32: + // Embedded Signature + this.embeddedSignature = new signature(); + this.embeddedSignature.read(bytes.substr(mypos)); + break; + default: + throw new Error("Unknown signature subpacket type " + type + " @:" + mypos); + break; + } + }; + + // Produces data to produce signature on + this.toSign = function (type, data) { + var t = enums.signature; + + switch (type) { + case t.binary: + case t.text: + return data.getBytes(); + + case t.standalone: + return ''; + + case t.cert_generic: + case t.cert_persona: + case t.cert_casual: + case t.cert_positive: + case t.cert_revocation: + var packet, tag; + + if (data.userid !== undefined) { + tag = 0xB4; + packet = data.userid; + } else if (data.userattribute !== undefined) { + tag = 0xD1; + packet = data.userattribute; + } else throw new Error('Either a userid or userattribute packet needs to be ' + + 'supplied for certification.'); + + var bytes = packet.write(); + + if (this.version == 4) { + return this.toSign(t.key, data) + + String.fromCharCode(tag) + + util.writeNumber(bytes.length, 4) + + bytes; + } else if (this.version == 3) { + return this.toSign(t.key, data) + + bytes; + } + break; + + case t.subkey_binding: + case t.key_binding: + return this.toSign(t.key, data) + this.toSign(t.key, { + key: data.bind + }); + + case t.key: + if (data.key == undefined) + throw new Error('Key packet is required for this sigtature.'); + + return data.key.writeOld(); + + case t.key_revocation: + case t.subkey_revocation: + return this.toSign(t.key, data); + case t.timestamp: + return ''; + case t.third_party: + throw new Error('Not implemented'); + break; + default: + throw new Error('Unknown signature type.') + } + } + + + this.calculateTrailer = function () { + // calculating the trailer + var trailer = ''; + // V3 signatures don't have a trailer + if (this.version == 3) return trailer; + trailer += String.fromCharCode(4); // Version + trailer += String.fromCharCode(0xFF); + trailer += util.writeNumber(this.signatureData.length, 4); + return trailer + } + + + /** + * verifys the signature packet. Note: not signature types are implemented + * @param {String|Object} data data which on the signature applies + * @param {module:packet/public_subkey|module:packet/public_key} key the public key to verify the signature + * @return {boolean} True if message is verified, else false. + */ + this.verify = function (key, data) { + var signatureType = enums.write(enums.signature, this.signatureType), + publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm), + hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); + + var bytes = this.toSign(signatureType, data), + trailer = this.calculateTrailer(); + + + var mpicount = 0; + // Algorithm-Specific Fields for RSA signatures: + // - multiprecision number (MPI) of RSA signature value m**d mod n. + if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4) + mpicount = 1; + // Algorithm-Specific Fields for DSA signatures: + // - MPI of DSA value r. + // - MPI of DSA value s. + else if (publicKeyAlgorithm == 17) + mpicount = 2; + + var mpi = [], + i = 0; + for (var j = 0; j < mpicount; j++) { + mpi[j] = new type_mpi(); + i += mpi[j].read(this.signature.substr(i)); + } + + this.verified = crypto.signature.verify(publicKeyAlgorithm, + hashAlgorithm, mpi, key.mpi, + bytes + this.signatureData + trailer); + + return this.verified; + } + + /** + * Verifies signature expiration date + * @return {Boolean} true if expired + */ + this.isExpired = function () { + if (!this.signatureNeverExpires) { + return Date.now() > (this.created.getTime() + this.signatureExpirationTime*1000); + } + return false; + } } -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -/** - * @class - * @classdesc Implementation of the User Attribute Packet (Tag 17) - * The User Attribute packet is a variation of the User ID packet. It - * is capable of storing more types of data than the User ID packet, - * which is limited to text. Like the User ID packet, a User Attribute - * packet may be certified by the key owner ("self-signed") or any other - * key owner who cares to certify it. Except as noted, a User Attribute - * packet may be used anywhere that a User ID packet may be used. - * - * While User Attribute packets are not a required part of the OpenPGP - * standard, implementations SHOULD provide at least enough - * compatibility to properly handle a certification signature on the - * User Attribute packet. A simple way to do this is by treating the - * User Attribute packet as a User ID packet with opaque contents, but - * an implementation may use any method desired. - */ -function openpgp_packet_userattribute() { - this.tagType = 17; - this.certificationSignatures = new Array(); - this.certificationRevocationSignatures = new Array(); - this.revocationSignatures = new Array(); - this.parentNode = null; - - /** - * parsing function for a user attribute packet (tag 17). - * @param {String} input payload of a tag 17 packet - * @param {Integer} position position to start reading from the input string - * @param {Integer} len length of the packet or the remaining length of input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - function read_packet (input, position, len) { - var total_len = 0; - this.packetLength = len; - this.userattributes = new Array(); - var count = 0; - var mypos = position; - while (len != total_len) { - var current_len = 0; - // 4.2.2.1. One-Octet Lengths - if (input.charCodeAt(mypos) < 192) { - packet_length = input.charCodeAt(mypos++); - current_len = 1; - // 4.2.2.2. Two-Octet Lengths - } else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) { - packet_length = ((input.charCodeAt(mypos++) - 192) << 8) - + (input.charCodeAt(mypos++)) + 192; - current_len = 2; - // 4.2.2.4. Partial Body Lengths - } else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) { - packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F); - current_len = 1; - // 4.2.2.3. Five-Octet Lengths - } else { - current_len = 5; - mypos++; - packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) - | (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); - } - - var subpackettype = input.charCodeAt(mypos++); - packet_length--; - current_len++; - this.userattributes[count] = new Array(); - this.userattributes[count] = input.substring(mypos, mypos + packet_length); - mypos += packet_length; - total_len += current_len+packet_length; - } - this.packetLength = mypos - position; - return this; - } - - /** - * generates debug output (pretty print) - * @return {String} String which gives some information about the user attribute packet - */ - function toString() { - var result = '5.12. User Attribute Packet (Tag 17)\n'+ - ' AttributePackets: (count = '+this.userattributes.length+')\n'; - for (var i = 0; i < this.userattributes.length; i++) { - result += ' ('+this.userattributes[i].length+') bytes: ['+util.hexidump(this.userattributes[i])+']\n'; - } - return result; - } - - /** - * Continue parsing packets belonging to the user attribute packet such as signatures - * @param {Object} parent_node the parent object - * @param {String} input input string to read the packet(s) from - * @param {Integer} position start position for the parser - * @param {Integer} len length of the packet(s) or remaining length of input - * @return {Integer} length of nodes read - */ - function read_nodes(parent_node, input, position, len) { - - this.parentNode = parent_node; - var exit = false; - var pos = position; - var l = len; - while (input.length != pos) { - var result = openpgp_packet.read_packet(input, pos, l); - if (result == null) { - util.print_error("openpgp.packet.userattribute.js\n"+'[user_attr] parsing ends here @:' + pos + " l:" + l); - break; - } else { - switch (result.tagType) { - case 2: // Signature Packet - if (result.signatureType > 15 - && result.signatureType < 20) // certification - // // - // signature - this.certificationSignatures[this.certificationSignatures.length] = result; - else if (result.signatureType == 32) // certification revocation signature - this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result; - pos += result.packetLength + result.headerLength; - l = len - (pos - position); - break; - default: - this.data = input; - this.position = position - parent_node.packetLength; - this.len = pos - position; - return this.len; - break; - } - } - } - this.data = input; - this.position = position - parent_node.packetLength; - this.len = pos - position; - return this.len; - - } - - this.read_packet = read_packet; - this.read_nodes = read_nodes; - this.toString = toString; - -}; +},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56,"./packet.js":39}],47:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -12530,346 +13037,462 @@ function openpgp_packet_userattribute() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Implementation of the User ID Packet (Tag 13) + * Implementation of the Sym. Encrypted Integrity Protected Data + * Packet (Tag 18)
      + *
      + * RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is + * a variant of the Symmetrically Encrypted Data packet. It is a new feature + * created for OpenPGP that addresses the problem of detecting a modification to + * encrypted data. It is used in combination with a Modification Detection Code + * packet. + * @requires crypto + * @requires util + * @module packet/sym_encrypted_integrity_protected + */ + +var util = require('../util'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function sym_encrypted_integrity_protected() { + /** The encrypted payload. */ + this.encrypted = null; // string + /** + * If after decrypting the packet this is set to true, + * a modification has been detected and thus the contents + * should be discarded. + * @type {Boolean} + */ + this.modification = false; + this.packets = null; + + + this.read = function (bytes) { + // - A one-octet version number. The only currently defined value is 1. + var version = bytes.charCodeAt(0); + + if (version != 1) { + throw new Error('Invalid packet version.'); + } + + // - Encrypted data, the output of the selected symmetric-key cipher + // operating in Cipher Feedback mode with shift amount equal to the + // block size of the cipher (CFB-n where n is the block size). + this.encrypted = bytes.substr(1); + }; + + this.write = function () { + + return String.fromCharCode(1) // Version + + this.encrypted; + }; + + this.encrypt = function (sessionKeyAlgorithm, key) { + var bytes = this.packets.write() + + var prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm); + var prefix = prefixrandom + prefixrandom.charAt(prefixrandom.length - 2) + prefixrandom.charAt(prefixrandom.length - + 1) + + var tohash = bytes; + + + // Modification detection code packet. + tohash += String.fromCharCode(0xD3); + tohash += String.fromCharCode(0x14); + + + tohash += crypto.hash.sha1(prefix + tohash); + + + this.encrypted = crypto.cfb.encrypt(prefixrandom, + sessionKeyAlgorithm, tohash, key, false).substring(0, + prefix.length + tohash.length); + }; + + /** + * Decrypts the encrypted data contained in this object read_packet must + * have been called before + * + * @param {Integer} sessionKeyAlgorithm + * The selected symmetric encryption algorithm to be used + * @param {String} key The key of cipher blocksize length to be used + * @return {String} The decrypted data of this packet + */ + this.decrypt = function (sessionKeyAlgorithm, key) { + var decrypted = crypto.cfb.decrypt( + sessionKeyAlgorithm, key, this.encrypted, false); + + + // there must be a modification detection code packet as the + // last packet and everything gets hashed except the hash itself + this.hash = crypto.hash.sha1( + crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted) + decrypted.substring(0, decrypted.length - 20)); + + + var mdc = decrypted.substr(decrypted.length - 20, 20); + + if (this.hash != mdc) { + throw new Error('Modification detected.'); + } else + this.packets.read(decrypted.substr(0, decrypted.length - 22)); + }; +}; + +},{"../crypto":16,"../util":56}],48:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Public-Key Encrypted Session Key Packets (Tag 1)
      + *
      + * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key + * used to encrypt a message. Zero or more Public-Key Encrypted Session Key + * packets and/or Symmetric-Key Encrypted Session Key packets may precede a + * Symmetrically Encrypted Data Packet, which holds an encrypted message. The + * message is encrypted with the session key, and the session key is itself + * encrypted and stored in the Encrypted Session Key packet(s). The + * Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted + * Session Key packet for each OpenPGP key to which the message is encrypted. + * The recipient of the message finds a session key that is encrypted to their + * public key, decrypts the session key, and then uses the session key to + * decrypt the message. + * @requires crypto + * @requires enums + * @requires type/s2k + * @module packet/sym_encrypted_session_key + */ + +var type_s2k = require('../type/s2k.js'), + enums = require('../enums.js'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function sym_encrypted_session_key() { + this.tag = 3; + this.sessionKeyEncryptionAlgorithm = null; + this.sessionKeyAlgorithm = 'aes256'; + this.encrypted = null; + this.s2k = new type_s2k(); + + /** + * Parsing function for a symmetric encrypted session key packet (tag 3). + * + * @param {String} input Payload of a tag 1 packet + * @param {Integer} position Position to start reading from the input string + * @param {Integer} len + * Length of the packet or the remaining length of + * input at position + * @return {module:packet/sym_encrypted_session_key} Object representation + */ + this.read = function(bytes) { + // A one-octet version number. The only currently defined version is 4. + this.version = bytes.charCodeAt(0); + + // A one-octet number describing the symmetric algorithm used. + var algo = enums.read(enums.symmetric, bytes.charCodeAt(1)); + + // A string-to-key (S2K) specifier, length as defined above. + var s2klength = this.s2k.read(bytes.substr(2)); + + // Optionally, the encrypted session key itself, which is decrypted + // with the string-to-key object. + var done = s2klength + 2; + + if (done < bytes.length) { + this.encrypted = bytes.substr(done); + this.sessionKeyEncryptionAlgorithm = algo + } else + this.sessionKeyAlgorithm = algo; + }; + + this.write = function() { + var algo = this.encrypted == null ? + this.sessionKeyAlgorithm : + this.sessionKeyEncryptionAlgorithm; + + var bytes = String.fromCharCode(this.version) + + String.fromCharCode(enums.write(enums.symmetric, algo)) + + this.s2k.write(); + + if (this.encrypted != null) + bytes += this.encrypted; + return bytes; + }; + + /** + * Decrypts the session key (only for public key encrypted session key + * packets (tag 1) + * + * @return {String} The unencrypted session key + */ + this.decrypt = function(passphrase) { + var algo = this.sessionKeyEncryptionAlgorithm != null ? + this.sessionKeyEncryptionAlgorithm : + this.sessionKeyAlgorithm; + + + var length = crypto.cipher[algo].keySize; + var key = this.s2k.produce_key(passphrase, length); + + if (this.encrypted == null) { + this.sessionKey = key; + + } else { + var decrypted = crypto.cfb.decrypt( + this.sessionKeyEncryptionAlgorithm, key, this.encrypted, true); + + this.sessionKeyAlgorithm = enums.read(enums.symmetric, + decrypted[0].keyCodeAt()); + + this.sessionKey = decrypted.substr(1); + } + }; + + this.encrypt = function(passphrase) { + var length = crypto.getKeyLength(this.sessionKeyEncryptionAlgorithm); + var key = this.s2k.produce_key(passphrase, length); + + var private_key = String.fromCharCode( + enums.write(enums.symmetric, this.sessionKeyAlgorithm)) + + + crypto.getRandomBytes( + crypto.getKeyLength(this.sessionKeyAlgorithm)); + + this.encrypted = crypto.cfb.encrypt( + crypto.getPrefixRandom(this.sessionKeyEncryptionAlgorithm), + this.sessionKeyEncryptionAlgorithm, key, private_key, true); + }; +}; + +},{"../crypto":16,"../enums.js":27,"../type/s2k.js":55}],49:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
      + *
      + * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted + * with a symmetric-key algorithm. When it has been decrypted, it contains other + * packets (usually a literal data packet or compressed data packet, but in + * theory other Symmetrically Encrypted Data packets or sequences of packets + * that form whole OpenPGP messages). + * @requires crypto + * @module packet/symmetrically_encrypted + */ + +var crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function symmetrically_encrypted() { + this.encrypted = null; + /** Decrypted packets contained within. + * @type {module:packet/packetlist} */ + this.packets = null; + + this.read = function(bytes) { + this.encrypted = bytes; + }; + + this.write = function() { + return this.encrypted; + }; + + /** + * Symmetrically decrypt the packet data + * + * @param {Integer} sessionKeyAlgorithm + * Symmetric key algorithm to use // See RFC4880 9.2 + * @param {String} key + * Key as string with the corresponding length to the + * algorithm + */ + this.decrypt = function(sessionKeyAlgorithm, key) { + var decrypted = crypto.cfb.decrypt( + sessionKeyAlgorithm, key, this.encrypted, true); + + this.packets.read(decrypted); + }; + + this.encrypt = function(algo, key) { + var data = this.packets.write(); + + this.encrypted = crypto.cfb.encrypt( + crypto.getPrefixRandom(algo), algo, data, key, true); + }; +}; + +},{"../crypto":16}],50:[function(require,module,exports){ +/** + * @module packet/trust + */ + +/** + * @constructor + */ +module.exports = function trust() { + +}; + +},{}],51:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the User Attribute Packet (Tag 17)
      + *
      + * The User Attribute packet is a variation of the User ID packet. It + * is capable of storing more types of data than the User ID packet, + * which is limited to text. Like the User ID packet, a User Attribute + * packet may be certified by the key owner ("self-signed") or any other + * key owner who cares to certify it. Except as noted, a User Attribute + * packet may be used anywhere that a User ID packet may be used. + *
      + * While User Attribute packets are not a required part of the OpenPGP + * standard, implementations SHOULD provide at least enough + * compatibility to properly handle a certification signature on the + * User Attribute packet. A simple way to do this is by treating the + * User Attribute packet as a User ID packet with opaque contents, but + * an implementation may use any method desired. + * module packet/user_attribute + * @module packet/user_attribute + */ + +var util = require('../util'), + packet = require('./packet.js'); + +/** + * @constructor + */ +module.exports = function user_attribute() { + this.tag = 17; + this.attributes = []; + + /** + * parsing function for a user attribute packet (tag 17). + * @param {String} input payload of a tag 17 packet + */ + this.read = function(bytes) { + var i = 0; + while (i < bytes.length) { + var len = packet.readSimpleLength(bytes.substr(i)); + i += len.offset; + + this.attributes.push(bytes.substr(i, len.len)); + i += len.len; + } + }; +}; + +},{"../util":56,"./packet.js":39}],52:[function(require,module,exports){ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the User ID Packet (Tag 13)
      + *
      * A User ID packet consists of UTF-8 text that is intended to represent * the name and email address of the key holder. By convention, it * includes an RFC 2822 [RFC2822] mail name-addr, but there are no * restrictions on its content. The packet length in the header - * specifies the length of the User ID. + * specifies the length of the User ID. + * @requires util + * @module packet/userid */ -function openpgp_packet_userid() { - this.text = '' - this.tagType = 13; - this.certificationSignatures = new Array(); - this.certificationRevocationSignatures = new Array(); - this.revocationSignatures = new Array(); - this.parentNode = null; - - /** - * Set the packet text field to a native javascript string - * Conversion to a proper utf8 encoding takes place when the - * packet is written. - * @param {String} str Any native javascript string - */ - this.set_text = function(str) { - this.text = str; - } +var util = require('../util'); - /** - * Set the packet text to value represented by the provided string - * of bytes. - * @param {String} bytes A string of bytes - */ - this.set_text_bytes = function(bytes) { - this.text = util.decode_utf8(bytes); - } +/** + * @constructor + */ +module.exports = function userid() { + /** A string containing the user id. Usually in the form + * John Doe + * @type {String} + */ + this.userid = ''; - /** - * Get the byte sequence representing the text of this packet. - * @returns {String} A sequence of bytes - */ - this.get_text_bytes = function() { - return util.encode_utf8(this.text); - } - - /** - * Parsing function for a user id packet (tag 13). - * @param {String} input payload of a tag 13 packet - * @param {Integer} position position to start reading from the input string - * @param {Integer} len length of the packet or the remaining length of input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - this.read_packet = function(input, position, len) { - this.packetLength = len; - this.set_text_bytes(input.substr(position, len)); - return this; - } + /** + * Parsing function for a user id packet (tag 13). + * @param {String} input payload of a tag 13 packet + */ + this.read = function (bytes) { + this.userid = util.decode_utf8(bytes); + }; - /** - * Creates a string representation of the user id packet - * @param {String} user_id the user id as string ("John Doe 15 - && result.signatureType < 20) { // certification - // // - // signature - this.certificationSignatures[this.certificationSignatures.length] = result; - break; - } else if (result.signatureType == 48) {// certification revocation signature - this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result; - break; - } else if (result.signatureType == 24) { // omg. standalone signature - this.certificationSignatures[this.certificationSignatures.length] = result; - break; - } else { - util.print_debug("unknown sig t: "+result.signatureType+"@"+(pos - (result.packetLength + result.headerLength))); - } - default: - this.data = input; - this.position = position - parent_node.packetLength; - this.len = pos - position -(result.headerLength + result.packetLength); - return this.len; - } - } - } - this.data = input; - this.position = position - parent_node.packetLength; - this.len = pos - position -(result.headerLength + result.packetLength); - return this.len; - } else if (parent_node.tagType == 5) { // secret Key - this.parentNode = parent_node; - var exit = false; - var pos = position; - while (input.length != pos) { - var result = openpgp_packet.read_packet(input, pos, l - (pos - position)); - if (result == null) { - util.print_error('parsing ends here @:' + pos + " l:" + l); - break; - } else { - pos += result.packetLength + result.headerLength; - l = input.length - pos; - switch (result.tagType) { - case 2: // Signature Packet certification signature - if (result.signatureType > 15 - && result.signatureType < 20) - this.certificationSignatures[this.certificationSignatures.length] = result; - // certification revocation signature - else if (result.signatureType == 48) - this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result; - default: - this.data = input; - this.position = position - parent_node.packetLength; - this.len = pos - position -(result.headerLength + result.packetLength); - return this.len; - } - } - } - } else { - util.print_error("unknown parent node for a userId packet "+parent_node.tagType); - } - } - - /** - * generates debug output (pretty print) - * @return {String} String which gives some information about the user id packet - */ - this.toString = function() { - var result = ' 5.11. User ID Packet (Tag 13)\n' + ' text (' - + this.text.length + '): "' + this.text.replace("<", "<") - + '"\n'; - result +="certification signatures:\n"; - for (var i = 0; i < this.certificationSignatures.length; i++) { - result += " "+this.certificationSignatures[i].toString(); - } - result +="certification revocation signatures:\n"; - for (var i = 0; i < this.certificationRevocationSignatures.length; i++) { - result += " "+this.certificationRevocationSignatures[i].toString(); - } - return result; - } - - /** - * lookup function to find certification revocation signatures - * @param {String} keyId string containing the key id of the issuer of this signature - * @return a CertificationRevocationSignature if found; otherwise null - */ - this.hasCertificationRevocationSignature = function(keyId) { - for (var i = 0; i < this.certificationRevocationSignatures.length; i++) { - if ((this.certificationRevocationSignatures[i].version == 3 && - this.certificationRevocationSignatures[i].keyId == keyId) || - (this.certificationRevocationSignatures[i].version == 4 && - this.certificationRevocationSignatures[i].issuerKeyId == keyId)) - return this.certificationRevocationSignatures[i]; - } - return null; - } - - /** - * Verifies all certification signatures. This method does not consider possible revocation signatures. - * @param {Object} publicKeyPacket the top level key material - * @return {Integer[]} An array of integers corresponding to the array of certification signatures. The meaning of each integer is the following: - * 0 = bad signature - * 1 = signature expired - * 2 = issuer key not available - * 3 = revoked - * 4 = signature valid - * 5 = signature by key owner expired - * 6 = signature by key owner revoked - */ - this.verifyCertificationSignatures = function(publicKeyPacket) { - var bytes = this.get_text_bytes(); - result = new Array(); - for (var i = 0 ; i < this.certificationSignatures.length; i++) { - // A certification signature (type 0x10 through 0x13) hashes the User - // ID being bound to the key into the hash context after the above - // data. A V3 certification hashes the contents of the User ID or - // attribute packet packet, without any header. A V4 certification - // hashes the constant 0xB4 for User ID certifications or the constant - // 0xD1 for User Attribute certifications, followed by a four-octet - // number giving the length of the User ID or User Attribute data, and - // then the User ID or User Attribute data. - - if (this.certificationSignatures[i].version == 4) { - if (this.certificationSignatures[i].signatureExpirationTime != null && - this.certificationSignatures[i].signatureExpirationTime != null && - this.certificationSignatures[i].signatureExpirationTime != 0 && - !this.certificationSignatures[i].signatureNeverExpires && - new Date(this.certificationSignatures[i].creationTime.getTime() +(this.certificationSignatures[i].signatureExpirationTime*1000)) < new Date()) { - if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId()) - result[i] = 5; - else - result[i] = 1; - continue; - } - if (this.certificationSignatures[i].issuerKeyId == null) { - result[i] = 0; - continue; - } - var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].issuerKeyId); - if (issuerPublicKey == null || issuerPublicKey.length == 0) { - result[i] = 2; - continue; - } - // TODO: try to verify all returned issuer public keys (key ids are not unique!) - var issuerPublicKey = issuerPublicKey[0]; - var signingKey = issuerPublicKey.obj.getSigningKey(); - if (signingKey == null) { - result[i] = 0; - continue; - } - var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].issuerKeyId); - if (revocation != null && revocation.creationTime > - this.certificationSignatures[i].creationTime) { - - var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+ - publicKeyPacket.data+String.fromCharCode(0xB4)+ - String.fromCharCode((bytes.length >> 24) & 0xFF)+ - String.fromCharCode((bytes.length >> 16) & 0xFF)+ - String.fromCharCode((bytes.length >> 8) & 0xFF)+ - String.fromCharCode((bytes.length) & 0xFF)+ - bytes; - if (revocation.verify(signaturedata, signingKey)) { - if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId()) - result[i] = 6; - else - result[i] = 3; - continue; - } - } - - var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+ - publicKeyPacket.data+String.fromCharCode(0xB4)+ - String.fromCharCode((bytes.length >> 24) & 0xFF)+ - String.fromCharCode((bytes.length >> 16) & 0xFF)+ - String.fromCharCode((bytes.length >> 8) & 0xFF)+ - String.fromCharCode((bytes.length) & 0xFF)+ - bytes; - if (this.certificationSignatures[i].verify(signaturedata, signingKey)) { - result[i] = 4; - } else - result[i] = 0; - } else if (this.certificationSignatures[i].version == 3) { - if (this.certificationSignatures[i].keyId == null) { - result[i] = 0; - continue; - } - var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].keyId); - if (issuerPublicKey == null || issuerPublicKey.length == 0) { - result[i] = 2; - continue; - } - issuerPublicKey = issuerPublicKey[0]; - var signingKey = publicKey.obj.getSigningKey(); - if (signingKey == null) { - result[i] = 0; - continue; - } - var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].keyId); - if (revocation != null && revocation.creationTime > - this.certificationSignatures[i].creationTime) { - var signaturedata = String.fromCharCode(0x99)+ this.publicKeyPacket.header.substring(1)+ - this.publicKeyPacket.data+bytes; - if (revocation.verify(signaturedata, signingKey)) { - if (revocation.keyId == publicKeyPacket.getKeyId()) - result[i] = 6; - else - result[i] = 3; - continue; - } - } - var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+ - publicKeyPacket.data + bytes; - if (this.certificationSignatures[i].verify(signaturedata, signingKey)) { - result[i] = 4; - } else - result[i] = 0; - } else { - result[i] = 0; - } - } - return result; - } - - /** - * verifies the signatures of the user id - * @return 0 if the userid is valid; 1 = userid expired; 2 = userid revoked - */ - this.verify = function(publicKeyPacket) { - var result = this.verifyCertificationSignatures(publicKeyPacket); - if (result.indexOf(6) != -1) - return 2; - if (result.indexOf(5) != -1) - return 1; - return 0; - } - - // TODO: implementation missing - this.addCertification = function(publicKeyPacket, privateKeyPacket) { - - } - - // TODO: implementation missing - this.revokeCertification = function(publicKeyPacket, privateKeyPacket) { - - } + /** + * Creates a string representation of the user id packet + * @return {String} string representation + */ + this.write = function () { + return util.encode_utf8(this.userid); + }; } + +},{"../util":56}],53:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -12888,37 +13511,56 @@ function openpgp_packet_userid() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Implementation of type key id (RFC4880 3.3) - * A Key ID is an eight-octet scalar that identifies a key. - Implementations SHOULD NOT assume that Key IDs are unique. The - section "Enhanced Key Formats" below describes how Key IDs are - formed. + * Implementation of type key id (RFC4880 3.3)
      + *
      + * A Key ID is an eight-octet scalar that identifies a key. + * Implementations SHOULD NOT assume that Key IDs are unique. The + * section "Enhanced Key Formats" below describes how Key IDs are + * formed. + * @requires util + * @module type/keyid */ -function openpgp_type_keyid() { - /** - * Parsing method for a key id - * @param {String} input Input to read the key id from - * @param {integer} position Position where to start reading the key - * id from input - * @return {openpgp_type_keyid} This object - */ - function read_packet(input, position) { - this.bytes = input.substring(position, position+8); - return this; - } - - /** - * Generates debug output (pretty print) - * @return {String} Key Id as hexadecimal string - */ - function toString() { - return util.hexstrdump(this.bytes); - } - - this.read_packet = read_packet; - this.toString = toString; + +var util = require('../util'); + +/** + * @constructor + */ +module.exports = function keyid() { + + this.bytes = ''; + + + /** + * Parsing method for a key id + * @param {String} input Input to read the key id from + */ + this.read = function(bytes) { + this.bytes = bytes.substr(0, 8); + }; + + this.write = function() { + return this.bytes; + }; + + this.toHex = function() { + return util.hexstrdump(this.bytes); + }; + + this.equals = function(keyid) { + return this.bytes == keyid.bytes; + }; + + this.isNull = function() { + return this.bytes === ''; + }; }; + +module.exports.mapToHex = function(keyId) { + return keyId.toHex(); +} + +},{"../util":56}],54:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -12942,118 +13584,85 @@ function openpgp_type_keyid() { // - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8) /** - * @class - * @classdescImplementation of type MPI (RFC4880 3.2) + * Implementation of type MPI (RFC4880 3.2)
      + *
      * Multiprecision integers (also called MPIs) are unsigned integers used * to hold large integers such as the ones used in cryptographic * calculations. * An MPI consists of two pieces: a two-octet scalar that is the length * of the MPI in bits followed by a string of octets that contain the * actual integer. + * @requires crypto/public_key/jsbn + * @requires util + * @module type/mpi */ -function openpgp_type_mpi() { - this.MPI = null; - this.mpiBitLength = null; - this.mpiByteLength = null; - this.data = null; - /** - * Parsing function for a mpi (RFC 4880 3.2). - * @param {String} input Payload of mpi data - * @param {Integer} position Position to start reading from the input - * string - * @param {Integer} len Length of the packet or the remaining length of - * input at position - * @return {openpgp_type_mpi} Object representation - */ - function read(input, position, len) { - var mypos = position; - - this.mpiBitLength = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); - - // Additional rules: - // - // The size of an MPI is ((MPI.length + 7) / 8) + 2 octets. - // - // The length field of an MPI describes the length starting from its - // most significant non-zero bit. Thus, the MPI [00 02 01] is not - // formed correctly. It should be [00 01 01]. - // TODO: Verification of this size method! This size calculation as - // specified above is not applicable in JavaScript - this.mpiByteLength = (this.mpiBitLength - (this.mpiBitLength % 8)) / 8; - if (this.mpiBitLength % 8 != 0) - this.mpiByteLength++; - - this.MPI = input.substring(mypos,mypos+this.mpiByteLength); - this.data = input.substring(position, position+2+this.mpiByteLength); - this.packetLength = this.mpiByteLength +2; - return this; - } - - /** - * Generates debug output (pretty print) - * @return {String} String which gives some information about the mpi - */ - function toString() { - var r = " MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x"; - r+=util.hexstrdump(this.MPI); - return r+'\n'; - } - - /** - * Converts the mpi to an BigInteger object - * @return {BigInteger} - */ - function getBigInteger() { - return new BigInteger(util.hexstrdump(this.MPI),16); - } +var BigInteger = require('../crypto/public_key/jsbn.js'), + util = require('../util'); - - function getBits(num) { - for (var i = 0; i < 9; i++) - if (num >> i == 0) - return i; - } - - /** - * Gets the length of the mpi in bytes - * @return {Integer} Mpi byte length - */ - function getByteLength() { - return this.mpiByteLength; - } - - /** - * Creates an mpi from the specified string - * @param {String} data Data to read the mpi from - * @return {openpgp_type_mpi} - */ - function create(data) { - this.MPI = data; - this.mpiBitLength = (data.length -1) *8 + getBits(data.charCodeAt(0)); - this.mpiByteLength = data.length; - return this; - } - - /** - * Converts the mpi object to a string as specified in RFC4880 3.2 - * @return {String} mpi Byte representation - */ - function toBin() { - var result = String.fromCharCode((this.mpiBitLength >> 8) & 0xFF); - result += String.fromCharCode(this.mpiBitLength & 0xFF); - result += this.MPI; - return result; - } - - this.read = read; - this.toBigInteger = getBigInteger; - this.toString = toString; - this.create = create; - this.toBin = toBin; - this.getByteLength = getByteLength; +/** + * @constructor + */ +module.exports = function mpi() { + /** An implementation dependent integer */ + this.data = null; + + /** + * Parsing function for a mpi (RFC 4880 3.2). + * @param {String} input Payload of mpi data + * @return {Integer} Length of data read + */ + this.read = function (bytes) { + var bits = (bytes.charCodeAt(0) << 8) | bytes.charCodeAt(1); + + // Additional rules: + // + // The size of an MPI is ((MPI.length + 7) / 8) + 2 octets. + // + // The length field of an MPI describes the length starting from its + // most significant non-zero bit. Thus, the MPI [00 02 01] is not + // formed correctly. It should be [00 01 01]. + + // TODO: Verification of this size method! This size calculation as + // specified above is not applicable in JavaScript + var bytelen = Math.ceil(bits / 8); + + var raw = bytes.substr(2, bytelen); + this.fromBytes(raw); + + return 2 + bytelen; + }; + + this.fromBytes = function (bytes) { + this.data = new BigInteger(util.hexstrdump(bytes), 16); + }; + + this.toBytes = function () { + return this.write().substr(2); + }; + + this.byteLength = function () { + return this.toBytes().length; + }; + + /** + * Converts the mpi object to a string as specified in RFC4880 3.2 + * @return {String} mpi Byte representation + */ + this.write = function () { + return this.data.toMPI(); + }; + + this.toBigInteger = function () { + return this.data.clone(); + }; + + this.fromBigInteger = function (bn) { + this.data = bn.clone(); + }; } +},{"../crypto/public_key/jsbn.js":21,"../util":56}],55:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -13072,129 +13681,170 @@ function openpgp_type_mpi() { // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @class - * @classdesc Implementation of the String-to-key specifier (RFC4880 3.7) + * Implementation of the String-to-key specifier (RFC4880 3.7)
      + *
      * String-to-key (S2K) specifiers are used to convert passphrase strings - into symmetric-key encryption/decryption keys. They are used in two - places, currently: to encrypt the secret part of private keys in the - private keyring, and to convert passphrases to encryption keys for - symmetrically encrypted messages. + * into symmetric-key encryption/decryption keys. They are used in two + * places, currently: to encrypt the secret part of private keys in the + * private keyring, and to convert passphrases to encryption keys for + * symmetrically encrypted messages. + * @requires crypto + * @requires enums + * @requires util + * @module type/s2k */ -function openpgp_type_s2k() { - /** - * Parsing function for a string-to-key specifier (RFC 4880 3.7). - * @param {String} input Payload of string-to-key specifier - * @param {Integer} position Position to start reading from the input string - * @return {openpgp_type_s2k} Object representation - */ - function read(input, position) { - var mypos = position; - this.type = input.charCodeAt(mypos++); - switch (this.type) { - case 0: // Simple S2K - // Octet 1: hash algorithm - this.hashAlgorithm = input.charCodeAt(mypos++); - this.s2kLength = 1; - break; - case 1: // Salted S2K - // Octet 1: hash algorithm - this.hashAlgorithm = input.charCodeAt(mypos++); +var enums = require('../enums.js'), + util = require('../util'), + crypto = require('../crypto'); - // Octets 2-9: 8-octet salt value - this.saltValue = input.substring(mypos, mypos+8); - mypos += 8; - this.s2kLength = 9; - break; +/** + * @constructor + */ +module.exports = function s2k() { + /** @type {module:enums.hash} */ + this.algorithm = 'sha256'; + /** @type {module:enums.s2k} */ + this.type = 'iterated'; + this.c = 96; + /** Eight bytes of salt in a binary string. + * @type {String} + */ + this.salt = crypto.random.getRandomBytes(8); - case 3: // Iterated and Salted S2K - // Octet 1: hash algorithm - this.hashAlgorithm = input.charCodeAt(mypos++); - // Octets 2-9: 8-octet salt value - this.saltValue = input.substring(mypos, mypos+8); - mypos += 8; + // Exponent bias, defined in RFC4880 + var expbias = 6; - // Octet 10: count, a one-octet, coded value - this.EXPBIAS = 6; - var c = input.charCodeAt(mypos++); - this.count = (16 + (c & 15)) << ((c >> 4) + this.EXPBIAS); - this.s2kLength = 10; - break; + this.get_count = function () { + return (16 + (this.c & 15)) << ((this.c >> 4) + expbias); + }; - case 101: - if(input.substring(mypos+1, mypos+4) == "GNU") { - this.hashAlgorithm = input.charCodeAt(mypos++); - mypos += 3; // GNU - var gnuExtType = 1000 + input.charCodeAt(mypos++); - if(gnuExtType == 1001) { - this.type = gnuExtType; - this.s2kLength = 5; - // GnuPG extension mode 1001 -- don't write secret key at all - } else { - util.print_error("unknown s2k gnu protection mode! "+this.type); - } - } else { - util.print_error("unknown s2k type! "+this.type); - } - break; + /** + * Parsing function for a string-to-key specifier (RFC 4880 3.7). + * @param {String} input Payload of string-to-key specifier + * @return {Integer} Actual length of the object + */ + this.read = function (bytes) { + var i = 0; + this.type = enums.read(enums.s2k, bytes.charCodeAt(i++)); + this.algorithm = enums.read(enums.hash, bytes.charCodeAt(i++)); - case 2: // Reserved value - default: - util.print_error("unknown s2k type! "+this.type); - break; - } - return this; - } - - - /** - * writes an s2k hash based on the inputs. - * @return {String} Produced key of hashAlgorithm hash length - */ - function write(type, hash, passphrase, salt, c){ - this.type = type; - if(this.type == 3){this.saltValue = salt; - this.hashAlgorithm = hash; - this.count = (16 + (c & 15)) << ((c >> 4) + 6); - this.s2kLength = 10; - } - return this.produce_key(passphrase); - } + switch (this.type) { + case 'simple': + break; - /** - * Produces a key using the specified passphrase and the defined - * hashAlgorithm - * @param {String} passphrase Passphrase containing user input - * @return {String} Produced key with a length corresponding to - * hashAlgorithm hash length - */ - function produce_key(passphrase, numBytes) { - passphrase = util.encode_utf8(passphrase); - if (this.type == 0) { - return openpgp_crypto_hashData(this.hashAlgorithm,passphrase); - } else if (this.type == 1) { - return openpgp_crypto_hashData(this.hashAlgorithm,this.saltValue+passphrase); - } else if (this.type == 3) { - var isp = []; - isp[0] = this.saltValue+passphrase; - while (isp.length*(this.saltValue+passphrase).length < this.count) - isp.push(this.saltValue+passphrase); - isp = isp.join(''); - if (isp.length > this.count) - isp = isp.substr(0, this.count); - if(numBytes && (numBytes == 24 || numBytes == 32)){ //This if accounts for RFC 4880 3.7.1.1 -- If hash size is greater than block size, use leftmost bits. If blocksize larger than hash size, we need to rehash isp and prepend with 0. - var key = openpgp_crypto_hashData(this.hashAlgorithm,isp); - return key + openpgp_crypto_hashData(this.hashAlgorithm,String.fromCharCode(0)+isp); - } - return openpgp_crypto_hashData(this.hashAlgorithm,isp); - } else return null; - } - - this.read = read; - this.write = write; - this.produce_key = produce_key; -} + case 'salted': + this.salt = bytes.substr(i, 8); + i += 8; + break; + + case 'iterated': + this.salt = bytes.substr(i, 8); + i += 8; + + // Octet 10: count, a one-octet, coded value + this.c = bytes.charCodeAt(i++); + break; + + case 'gnu': + if (bytes.substr(i, 3) == "GNU") { + i += 3; // GNU + var gnuExtType = 1000 + bytes.charCodeAt(i++); + if (gnuExtType == 1001) { + this.type = gnuExtType; + // GnuPG extension mode 1001 -- don't write secret key at all + } else { + throw new Error("Unknown s2k gnu protection mode."); + } + } else { + throw new Error("Unknown s2k type."); + } + break; + + default: + throw new Error("Unknown s2k type."); + break; + } + + return i; + }; + + + /** + * writes an s2k hash based on the inputs. + * @return {String} Produced key of hashAlgorithm hash length + */ + this.write = function () { + var bytes = String.fromCharCode(enums.write(enums.s2k, this.type)); + bytes += String.fromCharCode(enums.write(enums.hash, this.algorithm)); + + switch (this.type) { + case 'simple': + break; + case 'salted': + bytes += this.salt; + break; + case 'iterated': + bytes += this.salt; + bytes += String.fromCharCode(this.c); + break; + } + + return bytes; + }; + + /** + * Produces a key using the specified passphrase and the defined + * hashAlgorithm + * @param {String} passphrase Passphrase containing user input + * @return {String} Produced key with a length corresponding to + * hashAlgorithm hash length + */ + this.produce_key = function (passphrase, numBytes) { + passphrase = util.encode_utf8(passphrase); + + function round(prefix, s2k) { + var algorithm = enums.write(enums.hash, s2k.algorithm); + + switch (s2k.type) { + case 'simple': + return crypto.hash.digest(algorithm, prefix + passphrase); + + case 'salted': + return crypto.hash.digest(algorithm, + prefix + s2k.salt + passphrase); + + case 'iterated': + var isp = [], + count = s2k.get_count(); + data = s2k.salt + passphrase; + + while (isp.length * data.length < count) + isp.push(data); + + isp = isp.join(''); + + if (isp.length > count) + isp = isp.substr(0, count); + + return crypto.hash.digest(algorithm, prefix + isp); + } + } + + var result = '', + prefix = ''; + + while (result.length <= numBytes) { + result += round(prefix, this); + prefix += String.fromCharCode(0); + } + + return result.substr(0, numBytes); + }; +}; + +},{"../crypto":16,"../enums.js":27,"../util":56}],56:[function(require,module,exports){ // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -13212,317 +13862,294 @@ function openpgp_type_s2k() { // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -var Util = function() { +/** + * This object contains utility functions + * @requires config + * @module util/util + */ - this.emailRegEx = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; - - this.hexdump = function(str) { - var r=[]; - var e=str.length; - var c=0; - var h; - var i = 0; - while(c> (8 * (bytes - i - 1))) & 0xFF); + } + + return b; + }, + + readDate: function (bytes) { + var n = this.readNumber(bytes); + var d = new Date(); + d.setTime(n * 1000); + return d; + }, + + writeDate: function (time) { + var numeric = Math.round(time.getTime() / 1000); + + return this.writeNumber(numeric, 4); + }, + + emailRegEx: /^[+a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,6}$/, + + hexdump: function (str) { + var r = []; + var e = str.length; + var c = 0; + var h; + var i = 0; + while (c < e) { + h = str.charCodeAt(c++).toString(16); + while (h.length < 2) h = "0" + h; + r.push(" " + h); + i++; + if (i % 32 == 0) + r.push("\n "); + } + return r.join(''); + }, + + /** + * Create hexstring from a binary + * @param {String} str String to convert + * @return {String} String containing the hexadecimal values + */ + hexstrdump: function (str) { + if (str == null) + return ""; + var r = []; + var e = str.length; + var c = 0; + var h; + while (c < e) { + h = str.charCodeAt(c++).toString(16); + while (h.length < 2) h = "0" + h; + r.push("" + h); + } + return r.join(''); + }, + + /** + * Create binary string from a hex encoded string + * @param {String} str Hex string to convert + * @return {String} String containing the binary values + */ + hex2bin: function (hex) { + var str = ''; + for (var i = 0; i < hex.length; i += 2) + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + return str; + }, + + /** + * Creating a hex string from an binary array of integers (0..255) + * @param {String} str Array of bytes to convert + * @return {String} Hexadecimal representation of the array + */ + hexidump: function (str) { + var r = []; + var e = str.length; + var c = 0; + var h; + while (c < e) { + h = str[c++].toString(16); + while (h.length < 2) h = "0" + h; + r.push("" + h); + } + return r.join(''); + }, - /** - * Convert a native javascript string to a string of utf8 bytes - * @param {String} str The string to convert - * @return {String} A valid squence of utf8 bytes - */ - this.encode_utf8 = function(str) { - return unescape(encodeURIComponent(str)); - }; + /** + * Convert a native javascript string to a string of utf8 bytes + * @param {String} str The string to convert + * @return {String} A valid squence of utf8 bytes + */ + encode_utf8: function (str) { + return unescape(encodeURIComponent(str)); + }, - /** - * Convert a string of utf8 bytes to a native javascript string - * @param {String} utf8 A valid squence of utf8 bytes - * @return {String} A native javascript string - */ - this.decode_utf8 = function(utf8) { - try { + /** + * Convert a string of utf8 bytes to a native javascript string + * @param {String} utf8 A valid squence of utf8 bytes + * @return {String} A native javascript string + */ + decode_utf8: function (utf8) { + try { return decodeURIComponent(escape(utf8)); } catch (e) { return utf8; } - }; + }, - var str2bin = function(str, result) { - for (var i = 0; i < str.length; i++) { - result[i] = str.charCodeAt(i); - } + /** + * Convert an array of integers(0.255) to a string + * @param {Array} bin An array of (binary) integers to convert + * @return {String} The string representation of the array + */ + bin2str: function (bin) { + var result = []; - return result; - }; - - var bin2str = function(bin) { - var result = []; + for (var i = 0; i < bin.length; i++) { + result.push(String.fromCharCode(bin[i])); + } - for (var i = 0; i < bin.length; i++) { - result.push(String.fromCharCode(bin[i])); - } + return result.join(''); + }, - return result.join(''); - }; + _str2bin: function (str, result) { + for (var i = 0; i < str.length; i++) { + result[i] = str.charCodeAt(i); + } - /** - * Convert a string to an array of integers(0.255) - * @param {String} str String to convert - * @return {Integer[]} An array of (binary) integers - */ - this.str2bin = function(str) { - return str2bin(str, new Array(str.length)); - }; - - - /** - * Convert an array of integers(0.255) to a string - * @param {Integer[]} bin An array of (binary) integers to convert - * @return {String} The string representation of the array - */ - this.bin2str = bin2str; - - /** - * Convert a string to a Uint8Array - * @param {String} str String to convert - * @return {Uint8Array} The array of (binary) integers - */ - this.str2Uint8Array = function(str) { - return str2bin(str, new Uint8Array(new ArrayBuffer(str.length))); - }; - - /** - * Convert a Uint8Array to a string. This currently functions - * the same as bin2str. - * @param {Uint8Array} bin An array of (binary) integers to convert - * @return {String} String representation of the array - */ - this.Uint8Array2str = bin2str; - - /** - * Calculates a 16bit sum of a string by adding each character - * codes modulus 65535 - * @param {String} text String to create a sum of - * @return {Integer} An integer containing the sum of all character - * codes % 65535 - */ - this.calc_checksum = function(text) { - var checksum = { s: 0, add: function (sadd) { this.s = (this.s + sadd) % 65536; }}; - for (var i = 0; i < text.length; i++) { - checksum.add(text.charCodeAt(i)); - } - return checksum.s; - }; - - this.printLevel = { error: 1, warning: 2, info: 3, debug: 4 }; + return result; + }, - /** - * Helper function to print a debug message. Debug - * messages are only printed if - * openpgp.config.debug is set to true. The calling - * Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      ' - * @param {String} str String of the debug message - * @return {String} An HTML tt entity containing a paragraph with a - * style attribute where the debug message is HTMLencoded in. - */ - this.print_debug = function(str) { - if (openpgp.config.debug) { - this.print_output(this.printLevel.debug, str); - } - }; - - /** - * Helper function to print a debug message. Debug - * messages are only printed if - * openpgp.config.debug is set to true. The calling - * Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      ' - * Different than print_debug because will call hexstrdump iff necessary. - * @param {String} str String of the debug message - * @return {String} An HTML tt entity containing a paragraph with a - * style attribute where the debug message is HTMLencoded in. - */ - this.print_debug_hexstr_dump = function(str,strToHex) { - if (openpgp.config.debug) { - str = str + this.hexstrdump(strToHex); - this.print_output(this.printLevel.debug, str); - } - }; - - /** - * Helper function to print an error message. - * The calling Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      ' - * @param {String} str String of the error message - * @return {String} A HTML paragraph entity with a style attribute - * containing the HTML encoded error message - */ - this.print_error = function(str) { - this.print_output(this.printLevel.error, str); - }; - - /** - * Helper function to print an info message. - * The calling Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      '. - * @param {String} str String of the info message - * @return {String} A HTML paragraph entity with a style attribute - * containing the HTML encoded info message - */ - this.print_info = function(str) { - this.print_output(this.printLevel.info, str); - }; - - this.print_warning = function(str) { - this.print_output(this.printLevel.warning, str); - }; - - this.print_output = function(level, str) { - var html; - str = openpgp_encoding_html_encode(str).replace(/\n/g,"
      "); - if (level == this.printLevel.debug) { - html = "

      "+str+"

      "; - } else { - var color, heading; - switch (level) { - case this.printLevel.error: - color = "FF8888"; - heading = "ERROR"; - break; - case this.printLevel.warning: - color = 'FFAA88'; - heading = "WARNING"; - break; - case this.printLevel.info: - color = '88FF88'; - heading = 'INFO'; - break; - } - html = "

      "+heading+":"+str+"

      "; - } - showMessages(html); - } + /** + * Convert a string to an array of integers(0.255) + * @param {String} str String to convert + * @return {Array} An array of (binary) integers + */ + str2bin: function (str) { + return this._str2bin(str, new Array(str.length)); + }, - this.getLeftNBits = function (string, bitcount) { - var rest = bitcount % 8; - if (rest == 0) - return string.substring(0, bitcount / 8); - var bytes = (bitcount - rest) / 8 +1; - var result = string.substring(0, bytes); - return this.shiftRight(result, 8-rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF); - }; - /** - * Shifting a string to n bits right - * @param {String} value The string to shift - * @param {Integer} bitcount Amount of bits to shift (MUST be smaller - * than 9) - * @return {String} Resulting string. - */ - this.shiftRight = function(value, bitcount) { - var temp = util.str2bin(value); - if (bitcount % 8 != 0) { - for (var i = temp.length-1; i >= 0; i--) { - temp[i] >>= bitcount % 8; - if (i > 0) - temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF; - } - } else { - return value; - } - return util.bin2str(temp); - }; - - /** - * Return the algorithm type as string - * @return {String} String representing the message type - */ - this.get_hashAlgorithmString = function(algo) { - switch(algo) { - case 1: - return "MD5"; - case 2: - return "SHA1"; - case 3: - return "RIPEMD160"; - case 8: - return "SHA256"; - case 9: - return "SHA384"; - case 10: - return "SHA512"; - case 11: - return "SHA224"; - } - return "unknown"; - }; + /** + * Convert a string to a Uint8Array + * @param {String} str String to convert + * @return {Uint8Array} The array of (binary) integers + */ + str2Uint8Array: function (str) { + return this._str2bin(str, new Uint8Array(new ArrayBuffer(str.length))); + }, + + /** + * Convert a Uint8Array to a string. This currently functions + * the same as bin2str. + * @function module:util/util.Uint8Array2str + * @param {Uint8Array} bin An array of (binary) integers to convert + * @return {String} String representation of the array + */ + Uint8Array2str: function (bin) { + return this.bin2str(bin); + }, + + /** + * Calculates a 16bit sum of a string by adding each character + * codes modulus 65535 + * @param {String} text String to create a sum of + * @return {Integer} An integer containing the sum of all character + * codes % 65535 + */ + calc_checksum: function (text) { + var checksum = { + s: 0, + add: function (sadd) { + this.s = (this.s + sadd) % 65536; + } + }; + for (var i = 0; i < text.length; i++) { + checksum.add(text.charCodeAt(i)); + } + return checksum.s; + }, + + /** + * Helper function to print a debug message. Debug + * messages are only printed if + * @link module:config/config.debug is set to true. + * @param {String} str String of the debug message + */ + print_debug: function (str) { + if (config.debug) { + console.log(str); + } + }, + + /** + * Helper function to print a debug message. Debug + * messages are only printed if + * @link module:config/config.debug is set to true. + * Different than print_debug because will call hexstrdump iff necessary. + * @param {String} str String of the debug message + */ + print_debug_hexstr_dump: function (str, strToHex) { + if (config.debug) { + str = str + this.hexstrdump(strToHex); + console.log(str); + } + }, + + getLeftNBits: function (string, bitcount) { + var rest = bitcount % 8; + if (rest == 0) + return string.substring(0, bitcount / 8); + var bytes = (bitcount - rest) / 8 + 1; + var result = string.substring(0, bytes); + return this.shiftRight(result, 8 - rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF); + }, + + /** + * Shifting a string to n bits right + * @param {String} value The string to shift + * @param {Integer} bitcount Amount of bits to shift (MUST be smaller + * than 9) + * @return {String} Resulting string. + */ + shiftRight: function (value, bitcount) { + var temp = util.str2bin(value); + if (bitcount % 8 != 0) { + for (var i = temp.length - 1; i >= 0; i--) { + temp[i] >>= bitcount % 8; + if (i > 0) + temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF; + } + } else { + return value; + } + return util.bin2str(temp); + }, + + /** + * Return the algorithm type as string + * @return {String} String representing the message type + */ + get_hashAlgorithmString: function (algo) { + switch (algo) { + case 1: + return "MD5"; + case 2: + return "SHA1"; + case 3: + return "RIPEMD160"; + case 8: + return "SHA256"; + case 9: + return "SHA384"; + case 10: + return "SHA512"; + case 11: + return "SHA224"; + } + return "unknown"; + } }; -/** - * an instance that should be used. - */ -var util = new Util(); +},{"../config":3}]},{},[]) +//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2NsZWFydGV4dC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY29tcHJlc3Npb24vanhnLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jb25maWcvY29uZmlnLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jcnlwdG8vY2ZiLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jcnlwdG8vY2lwaGVyL2Flcy5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL2NpcGhlci9ibG93ZmlzaC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL2NpcGhlci9jYXN0NS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL2NpcGhlci9kZXMuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2NyeXB0by9jaXBoZXIvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2NyeXB0by9jaXBoZXIvdHdvZmlzaC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL2NyeXB0by5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL2hhc2gvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2NyeXB0by9oYXNoL21kNS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL2hhc2gvcmlwZS1tZC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL2hhc2gvc2hhLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jcnlwdG8vaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2NyeXB0by9wa2NzMS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL3B1YmxpY19rZXkvZHNhLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jcnlwdG8vcHVibGljX2tleS9lbGdhbWFsLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jcnlwdG8vcHVibGljX2tleS9pbmRleC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL3B1YmxpY19rZXkvanNibi5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvY3J5cHRvL3B1YmxpY19rZXkvcnNhLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jcnlwdG8vcmFuZG9tLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9jcnlwdG8vc2lnbmF0dXJlLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9lbmNvZGluZy9hcm1vci5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvZW5jb2RpbmcvYmFzZTY0LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9lbnVtcy5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL2tleS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvbWVzc2FnZS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvb3BlbnBncC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L2FsbF9wYWNrZXRzLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9wYWNrZXQvY29tcHJlc3NlZC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L2luZGV4LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9wYWNrZXQvbGl0ZXJhbC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L21hcmtlci5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L29uZV9wYXNzX3NpZ25hdHVyZS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L3BhY2tldC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L3BhY2tldGxpc3QuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL3BhY2tldC9wdWJsaWNfa2V5LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9wYWNrZXQvcHVibGljX2tleV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXkuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL3BhY2tldC9wdWJsaWNfc3Via2V5LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9wYWNrZXQvc2VjcmV0X2tleS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L3NlY3JldF9zdWJrZXkuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL3BhY2tldC9zaWduYXR1cmUuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL3BhY2tldC9zeW1fZW5jcnlwdGVkX2ludGVncml0eV9wcm90ZWN0ZWQuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL3BhY2tldC9zeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9wYWNrZXQvc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL3BhY2tldC90cnVzdC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvcGFja2V0L3VzZXJfYXR0cmlidXRlLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy9wYWNrZXQvdXNlcmlkLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy90eXBlL2tleWlkLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWRldmVsL3NyYy90eXBlL21waS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1kZXZlbC9zcmMvdHlwZS9zMmsuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMtZGV2ZWwvc3JjL3V0aWwvdXRpbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbnZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzU0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN2xCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3paQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9OQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNybUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlxREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzl2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1VEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaG9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQHJlcXVpcmVzIGNvbmZpZ1xuICogQHJlcXVpcmVzIGVuY29kaW5nL2FybW9yXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEByZXF1aXJlcyBwYWNrZXRcbiAqIEBtb2R1bGUgY2xlYXJ0ZXh0XG4gKi9cblxudmFyIGNvbmZpZyA9IHJlcXVpcmUoJy4vY29uZmlnJyksXG4gIHBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0JyksXG4gIGVudW1zID0gcmVxdWlyZSgnLi9lbnVtcy5qcycpLFxuICBhcm1vciA9IHJlcXVpcmUoJy4vZW5jb2RpbmcvYXJtb3IuanMnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgQ2xhc3MgdGhhdCByZXByZXNlbnRzIGFuIE9wZW5QR1AgY2xlYXJ0ZXh0IHNpZ25lZCBtZXNzYWdlLlxuICogU2VlIGh0dHA6Ly90b29scy5pZXRmLm9yZy9odG1sL3JmYzQ4ODAjc2VjdGlvbi03XG4gKiBAcGFyYW0gIHtTdHJpbmd9ICAgICB0ZXh0ICAgICAgIFRoZSBjbGVhcnRleHQgb2YgdGhlIHNpZ25lZCBtZXNzYWdlXG4gKiBAcGFyYW0gIHttb2R1bGU6cGFja2V0L3BhY2tldGxpc3R9IHBhY2tldGxpc3QgVGhlIHBhY2tldGxpc3Qgd2l0aCBzaWduYXR1cmUgcGFja2V0cyBvciB1bmRlZmluZWRcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgbWVzc2FnZSBub3QgeWV0IHNpZ25lZFxuICovXG5cbmZ1bmN0aW9uIENsZWFydGV4dE1lc3NhZ2UodGV4dCwgcGFja2V0bGlzdCkge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgQ2xlYXJ0ZXh0TWVzc2FnZSkpIHtcbiAgICByZXR1cm4gbmV3IENsZWFydGV4dE1lc3NhZ2UocGFja2V0bGlzdCk7XG4gIH1cbiAgLy8gbm9ybWFsaXplIEVPTCB0byBjYW5vbmljYWwgZm9ybSA8Q1I+PExGPlxuICB0aGlzLnRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcci9nLCAnJykucmVwbGFjZSgvW1xcdCBdK1xcbi9nLCBcIlxcblwiKS5yZXBsYWNlKC9cXG4vZyxcIlxcclxcblwiKTtcbiAgdGhpcy5wYWNrZXRzID0gcGFja2V0bGlzdCB8fCBuZXcgcGFja2V0Lmxpc3QoKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBrZXkgSURzIG9mIHRoZSBrZXlzIHRoYXQgc2lnbmVkIHRoZSBjbGVhcnRleHQgbWVzc2FnZVxuICogQHJldHVybiB7QXJyYXk8bW9kdWxlOnR5cGUva2V5aWQ+fSBhcnJheSBvZiBrZXlpZCBvYmplY3RzXG4gKi9cbkNsZWFydGV4dE1lc3NhZ2UucHJvdG90eXBlLmdldFNpZ25pbmdLZXlJZHMgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGtleUlkcyA9IFtdO1xuICB2YXIgc2lnbmF0dXJlTGlzdCA9IHRoaXMucGFja2V0cy5maWx0ZXJCeVRhZyhlbnVtcy5wYWNrZXQuc2lnbmF0dXJlKTtcbiAgc2lnbmF0dXJlTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKHBhY2tldCkge1xuICAgIGtleUlkcy5wdXNoKHBhY2tldC5pc3N1ZXJLZXlJZCk7XG4gIH0pO1xuICByZXR1cm4ga2V5SWRzO1xufTtcblxuLyoqXG4gKiBTaWduIHRoZSBjbGVhcnRleHQgbWVzc2FnZVxuICogQHBhcmFtICB7QXJyYXk8bW9kdWxlOmtleX5LZXk+fSBwcml2YXRlS2V5cyBwcml2YXRlIGtleXMgd2l0aCBkZWNyeXB0ZWQgc2VjcmV0IGtleSBkYXRhIGZvciBzaWduaW5nXG4gKi9cbkNsZWFydGV4dE1lc3NhZ2UucHJvdG90eXBlLnNpZ24gPSBmdW5jdGlvbihwcml2YXRlS2V5cykge1xuICB2YXIgcGFja2V0bGlzdCA9IG5ldyBwYWNrZXQubGlzdCgpOyAgXG4gIHZhciBsaXRlcmFsRGF0YVBhY2tldCA9IG5ldyBwYWNrZXQubGl0ZXJhbCgpO1xuICBsaXRlcmFsRGF0YVBhY2tldC5zZXRUZXh0KHRoaXMudGV4dCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgcHJpdmF0ZUtleXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgc2lnbmF0dXJlUGFja2V0ID0gbmV3IHBhY2tldC5zaWduYXR1cmUoKTtcbiAgICBzaWduYXR1cmVQYWNrZXQuc2lnbmF0dXJlVHlwZSA9IGVudW1zLnNpZ25hdHVyZS50ZXh0O1xuICAgIHNpZ25hdHVyZVBhY2tldC5oYXNoQWxnb3JpdGhtID0gY29uZmlnLnByZWZlcl9oYXNoX2FsZ29yaXRobTtcbiAgICB2YXIgc2lnbmluZ0tleVBhY2tldCA9IHByaXZhdGVLZXlzW2ldLmdldFNpZ25pbmdLZXlQYWNrZXQoKTtcbiAgICBzaWduYXR1cmVQYWNrZXQucHVibGljS2V5QWxnb3JpdGhtID0gc2lnbmluZ0tleVBhY2tldC5hbGdvcml0aG07XG4gICAgaWYgKCFzaWduaW5nS2V5UGFja2V0LmlzRGVjcnlwdGVkKSB0aHJvdyBuZXcgRXJyb3IoJ1ByaXZhdGUga2V5IGlzIG5vdCBkZWNyeXB0ZWQuJyk7XG4gICAgc2lnbmF0dXJlUGFja2V0LnNpZ24oc2lnbmluZ0tleVBhY2tldCwgbGl0ZXJhbERhdGFQYWNrZXQpO1xuICAgIHBhY2tldGxpc3QucHVzaChzaWduYXR1cmVQYWNrZXQpO1xuICB9XG4gIHRoaXMucGFja2V0cyA9IHBhY2tldGxpc3Q7XG59O1xuXG4vKipcbiAqIFZlcmlmeSBzaWduYXR1cmVzIG9mIGNsZWFydGV4dCBzaWduZWQgbWVzc2FnZVxuICogQHBhcmFtIHtBcnJheTxtb2R1bGU6a2V5fktleT59IHB1YmxpY0tleXMgcHVibGljIGtleXMgdG8gdmVyaWZ5IHNpZ25hdHVyZXNcbiAqIEByZXR1cm4ge0FycmF5PHtrZXlpZDogbW9kdWxlOnR5cGUva2V5aWQsIHZhbGlkOiBCb29sZWFufT59IGxpc3Qgb2Ygc2lnbmVyJ3Mga2V5aWQgYW5kIHZhbGlkaXR5IG9mIHNpZ25hdHVyZVxuICovXG5DbGVhcnRleHRNZXNzYWdlLnByb3RvdHlwZS52ZXJpZnkgPSBmdW5jdGlvbihwdWJsaWNLZXlzKSB7XG4gIHZhciByZXN1bHQgPSBbXTtcbiAgdmFyIHNpZ25hdHVyZUxpc3QgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnNpZ25hdHVyZSk7XG4gIHZhciBsaXRlcmFsRGF0YVBhY2tldCA9IG5ldyBwYWNrZXQubGl0ZXJhbCgpO1xuICAvLyB3ZSBhc3N1bWUgdGhhdCBjbGVhcnRleHQgc2lnbmF0dXJlIGlzIGdlbmVyYXRlZCBiYXNlZCBvbiBVVEY4IGNsZWFydGV4dFxuICBsaXRlcmFsRGF0YVBhY2tldC5zZXRUZXh0KHRoaXMudGV4dCk7XG4gIHB1YmxpY0tleXMuZm9yRWFjaChmdW5jdGlvbihwdWJLZXkpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpZ25hdHVyZUxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBwdWJsaWNLZXlQYWNrZXQgPSBwdWJLZXkuZ2V0UHVibGljS2V5UGFja2V0KFtzaWduYXR1cmVMaXN0W2ldLmlzc3VlcktleUlkXSk7XG4gICAgICBpZiAocHVibGljS2V5UGFja2V0KSB7XG4gICAgICAgIHZhciB2ZXJpZmllZFNpZyA9IHt9O1xuICAgICAgICB2ZXJpZmllZFNpZy5rZXlpZCA9IHNpZ25hdHVyZUxpc3RbaV0uaXNzdWVyS2V5SWQ7XG4gICAgICAgIHZlcmlmaWVkU2lnLnZhbGlkID0gc2lnbmF0dXJlTGlzdFtpXS52ZXJpZnkocHVibGljS2V5UGFja2V0LCBsaXRlcmFsRGF0YVBhY2tldCk7XG4gICAgICAgIHJlc3VsdC5wdXNoKHZlcmlmaWVkU2lnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8qKlxuICogR2V0IGNsZWFydGV4dFxuICogQHJldHVybiB7U3RyaW5nfSBjbGVhcnRleHQgb2YgbWVzc2FnZVxuICovXG5DbGVhcnRleHRNZXNzYWdlLnByb3RvdHlwZS5nZXRUZXh0ID0gZnVuY3Rpb24oKSB7XG4gIC8vIG5vcm1hbGl6ZSBlbmQgb2YgbGluZSB0byBcXG5cbiAgcmV0dXJuIHRoaXMudGV4dC5yZXBsYWNlKC9cXHJcXG4vZyxcIlxcblwiKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBBU0NJSSBhcm1vcmVkIHRleHQgb2YgY2xlYXJ0ZXh0IHNpZ25lZCBtZXNzYWdlXG4gKiBAcmV0dXJuIHtTdHJpbmd9IEFTQ0lJIGFybW9yXG4gKi9cbkNsZWFydGV4dE1lc3NhZ2UucHJvdG90eXBlLmFybW9yID0gZnVuY3Rpb24oKSB7XG4gIHZhciBib2R5ID0ge1xuICAgIGhhc2g6IGVudW1zLnJlYWQoZW51bXMuaGFzaCwgY29uZmlnLnByZWZlcl9oYXNoX2FsZ29yaXRobSkudG9VcHBlckNhc2UoKSxcbiAgICB0ZXh0OiB0aGlzLnRleHQsXG4gICAgZGF0YTogdGhpcy5wYWNrZXRzLndyaXRlKClcbiAgfVxuICByZXR1cm4gYXJtb3IuZW5jb2RlKGVudW1zLmFybW9yLnNpZ25lZCwgYm9keSk7XG59O1xuXG5cbi8qKlxuICogcmVhZHMgYW4gT3BlblBHUCBjbGVhcnRleHQgc2lnbmVkIG1lc3NhZ2UgYW5kIHJldHVybnMgYSBDbGVhcnRleHRNZXNzYWdlIG9iamVjdFxuICogQHBhcmFtIHtTdHJpbmd9IGFybW9yZWRUZXh0IHRleHQgdG8gYmUgcGFyc2VkXG4gKiBAcmV0dXJuIHttb2R1bGU6Y2xlYXJ0ZXh0fkNsZWFydGV4dE1lc3NhZ2V9IG5ldyBjbGVhcnRleHQgbWVzc2FnZSBvYmplY3RcbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gcmVhZEFybW9yZWQoYXJtb3JlZFRleHQpIHtcbiAgdmFyIGlucHV0ID0gYXJtb3IuZGVjb2RlKGFybW9yZWRUZXh0KTtcbiAgaWYgKGlucHV0LnR5cGUgIT09IGVudW1zLmFybW9yLnNpZ25lZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignTm8gY2xlYXJ0ZXh0IHNpZ25lZCBtZXNzYWdlLicpO1xuICB9XG4gIHZhciBwYWNrZXRsaXN0ID0gbmV3IHBhY2tldC5saXN0KCk7XG4gIHBhY2tldGxpc3QucmVhZChpbnB1dC5kYXRhKTtcbiAgdmFyIG5ld01lc3NhZ2UgPSBuZXcgQ2xlYXJ0ZXh0TWVzc2FnZShpbnB1dC50ZXh0LCBwYWNrZXRsaXN0KTtcbiAgcmV0dXJuIG5ld01lc3NhZ2U7XG59XG5cbmV4cG9ydHMuQ2xlYXJ0ZXh0TWVzc2FnZSA9IENsZWFydGV4dE1lc3NhZ2U7XG5leHBvcnRzLnJlYWRBcm1vcmVkID0gcmVhZEFybW9yZWQ7XG4iLCJKWEcgPSB7XG4gIGV4aXN0czogKGZ1bmN0aW9uKHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBmdW5jdGlvbih2KSB7XG4gICAgICByZXR1cm4gISh2ID09PSB1bmRlZmluZWQgfHwgdiA9PT0gbnVsbCk7XG4gICAgfVxuICB9KSgpXG59O1xuSlhHLmRlY29tcHJlc3MgPSBmdW5jdGlvbihzdHIpIHtcbiAgcmV0dXJuIHVuZXNjYXBlKChuZXcgSlhHLlV0aWwuVW56aXAoSlhHLlV0aWwuQmFzZTY0LmRlY29kZUFzQXJyYXkoc3RyKSkpLnVuemlwKClbMF1bMF0pO1xufTtcbi8qXG4gICAgQ29weXJpZ2h0IDIwMDgtMjAxMlxuICAgICAgICBNYXR0aGlhcyBFaG1hbm4sXG4gICAgICAgIE1pY2hhZWwgR2VyaGFldXNlcixcbiAgICAgICAgQ2Fyc3RlbiBNaWxsZXIsXG4gICAgICAgIEJpYW5jYSBWYWxlbnRpbixcbiAgICAgICAgQWxmcmVkIFdhc3Nlcm1hbm4sXG4gICAgICAgIFBldGVyIFdpbGZhaHJ0XG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBKU1hHcmFwaC5cbiAgICBcbiAgICBEdWFsIGxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSBWZXJzaW9uIDIuMCwgb3IgTEdQTCBWZXJzaW9uIDMgbGljZW5zZXMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIEpTWENvbXByZXNzb3IuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4gICAgXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgQXBhY2hlIExpY2Vuc2UgYWxvbmcgd2l0aCBKU1hDb21wcmVzc29yLiAgXG4gICAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy8+LlxuXG4qL1xuXG4vKipcbiAqIEBjbGFzcyBVdGlsIGNsYXNzXG4gKiBAY2xhc3NkZXNjIFV0aWxpdGllcyBmb3IgdW5jb21wcmVzc2luZyBhbmQgYmFzZTY0IGRlY29kaW5nXG4gKiBDbGFzcyBmb3IgZ3VuemlwcGluZywgdW56aXBwaW5nIGFuZCBiYXNlNjQgZGVjb2Rpbmcgb2YgZmlsZXMuXG4gKiBJdCBpcyB1c2VkIGZvciByZWFkaW5nIEdFT05FeFQsIEdlb2dlYnJhIGFuZCBJbnRlcmdlbyBmaWxlcy5cbiAqXG4gKiBPbmx5IEh1ZmZtYW4gY29kZXMgYXJlIGRlY29kZWQgaW4gZ3VuemlwLlxuICogVGhlIGNvZGUgaXMgYmFzZWQgb24gdGhlIHNvdXJjZSBjb2RlIGZvciBndW56aXAuYyBieSBQYXNpIE9qYWxhIFxuICoge0BsaW5rIGh0dHA6Ly93d3cuY3MudHV0LmZpL35hbGJlcnQvRGV2L2d1bnppcC9ndW56aXAuY31cbiAqIHtAbGluayBodHRwOi8vd3d3LmNzLnR1dC5maS9+YWxiZXJ0fVxuICovXG5KWEcuVXRpbCA9IHt9O1xuXG4vKipcbiAqIFVuemlwIHppcCBmaWxlc1xuICovXG5KWEcuVXRpbC5VbnppcCA9IGZ1bmN0aW9uKGJhcnJheSkge1xuICB2YXIgb3V0cHV0QXJyID0gW10sXG4gICAgb3V0cHV0ID0gXCJcIixcbiAgICBkZWJ1ZyA9IGZhbHNlLFxuICAgIGdwZmxhZ3MsXG4gICAgZmlsZXMgPSAwLFxuICAgIHVuemlwcGVkID0gW10sXG4gICAgY3JjLFxuICAgIGJ1ZjMyayA9IG5ldyBBcnJheSgzMjc2OCksXG4gICAgYklkeCA9IDAsXG4gICAgbW9kZVpJUCA9IGZhbHNlLFxuXG4gICAgQ1JDLCBTSVpFLFxuXG4gICAgYml0UmV2ZXJzZSA9IFtcbiAgICAgICAgMHgwMCwgMHg4MCwgMHg0MCwgMHhjMCwgMHgyMCwgMHhhMCwgMHg2MCwgMHhlMCxcbiAgICAgICAgMHgxMCwgMHg5MCwgMHg1MCwgMHhkMCwgMHgzMCwgMHhiMCwgMHg3MCwgMHhmMCxcbiAgICAgICAgMHgwOCwgMHg4OCwgMHg0OCwgMHhjOCwgMHgyOCwgMHhhOCwgMHg2OCwgMHhlOCxcbiAgICAgICAgMHgxOCwgMHg5OCwgMHg1OCwgMHhkOCwgMHgzOCwgMHhiOCwgMHg3OCwgMHhmOCxcbiAgICAgICAgMHgwNCwgMHg4NCwgMHg0NCwgMHhjNCwgMHgyNCwgMHhhNCwgMHg2NCwgMHhlNCxcbiAgICAgICAgMHgxNCwgMHg5NCwgMHg1NCwgMHhkNCwgMHgzNCwgMHhiNCwgMHg3NCwgMHhmNCxcbiAgICAgICAgMHgwYywgMHg4YywgMHg0YywgMHhjYywgMHgyYywgMHhhYywgMHg2YywgMHhlYyxcbiAgICAgICAgMHgxYywgMHg5YywgMHg1YywgMHhkYywgMHgzYywgMHhiYywgMHg3YywgMHhmYyxcbiAgICAgICAgMHgwMiwgMHg4MiwgMHg0MiwgMHhjMiwgMHgyMiwgMHhhMiwgMHg2MiwgMHhlMixcbiAgICAgICAgMHgxMiwgMHg5MiwgMHg1MiwgMHhkMiwgMHgzMiwgMHhiMiwgMHg3MiwgMHhmMixcbiAgICAgICAgMHgwYSwgMHg4YSwgMHg0YSwgMHhjYSwgMHgyYSwgMHhhYSwgMHg2YSwgMHhlYSxcbiAgICAgICAgMHgxYSwgMHg5YSwgMHg1YSwgMHhkYSwgMHgzYSwgMHhiYSwgMHg3YSwgMHhmYSxcbiAgICAgICAgMHgwNiwgMHg4NiwgMHg0NiwgMHhjNiwgMHgyNiwgMHhhNiwgMHg2NiwgMHhlNixcbiAgICAgICAgMHgxNiwgMHg5NiwgMHg1NiwgMHhkNiwgMHgzNiwgMHhiNiwgMHg3NiwgMHhmNixcbiAgICAgICAgMHgwZSwgMHg4ZSwgMHg0ZSwgMHhjZSwgMHgyZSwgMHhhZSwgMHg2ZSwgMHhlZSxcbiAgICAgICAgMHgxZSwgMHg5ZSwgMHg1ZSwgMHhkZSwgMHgzZSwgMHhiZSwgMHg3ZSwgMHhmZSxcbiAgICAgICAgMHgwMSwgMHg4MSwgMHg0MSwgMHhjMSwgMHgyMSwgMHhhMSwgMHg2MSwgMHhlMSxcbiAgICAgICAgMHgxMSwgMHg5MSwgMHg1MSwgMHhkMSwgMHgzMSwgMHhiMSwgMHg3MSwgMHhmMSxcbiAgICAgICAgMHgwOSwgMHg4OSwgMHg0OSwgMHhjOSwgMHgyOSwgMHhhOSwgMHg2OSwgMHhlOSxcbiAgICAgICAgMHgxOSwgMHg5OSwgMHg1OSwgMHhkOSwgMHgzOSwgMHhiOSwgMHg3OSwgMHhmOSxcbiAgICAgICAgMHgwNSwgMHg4NSwgMHg0NSwgMHhjNSwgMHgyNSwgMHhhNSwgMHg2NSwgMHhlNSxcbiAgICAgICAgMHgxNSwgMHg5NSwgMHg1NSwgMHhkNSwgMHgzNSwgMHhiNSwgMHg3NSwgMHhmNSxcbiAgICAgICAgMHgwZCwgMHg4ZCwgMHg0ZCwgMHhjZCwgMHgyZCwgMHhhZCwgMHg2ZCwgMHhlZCxcbiAgICAgICAgMHgxZCwgMHg5ZCwgMHg1ZCwgMHhkZCwgMHgzZCwgMHhiZCwgMHg3ZCwgMHhmZCxcbiAgICAgICAgMHgwMywgMHg4MywgMHg0MywgMHhjMywgMHgyMywgMHhhMywgMHg2MywgMHhlMyxcbiAgICAgICAgMHgxMywgMHg5MywgMHg1MywgMHhkMywgMHgzMywgMHhiMywgMHg3MywgMHhmMyxcbiAgICAgICAgMHgwYiwgMHg4YiwgMHg0YiwgMHhjYiwgMHgyYiwgMHhhYiwgMHg2YiwgMHhlYixcbiAgICAgICAgMHgxYiwgMHg5YiwgMHg1YiwgMHhkYiwgMHgzYiwgMHhiYiwgMHg3YiwgMHhmYixcbiAgICAgICAgMHgwNywgMHg4NywgMHg0NywgMHhjNywgMHgyNywgMHhhNywgMHg2NywgMHhlNyxcbiAgICAgICAgMHgxNywgMHg5NywgMHg1NywgMHhkNywgMHgzNywgMHhiNywgMHg3NywgMHhmNyxcbiAgICAgICAgMHgwZiwgMHg4ZiwgMHg0ZiwgMHhjZiwgMHgyZiwgMHhhZiwgMHg2ZiwgMHhlZixcbiAgICAgICAgMHgxZiwgMHg5ZiwgMHg1ZiwgMHhkZiwgMHgzZiwgMHhiZiwgMHg3ZiwgMHhmZlxuICAgIF0sXG5cbiAgICBjcGxlbnMgPSBbXG4gICAgICAgIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwLCAxMSwgMTMsIDE1LCAxNywgMTksIDIzLCAyNywgMzEsXG4gICAgICAgIDM1LCA0MywgNTEsIDU5LCA2NywgODMsIDk5LCAxMTUsIDEzMSwgMTYzLCAxOTUsIDIyNywgMjU4LCAwLCAwXG4gICAgXSxcblxuICAgIGNwbGV4dCA9IFtcbiAgICAgICAgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMSwgMSwgMSwgMSwgMiwgMiwgMiwgMixcbiAgICAgICAgMywgMywgMywgMywgNCwgNCwgNCwgNCwgNSwgNSwgNSwgNSwgMCwgOTksIDk5XG4gICAgXSxcbiAgICAvKiA5OT09aW52YWxpZCAqL1xuXG4gICAgY3BkaXN0ID0gW1xuICAgICAgICAweDAwMDEsIDB4MDAwMiwgMHgwMDAzLCAweDAwMDQsIDB4MDAwNSwgMHgwMDA3LCAweDAwMDksIDB4MDAwZCxcbiAgICAgICAgMHgwMDExLCAweDAwMTksIDB4MDAyMSwgMHgwMDMxLCAweDAwNDEsIDB4MDA2MSwgMHgwMDgxLCAweDAwYzEsXG4gICAgICAgIDB4MDEwMSwgMHgwMTgxLCAweDAyMDEsIDB4MDMwMSwgMHgwNDAxLCAweDA2MDEsIDB4MDgwMSwgMHgwYzAxLFxuICAgICAgICAweDEwMDEsIDB4MTgwMSwgMHgyMDAxLCAweDMwMDEsIDB4NDAwMSwgMHg2MDAxXG4gICAgXSxcblxuICAgIGNwZGV4dCA9IFtcbiAgICAgICAgMCwgMCwgMCwgMCwgMSwgMSwgMiwgMixcbiAgICAgICAgMywgMywgNCwgNCwgNSwgNSwgNiwgNixcbiAgICAgICAgNywgNywgOCwgOCwgOSwgOSwgMTAsIDEwLFxuICAgICAgICAxMSwgMTEsIDEyLCAxMiwgMTMsIDEzXG4gICAgXSxcblxuICAgIGJvcmRlciA9IFsxNiwgMTcsIDE4LCAwLCA4LCA3LCA5LCA2LCAxMCwgNSwgMTEsIDQsIDEyLCAzLCAxMywgMiwgMTQsIDEsIDE1XSxcblxuICAgIGJBID0gYmFycmF5LFxuXG4gICAgYnl0ZXBvcyA9IDAsXG4gICAgYml0cG9zID0gMCxcbiAgICBiYiA9IDEsXG4gICAgYml0cyA9IDAsXG5cbiAgICBOQU1FTUFYID0gMjU2LFxuXG4gICAgbmFtZUJ1ZiA9IFtdLFxuXG4gICAgZmlsZW91dDtcblxuICBmdW5jdGlvbiByZWFkQnl0ZSgpIHtcbiAgICBiaXRzICs9IDg7XG4gICAgaWYgKGJ5dGVwb3MgPCBiQS5sZW5ndGgpIHtcbiAgICAgIC8vaWYgKGRlYnVnKVxuICAgICAgLy8gICAgZG9jdW1lbnQud3JpdGUoYnl0ZXBvcytcIjogXCIrYkFbYnl0ZXBvc10rXCI8YnI+XCIpO1xuICAgICAgcmV0dXJuIGJBW2J5dGVwb3MrK107XG4gICAgfSBlbHNlXG4gICAgICByZXR1cm4gLTE7XG4gIH07XG5cbiAgZnVuY3Rpb24gYnl0ZUFsaWduKCkge1xuICAgIGJiID0gMTtcbiAgfTtcblxuICBmdW5jdGlvbiByZWFkQml0KCkge1xuICAgIHZhciBjYXJyeTtcbiAgICBiaXRzKys7XG4gICAgY2FycnkgPSAoYmIgJiAxKTtcbiAgICBiYiA+Pj0gMTtcbiAgICBpZiAoYmIgPT0gMCkge1xuICAgICAgYmIgPSByZWFkQnl0ZSgpO1xuICAgICAgY2FycnkgPSAoYmIgJiAxKTtcbiAgICAgIGJiID0gKGJiID4+IDEpIHwgMHg4MDtcbiAgICB9XG4gICAgcmV0dXJuIGNhcnJ5O1xuICB9O1xuXG4gIGZ1bmN0aW9uIHJlYWRCaXRzKGEpIHtcbiAgICB2YXIgcmVzID0gMCxcbiAgICAgIGkgPSBhO1xuXG4gICAgd2hpbGUgKGktLSkge1xuICAgICAgcmVzID0gKHJlcyA8PCAxKSB8IHJlYWRCaXQoKTtcbiAgICB9XG4gICAgaWYgKGEpIHtcbiAgICAgIHJlcyA9IGJpdFJldmVyc2VbcmVzXSA+PiAoOCAtIGEpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzO1xuICB9O1xuXG4gIGZ1bmN0aW9uIGZsdXNoQnVmZmVyKCkge1xuICAgIC8vZG9jdW1lbnQud3JpdGUoJ0ZMVVNIQlVGRkVSOicrYnVmMzJrKTtcbiAgICBiSWR4ID0gMDtcbiAgfTtcblxuICBmdW5jdGlvbiBhZGRCdWZmZXIoYSkge1xuICAgIFNJWkUrKztcbiAgICAvL0NSQz11cGRjcmMoYSxjcmMpO1xuICAgIGJ1ZjMya1tiSWR4KytdID0gYTtcbiAgICBvdXRwdXRBcnIucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGEpKTtcbiAgICAvL291dHB1dCs9U3RyaW5nLmZyb21DaGFyQ29kZShhKTtcbiAgICBpZiAoYklkeCA9PSAweDgwMDApIHtcbiAgICAgIC8vZG9jdW1lbnQud3JpdGUoJ0FEREJVRkZFUjonK2J1ZjMyayk7XG4gICAgICBiSWR4ID0gMDtcbiAgICB9XG4gIH07XG5cbiAgZnVuY3Rpb24gSHVmTm9kZSgpIHtcbiAgICB0aGlzLmIwID0gMDtcbiAgICB0aGlzLmIxID0gMDtcbiAgICB0aGlzLmp1bXAgPSBudWxsO1xuICAgIHRoaXMuanVtcHBvcyA9IC0xO1xuICB9O1xuXG4gIHZhciBMSVRFUkFMUyA9IDI4ODtcblxuICB2YXIgbGl0ZXJhbFRyZWUgPSBuZXcgQXJyYXkoTElURVJBTFMpO1xuICB2YXIgZGlzdGFuY2VUcmVlID0gbmV3IEFycmF5KDMyKTtcbiAgdmFyIHRyZWVwb3MgPSAwO1xuICB2YXIgUGxhY2VzID0gbnVsbDtcbiAgdmFyIFBsYWNlczIgPSBudWxsO1xuXG4gIHZhciBpbXBEaXN0YW5jZVRyZWUgPSBuZXcgQXJyYXkoNjQpO1xuICB2YXIgaW1wTGVuZ3RoVHJlZSA9IG5ldyBBcnJheSg2NCk7XG5cbiAgdmFyIGxlbiA9IDA7XG4gIHZhciBmcG9zID0gbmV3IEFycmF5KDE3KTtcbiAgZnBvc1swXSA9IDA7XG4gIHZhciBmbGVucztcbiAgdmFyIGZtYXg7XG5cbiAgZnVuY3Rpb24gSXNQYXQoKSB7XG4gICAgd2hpbGUgKDEpIHtcbiAgICAgIGlmIChmcG9zW2xlbl0gPj0gZm1heClcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgaWYgKGZsZW5zW2Zwb3NbbGVuXV0gPT0gbGVuKVxuICAgICAgICByZXR1cm4gZnBvc1tsZW5dKys7XG4gICAgICBmcG9zW2xlbl0rKztcbiAgICB9XG4gIH07XG5cbiAgZnVuY3Rpb24gUmVjKCkge1xuICAgIHZhciBjdXJwbGFjZSA9IFBsYWNlc1t0cmVlcG9zXTtcbiAgICB2YXIgdG1wO1xuICAgIGlmIChkZWJ1ZylcbiAgICAgIGRvY3VtZW50LndyaXRlKFwiPGJyPmxlbjpcIiArIGxlbiArIFwiIHRyZWVwb3M6XCIgKyB0cmVlcG9zKTtcbiAgICBpZiAobGVuID09IDE3KSB7IC8vd2FyIDE3XG4gICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIHRyZWVwb3MrKztcbiAgICBsZW4rKztcblxuICAgIHRtcCA9IElzUGF0KCk7XG4gICAgaWYgKGRlYnVnKVxuICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+SXNQYXQgXCIgKyB0bXApO1xuICAgIGlmICh0bXAgPj0gMCkge1xuICAgICAgY3VycGxhY2UuYjAgPSB0bXA7IC8qIGxlYWYgY2VsbCBmb3IgMC1iaXQgKi9cbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+YjAgXCIgKyBjdXJwbGFjZS5iMCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8qIE5vdCBhIExlYWYgY2VsbCAqL1xuICAgICAgY3VycGxhY2UuYjAgPSAweDgwMDA7XG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGRvY3VtZW50LndyaXRlKFwiPGJyPmIwIFwiICsgY3VycGxhY2UuYjApO1xuICAgICAgaWYgKFJlYygpKVxuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIHRtcCA9IElzUGF0KCk7XG4gICAgaWYgKHRtcCA+PSAwKSB7XG4gICAgICBjdXJwbGFjZS5iMSA9IHRtcDsgLyogbGVhZiBjZWxsIGZvciAxLWJpdCAqL1xuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBkb2N1bWVudC53cml0ZShcIjxicj5iMSBcIiArIGN1cnBsYWNlLmIxKTtcbiAgICAgIGN1cnBsYWNlLmp1bXAgPSBudWxsOyAvKiBKdXN0IGZvciB0aGUgZGlzcGxheSByb3V0aW5lICovXG4gICAgfSBlbHNlIHtcbiAgICAgIC8qIE5vdCBhIExlYWYgY2VsbCAqL1xuICAgICAgY3VycGxhY2UuYjEgPSAweDgwMDA7XG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGRvY3VtZW50LndyaXRlKFwiPGJyPmIxIFwiICsgY3VycGxhY2UuYjEpO1xuICAgICAgY3VycGxhY2UuanVtcCA9IFBsYWNlc1t0cmVlcG9zXTtcbiAgICAgIGN1cnBsYWNlLmp1bXBwb3MgPSB0cmVlcG9zO1xuICAgICAgaWYgKFJlYygpKVxuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIGxlbi0tO1xuICAgIHJldHVybiAwO1xuICB9O1xuXG4gIGZ1bmN0aW9uIENyZWF0ZVRyZWUoY3VycmVudFRyZWUsIG51bXZhbCwgbGVuZ3Rocywgc2hvdykge1xuICAgIHZhciBpO1xuICAgIC8qIENyZWF0ZSB0aGUgSHVmZm1hbiBkZWNvZGUgdHJlZS90YWJsZSAqL1xuICAgIC8vZG9jdW1lbnQud3JpdGUoXCI8YnI+Y3JlYXRldHJlZTxicj5cIik7XG4gICAgaWYgKGRlYnVnKVxuICAgICAgZG9jdW1lbnQud3JpdGUoXCJjdXJyZW50VHJlZSBcIiArIGN1cnJlbnRUcmVlICsgXCIgbnVtdmFsIFwiICsgbnVtdmFsICsgXCIgbGVuZ3RocyBcIiArIGxlbmd0aHMgKyBcIiBzaG93IFwiICsgc2hvdyk7XG4gICAgUGxhY2VzID0gY3VycmVudFRyZWU7XG4gICAgdHJlZXBvcyA9IDA7XG4gICAgZmxlbnMgPSBsZW5ndGhzO1xuICAgIGZtYXggPSBudW12YWw7XG4gICAgZm9yIChpID0gMDsgaSA8IDE3OyBpKyspXG4gICAgICBmcG9zW2ldID0gMDtcbiAgICBsZW4gPSAwO1xuICAgIGlmIChSZWMoKSkge1xuICAgICAgLy9mcHJpbnRmKHN0ZGVyciwgXCJpbnZhbGlkIGh1ZmZtYW4gdHJlZVxcblwiKTtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQoXCJpbnZhbGlkIGh1ZmZtYW4gdHJlZVxcblwiKTtcbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgaWYgKGRlYnVnKSB7XG4gICAgICBkb2N1bWVudC53cml0ZSgnPGJyPlRyZWU6ICcgKyBQbGFjZXMubGVuZ3RoKTtcbiAgICAgIGZvciAodmFyIGEgPSAwOyBhIDwgMzI7IGErKykge1xuICAgICAgICBkb2N1bWVudC53cml0ZShcIlBsYWNlc1tcIiArIGEgKyBcIl0uYjA9XCIgKyBQbGFjZXNbYV0uYjAgKyBcIjxicj5cIik7XG4gICAgICAgIGRvY3VtZW50LndyaXRlKFwiUGxhY2VzW1wiICsgYSArIFwiXS5iMT1cIiArIFBsYWNlc1thXS5iMSArIFwiPGJyPlwiKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKmlmKHNob3cpIHtcbiAgICAgICAgICAgIHZhciB0bXA7XG4gICAgICAgICAgICBmb3IodG1wPWN1cnJlbnRUcmVlO3RtcDxQbGFjZXM7dG1wKyspIHtcbiAgICAgICAgICAgICAgICBmcHJpbnRmKHN0ZG91dCwgXCIweCUwM3ggIDB4JTAzeCAoMHglMDR4KVwiLHRtcC1jdXJyZW50VHJlZSwgdG1wLT5qdW1wP3RtcC0+anVtcC1jdXJyZW50VHJlZTowLCh0bXAtPmp1bXA/dG1wLT5qdW1wLWN1cnJlbnRUcmVlOjApKjYrMHhjZjApO1xuICAgICAgICAgICAgICAgIGlmKCEodG1wLmIwICYgMHg4MDAwKSkge1xuICAgICAgICAgICAgICAgICAgICAvL2ZwcmludGYoc3Rkb3V0LCBcIiAgMHglMDN4ICglYylcIiwgdG1wLT5iMCwodG1wLT5iMDwyNTYgJiYgaXNwcmludCh0bXAtPmIwKSk/dG1wLT5iMDon77+9Jyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmKCEodG1wLmIxICYgMHg4MDAwKSkge1xuICAgICAgICAgICAgICAgICAgICBpZigodG1wLmIwICYgMHg4MDAwKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGZwcmludGYoc3Rkb3V0LCBcIiAgICAgICAgICAgXCIpO1xuICAgICAgICAgICAgICAgICAgICBmcHJpbnRmKHN0ZG91dCwgXCIgIDB4JTAzeCAoJWMpXCIsIHRtcC0+YjEsKHRtcC0+YjE8MjU2ICYmIGlzcHJpbnQodG1wLT5iMSkpP3RtcC0+YjE6J++/vScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBmcHJpbnRmKHN0ZG91dCwgXCJcXG5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0qL1xuICAgIHJldHVybiAwO1xuICB9O1xuXG4gIGZ1bmN0aW9uIERlY29kZVZhbHVlKGN1cnJlbnRUcmVlKSB7XG4gICAgdmFyIGxlbiwgaSxcbiAgICAgIHh0cmVlcG9zID0gMCxcbiAgICAgIFggPSBjdXJyZW50VHJlZVt4dHJlZXBvc10sXG4gICAgICBiO1xuXG4gICAgLyogZGVjb2RlIG9uZSBzeW1ib2wgb2YgdGhlIGRhdGEgKi9cbiAgICB3aGlsZSAoMSkge1xuICAgICAgYiA9IHJlYWRCaXQoKTtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgZG9jdW1lbnQud3JpdGUoXCJiPVwiICsgYik7XG4gICAgICBpZiAoYikge1xuICAgICAgICBpZiAoIShYLmIxICYgMHg4MDAwKSkge1xuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGRvY3VtZW50LndyaXRlKFwicmV0MVwiKTtcbiAgICAgICAgICByZXR1cm4gWC5iMTsgLyogSWYgbGVhZiBub2RlLCByZXR1cm4gZGF0YSAqL1xuICAgICAgICB9XG4gICAgICAgIFggPSBYLmp1bXA7XG4gICAgICAgIGxlbiA9IGN1cnJlbnRUcmVlLmxlbmd0aDtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgaWYgKGN1cnJlbnRUcmVlW2ldID09PSBYKSB7XG4gICAgICAgICAgICB4dHJlZXBvcyA9IGk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy94dHJlZXBvcysrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKCEoWC5iMCAmIDB4ODAwMCkpIHtcbiAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBkb2N1bWVudC53cml0ZShcInJldDJcIik7XG4gICAgICAgICAgcmV0dXJuIFguYjA7IC8qIElmIGxlYWYgbm9kZSwgcmV0dXJuIGRhdGEgKi9cbiAgICAgICAgfVxuICAgICAgICAvL1grKzsgLy8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz9cbiAgICAgICAgeHRyZWVwb3MrKztcbiAgICAgICAgWCA9IGN1cnJlbnRUcmVlW3h0cmVlcG9zXTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgZnVuY3Rpb24gRGVmbGF0ZUxvb3AoKSB7XG4gICAgdmFyIGxhc3QsIGMsIHR5cGUsIGksIGxlbjtcblxuICAgIGRvIHtcbiAgICAgIC8qaWYoKGxhc3QgPSByZWFkQml0KCkpKXtcbiAgICAgICAgICAgIGZwcmludGYoZXJyZnAsIFwiTGFzdCBCbG9jazogXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZnByaW50ZihlcnJmcCwgXCJOb3QgTGFzdCBCbG9jazogXCIpO1xuICAgICAgICB9Ki9cbiAgICAgIGxhc3QgPSByZWFkQml0KCk7XG4gICAgICB0eXBlID0gcmVhZEJpdHMoMik7XG4gICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgY2FzZSAwOlxuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGFsZXJ0KFwiU3RvcmVkXFxuXCIpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgYWxlcnQoXCJGaXhlZCBIdWZmbWFuIGNvZGVzXFxuXCIpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgYWxlcnQoXCJEeW5hbWljIEh1ZmZtYW4gY29kZXNcXG5cIik7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBhbGVydChcIlJlc2VydmVkIGJsb2NrIHR5cGUhIVxcblwiKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBhbGVydChcIlVuZXhwZWN0ZWQgdmFsdWUgJWQhXFxuXCIsIHR5cGUpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZSA9PSAwKSB7XG4gICAgICAgIHZhciBibG9ja0xlbiwgY1N1bTtcblxuICAgICAgICAvLyBTdG9yZWQgXG4gICAgICAgIGJ5dGVBbGlnbigpO1xuICAgICAgICBibG9ja0xlbiA9IHJlYWRCeXRlKCk7XG4gICAgICAgIGJsb2NrTGVuIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuXG4gICAgICAgIGNTdW0gPSByZWFkQnl0ZSgpO1xuICAgICAgICBjU3VtIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuXG4gICAgICAgIGlmICgoKGJsb2NrTGVuIF4gfmNTdW0pICYgMHhmZmZmKSkge1xuICAgICAgICAgIGRvY3VtZW50LndyaXRlKFwiQmxvY2tMZW4gY2hlY2tzdW0gbWlzbWF0Y2hcXG5cIik7XG4gICAgICAgIH1cbiAgICAgICAgd2hpbGUgKGJsb2NrTGVuLS0pIHtcbiAgICAgICAgICBjID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgICBhZGRCdWZmZXIoYyk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PSAxKSB7XG4gICAgICAgIHZhciBqO1xuXG4gICAgICAgIC8qIEZpeGVkIEh1ZmZtYW4gdGFibGVzIC0tIGZpeGVkIGRlY29kZSByb3V0aW5lICovXG4gICAgICAgIHdoaWxlICgxKSB7XG4gICAgICAgICAgLypcbiAgICAgICAgICAgICAgICAyNTYgICAgMDAwMDAwMCAgICAgICAgMFxuICAgICAgICAgICAgICAgIDogICA6ICAgICA6XG4gICAgICAgICAgICAgICAgMjc5ICAgIDAwMTAxMTEgICAgICAgIDIzXG4gICAgICAgICAgICAgICAgMCAgIDAwMTEwMDAwICAgIDQ4XG4gICAgICAgICAgICAgICAgOiAgICA6ICAgICAgOlxuICAgICAgICAgICAgICAgIDE0MyAgICAxMDExMTExMSAgICAxOTFcbiAgICAgICAgICAgICAgICAyODAgMTEwMDAwMDAgICAgMTkyXG4gICAgICAgICAgICAgICAgOiAgICA6ICAgICAgOlxuICAgICAgICAgICAgICAgIDI4NyAxMTAwMDExMSAgICAxOTlcbiAgICAgICAgICAgICAgICAxNDQgICAgMTEwMDEwMDAwICAgIDQwMFxuICAgICAgICAgICAgICAgIDogICAgOiAgICAgICA6XG4gICAgICAgICAgICAgICAgMjU1ICAgIDExMTExMTExMSAgICA1MTFcbiAgICBcbiAgICAgICAgICAgICAgICBOb3RlIHRoZSBiaXQgb3JkZXIhXG4gICAgICAgICAgICAgICAgKi9cblxuICAgICAgICAgIGogPSAoYml0UmV2ZXJzZVtyZWFkQml0cyg3KV0gPj4gMSk7XG4gICAgICAgICAgaWYgKGogPiAyMykge1xuICAgICAgICAgICAgaiA9IChqIDw8IDEpIHwgcmVhZEJpdCgpOyAvKiA0OC4uMjU1ICovXG5cbiAgICAgICAgICAgIGlmIChqID4gMTk5KSB7IC8qIDIwMC4uMjU1ICovXG4gICAgICAgICAgICAgIGogLT0gMTI4OyAvKiAgNzIuLjEyNyAqL1xuICAgICAgICAgICAgICBqID0gKGogPDwgMSkgfCByZWFkQml0KCk7IC8qIDE0NC4uMjU1IDw8ICovXG4gICAgICAgICAgICB9IGVsc2UgeyAvKiAgNDguLjE5OSAqL1xuICAgICAgICAgICAgICBqIC09IDQ4OyAvKiAgIDAuLjE1MSAqL1xuICAgICAgICAgICAgICBpZiAoaiA+IDE0Mykge1xuICAgICAgICAgICAgICAgIGogPSBqICsgMTM2OyAvKiAyODAuLjI4NyA8PCAqL1xuICAgICAgICAgICAgICAgIC8qICAgMC4uMTQzIDw8ICovXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgeyAvKiAgIDAuLjIzICovXG4gICAgICAgICAgICBqICs9IDI1NjsgLyogMjU2Li4yNzkgPDwgKi9cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGogPCAyNTYpIHtcbiAgICAgICAgICAgIGFkZEJ1ZmZlcihqKTtcbiAgICAgICAgICAgIC8vZG9jdW1lbnQud3JpdGUoXCJvdXQ6XCIrU3RyaW5nLmZyb21DaGFyQ29kZShqKSk7XG4gICAgICAgICAgICAvKmZwcmludGYoZXJyZnAsIFwiQCVkICUwMnhcXG5cIiwgU0laRSwgaik7Ki9cbiAgICAgICAgICB9IGVsc2UgaWYgKGogPT0gMjU2KSB7XG4gICAgICAgICAgICAvKiBFT0YgKi9cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgbGVuLCBkaXN0O1xuXG4gICAgICAgICAgICBqIC09IDI1NiArIDE7IC8qIGJ5dGVzICsgRU9GICovXG4gICAgICAgICAgICBsZW4gPSByZWFkQml0cyhjcGxleHRbal0pICsgY3BsZW5zW2pdO1xuXG4gICAgICAgICAgICBqID0gYml0UmV2ZXJzZVtyZWFkQml0cyg1KV0gPj4gMztcbiAgICAgICAgICAgIGlmIChjcGRleHRbal0gPiA4KSB7XG4gICAgICAgICAgICAgIGRpc3QgPSByZWFkQml0cyg4KTtcbiAgICAgICAgICAgICAgZGlzdCB8PSAocmVhZEJpdHMoY3BkZXh0W2pdIC0gOCkgPDwgOCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBkaXN0ID0gcmVhZEJpdHMoY3BkZXh0W2pdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRpc3QgKz0gY3BkaXN0W2pdO1xuXG4gICAgICAgICAgICAvKmZwcmludGYoZXJyZnAsIFwiQCVkIChsJTAyeCxkJTA0eClcXG5cIiwgU0laRSwgbGVuLCBkaXN0KTsqL1xuICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IGxlbjsgaisrKSB7XG4gICAgICAgICAgICAgIHZhciBjID0gYnVmMzJrWyhiSWR4IC0gZGlzdCkgJiAweDdmZmZdO1xuICAgICAgICAgICAgICBhZGRCdWZmZXIoYyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIHdoaWxlXG4gICAgICB9IGVsc2UgaWYgKHR5cGUgPT0gMikge1xuICAgICAgICB2YXIgaiwgbiwgbGl0ZXJhbENvZGVzLCBkaXN0Q29kZXMsIGxlbkNvZGVzO1xuICAgICAgICB2YXIgbGwgPSBuZXcgQXJyYXkoMjg4ICsgMzIpOyAvLyBcInN0YXRpY1wiIGp1c3QgdG8gcHJlc2VydmUgc3RhY2tcblxuICAgICAgICAvLyBEeW5hbWljIEh1ZmZtYW4gdGFibGVzIFxuXG4gICAgICAgIGxpdGVyYWxDb2RlcyA9IDI1NyArIHJlYWRCaXRzKDUpO1xuICAgICAgICBkaXN0Q29kZXMgPSAxICsgcmVhZEJpdHMoNSk7XG4gICAgICAgIGxlbkNvZGVzID0gNCArIHJlYWRCaXRzKDQpO1xuICAgICAgICAvL2RvY3VtZW50LndyaXRlKFwiPGJyPnBhcmFtOiBcIitsaXRlcmFsQ29kZXMrXCIgXCIrZGlzdENvZGVzK1wiIFwiK2xlbkNvZGVzK1wiPGJyPlwiKTtcbiAgICAgICAgZm9yIChqID0gMDsgaiA8IDE5OyBqKyspIHtcbiAgICAgICAgICBsbFtqXSA9IDA7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBHZXQgdGhlIGRlY29kZSB0cmVlIGNvZGUgbGVuZ3Roc1xuXG4gICAgICAgIC8vZG9jdW1lbnQud3JpdGUoXCI8YnI+XCIpO1xuICAgICAgICBmb3IgKGogPSAwOyBqIDwgbGVuQ29kZXM7IGorKykge1xuICAgICAgICAgIGxsW2JvcmRlcltqXV0gPSByZWFkQml0cygzKTtcbiAgICAgICAgICAvL2RvY3VtZW50LndyaXRlKGxsW2JvcmRlcltqXV0rXCIgXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vZnByaW50ZihlcnJmcCwgXCJcXG5cIik7XG4gICAgICAgIC8vZG9jdW1lbnQud3JpdGUoJzxicj5sbDonK2xsKTtcbiAgICAgICAgbGVuID0gZGlzdGFuY2VUcmVlLmxlbmd0aDtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKVxuICAgICAgICAgIGRpc3RhbmNlVHJlZVtpXSA9IG5ldyBIdWZOb2RlKCk7XG4gICAgICAgIGlmIChDcmVhdGVUcmVlKGRpc3RhbmNlVHJlZSwgMTksIGxsLCAwKSkge1xuICAgICAgICAgIGZsdXNoQnVmZmVyKCk7XG4gICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRlYnVnKSB7XG4gICAgICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+ZGlzdGFuY2VUcmVlXCIpO1xuICAgICAgICAgIGZvciAodmFyIGEgPSAwOyBhIDwgZGlzdGFuY2VUcmVlLmxlbmd0aDsgYSsrKSB7XG4gICAgICAgICAgICBkb2N1bWVudC53cml0ZShcIjxicj5cIiArIGRpc3RhbmNlVHJlZVthXS5iMCArIFwiIFwiICsgZGlzdGFuY2VUcmVlW2FdLmIxICsgXCIgXCIgKyBkaXN0YW5jZVRyZWVbYV0uanVtcCArIFwiIFwiICtcbiAgICAgICAgICAgICAgZGlzdGFuY2VUcmVlW2FdLmp1bXBwb3MpO1xuICAgICAgICAgICAgLyppZiAoZGlzdGFuY2VUcmVlW2FdLmp1bXBwb3MhPS0xKVxuICAgICAgICAgICAgICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwiIFwiK2Rpc3RhbmNlVHJlZVthXS5qdW1wLmIwK1wiIFwiK2Rpc3RhbmNlVHJlZVthXS5qdW1wLmIxKTtcbiAgICAgICAgICAgICAgICBcdCovXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vZG9jdW1lbnQud3JpdGUoJzxCUj50cmVlIGNyZWF0ZWQnKTtcblxuICAgICAgICAvL3JlYWQgaW4gbGl0ZXJhbCBhbmQgZGlzdGFuY2UgY29kZSBsZW5ndGhzXG4gICAgICAgIG4gPSBsaXRlcmFsQ29kZXMgKyBkaXN0Q29kZXM7XG4gICAgICAgIGkgPSAwO1xuICAgICAgICB2YXIgeiA9IC0xO1xuICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+bj1cIiArIG4gKyBcIiBiaXRzOiBcIiArIGJpdHMgKyBcIjxicj5cIik7XG4gICAgICAgIHdoaWxlIChpIDwgbikge1xuICAgICAgICAgIHorKztcbiAgICAgICAgICBqID0gRGVjb2RlVmFsdWUoZGlzdGFuY2VUcmVlKTtcbiAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBkb2N1bWVudC53cml0ZShcIjxicj5cIiArIHogKyBcIiBpOlwiICsgaSArIFwiIGRlY29kZTogXCIgKyBqICsgXCIgICAgYml0cyBcIiArIGJpdHMgKyBcIjxicj5cIik7XG4gICAgICAgICAgaWYgKGogPCAxNikgeyAvLyBsZW5ndGggb2YgY29kZSBpbiBiaXRzICgwLi4xNSlcbiAgICAgICAgICAgIGxsW2krK10gPSBqO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaiA9PSAxNikgeyAvLyByZXBlYXQgbGFzdCBsZW5ndGggMyB0byA2IHRpbWVzIFxuICAgICAgICAgICAgdmFyIGw7XG4gICAgICAgICAgICBqID0gMyArIHJlYWRCaXRzKDIpO1xuICAgICAgICAgICAgaWYgKGkgKyBqID4gbikge1xuICAgICAgICAgICAgICBmbHVzaEJ1ZmZlcigpO1xuICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGwgPSBpID8gbGxbaSAtIDFdIDogMDtcbiAgICAgICAgICAgIHdoaWxlIChqLS0pIHtcbiAgICAgICAgICAgICAgbGxbaSsrXSA9IGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChqID09IDE3KSB7IC8vIDMgdG8gMTAgemVybyBsZW5ndGggY29kZXNcbiAgICAgICAgICAgICAgaiA9IDMgKyByZWFkQml0cygzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7IC8vIGogPT0gMTg6IDExIHRvIDEzOCB6ZXJvIGxlbmd0aCBjb2RlcyBcbiAgICAgICAgICAgICAgaiA9IDExICsgcmVhZEJpdHMoNyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaSArIGogPiBuKSB7XG4gICAgICAgICAgICAgIGZsdXNoQnVmZmVyKCk7XG4gICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd2hpbGUgKGotLSkge1xuICAgICAgICAgICAgICBsbFtpKytdID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLypmb3Ioaj0wOyBqPGxpdGVyYWxDb2RlcytkaXN0Q29kZXM7IGorKykge1xuICAgICAgICAgICAgICAgIC8vZnByaW50ZihlcnJmcCwgXCIlZCBcIiwgbGxbal0pO1xuICAgICAgICAgICAgICAgIGlmICgoaiY3KT09NylcbiAgICAgICAgICAgICAgICAgICAgZnByaW50ZihlcnJmcCwgXCJcXG5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmcHJpbnRmKGVycmZwLCBcIlxcblwiKTsqL1xuICAgICAgICAvLyBDYW4gb3ZlcndyaXRlIHRyZWUgZGVjb2RlIHRyZWUgYXMgaXQgaXMgbm90IHVzZWQgYW55bW9yZVxuICAgICAgICBsZW4gPSBsaXRlcmFsVHJlZS5sZW5ndGg7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgICAgICBsaXRlcmFsVHJlZVtpXSA9IG5ldyBIdWZOb2RlKCk7XG4gICAgICAgIGlmIChDcmVhdGVUcmVlKGxpdGVyYWxUcmVlLCBsaXRlcmFsQ29kZXMsIGxsLCAwKSkge1xuICAgICAgICAgIGZsdXNoQnVmZmVyKCk7XG4gICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH1cbiAgICAgICAgbGVuID0gbGl0ZXJhbFRyZWUubGVuZ3RoO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICAgICAgZGlzdGFuY2VUcmVlW2ldID0gbmV3IEh1Zk5vZGUoKTtcbiAgICAgICAgdmFyIGxsMiA9IG5ldyBBcnJheSgpO1xuICAgICAgICBmb3IgKGkgPSBsaXRlcmFsQ29kZXM7IGkgPCBsbC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGxsMltpIC0gbGl0ZXJhbENvZGVzXSA9IGxsW2ldO1xuICAgICAgICB9XG4gICAgICAgIGlmIChDcmVhdGVUcmVlKGRpc3RhbmNlVHJlZSwgZGlzdENvZGVzLCBsbDIsIDApKSB7XG4gICAgICAgICAgZmx1c2hCdWZmZXIoKTtcbiAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+bGl0ZXJhbFRyZWVcIik7XG4gICAgICAgIG91dGVyOiB3aGlsZSAoMSkge1xuICAgICAgICAgIGogPSBEZWNvZGVWYWx1ZShsaXRlcmFsVHJlZSk7XG4gICAgICAgICAgaWYgKGogPj0gMjU2KSB7IC8vIEluIEM2NDogaWYgY2Fycnkgc2V0XG4gICAgICAgICAgICB2YXIgbGVuLCBkaXN0O1xuICAgICAgICAgICAgaiAtPSAyNTY7XG4gICAgICAgICAgICBpZiAoaiA9PSAwKSB7XG4gICAgICAgICAgICAgIC8vIEVPRlxuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGotLTtcbiAgICAgICAgICAgIGxlbiA9IHJlYWRCaXRzKGNwbGV4dFtqXSkgKyBjcGxlbnNbal07XG5cbiAgICAgICAgICAgIGogPSBEZWNvZGVWYWx1ZShkaXN0YW5jZVRyZWUpO1xuICAgICAgICAgICAgaWYgKGNwZGV4dFtqXSA+IDgpIHtcbiAgICAgICAgICAgICAgZGlzdCA9IHJlYWRCaXRzKDgpO1xuICAgICAgICAgICAgICBkaXN0IHw9IChyZWFkQml0cyhjcGRleHRbal0gLSA4KSA8PCA4KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGRpc3QgPSByZWFkQml0cyhjcGRleHRbal0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGlzdCArPSBjcGRpc3Rbal07XG4gICAgICAgICAgICB3aGlsZSAobGVuLS0pIHtcbiAgICAgICAgICAgICAgaWYgKGJJZHggLSBkaXN0IDwgMCkge1xuICAgICAgICAgICAgICAgIGJyZWFrIG91dGVyO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHZhciBjID0gYnVmMzJrWyhiSWR4IC0gZGlzdCkgJiAweDdmZmZdO1xuICAgICAgICAgICAgICBhZGRCdWZmZXIoYyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGFkZEJ1ZmZlcihqKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IHdoaWxlICghbGFzdCk7XG4gICAgZmx1c2hCdWZmZXIoKTtcblxuICAgIGJ5dGVBbGlnbigpO1xuICAgIHJldHVybiAwO1xuICB9O1xuXG4gIEpYRy5VdGlsLlVuemlwLnByb3RvdHlwZS51bnppcEZpbGUgPSBmdW5jdGlvbihuYW1lKSB7XG4gICAgdmFyIGk7XG4gICAgdGhpcy51bnppcCgpO1xuICAgIC8vYWxlcnQodW56aXBwZWRbMF1bMV0pO1xuICAgIGZvciAoaSA9IDA7IGkgPCB1bnppcHBlZC5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHVuemlwcGVkW2ldWzFdID09IG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHVuemlwcGVkW2ldWzBdO1xuICAgICAgfVxuICAgIH1cblxuICB9O1xuXG4gIEpYRy5VdGlsLlVuemlwLnByb3RvdHlwZS5kZWZsYXRlID0gZnVuY3Rpb24oKSB7XG4gICAgb3V0cHV0QXJyID0gW107XG4gICAgdmFyIHRtcCA9IFtdO1xuICAgIG1vZGVaSVAgPSBmYWxzZTtcbiAgICBEZWZsYXRlTG9vcCgpO1xuICAgIGlmIChkZWJ1ZylcbiAgICAgIGFsZXJ0KG91dHB1dEFyci5qb2luKCcnKSk7XG4gICAgdW56aXBwZWRbZmlsZXNdID0gbmV3IEFycmF5KDIpO1xuICAgIHVuemlwcGVkW2ZpbGVzXVswXSA9IG91dHB1dEFyci5qb2luKCcnKTtcbiAgICB1bnppcHBlZFtmaWxlc11bMV0gPSBcIkRFRkxBVEVcIjtcbiAgICBmaWxlcysrO1xuICAgIHJldHVybiB1bnppcHBlZDtcbiAgfVxuXG4gIEpYRy5VdGlsLlVuemlwLnByb3RvdHlwZS51bnppcCA9IGZ1bmN0aW9uKCkge1xuICAgIC8vY29udmVydFRvQnl0ZUFycmF5KGlucHV0KTtcbiAgICBpZiAoZGVidWcpXG4gICAgICBhbGVydChiQSk7XG4gICAgLypmb3IgKGk9MDtpPGJBLmxlbmd0aCo4O2krKyl7XG5cdFx0ZG9jdW1lbnQud3JpdGUocmVhZEJpdCgpKTtcblx0XHRpZiAoKGkrMSklOD09MClcblx0XHRcdGRvY3VtZW50LndyaXRlKFwiIFwiKTtcblx0fSovXG4gICAgLypmb3IgKGk9MDtpPGJBLmxlbmd0aDtpKyspe1xuXHRcdGRvY3VtZW50LndyaXRlKHJlYWRCeXRlKCkrXCIgXCIpO1xuXHRcdGlmICgoaSsxKSU4PT0wKVxuXHRcdFx0ZG9jdW1lbnQud3JpdGUoXCIgXCIpO1xuXHR9XG5cdGZvciAoaT0wO2k8YkEubGVuZ3RoO2krKyl7XG5cdFx0ZG9jdW1lbnQud3JpdGUoYkFbaV0rXCIgXCIpO1xuXHRcdGlmICgoaSsxKSUxNj09MClcblx0XHRcdGRvY3VtZW50LndyaXRlKFwiPGJyPlwiKTtcblx0fVx0XG5cdCovXG4gICAgLy9hbGVydChiQSk7XG4gICAgbmV4dEZpbGUoKTtcbiAgICByZXR1cm4gdW56aXBwZWQ7XG4gIH07XG5cbiAgZnVuY3Rpb24gbmV4dEZpbGUoKSB7XG4gICAgaWYgKGRlYnVnKVxuICAgICAgYWxlcnQoXCJORVhURklMRVwiKTtcbiAgICBvdXRwdXRBcnIgPSBbXTtcbiAgICB2YXIgdG1wID0gW107XG4gICAgbW9kZVpJUCA9IGZhbHNlO1xuICAgIHRtcFswXSA9IHJlYWRCeXRlKCk7XG4gICAgdG1wWzFdID0gcmVhZEJ5dGUoKTtcbiAgICBpZiAoZGVidWcpXG4gICAgICBhbGVydChcInR5cGU6IFwiICsgdG1wWzBdICsgXCIgXCIgKyB0bXBbMV0pO1xuICAgIGlmICh0bXBbMF0gPT0gcGFyc2VJbnQoXCI3OFwiLCAxNikgJiYgdG1wWzFdID09IHBhcnNlSW50KFwiZGFcIiwgMTYpKSB7IC8vR1pJUFxuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChcIkdFT05FeFQtR1pJUFwiKTtcbiAgICAgIERlZmxhdGVMb29wKCk7XG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGFsZXJ0KG91dHB1dEFyci5qb2luKCcnKSk7XG4gICAgICB1bnppcHBlZFtmaWxlc10gPSBuZXcgQXJyYXkoMik7XG4gICAgICB1bnppcHBlZFtmaWxlc11bMF0gPSBvdXRwdXRBcnIuam9pbignJyk7XG4gICAgICB1bnppcHBlZFtmaWxlc11bMV0gPSBcImdlb25leHQuZ3h0XCI7XG4gICAgICBmaWxlcysrO1xuICAgIH1cbiAgICBpZiAodG1wWzBdID09IHBhcnNlSW50KFwiNzhcIiwgMTYpICYmIHRtcFsxXSA9PSBwYXJzZUludChcIjljXCIsIDE2KSkgeyAvL1pMSUJcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQoXCJaTElCXCIpO1xuICAgICAgRGVmbGF0ZUxvb3AoKTtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQob3V0cHV0QXJyLmpvaW4oJycpKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXSA9IG5ldyBBcnJheSgyKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXVswXSA9IG91dHB1dEFyci5qb2luKCcnKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXVsxXSA9IFwiWkxJQlwiO1xuICAgICAgZmlsZXMrKztcbiAgICB9XG4gICAgaWYgKHRtcFswXSA9PSBwYXJzZUludChcIjFmXCIsIDE2KSAmJiB0bXBbMV0gPT0gcGFyc2VJbnQoXCI4YlwiLCAxNikpIHsgLy9HWklQXG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGFsZXJ0KFwiR1pJUFwiKTtcbiAgICAgIC8vRGVmbGF0ZUxvb3AoKTtcbiAgICAgIHNraXBkaXIoKTtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQob3V0cHV0QXJyLmpvaW4oJycpKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXSA9IG5ldyBBcnJheSgyKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXVswXSA9IG91dHB1dEFyci5qb2luKCcnKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXVsxXSA9IFwiZmlsZVwiO1xuICAgICAgZmlsZXMrKztcbiAgICB9XG4gICAgaWYgKHRtcFswXSA9PSBwYXJzZUludChcIjUwXCIsIDE2KSAmJiB0bXBbMV0gPT0gcGFyc2VJbnQoXCI0YlwiLCAxNikpIHsgLy9aSVBcbiAgICAgIG1vZGVaSVAgPSB0cnVlO1xuICAgICAgdG1wWzJdID0gcmVhZEJ5dGUoKTtcbiAgICAgIHRtcFszXSA9IHJlYWRCeXRlKCk7XG4gICAgICBpZiAodG1wWzJdID09IHBhcnNlSW50KFwiM1wiLCAxNikgJiYgdG1wWzNdID09IHBhcnNlSW50KFwiNFwiLCAxNikpIHtcbiAgICAgICAgLy9NT0RFX1pJUFxuICAgICAgICB0bXBbMF0gPSByZWFkQnl0ZSgpO1xuICAgICAgICB0bXBbMV0gPSByZWFkQnl0ZSgpO1xuICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgYWxlcnQoXCJaSVAtVmVyc2lvbjogXCIgKyB0bXBbMV0gKyBcIiBcIiArIHRtcFswXSAvIDEwICsgXCIuXCIgKyB0bXBbMF0gJSAxMCk7XG5cbiAgICAgICAgZ3BmbGFncyA9IHJlYWRCeXRlKCk7XG4gICAgICAgIGdwZmxhZ3MgfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG4gICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICBhbGVydChcImdwZmxhZ3M6IFwiICsgZ3BmbGFncyk7XG5cbiAgICAgICAgdmFyIG1ldGhvZCA9IHJlYWRCeXRlKCk7XG4gICAgICAgIG1ldGhvZCB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcbiAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgIGFsZXJ0KFwibWV0aG9kOiBcIiArIG1ldGhvZCk7XG5cbiAgICAgICAgcmVhZEJ5dGUoKTtcbiAgICAgICAgcmVhZEJ5dGUoKTtcbiAgICAgICAgcmVhZEJ5dGUoKTtcbiAgICAgICAgcmVhZEJ5dGUoKTtcblxuICAgICAgICB2YXIgY3JjID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgY3JjIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuICAgICAgICBjcmMgfD0gKHJlYWRCeXRlKCkgPDwgMTYpO1xuICAgICAgICBjcmMgfD0gKHJlYWRCeXRlKCkgPDwgMjQpO1xuXG4gICAgICAgIHZhciBjb21wU2l6ZSA9IHJlYWRCeXRlKCk7XG4gICAgICAgIGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuICAgICAgICBjb21wU2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgICAgIGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpIDw8IDI0KTtcblxuICAgICAgICB2YXIgc2l6ZSA9IHJlYWRCeXRlKCk7XG4gICAgICAgIHNpemUgfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG4gICAgICAgIHNpemUgfD0gKHJlYWRCeXRlKCkgPDwgMTYpO1xuICAgICAgICBzaXplIHw9IChyZWFkQnl0ZSgpIDw8IDI0KTtcblxuICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgYWxlcnQoXCJsb2NhbCBDUkM6IFwiICsgY3JjICsgXCJcXG5sb2NhbCBTaXplOiBcIiArIHNpemUgKyBcIlxcbmxvY2FsIENvbXBTaXplOiBcIiArIGNvbXBTaXplKTtcblxuICAgICAgICB2YXIgZmlsZWxlbiA9IHJlYWRCeXRlKCk7XG4gICAgICAgIGZpbGVsZW4gfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG5cbiAgICAgICAgdmFyIGV4dHJhbGVuID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgZXh0cmFsZW4gfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG5cbiAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgIGFsZXJ0KFwiZmlsZWxlbiBcIiArIGZpbGVsZW4pO1xuICAgICAgICBpID0gMDtcbiAgICAgICAgbmFtZUJ1ZiA9IFtdO1xuICAgICAgICB3aGlsZSAoZmlsZWxlbi0tKSB7XG4gICAgICAgICAgdmFyIGMgPSByZWFkQnl0ZSgpO1xuICAgICAgICAgIGlmIChjID09IFwiL1wiIHwgYyA9PSBcIjpcIikge1xuICAgICAgICAgICAgaSA9IDA7XG4gICAgICAgICAgfSBlbHNlIGlmIChpIDwgTkFNRU1BWCAtIDEpXG4gICAgICAgICAgICBuYW1lQnVmW2krK10gPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGMpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICBhbGVydChcIm5hbWVCdWY6IFwiICsgbmFtZUJ1Zik7XG5cbiAgICAgICAgLy9uYW1lQnVmW2ldID0gXCJcXDBcIjtcbiAgICAgICAgaWYgKCFmaWxlb3V0KVxuICAgICAgICAgIGZpbGVvdXQgPSBuYW1lQnVmO1xuXG4gICAgICAgIHZhciBpID0gMDtcbiAgICAgICAgd2hpbGUgKGkgPCBleHRyYWxlbikge1xuICAgICAgICAgIGMgPSByZWFkQnl0ZSgpO1xuICAgICAgICAgIGkrKztcbiAgICAgICAgfVxuXG4gICAgICAgIENSQyA9IDB4ZmZmZmZmZmY7XG4gICAgICAgIFNJWkUgPSAwO1xuXG4gICAgICAgIGlmIChzaXplID09IDAgJiYgZmlsZU91dC5jaGFyQXQoZmlsZW91dC5sZW5ndGggLSAxKSA9PSBcIi9cIikge1xuICAgICAgICAgIC8vc2tpcGRpclxuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGFsZXJ0KFwic2tpcGRpclwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWV0aG9kID09IDgpIHtcbiAgICAgICAgICBEZWZsYXRlTG9vcCgpO1xuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGFsZXJ0KG91dHB1dEFyci5qb2luKCcnKSk7XG4gICAgICAgICAgdW56aXBwZWRbZmlsZXNdID0gbmV3IEFycmF5KDIpO1xuICAgICAgICAgIHVuemlwcGVkW2ZpbGVzXVswXSA9IG91dHB1dEFyci5qb2luKCcnKTtcbiAgICAgICAgICB1bnppcHBlZFtmaWxlc11bMV0gPSBuYW1lQnVmLmpvaW4oJycpO1xuICAgICAgICAgIGZpbGVzKys7XG4gICAgICAgICAgLy9yZXR1cm4gb3V0cHV0QXJyLmpvaW4oJycpO1xuICAgICAgICB9XG4gICAgICAgIHNraXBkaXIoKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgZnVuY3Rpb24gc2tpcGRpcigpIHtcbiAgICB2YXIgY3JjLFxuICAgICAgdG1wID0gW10sXG4gICAgICBjb21wU2l6ZSwgc2l6ZSwgb3MsIGksIGM7XG5cbiAgICBpZiAoKGdwZmxhZ3MgJiA4KSkge1xuICAgICAgdG1wWzBdID0gcmVhZEJ5dGUoKTtcbiAgICAgIHRtcFsxXSA9IHJlYWRCeXRlKCk7XG4gICAgICB0bXBbMl0gPSByZWFkQnl0ZSgpO1xuICAgICAgdG1wWzNdID0gcmVhZEJ5dGUoKTtcblxuICAgICAgaWYgKHRtcFswXSA9PSBwYXJzZUludChcIjUwXCIsIDE2KSAmJlxuICAgICAgICB0bXBbMV0gPT0gcGFyc2VJbnQoXCI0YlwiLCAxNikgJiZcbiAgICAgICAgdG1wWzJdID09IHBhcnNlSW50KFwiMDdcIiwgMTYpICYmXG4gICAgICAgIHRtcFszXSA9PSBwYXJzZUludChcIjA4XCIsIDE2KSkge1xuICAgICAgICBjcmMgPSByZWFkQnl0ZSgpO1xuICAgICAgICBjcmMgfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG4gICAgICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCAyNCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjcmMgPSB0bXBbMF0gfCAodG1wWzFdIDw8IDgpIHwgKHRtcFsyXSA8PCAxNikgfCAodG1wWzNdIDw8IDI0KTtcbiAgICAgIH1cblxuICAgICAgY29tcFNpemUgPSByZWFkQnl0ZSgpO1xuICAgICAgY29tcFNpemUgfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG4gICAgICBjb21wU2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgICBjb21wU2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAyNCk7XG5cbiAgICAgIHNpemUgPSByZWFkQnl0ZSgpO1xuICAgICAgc2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcbiAgICAgIHNpemUgfD0gKHJlYWRCeXRlKCkgPDwgMTYpO1xuICAgICAgc2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAyNCk7XG5cbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQoXCJDUkM6XCIpO1xuICAgIH1cblxuICAgIGlmIChtb2RlWklQKVxuICAgICAgbmV4dEZpbGUoKTtcblxuICAgIHRtcFswXSA9IHJlYWRCeXRlKCk7XG4gICAgaWYgKHRtcFswXSAhPSA4KSB7XG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGFsZXJ0KFwiVW5rbm93biBjb21wcmVzc2lvbiBtZXRob2QhXCIpO1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgZ3BmbGFncyA9IHJlYWRCeXRlKCk7XG4gICAgaWYgKGRlYnVnKSB7XG4gICAgICBpZiAoKGdwZmxhZ3MgJiB+KHBhcnNlSW50KFwiMWZcIiwgMTYpKSkpXG4gICAgICAgIGFsZXJ0KFwiVW5rbm93biBmbGFncyBzZXQhXCIpO1xuICAgIH1cblxuICAgIHJlYWRCeXRlKCk7XG4gICAgcmVhZEJ5dGUoKTtcbiAgICByZWFkQnl0ZSgpO1xuICAgIHJlYWRCeXRlKCk7XG5cbiAgICByZWFkQnl0ZSgpO1xuICAgIG9zID0gcmVhZEJ5dGUoKTtcblxuICAgIGlmICgoZ3BmbGFncyAmIDQpKSB7XG4gICAgICB0bXBbMF0gPSByZWFkQnl0ZSgpO1xuICAgICAgdG1wWzJdID0gcmVhZEJ5dGUoKTtcbiAgICAgIGxlbiA9IHRtcFswXSArIDI1NiAqIHRtcFsxXTtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQoXCJFeHRyYSBmaWVsZCBzaXplOiBcIiArIGxlbik7XG4gICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICAgIHJlYWRCeXRlKCk7XG4gICAgfVxuXG4gICAgaWYgKChncGZsYWdzICYgOCkpIHtcbiAgICAgIGkgPSAwO1xuICAgICAgbmFtZUJ1ZiA9IFtdO1xuICAgICAgd2hpbGUgKGMgPSByZWFkQnl0ZSgpKSB7XG4gICAgICAgIGlmIChjID09IFwiN1wiIHx8IGMgPT0gXCI6XCIpXG4gICAgICAgICAgaSA9IDA7XG4gICAgICAgIGlmIChpIDwgTkFNRU1BWCAtIDEpXG4gICAgICAgICAgbmFtZUJ1ZltpKytdID0gYztcbiAgICAgIH1cbiAgICAgIC8vbmFtZUJ1ZltpXSA9IFwiXFwwXCI7XG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGFsZXJ0KFwib3JpZ2luYWwgZmlsZSBuYW1lOiBcIiArIG5hbWVCdWYpO1xuICAgIH1cblxuICAgIGlmICgoZ3BmbGFncyAmIDE2KSkge1xuICAgICAgd2hpbGUgKGMgPSByZWFkQnl0ZSgpKSB7XG4gICAgICAgIC8vRklMRSBDT01NRU5UXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKChncGZsYWdzICYgMikpIHtcbiAgICAgIHJlYWRCeXRlKCk7XG4gICAgICByZWFkQnl0ZSgpO1xuICAgIH1cblxuICAgIERlZmxhdGVMb29wKCk7XG5cbiAgICBjcmMgPSByZWFkQnl0ZSgpO1xuICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcbiAgICBjcmMgfD0gKHJlYWRCeXRlKCkgPDwgMTYpO1xuICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCAyNCk7XG5cbiAgICBzaXplID0gcmVhZEJ5dGUoKTtcbiAgICBzaXplIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuICAgIHNpemUgfD0gKHJlYWRCeXRlKCkgPDwgMTYpO1xuICAgIHNpemUgfD0gKHJlYWRCeXRlKCkgPDwgMjQpO1xuXG4gICAgaWYgKG1vZGVaSVApXG4gICAgICBuZXh0RmlsZSgpO1xuXG4gIH07XG5cbn07XG5cbi8qKlxuICogIEJhc2U2NCBlbmNvZGluZyAvIGRlY29kaW5nXG4gKiAge0BsaW5rIGh0dHA6Ly93d3cud2VidG9vbGtpdC5pbmZvL31cbiAqL1xuSlhHLlV0aWwuQmFzZTY0ID0ge1xuXG4gIC8vIHByaXZhdGUgcHJvcGVydHlcbiAgX2tleVN0cjogXCJBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvPVwiLFxuXG4gIC8vIHB1YmxpYyBtZXRob2QgZm9yIGVuY29kaW5nXG4gIGVuY29kZTogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICB2YXIgb3V0cHV0ID0gW10sXG4gICAgICBjaHIxLCBjaHIyLCBjaHIzLCBlbmMxLCBlbmMyLCBlbmMzLCBlbmM0LFxuICAgICAgaSA9IDA7XG5cbiAgICBpbnB1dCA9IEpYRy5VdGlsLkJhc2U2NC5fdXRmOF9lbmNvZGUoaW5wdXQpO1xuXG4gICAgd2hpbGUgKGkgPCBpbnB1dC5sZW5ndGgpIHtcblxuICAgICAgY2hyMSA9IGlucHV0LmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgIGNocjIgPSBpbnB1dC5jaGFyQ29kZUF0KGkrKyk7XG4gICAgICBjaHIzID0gaW5wdXQuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICBlbmMxID0gY2hyMSA+PiAyO1xuICAgICAgZW5jMiA9ICgoY2hyMSAmIDMpIDw8IDQpIHwgKGNocjIgPj4gNCk7XG4gICAgICBlbmMzID0gKChjaHIyICYgMTUpIDw8IDIpIHwgKGNocjMgPj4gNik7XG4gICAgICBlbmM0ID0gY2hyMyAmIDYzO1xuXG4gICAgICBpZiAoaXNOYU4oY2hyMikpIHtcbiAgICAgICAgZW5jMyA9IGVuYzQgPSA2NDtcbiAgICAgIH0gZWxzZSBpZiAoaXNOYU4oY2hyMykpIHtcbiAgICAgICAgZW5jNCA9IDY0O1xuICAgICAgfVxuXG4gICAgICBvdXRwdXQucHVzaChbdGhpcy5fa2V5U3RyLmNoYXJBdChlbmMxKSxcbiAgICAgICAgICB0aGlzLl9rZXlTdHIuY2hhckF0KGVuYzIpLFxuICAgICAgICAgIHRoaXMuX2tleVN0ci5jaGFyQXQoZW5jMyksXG4gICAgICAgICAgdGhpcy5fa2V5U3RyLmNoYXJBdChlbmM0KVxuICAgICAgXS5qb2luKCcnKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG91dHB1dC5qb2luKCcnKTtcbiAgfSxcblxuICAvLyBwdWJsaWMgbWV0aG9kIGZvciBkZWNvZGluZ1xuICBkZWNvZGU6IGZ1bmN0aW9uKGlucHV0LCB1dGY4KSB7XG4gICAgdmFyIG91dHB1dCA9IFtdLFxuICAgICAgY2hyMSwgY2hyMiwgY2hyMyxcbiAgICAgIGVuYzEsIGVuYzIsIGVuYzMsIGVuYzQsXG4gICAgICBpID0gMDtcblxuICAgIGlucHV0ID0gaW5wdXQucmVwbGFjZSgvW15BLVphLXowLTlcXCtcXC9cXD1dL2csIFwiXCIpO1xuXG4gICAgd2hpbGUgKGkgPCBpbnB1dC5sZW5ndGgpIHtcblxuICAgICAgZW5jMSA9IHRoaXMuX2tleVN0ci5pbmRleE9mKGlucHV0LmNoYXJBdChpKyspKTtcbiAgICAgIGVuYzIgPSB0aGlzLl9rZXlTdHIuaW5kZXhPZihpbnB1dC5jaGFyQXQoaSsrKSk7XG4gICAgICBlbmMzID0gdGhpcy5fa2V5U3RyLmluZGV4T2YoaW5wdXQuY2hhckF0KGkrKykpO1xuICAgICAgZW5jNCA9IHRoaXMuX2tleVN0ci5pbmRleE9mKGlucHV0LmNoYXJBdChpKyspKTtcblxuICAgICAgY2hyMSA9IChlbmMxIDw8IDIpIHwgKGVuYzIgPj4gNCk7XG4gICAgICBjaHIyID0gKChlbmMyICYgMTUpIDw8IDQpIHwgKGVuYzMgPj4gMik7XG4gICAgICBjaHIzID0gKChlbmMzICYgMykgPDwgNikgfCBlbmM0O1xuXG4gICAgICBvdXRwdXQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGNocjEpKTtcblxuICAgICAgaWYgKGVuYzMgIT0gNjQpIHtcbiAgICAgICAgb3V0cHV0LnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShjaHIyKSk7XG4gICAgICB9XG4gICAgICBpZiAoZW5jNCAhPSA2NCkge1xuICAgICAgICBvdXRwdXQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGNocjMpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBvdXRwdXQgPSBvdXRwdXQuam9pbignJyk7XG5cbiAgICBpZiAodXRmOCkge1xuICAgICAgb3V0cHV0ID0gSlhHLlV0aWwuQmFzZTY0Ll91dGY4X2RlY29kZShvdXRwdXQpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuXG4gIH0sXG5cbiAgLy8gcHJpdmF0ZSBtZXRob2QgZm9yIFVURi04IGVuY29kaW5nXG4gIF91dGY4X2VuY29kZTogZnVuY3Rpb24oc3RyaW5nKSB7XG4gICAgc3RyaW5nID0gc3RyaW5nLnJlcGxhY2UoL1xcclxcbi9nLCBcIlxcblwiKTtcbiAgICB2YXIgdXRmdGV4dCA9IFwiXCI7XG5cbiAgICBmb3IgKHZhciBuID0gMDsgbiA8IHN0cmluZy5sZW5ndGg7IG4rKykge1xuXG4gICAgICB2YXIgYyA9IHN0cmluZy5jaGFyQ29kZUF0KG4pO1xuXG4gICAgICBpZiAoYyA8IDEyOCkge1xuICAgICAgICB1dGZ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYyk7XG4gICAgICB9IGVsc2UgaWYgKChjID4gMTI3KSAmJiAoYyA8IDIwNDgpKSB7XG4gICAgICAgIHV0ZnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoYyA+PiA2KSB8IDE5Mik7XG4gICAgICAgIHV0ZnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoYyAmIDYzKSB8IDEyOCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB1dGZ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgPj4gMTIpIHwgMjI0KTtcbiAgICAgICAgdXRmdGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCgoYyA+PiA2KSAmIDYzKSB8IDEyOCk7XG4gICAgICAgIHV0ZnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoYyAmIDYzKSB8IDEyOCk7XG4gICAgICB9XG5cbiAgICB9XG5cbiAgICByZXR1cm4gdXRmdGV4dDtcbiAgfSxcblxuICAvLyBwcml2YXRlIG1ldGhvZCBmb3IgVVRGLTggZGVjb2RpbmdcbiAgX3V0ZjhfZGVjb2RlOiBmdW5jdGlvbih1dGZ0ZXh0KSB7XG4gICAgdmFyIHN0cmluZyA9IFtdLFxuICAgICAgaSA9IDAsXG4gICAgICBjID0gMCxcbiAgICAgIGMyID0gMCxcbiAgICAgIGMzID0gMDtcblxuICAgIHdoaWxlIChpIDwgdXRmdGV4dC5sZW5ndGgpIHtcbiAgICAgIGMgPSB1dGZ0ZXh0LmNoYXJDb2RlQXQoaSk7XG4gICAgICBpZiAoYyA8IDEyOCkge1xuICAgICAgICBzdHJpbmcucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGMpKTtcbiAgICAgICAgaSsrO1xuICAgICAgfSBlbHNlIGlmICgoYyA+IDE5MSkgJiYgKGMgPCAyMjQpKSB7XG4gICAgICAgIGMyID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkgKyAxKTtcbiAgICAgICAgc3RyaW5nLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZSgoKGMgJiAzMSkgPDwgNikgfCAoYzIgJiA2MykpKTtcbiAgICAgICAgaSArPSAyO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYzIgPSB1dGZ0ZXh0LmNoYXJDb2RlQXQoaSArIDEpO1xuICAgICAgICBjMyA9IHV0ZnRleHQuY2hhckNvZGVBdChpICsgMik7XG4gICAgICAgIHN0cmluZy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoKChjICYgMTUpIDw8IDEyKSB8ICgoYzIgJiA2MykgPDwgNikgfCAoYzMgJiA2MykpKTtcbiAgICAgICAgaSArPSAzO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gc3RyaW5nLmpvaW4oJycpO1xuICB9LFxuXG4gIF9kZXN0cmlwOiBmdW5jdGlvbihzdHJpcHBlZCwgd3JhcCkge1xuICAgIHZhciBsaW5lcyA9IFtdLFxuICAgICAgbGluZW5vLCBpLFxuICAgICAgZGVzdHJpcHBlZCA9IFtdO1xuXG4gICAgaWYgKHdyYXAgPT0gbnVsbClcbiAgICAgIHdyYXAgPSA3NjtcblxuICAgIHN0cmlwcGVkLnJlcGxhY2UoLyAvZywgXCJcIik7XG4gICAgbGluZW5vID0gc3RyaXBwZWQubGVuZ3RoIC8gd3JhcDtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGluZW5vOyBpKyspXG4gICAgICBsaW5lc1tpXSA9IHN0cmlwcGVkLnN1YnN0cihpICogd3JhcCwgd3JhcCk7XG4gICAgaWYgKGxpbmVubyAhPSBzdHJpcHBlZC5sZW5ndGggLyB3cmFwKVxuICAgICAgbGluZXNbbGluZXMubGVuZ3RoXSA9IHN0cmlwcGVkLnN1YnN0cihsaW5lbm8gKiB3cmFwLCBzdHJpcHBlZC5sZW5ndGggLSAobGluZW5vICogd3JhcCkpO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKVxuICAgICAgZGVzdHJpcHBlZC5wdXNoKGxpbmVzW2ldKTtcbiAgICByZXR1cm4gZGVzdHJpcHBlZC5qb2luKCdcXG4nKTtcbiAgfSxcblxuICBkZWNvZGVBc0FycmF5OiBmdW5jdGlvbihpbnB1dCkge1xuICAgIHZhciBkZWMgPSB0aGlzLmRlY29kZShpbnB1dCksXG4gICAgICBhciA9IFtdLFxuICAgICAgaTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgZGVjLmxlbmd0aDsgaSsrKSB7XG4gICAgICBhcltpXSA9IGRlYy5jaGFyQ29kZUF0KGkpO1xuICAgIH1cbiAgICByZXR1cm4gYXI7XG4gIH0sXG5cbiAgZGVjb2RlR0VPTkV4VDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICByZXR1cm4gZGVjb2RlQXNBcnJheShkZXN0cmlwKGlucHV0KSwgZmFsc2UpO1xuICB9XG59O1xuXG4vKipcbiAqIEBwcml2YXRlXG4gKi9cbkpYRy5VdGlsLmFzY2lpQ2hhckNvZGVBdCA9IGZ1bmN0aW9uKHN0ciwgaSkge1xuICB2YXIgYyA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuICBpZiAoYyA+IDI1NSkge1xuICAgIHN3aXRjaCAoYykge1xuICAgICAgY2FzZSA4MzY0OlxuICAgICAgICBjID0gMTI4O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIxODpcbiAgICAgICAgYyA9IDEzMDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDQwMjpcbiAgICAgICAgYyA9IDEzMTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMjI6XG4gICAgICAgIGMgPSAxMzI7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjMwOlxuICAgICAgICBjID0gMTMzO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIyNDpcbiAgICAgICAgYyA9IDEzNDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMjU6XG4gICAgICAgIGMgPSAxMzU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA3MTA6XG4gICAgICAgIGMgPSAxMzY7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjQwOlxuICAgICAgICBjID0gMTM3O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzUyOlxuICAgICAgICBjID0gMTM4O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODI0OTpcbiAgICAgICAgYyA9IDEzOTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDMzODpcbiAgICAgICAgYyA9IDE0MDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM4MTpcbiAgICAgICAgYyA9IDE0MjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMTY6XG4gICAgICAgIGMgPSAxNDU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjE3OlxuICAgICAgICBjID0gMTQ2O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIyMDpcbiAgICAgICAgYyA9IDE0NztcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMjE6XG4gICAgICAgIGMgPSAxNDg7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjI2OlxuICAgICAgICBjID0gMTQ5O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIxMTpcbiAgICAgICAgYyA9IDE1MDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMTI6XG4gICAgICAgIGMgPSAxNTE7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA3MzI6XG4gICAgICAgIGMgPSAxNTI7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4NDgyOlxuICAgICAgICBjID0gMTUzO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzUzOlxuICAgICAgICBjID0gMTU0O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODI1MDpcbiAgICAgICAgYyA9IDE1NTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDMzOTpcbiAgICAgICAgYyA9IDE1NjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM4MjpcbiAgICAgICAgYyA9IDE1ODtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM3NjpcbiAgICAgICAgYyA9IDE1OTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGM7XG59O1xuXG4vKipcbiAqIERlY29kaW5nIHN0cmluZyBpbnRvIHV0Zi04XG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyaW5nIHRvIGRlY29kZVxuICogQHJldHVybiB7U3RyaW5nfSB1dGY4IGRlY29kZWQgc3RyaW5nXG4gKi9cbkpYRy5VdGlsLnV0ZjhEZWNvZGUgPSBmdW5jdGlvbih1dGZ0ZXh0KSB7XG4gIHZhciBzdHJpbmcgPSBbXTtcbiAgdmFyIGkgPSAwO1xuICB2YXIgYyA9IDAsXG4gICAgYzEgPSAwLFxuICAgIGMyID0gMCxcbiAgICBjMztcbiAgaWYgKCFKWEcuZXhpc3RzKHV0ZnRleHQpKSByZXR1cm4gJyc7XG5cbiAgd2hpbGUgKGkgPCB1dGZ0ZXh0Lmxlbmd0aCkge1xuICAgIGMgPSB1dGZ0ZXh0LmNoYXJDb2RlQXQoaSk7XG5cbiAgICBpZiAoYyA8IDEyOCkge1xuICAgICAgc3RyaW5nLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShjKSk7XG4gICAgICBpKys7XG4gICAgfSBlbHNlIGlmICgoYyA+IDE5MSkgJiYgKGMgPCAyMjQpKSB7XG4gICAgICBjMiA9IHV0ZnRleHQuY2hhckNvZGVBdChpICsgMSk7XG4gICAgICBzdHJpbmcucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKCgoYyAmIDMxKSA8PCA2KSB8IChjMiAmIDYzKSkpO1xuICAgICAgaSArPSAyO1xuICAgIH0gZWxzZSB7XG4gICAgICBjMiA9IHV0ZnRleHQuY2hhckNvZGVBdChpICsgMSk7XG4gICAgICBjMyA9IHV0ZnRleHQuY2hhckNvZGVBdChpICsgMik7XG4gICAgICBzdHJpbmcucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKCgoYyAmIDE1KSA8PCAxMikgfCAoKGMyICYgNjMpIDw8IDYpIHwgKGMzICYgNjMpKSk7XG4gICAgICBpICs9IDM7XG4gICAgfVxuICB9O1xuICByZXR1cm4gc3RyaW5nLmpvaW4oJycpO1xufTtcblxuLyoqXG4gKiBHZW5lcmF0ZSBhIHJhbmRvbSB1dWlkLlxuICogaHR0cDovL3d3dy5icm9vZmEuY29tXG4gKiBtYWlsdG86cm9iZXJ0QGJyb29mYS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAgUm9iZXJ0IEtpZWZmZXJcbiAqIER1YWwgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBhbmQgR1BMIGxpY2Vuc2VzLlxuICpcbiAqIEVYQU1QTEVTOlxuICogICA+Pj4gTWF0aC51dWlkKClcbiAqICAgXCI5MjMyOUQzOS02RjVDLTQ1MjAtQUJGQy1BQUI2NDU0NEUxNzJcIlxuICovXG5KWEcuVXRpbC5nZW5VVUlEID0gZnVuY3Rpb24oKSB7XG4gIC8vIFByaXZhdGUgYXJyYXkgb2YgY2hhcnMgdG8gdXNlXG4gIHZhciBjaGFycyA9ICcwMTIzNDU2Nzg5QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eicuc3BsaXQoJycpLFxuICAgIHV1aWQgPSBuZXcgQXJyYXkoMzYpLFxuICAgIHJuZCA9IDAsXG4gICAgcjtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IDM2OyBpKyspIHtcbiAgICBpZiAoaSA9PSA4IHx8IGkgPT0gMTMgfHwgaSA9PSAxOCB8fCBpID09IDIzKSB7XG4gICAgICB1dWlkW2ldID0gJy0nO1xuICAgIH0gZWxzZSBpZiAoaSA9PSAxNCkge1xuICAgICAgdXVpZFtpXSA9ICc0JztcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHJuZCA8PSAweDAyKSBybmQgPSAweDIwMDAwMDAgKyAoTWF0aC5yYW5kb20oKSAqIDB4MTAwMDAwMCkgfCAwO1xuICAgICAgciA9IHJuZCAmIDB4ZjtcbiAgICAgIHJuZCA9IHJuZCA+PiA0O1xuICAgICAgdXVpZFtpXSA9IGNoYXJzWyhpID09IDE5KSA/IChyICYgMHgzKSB8IDB4OCA6IHJdO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB1dWlkLmpvaW4oJycpO1xufTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IEpYRztcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy9cbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vL1xuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vL1xuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogVGhpcyBvYmplY3QgY29udGFpbnMgY29uZmlndXJhdGlvbiB2YWx1ZXMuXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEBwcm9wZXJ0eSB7SW50ZWdlcn0gcHJlZmVyX2hhc2hfYWxnb3JpdGhtXG4gKiBAcHJvcGVydHkge0ludGVnZXJ9IGVuY3J5cHRpb25fY2lwaGVyXG4gKiBAcHJvcGVydHkge0ludGVnZXJ9IGNvbXByZXNzaW9uXG4gKiBAcHJvcGVydHkge0Jvb2xlYW59IHNob3dfdmVyc2lvblxuICogQHByb3BlcnR5IHtCb29sZWFufSBzaG93X2NvbW1lbnRcbiAqIEBwcm9wZXJ0eSB7Qm9vbGVhbn0gaW50ZWdyaXR5X3Byb3RlY3RcbiAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBrZXlzZXJ2ZXJcbiAqIEBwcm9wZXJ0eSB7Qm9vbGVhbn0gZGVidWcgSWYgZW5hYmxlZCwgZGVidWcgbWVzc2FnZXMgd2lsbCBiZSBwcmludGVkXG4gKiBAbW9kdWxlIGNvbmZpZy9jb25maWdcbiAqL1xuXG52YXIgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgcHJlZmVyX2hhc2hfYWxnb3JpdGhtOiBlbnVtcy5oYXNoLnNoYTI1NixcbiAgZW5jcnlwdGlvbl9jaXBoZXI6IGVudW1zLnN5bW1ldHJpYy5hZXMyNTYsXG4gIGNvbXByZXNzaW9uOiBlbnVtcy5jb21wcmVzc2lvbi56aXAsXG4gIHNob3dfdmVyc2lvbjogdHJ1ZSxcbiAgc2hvd19jb21tZW50OiB0cnVlLFxuICBpbnRlZ3JpdHlfcHJvdGVjdDogdHJ1ZSxcbiAga2V5c2VydmVyOiBcImtleXNlcnZlci5saW51eC5pdFwiLCAvLyBcInBncC5taXQuZWR1OjExMzcxXCJcblxuICB2ZXJzaW9uc3RyaW5nOiBcIk9wZW5QR1AuanMgVkVSU0lPTlwiLFxuICBjb21tZW50c3RyaW5nOiBcImh0dHA6Ly9vcGVucGdwanMub3JnXCIsXG5cbiAgZGVidWc6IGZhbHNlXG59O1xuIiwiLy8gTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIIFxuXG4vLyBtb2RpZmllZCB2ZXJzaW9uIG9mIGh0dHA6Ly93d3cuaGFuZXdpbi5uZXQvZW5jcnlwdC9QR2RlY29kZS5qczpcblxuLyogT3BlblBHUCBlbmNyeXB0aW9uIHVzaW5nIFJTQS9BRVNcbiAqIENvcHlyaWdodCAyMDA1LTIwMDYgSGVyYmVydCBIYW5ld2lua2VsLCB3d3cuaGFuZVdJTi5kZVxuICogdmVyc2lvbiAyLjAsIGNoZWNrIHd3dy5oYW5lV0lOLmRlIGZvciB0aGUgbGF0ZXN0IHZlcnNpb25cblxuICogVGhpcyBzb2Z0d2FyZSBpcyBwcm92aWRlZCBhcy1pcywgd2l0aG91dCBleHByZXNzIG9yIGltcGxpZWQgd2FycmFudHkuICBcbiAqIFBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGRpc3RyaWJ1dGUgb3Igc2VsbCB0aGlzIHNvZnR3YXJlLCB3aXRoIG9yXG4gKiB3aXRob3V0IGZlZSwgZm9yIGFueSBwdXJwb3NlIGFuZCBieSBhbnkgaW5kaXZpZHVhbCBvciBvcmdhbml6YXRpb24sIGlzIGhlcmVieVxuICogZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwYXJhZ3JhcGggYXBwZWFyIFxuICogaW4gYWxsIGNvcGllcy4gRGlzdHJpYnV0aW9uIGFzIGEgcGFydCBvZiBhbiBhcHBsaWNhdGlvbiBvciBiaW5hcnkgbXVzdFxuICogaW5jbHVkZSB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXJcbiAqIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZSBhcHBsaWNhdGlvbiBvciBkaXN0cmlidXRpb24uXG4gKi9cblxuLyoqXG4gKiBAcmVxdWlyZXMgY3J5cHRvL2NpcGhlclxuICogQHJlcXVpcmVzIHV0aWxcbiAqIEBtb2R1bGUgY3J5cHRvL2NmYlxuICovXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuICBjaXBoZXIgPSByZXF1aXJlKCcuL2NpcGhlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcblxuICAvKipcbiAgICogVGhpcyBmdW5jdGlvbiBlbmNyeXB0cyBhIGdpdmVuIHdpdGggdGhlIHNwZWNpZmllZCBwcmVmaXhyYW5kb20gXG4gICAqIHVzaW5nIHRoZSBzcGVjaWZpZWQgYmxvY2tjaXBoZXIgdG8gZW5jcnlwdCBhIG1lc3NhZ2VcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByZWZpeHJhbmRvbSByYW5kb20gYnl0ZXMgb2YgYmxvY2tfc2l6ZSBsZW5ndGggcHJvdmlkZWQgXG4gICAqICBhcyBhIHN0cmluZyB0byBiZSB1c2VkIGluIHByZWZpeGluZyB0aGUgZGF0YVxuICAgKiBAcGFyYW0ge1N0cmluZ30gY2lwaGVyZm4gdGhlIGFsZ29yaXRobSBjaXBoZXIgY2xhc3MgdG8gZW5jcnlwdFxuICAgKiAgZGF0YSBpbiBvbmUgYmxvY2tfc2l6ZSBlbmNyeXB0aW9uLCBAc2VlIG1vZHVsZTpjcnlwdG8vY2lwaGVyLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gcGxhaW50ZXh0IGRhdGEgdG8gYmUgZW5jcnlwdGVkIHByb3ZpZGVkIGFzIGEgc3RyaW5nXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBrZXkgYmluYXJ5IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBrZXkgdG8gYmUgdXNlZCB0byBlbmNyeXB0IHRoZSBwbGFpbnRleHQuXG4gICAqIFRoaXMgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGNpcGhlcmZuXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gcmVzeW5jIGEgYm9vbGVhbiB2YWx1ZSBzcGVjaWZ5aW5nIGlmIGEgcmVzeW5jIG9mIHRoZVxuICAgKiAgSVYgc2hvdWxkIGJlIHVzZWQgb3Igbm90LiBUaGUgZW5jcnlwdGVkZGF0YXBhY2tldCB1c2VzIHRoZSBcbiAgICogIFwib2xkXCIgc3R5bGUgd2l0aCBhIHJlc3luYy4gRW5jcnlwdGlvbiB3aXRoaW4gYW4gXG4gICAqICBlbmNyeXB0ZWRpbnRlZ3JpdHlwcm90ZWN0ZWRkYXRhIHBhY2tldCBpcyBub3QgcmVzeW5jaW5nIHRoZSBJVi5cbiAgICogQHJldHVybiB7U3RyaW5nfSBhIHN0cmluZyB3aXRoIHRoZSBlbmNyeXB0ZWQgZGF0YVxuICAgKi9cbiAgZW5jcnlwdDogZnVuY3Rpb24ocHJlZml4cmFuZG9tLCBjaXBoZXJmbiwgcGxhaW50ZXh0LCBrZXksIHJlc3luYykge1xuICAgIGNpcGhlcmZuID0gbmV3IGNpcGhlcltjaXBoZXJmbl0oa2V5KTtcbiAgICB2YXIgYmxvY2tfc2l6ZSA9IGNpcGhlcmZuLmJsb2NrU2l6ZTtcblxuICAgIHZhciBGUiA9IG5ldyBBcnJheShibG9ja19zaXplKTtcbiAgICB2YXIgRlJFID0gbmV3IEFycmF5KGJsb2NrX3NpemUpO1xuXG4gICAgcHJlZml4cmFuZG9tID0gcHJlZml4cmFuZG9tICsgcHJlZml4cmFuZG9tLmNoYXJBdChibG9ja19zaXplIC0gMikgKyBwcmVmaXhyYW5kb20uY2hhckF0KGJsb2NrX3NpemUgLSAxKTtcbiAgICB1dGlsLnByaW50X2RlYnVnKFwicHJlZml4cmFuZG9tOlwiICsgdXRpbC5oZXhzdHJkdW1wKHByZWZpeHJhbmRvbSkpO1xuICAgIHZhciBjaXBoZXJ0ZXh0ID0gXCJcIjtcbiAgICAvLyAxLiAgVGhlIGZlZWRiYWNrIHJlZ2lzdGVyIChGUikgaXMgc2V0IHRvIHRoZSBJViwgd2hpY2ggaXMgYWxsIHplcm9zLlxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IDA7XG5cbiAgICAvLyAyLiAgRlIgaXMgZW5jcnlwdGVkIHRvIHByb2R1Y2UgRlJFIChGUiBFbmNyeXB0ZWQpLiAgVGhpcyBpcyB0aGVcbiAgICAvLyAgICAgZW5jcnlwdGlvbiBvZiBhbiBhbGwtemVybyB2YWx1ZS5cbiAgICBGUkUgPSBjaXBoZXJmbi5lbmNyeXB0KEZSKTtcbiAgICAvLyAzLiAgRlJFIGlzIHhvcmVkIHdpdGggdGhlIGZpcnN0IEJTIG9jdGV0cyBvZiByYW5kb20gZGF0YSBwcmVmaXhlZCB0b1xuICAgIC8vICAgICB0aGUgcGxhaW50ZXh0IHRvIHByb2R1Y2UgQ1sxXSB0aHJvdWdoIENbQlNdLCB0aGUgZmlyc3QgQlMgb2N0ZXRzXG4gICAgLy8gICAgIG9mIGNpcGhlcnRleHQuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIGNpcGhlcnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShGUkVbaV0gXiBwcmVmaXhyYW5kb20uY2hhckNvZGVBdChpKSk7XG5cbiAgICAvLyA0LiAgRlIgaXMgbG9hZGVkIHdpdGggQ1sxXSB0aHJvdWdoIENbQlNdLlxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChpKTtcblxuICAgIC8vIDUuICBGUiBpcyBlbmNyeXB0ZWQgdG8gcHJvZHVjZSBGUkUsIHRoZSBlbmNyeXB0aW9uIG9mIHRoZSBmaXJzdCBCU1xuICAgIC8vIFx0ICAgb2N0ZXRzIG9mIGNpcGhlcnRleHQuXG4gICAgRlJFID0gY2lwaGVyZm4uZW5jcnlwdChGUik7XG5cbiAgICAvLyA2LiAgVGhlIGxlZnQgdHdvIG9jdGV0cyBvZiBGUkUgZ2V0IHhvcmVkIHdpdGggdGhlIG5leHQgdHdvIG9jdGV0cyBvZlxuICAgIC8vICAgICBkYXRhIHRoYXQgd2VyZSBwcmVmaXhlZCB0byB0aGUgcGxhaW50ZXh0LiAgVGhpcyBwcm9kdWNlcyBDW0JTKzFdXG4gICAgLy8gICAgIGFuZCBDW0JTKzJdLCB0aGUgbmV4dCB0d28gb2N0ZXRzIG9mIGNpcGhlcnRleHQuXG4gICAgY2lwaGVydGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVswXSBeIHByZWZpeHJhbmRvbS5jaGFyQ29kZUF0KGJsb2NrX3NpemUpKTtcbiAgICBjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFWzFdIF4gcHJlZml4cmFuZG9tLmNoYXJDb2RlQXQoYmxvY2tfc2l6ZSArIDEpKTtcblxuICAgIGlmIChyZXN5bmMpIHtcbiAgICAgIC8vIDcuICAoVGhlIHJlc3luYyBzdGVwKSBGUiBpcyBsb2FkZWQgd2l0aCBDMy1DMTAuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykgRlJbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSArIDIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykgRlJbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSk7XG4gICAgfVxuICAgIC8vIDguICBGUiBpcyBlbmNyeXB0ZWQgdG8gcHJvZHVjZSBGUkUuXG4gICAgRlJFID0gY2lwaGVyZm4uZW5jcnlwdChGUiwga2V5KTtcblxuICAgIGlmIChyZXN5bmMpIHtcbiAgICAgIC8vIDkuICBGUkUgaXMgeG9yZWQgd2l0aCB0aGUgZmlyc3QgOCBvY3RldHMgb2YgdGhlIGdpdmVuIHBsYWludGV4dCwgbm93XG4gICAgICAvL1x0ICAgdGhhdCB3ZSBoYXZlIGZpbmlzaGVkIGVuY3J5cHRpbmcgdGhlIDEwIG9jdGV0cyBvZiBwcmVmaXhlZCBkYXRhLlxuICAgICAgLy8gXHQgICBUaGlzIHByb2R1Y2VzIEMxMS1DMTgsIHRoZSBuZXh0IDggb2N0ZXRzIG9mIGNpcGhlcnRleHQuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKylcbiAgICAgICAgY2lwaGVydGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVtpXSBeIHBsYWludGV4dC5jaGFyQ29kZUF0KGkpKTtcbiAgICAgIGZvciAobiA9IGJsb2NrX3NpemUgKyAyOyBuIDwgcGxhaW50ZXh0Lmxlbmd0aDsgbiArPSBibG9ja19zaXplKSB7XG4gICAgICAgIC8vIDEwLiBGUiBpcyBsb2FkZWQgd2l0aCBDMTEtQzE4XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChuICsgaSk7XG5cbiAgICAgICAgLy8gMTEuIEZSIGlzIGVuY3J5cHRlZCB0byBwcm9kdWNlIEZSRS5cbiAgICAgICAgRlJFID0gY2lwaGVyZm4uZW5jcnlwdChGUik7XG5cbiAgICAgICAgLy8gMTIuIEZSRSBpcyB4b3JlZCB3aXRoIHRoZSBuZXh0IDggb2N0ZXRzIG9mIHBsYWludGV4dCwgdG8gcHJvZHVjZSB0aGVcbiAgICAgICAgLy8gbmV4dCA4IG9jdGV0cyBvZiBjaXBoZXJ0ZXh0LiAgVGhlc2UgYXJlIGxvYWRlZCBpbnRvIEZSIGFuZCB0aGVcbiAgICAgICAgLy8gcHJvY2VzcyBpcyByZXBlYXRlZCB1bnRpbCB0aGUgcGxhaW50ZXh0IGlzIHVzZWQgdXAuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFW2ldIF4gcGxhaW50ZXh0LmNoYXJDb2RlQXQoKG4gLSAyKSArXG4gICAgICAgICAgICBpKSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHBsYWludGV4dCA9IFwiICBcIiArIHBsYWludGV4dDtcbiAgICAgIC8vIDkuICBGUkUgaXMgeG9yZWQgd2l0aCB0aGUgZmlyc3QgOCBvY3RldHMgb2YgdGhlIGdpdmVuIHBsYWludGV4dCwgbm93XG4gICAgICAvL1x0ICAgdGhhdCB3ZSBoYXZlIGZpbmlzaGVkIGVuY3J5cHRpbmcgdGhlIDEwIG9jdGV0cyBvZiBwcmVmaXhlZCBkYXRhLlxuICAgICAgLy8gXHQgICBUaGlzIHByb2R1Y2VzIEMxMS1DMTgsIHRoZSBuZXh0IDggb2N0ZXRzIG9mIGNpcGhlcnRleHQuXG4gICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGJsb2NrX3NpemU7IGkrKykgY2lwaGVydGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVtpXSBeIHBsYWludGV4dC5jaGFyQ29kZUF0KGkpKTtcbiAgICAgIHZhciB0ZW1wQ2lwaGVydGV4dCA9IGNpcGhlcnRleHQuc3Vic3RyaW5nKDAsIDIgKiBibG9ja19zaXplKS5zcGxpdCgnJyk7XG4gICAgICB2YXIgdGVtcENpcGhlcnRleHRTdHJpbmcgPSBjaXBoZXJ0ZXh0LnN1YnN0cmluZyhibG9ja19zaXplKTtcbiAgICAgIGZvciAobiA9IGJsb2NrX3NpemU7IG4gPCBwbGFpbnRleHQubGVuZ3RoOyBuICs9IGJsb2NrX3NpemUpIHtcbiAgICAgICAgLy8gMTAuIEZSIGlzIGxvYWRlZCB3aXRoIEMxMS1DMThcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIEZSW2ldID0gdGVtcENpcGhlcnRleHRTdHJpbmcuY2hhckNvZGVBdChpKTtcbiAgICAgICAgdGVtcENpcGhlcnRleHRTdHJpbmcgPSAnJztcblxuICAgICAgICAvLyAxMS4gRlIgaXMgZW5jcnlwdGVkIHRvIHByb2R1Y2UgRlJFLlxuICAgICAgICBGUkUgPSBjaXBoZXJmbi5lbmNyeXB0KEZSKTtcblxuICAgICAgICAvLyAxMi4gRlJFIGlzIHhvcmVkIHdpdGggdGhlIG5leHQgOCBvY3RldHMgb2YgcGxhaW50ZXh0LCB0byBwcm9kdWNlIHRoZVxuICAgICAgICAvLyAgICAgbmV4dCA4IG9jdGV0cyBvZiBjaXBoZXJ0ZXh0LiAgVGhlc2UgYXJlIGxvYWRlZCBpbnRvIEZSIGFuZCB0aGVcbiAgICAgICAgLy8gICAgIHByb2Nlc3MgaXMgcmVwZWF0ZWQgdW50aWwgdGhlIHBsYWludGV4dCBpcyB1c2VkIHVwLlxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykge1xuICAgICAgICAgIHRlbXBDaXBoZXJ0ZXh0LnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShGUkVbaV0gXiBwbGFpbnRleHQuY2hhckNvZGVBdChuICsgaSkpKTtcbiAgICAgICAgICB0ZW1wQ2lwaGVydGV4dFN0cmluZyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVtpXSBeIHBsYWludGV4dC5jaGFyQ29kZUF0KG4gKyBpKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGNpcGhlcnRleHQgPSB0ZW1wQ2lwaGVydGV4dC5qb2luKCcnKTtcblxuICAgIH1cblxuICAgIGNpcGhlcnRleHQgPSBjaXBoZXJ0ZXh0LnN1YnN0cmluZygwLCBwbGFpbnRleHQubGVuZ3RoICsgMiArIGJsb2NrX3NpemUpO1xuXG4gICAgcmV0dXJuIGNpcGhlcnRleHQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIERlY3J5cHRzIHRoZSBwcmVmaXhlZCBkYXRhIGZvciB0aGUgTW9kaWZpY2F0aW9uIERldGVjdGlvbiBDb2RlIChNREMpIGNvbXB1dGF0aW9uXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBjaXBoZXJmbi5lbmNyeXB0IENpcGhlciBmdW5jdGlvbiB0byB1c2UsXG4gICAqICBAc2VlIG1vZHVsZTpjcnlwdG8vY2lwaGVyLlxuICAgKiBAcGFyYW0ge1N0cmluZ30ga2V5IGJpbmFyeSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2Yga2V5IHRvIGJlIHVzZWQgdG8gY2hlY2sgdGhlIG1kY1xuICAgKiBUaGlzIHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBjaXBoZXJmblxuICAgKiBAcGFyYW0ge1N0cmluZ30gY2lwaGVydGV4dCBUaGUgZW5jcnlwdGVkIGRhdGFcbiAgICogQHJldHVybiB7U3RyaW5nfSBwbGFpbnRleHQgRGF0YSBvZiBEKGNpcGhlcnRleHQpIHdpdGggYmxvY2tzaXplIGxlbmd0aCArMlxuICAgKi9cbiAgbWRjOiBmdW5jdGlvbihjaXBoZXJmbiwga2V5LCBjaXBoZXJ0ZXh0KSB7XG4gICAgY2lwaGVyZm4gPSBuZXcgY2lwaGVyW2NpcGhlcmZuXShrZXkpO1xuICAgIHZhciBibG9ja19zaXplID0gY2lwaGVyZm4uYmxvY2tTaXplO1xuXG4gICAgdmFyIGlibG9jayA9IG5ldyBBcnJheShibG9ja19zaXplKTtcbiAgICB2YXIgYWJsb2NrID0gbmV3IEFycmF5KGJsb2NrX3NpemUpO1xuICAgIHZhciBpO1xuXG5cbiAgICAvLyBpbml0aWFsaXNhdGlvbiB2ZWN0b3JcbiAgICBmb3IgKGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBpYmxvY2tbaV0gPSAwO1xuXG4gICAgaWJsb2NrID0gY2lwaGVyZm4uZW5jcnlwdChpYmxvY2spO1xuICAgIGZvciAoaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIHtcbiAgICAgIGFibG9ja1tpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChpKTtcbiAgICAgIGlibG9ja1tpXSBePSBhYmxvY2tbaV07XG4gICAgfVxuXG4gICAgYWJsb2NrID0gY2lwaGVyZm4uZW5jcnlwdChhYmxvY2spO1xuXG4gICAgcmV0dXJuIHV0aWwuYmluMnN0cihpYmxvY2spICtcbiAgICAgIFN0cmluZy5mcm9tQ2hhckNvZGUoYWJsb2NrWzBdIF4gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGJsb2NrX3NpemUpKSArXG4gICAgICBTdHJpbmcuZnJvbUNoYXJDb2RlKGFibG9ja1sxXSBeIGNpcGhlcnRleHQuY2hhckNvZGVBdChibG9ja19zaXplICsgMSkpO1xuICB9LFxuICAvKipcbiAgICogVGhpcyBmdW5jdGlvbiBkZWNyeXB0cyBhIGdpdmVuIHBsYWludGV4dCB1c2luZyB0aGUgc3BlY2lmaWVkXG4gICAqIGJsb2NrY2lwaGVyIHRvIGRlY3J5cHQgYSBtZXNzYWdlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBjaXBoZXJmbiB0aGUgYWxnb3JpdGhtIGNpcGhlciBjbGFzcyB0byBkZWNyeXB0XG4gICAqICBkYXRhIGluIG9uZSBibG9ja19zaXplIGVuY3J5cHRpb24sIEBzZWUgbW9kdWxlOmNyeXB0by9jaXBoZXIuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBrZXkgYmluYXJ5IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBrZXkgdG8gYmUgdXNlZCB0byBkZWNyeXB0IHRoZSBjaXBoZXJ0ZXh0LlxuICAgKiBUaGlzIHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBjaXBoZXJmblxuICAgKiBAcGFyYW0ge1N0cmluZ30gY2lwaGVydGV4dCB0byBiZSBkZWNyeXB0ZWQgcHJvdmlkZWQgYXMgYSBzdHJpbmdcbiAgICogQHBhcmFtIHtCb29sZWFufSByZXN5bmMgYSBib29sZWFuIHZhbHVlIHNwZWNpZnlpbmcgaWYgYSByZXN5bmMgb2YgdGhlXG4gICAqICBJViBzaG91bGQgYmUgdXNlZCBvciBub3QuIFRoZSBlbmNyeXB0ZWRkYXRhcGFja2V0IHVzZXMgdGhlIFxuICAgKiAgXCJvbGRcIiBzdHlsZSB3aXRoIGEgcmVzeW5jLiBEZWNyeXB0aW9uIHdpdGhpbiBhbiBcbiAgICogIGVuY3J5cHRlZGludGVncml0eXByb3RlY3RlZGRhdGEgcGFja2V0IGlzIG5vdCByZXN5bmNpbmcgdGhlIElWLlxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IGEgc3RyaW5nIHdpdGggdGhlIHBsYWludGV4dCBkYXRhXG4gICAqL1xuXG4gIGRlY3J5cHQ6IGZ1bmN0aW9uKGNpcGhlcmZuLCBrZXksIGNpcGhlcnRleHQsIHJlc3luYykge1xuICAgIGNpcGhlcmZuID0gbmV3IGNpcGhlcltjaXBoZXJmbl0oa2V5KTtcbiAgICB2YXIgYmxvY2tfc2l6ZSA9IGNpcGhlcmZuLmJsb2NrU2l6ZTtcblxuICAgIHZhciBpYmxvY2sgPSBuZXcgQXJyYXkoYmxvY2tfc2l6ZSk7XG4gICAgdmFyIGFibG9jayA9IG5ldyBBcnJheShibG9ja19zaXplKTtcbiAgICB2YXIgaSwgbiA9ICcnO1xuICAgIHZhciB0ZXh0ID0gW107XG5cbiAgICAvLyBpbml0aWFsaXNhdGlvbiB2ZWN0b3JcbiAgICBmb3IgKGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBpYmxvY2tbaV0gPSAwO1xuXG4gICAgaWJsb2NrID0gY2lwaGVyZm4uZW5jcnlwdChpYmxvY2ssIGtleSk7XG4gICAgZm9yIChpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykge1xuICAgICAgYWJsb2NrW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGkpO1xuICAgICAgaWJsb2NrW2ldIF49IGFibG9ja1tpXTtcbiAgICB9XG5cbiAgICBhYmxvY2sgPSBjaXBoZXJmbi5lbmNyeXB0KGFibG9jaywga2V5KTtcblxuICAgIC8vIHRlc3QgY2hlY2sgb2N0ZXRzXG4gICAgaWYgKGlibG9ja1tibG9ja19zaXplIC0gMl0gIT0gKGFibG9ja1swXSBeIGNpcGhlcnRleHQuY2hhckNvZGVBdChibG9ja19zaXplKSkgfHwgaWJsb2NrW2Jsb2NrX3NpemUgLSAxXSAhPSAoYWJsb2NrW1xuICAgICAgMV0gXiBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoYmxvY2tfc2l6ZSArIDEpKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGRhdGEuJyk7XG4gICAgfVxuXG4gICAgLyogIFJGQzQ4ODA6IFRhZyAxOCBhbmQgUmVzeW5jOlxuXHRcdCAqICBbLi4uXSBVbmxpa2UgdGhlIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgUGFja2V0LCBub1xuXHRcdCAqICBzcGVjaWFsIENGQiByZXN5bmNocm9uaXphdGlvbiBpcyBkb25lIGFmdGVyIGVuY3J5cHRpbmcgdGhpcyBwcmVmaXhcblx0XHQgKiAgZGF0YS4gIFNlZSBcIk9wZW5QR1AgQ0ZCIE1vZGVcIiBiZWxvdyBmb3IgbW9yZSBkZXRhaWxzLlxuXG5cdFx0ICovXG5cbiAgICBpZiAocmVzeW5jKSB7XG4gICAgICBmb3IgKGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBpYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSArIDIpO1xuICAgICAgZm9yIChuID0gYmxvY2tfc2l6ZSArIDI7IG4gPCBjaXBoZXJ0ZXh0Lmxlbmd0aDsgbiArPSBibG9ja19zaXplKSB7XG4gICAgICAgIGFibG9jayA9IGNpcGhlcmZuLmVuY3J5cHQoaWJsb2NrKTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYmxvY2tfc2l6ZSAmJiBpICsgbiA8IGNpcGhlcnRleHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICBpYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQobiArIGkpO1xuICAgICAgICAgIHRleHQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGFibG9ja1tpXSBeIGlibG9ja1tpXSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGZvciAoaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIGlibG9ja1tpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChpKTtcbiAgICAgIGZvciAobiA9IGJsb2NrX3NpemU7IG4gPCBjaXBoZXJ0ZXh0Lmxlbmd0aDsgbiArPSBibG9ja19zaXplKSB7XG4gICAgICAgIGFibG9jayA9IGNpcGhlcmZuLmVuY3J5cHQoaWJsb2NrKTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGJsb2NrX3NpemUgJiYgaSArIG4gPCBjaXBoZXJ0ZXh0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaWJsb2NrW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KG4gKyBpKTtcbiAgICAgICAgICB0ZXh0LnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShhYmxvY2tbaV0gXiBpYmxvY2tbaV0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBuID0gcmVzeW5jID8gMCA6IDI7XG5cbiAgICB0ZXh0ID0gdGV4dC5qb2luKCcnKTtcblxuICAgIHRleHQgPSB0ZXh0LnN1YnN0cmluZyhuLCBjaXBoZXJ0ZXh0Lmxlbmd0aCAtIGJsb2NrX3NpemUgLSAyICsgbik7XG5cblxuICAgIHJldHVybiB0ZXh0O1xuICB9LFxuXG5cbiAgbm9ybWFsRW5jcnlwdDogZnVuY3Rpb24oY2lwaGVyZm4sIGtleSwgcGxhaW50ZXh0LCBpdikge1xuICAgIGNpcGhlcmZuID0gbmV3IGNpcGhlcltjaXBoZXJmbl0oa2V5KTtcbiAgICB2YXIgYmxvY2tfc2l6ZSA9IGNpcGhlcmZuLmJsb2NrU2l6ZTtcblxuICAgIHZhciBibG9ja2kgPSBcIlwiO1xuICAgIHZhciBibG9ja2MgPSBcIlwiO1xuICAgIHZhciBwb3MgPSAwO1xuICAgIHZhciBjeXBoZXJ0ZXh0ID0gW107XG4gICAgdmFyIHRlbXBCbG9jayA9IFtdO1xuICAgIGJsb2NrYyA9IGl2LnN1YnN0cmluZygwLCBibG9ja19zaXplKTtcbiAgICB3aGlsZSAocGxhaW50ZXh0Lmxlbmd0aCA+IGJsb2NrX3NpemUgKiBwb3MpIHtcbiAgICAgIHZhciBlbmNibG9jayA9IGNpcGhlcmZuLmVuY3J5cHQodXRpbC5zdHIyYmluKGJsb2NrYykpO1xuICAgICAgYmxvY2tpID0gcGxhaW50ZXh0LnN1YnN0cmluZygocG9zICogYmxvY2tfc2l6ZSksIChwb3MgKiBibG9ja19zaXplKSArIGJsb2NrX3NpemUpO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja2kubGVuZ3RoOyBpKyspXG4gICAgICAgIHRlbXBCbG9jay5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYmxvY2tpLmNoYXJDb2RlQXQoaSkgXiBlbmNibG9ja1tpXSkpO1xuICAgICAgYmxvY2tjID0gdGVtcEJsb2NrLmpvaW4oJycpO1xuICAgICAgdGVtcEJsb2NrID0gW107XG4gICAgICBjeXBoZXJ0ZXh0LnB1c2goYmxvY2tjKTtcbiAgICAgIHBvcysrO1xuICAgIH1cbiAgICByZXR1cm4gY3lwaGVydGV4dC5qb2luKCcnKTtcbiAgfSxcblxuICBub3JtYWxEZWNyeXB0OiBmdW5jdGlvbihjaXBoZXJmbiwga2V5LCBjaXBoZXJ0ZXh0LCBpdikge1xuICAgIGNpcGhlcmZuID0gbmV3IGNpcGhlcltjaXBoZXJmbl0oa2V5KTtcbiAgICB2YXIgYmxvY2tfc2l6ZSA9IGNpcGhlcmZuLmJsb2NrU2l6ZTtcblxuICAgIHZhciBibG9ja3AgPSBcIlwiO1xuICAgIHZhciBwb3MgPSAwO1xuICAgIHZhciBwbGFpbnRleHQgPSBbXTtcbiAgICB2YXIgb2Zmc2V0ID0gMDtcbiAgICBpZiAoaXYgPT0gbnVsbClcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBibG9ja3AgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKTtcbiAgICBlbHNlXG4gICAgICBibG9ja3AgPSBpdi5zdWJzdHJpbmcoMCwgYmxvY2tfc2l6ZSk7XG4gICAgd2hpbGUgKGNpcGhlcnRleHQubGVuZ3RoID4gKGJsb2NrX3NpemUgKiBwb3MpKSB7XG4gICAgICB2YXIgZGVjYmxvY2sgPSBjaXBoZXJmbi5lbmNyeXB0KHV0aWwuc3RyMmJpbihibG9ja3ApKTtcbiAgICAgIGJsb2NrcCA9IGNpcGhlcnRleHQuc3Vic3RyaW5nKChwb3MgKiAoYmxvY2tfc2l6ZSkpICsgb2Zmc2V0LCAocG9zICogKGJsb2NrX3NpemUpKSArIChibG9ja19zaXplKSArIG9mZnNldCk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrcC5sZW5ndGg7IGkrKykge1xuICAgICAgICBwbGFpbnRleHQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGJsb2NrcC5jaGFyQ29kZUF0KGkpIF4gZGVjYmxvY2tbaV0pKTtcbiAgICAgIH1cbiAgICAgIHBvcysrO1xuICAgIH1cblxuICAgIHJldHVybiBwbGFpbnRleHQuam9pbignJyk7XG4gIH1cbn1cbiIsIi8qIFJpam5kYWVsIChBRVMpIEVuY3J5cHRpb25cbiAqIENvcHlyaWdodCAyMDA1IEhlcmJlcnQgSGFuZXdpbmtlbCwgd3d3LmhhbmVXSU4uZGVcbiAqIHZlcnNpb24gMS4xLCBjaGVjayB3d3cuaGFuZVdJTi5kZSBmb3IgdGhlIGxhdGVzdCB2ZXJzaW9uXG5cbiAqIFRoaXMgc29mdHdhcmUgaXMgcHJvdmlkZWQgYXMtaXMsIHdpdGhvdXQgZXhwcmVzcyBvciBpbXBsaWVkIHdhcnJhbnR5LiAgXG4gKiBQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBkaXN0cmlidXRlIG9yIHNlbGwgdGhpcyBzb2Z0d2FyZSwgd2l0aCBvclxuICogd2l0aG91dCBmZWUsIGZvciBhbnkgcHVycG9zZSBhbmQgYnkgYW55IGluZGl2aWR1YWwgb3Igb3JnYW5pemF0aW9uLCBpcyBoZXJlYnlcbiAqIGdyYW50ZWQsIHByb3ZpZGVkIHRoYXQgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGFyYWdyYXBoIGFwcGVhciBcbiAqIGluIGFsbCBjb3BpZXMuIERpc3RyaWJ1dGlvbiBhcyBhIHBhcnQgb2YgYW4gYXBwbGljYXRpb24gb3IgYmluYXJ5IG11c3RcbiAqIGluY2x1ZGUgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyXG4gKiBtYXRlcmlhbHMgcHJvdmlkZWQgd2l0aCB0aGUgYXBwbGljYXRpb24gb3IgZGlzdHJpYnV0aW9uLlxuICovXG5cbi8qKlxuICogQHJlcXVpcmVzIHV0aWxcbiAqIEBtb2R1bGUgY3J5cHRvL2NpcGhlci9hZXNcbiAqL1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuLy8gVGhlIHJvdW5kIGNvbnN0YW50cyB1c2VkIGluIHN1YmtleSBleHBhbnNpb25cbnZhciBSY29uID0gW1xuICAgIDB4MDEsIDB4MDIsIDB4MDQsIDB4MDgsIDB4MTAsIDB4MjAsIDB4NDAsIDB4ODAsIDB4MWIsIDB4MzYsIDB4NmMsIDB4ZDgsXG4gICAgMHhhYiwgMHg0ZCwgMHg5YSwgMHgyZiwgMHg1ZSwgMHhiYywgMHg2MywgMHhjNiwgMHg5NywgMHgzNSwgMHg2YSwgMHhkNCxcbiAgICAweGIzLCAweDdkLCAweGZhLCAweGVmLCAweGM1LCAweDkxXG5dO1xuXG4vLyBQcmVjb21wdXRlZCBsb29rdXAgdGFibGUgZm9yIHRoZSBTQm94XG52YXIgUyA9IFtcbiAgICA5OSwgMTI0LCAxMTksIDEyMywgMjQyLCAxMDcsIDExMSwgMTk3LCA0OCwgMSwgMTAzLCA0MywgMjU0LCAyMTUsIDE3MSxcbiAgICAxMTgsIDIwMiwgMTMwLCAyMDEsIDEyNSwgMjUwLCA4OSwgNzEsIDI0MCwgMTczLCAyMTIsIDE2MiwgMTc1LCAxNTYsIDE2NCxcbiAgICAxMTQsIDE5MiwgMTgzLCAyNTMsIDE0NywgMzgsIDU0LCA2MywgMjQ3LCAyMDQsIDUyLCAxNjUsIDIyOSwgMjQxLCAxMTMsXG4gICAgMjE2LCA0OSwgMjEsIDQsIDE5OSwgMzUsIDE5NSwgMjQsIDE1MCwgNSwgMTU0LCA3LCAxOCwgMTI4LCAyMjYsXG4gICAgMjM1LCAzOSwgMTc4LCAxMTcsIDksIDEzMSwgNDQsIDI2LCAyNywgMTEwLCA5MCwgMTYwLCA4MiwgNTksIDIxNCxcbiAgICAxNzksIDQxLCAyMjcsIDQ3LCAxMzIsIDgzLCAyMDksIDAsIDIzNywgMzIsIDI1MiwgMTc3LCA5MSwgMTA2LCAyMDMsXG4gICAgMTkwLCA1NywgNzQsIDc2LCA4OCwgMjA3LCAyMDgsIDIzOSwgMTcwLCAyNTEsIDY3LCA3NywgNTEsIDEzMywgNjksXG4gICAgMjQ5LCAyLCAxMjcsIDgwLCA2MCwgMTU5LCAxNjgsIDgxLCAxNjMsIDY0LCAxNDMsIDE0NiwgMTU3LCA1NiwgMjQ1LFxuICAgIDE4OCwgMTgyLCAyMTgsIDMzLCAxNiwgMjU1LCAyNDMsIDIxMCwgMjA1LCAxMiwgMTksIDIzNiwgOTUsIDE1MSwgNjgsXG4gICAgMjMsIDE5NiwgMTY3LCAxMjYsIDYxLCAxMDAsIDkzLCAyNSwgMTE1LCA5NiwgMTI5LCA3OSwgMjIwLCAzNCwgNDIsXG4gICAgMTQ0LCAxMzYsIDcwLCAyMzgsIDE4NCwgMjAsIDIyMiwgOTQsIDExLCAyMTksIDIyNCwgNTAsIDU4LCAxMCwgNzMsXG4gICAgNiwgMzYsIDkyLCAxOTQsIDIxMSwgMTcyLCA5OCwgMTQ1LCAxNDksIDIyOCwgMTIxLCAyMzEsIDIwMCwgNTUsIDEwOSxcbiAgICAxNDEsIDIxMywgNzgsIDE2OSwgMTA4LCA4NiwgMjQ0LCAyMzQsIDEwMSwgMTIyLCAxNzQsIDgsIDE4NiwgMTIwLCAzNyxcbiAgICA0NiwgMjgsIDE2NiwgMTgwLCAxOTgsIDIzMiwgMjIxLCAxMTYsIDMxLCA3NSwgMTg5LCAxMzksIDEzOCwgMTEyLCA2MixcbiAgICAxODEsIDEwMiwgNzIsIDMsIDI0NiwgMTQsIDk3LCA1MywgODcsIDE4NSwgMTM0LCAxOTMsIDI5LCAxNTgsIDIyNSxcbiAgICAyNDgsIDE1MiwgMTcsIDEwNSwgMjE3LCAxNDIsIDE0OCwgMTU1LCAzMCwgMTM1LCAyMzMsIDIwNiwgODUsIDQwLCAyMjMsXG4gICAgMTQwLCAxNjEsIDEzNywgMTMsIDE5MSwgMjMwLCA2NiwgMTA0LCA2NSwgMTUzLCA0NSwgMTUsIDE3NiwgODQsIDE4NyxcbiAgICAyMlxuXTtcblxudmFyIFQxID0gW1xuICAgIDB4YTU2MzYzYzYsIDB4ODQ3YzdjZjgsIDB4OTk3Nzc3ZWUsIDB4OGQ3YjdiZjYsXG4gICAgMHgwZGYyZjJmZiwgMHhiZDZiNmJkNiwgMHhiMTZmNmZkZSwgMHg1NGM1YzU5MSxcbiAgICAweDUwMzAzMDYwLCAweDAzMDEwMTAyLCAweGE5Njc2N2NlLCAweDdkMmIyYjU2LFxuICAgIDB4MTlmZWZlZTcsIDB4NjJkN2Q3YjUsIDB4ZTZhYmFiNGQsIDB4OWE3Njc2ZWMsXG4gICAgMHg0NWNhY2E4ZiwgMHg5ZDgyODIxZiwgMHg0MGM5Yzk4OSwgMHg4NzdkN2RmYSxcbiAgICAweDE1ZmFmYWVmLCAweGViNTk1OWIyLCAweGM5NDc0NzhlLCAweDBiZjBmMGZiLFxuICAgIDB4ZWNhZGFkNDEsIDB4NjdkNGQ0YjMsIDB4ZmRhMmEyNWYsIDB4ZWFhZmFmNDUsXG4gICAgMHhiZjljOWMyMywgMHhmN2E0YTQ1MywgMHg5NjcyNzJlNCwgMHg1YmMwYzA5YixcbiAgICAweGMyYjdiNzc1LCAweDFjZmRmZGUxLCAweGFlOTM5MzNkLCAweDZhMjYyNjRjLFxuICAgIDB4NWEzNjM2NmMsIDB4NDEzZjNmN2UsIDB4MDJmN2Y3ZjUsIDB4NGZjY2NjODMsXG4gICAgMHg1YzM0MzQ2OCwgMHhmNGE1YTU1MSwgMHgzNGU1ZTVkMSwgMHgwOGYxZjFmOSxcbiAgICAweDkzNzE3MWUyLCAweDczZDhkOGFiLCAweDUzMzEzMTYyLCAweDNmMTUxNTJhLFxuICAgIDB4MGMwNDA0MDgsIDB4NTJjN2M3OTUsIDB4NjUyMzIzNDYsIDB4NWVjM2MzOWQsXG4gICAgMHgyODE4MTgzMCwgMHhhMTk2OTYzNywgMHgwZjA1MDUwYSwgMHhiNTlhOWEyZixcbiAgICAweDA5MDcwNzBlLCAweDM2MTIxMjI0LCAweDliODA4MDFiLCAweDNkZTJlMmRmLFxuICAgIDB4MjZlYmViY2QsIDB4NjkyNzI3NGUsIDB4Y2RiMmIyN2YsIDB4OWY3NTc1ZWEsXG4gICAgMHgxYjA5MDkxMiwgMHg5ZTgzODMxZCwgMHg3NDJjMmM1OCwgMHgyZTFhMWEzNCxcbiAgICAweDJkMWIxYjM2LCAweGIyNmU2ZWRjLCAweGVlNWE1YWI0LCAweGZiYTBhMDViLFxuICAgIDB4ZjY1MjUyYTQsIDB4NGQzYjNiNzYsIDB4NjFkNmQ2YjcsIDB4Y2ViM2IzN2QsXG4gICAgMHg3YjI5Mjk1MiwgMHgzZWUzZTNkZCwgMHg3MTJmMmY1ZSwgMHg5Nzg0ODQxMyxcbiAgICAweGY1NTM1M2E2LCAweDY4ZDFkMWI5LCAweDAwMDAwMDAwLCAweDJjZWRlZGMxLFxuICAgIDB4NjAyMDIwNDAsIDB4MWZmY2ZjZTMsIDB4YzhiMWIxNzksIDB4ZWQ1YjViYjYsXG4gICAgMHhiZTZhNmFkNCwgMHg0NmNiY2I4ZCwgMHhkOWJlYmU2NywgMHg0YjM5Mzk3MixcbiAgICAweGRlNGE0YTk0LCAweGQ0NGM0Yzk4LCAweGU4NTg1OGIwLCAweDRhY2ZjZjg1LFxuICAgIDB4NmJkMGQwYmIsIDB4MmFlZmVmYzUsIDB4ZTVhYWFhNGYsIDB4MTZmYmZiZWQsXG4gICAgMHhjNTQzNDM4NiwgMHhkNzRkNGQ5YSwgMHg1NTMzMzM2NiwgMHg5NDg1ODUxMSxcbiAgICAweGNmNDU0NThhLCAweDEwZjlmOWU5LCAweDA2MDIwMjA0LCAweDgxN2Y3ZmZlLFxuICAgIDB4ZjA1MDUwYTAsIDB4NDQzYzNjNzgsIDB4YmE5ZjlmMjUsIDB4ZTNhOGE4NGIsXG4gICAgMHhmMzUxNTFhMiwgMHhmZWEzYTM1ZCwgMHhjMDQwNDA4MCwgMHg4YThmOGYwNSxcbiAgICAweGFkOTI5MjNmLCAweGJjOWQ5ZDIxLCAweDQ4MzgzODcwLCAweDA0ZjVmNWYxLFxuICAgIDB4ZGZiY2JjNjMsIDB4YzFiNmI2NzcsIDB4NzVkYWRhYWYsIDB4NjMyMTIxNDIsXG4gICAgMHgzMDEwMTAyMCwgMHgxYWZmZmZlNSwgMHgwZWYzZjNmZCwgMHg2ZGQyZDJiZixcbiAgICAweDRjY2RjZDgxLCAweDE0MGMwYzE4LCAweDM1MTMxMzI2LCAweDJmZWNlY2MzLFxuICAgIDB4ZTE1ZjVmYmUsIDB4YTI5Nzk3MzUsIDB4Y2M0NDQ0ODgsIDB4MzkxNzE3MmUsXG4gICAgMHg1N2M0YzQ5MywgMHhmMmE3YTc1NSwgMHg4MjdlN2VmYywgMHg0NzNkM2Q3YSxcbiAgICAweGFjNjQ2NGM4LCAweGU3NWQ1ZGJhLCAweDJiMTkxOTMyLCAweDk1NzM3M2U2LFxuICAgIDB4YTA2MDYwYzAsIDB4OTg4MTgxMTksIDB4ZDE0ZjRmOWUsIDB4N2ZkY2RjYTMsXG4gICAgMHg2NjIyMjI0NCwgMHg3ZTJhMmE1NCwgMHhhYjkwOTAzYiwgMHg4Mzg4ODgwYixcbiAgICAweGNhNDY0NjhjLCAweDI5ZWVlZWM3LCAweGQzYjhiODZiLCAweDNjMTQxNDI4LFxuICAgIDB4NzlkZWRlYTcsIDB4ZTI1ZTVlYmMsIDB4MWQwYjBiMTYsIDB4NzZkYmRiYWQsXG4gICAgMHgzYmUwZTBkYiwgMHg1NjMyMzI2NCwgMHg0ZTNhM2E3NCwgMHgxZTBhMGExNCxcbiAgICAweGRiNDk0OTkyLCAweDBhMDYwNjBjLCAweDZjMjQyNDQ4LCAweGU0NWM1Y2I4LFxuICAgIDB4NWRjMmMyOWYsIDB4NmVkM2QzYmQsIDB4ZWZhY2FjNDMsIDB4YTY2MjYyYzQsXG4gICAgMHhhODkxOTEzOSwgMHhhNDk1OTUzMSwgMHgzN2U0ZTRkMywgMHg4Yjc5NzlmMixcbiAgICAweDMyZTdlN2Q1LCAweDQzYzhjODhiLCAweDU5MzczNzZlLCAweGI3NmQ2ZGRhLFxuICAgIDB4OGM4ZDhkMDEsIDB4NjRkNWQ1YjEsIDB4ZDI0ZTRlOWMsIDB4ZTBhOWE5NDksXG4gICAgMHhiNDZjNmNkOCwgMHhmYTU2NTZhYywgMHgwN2Y0ZjRmMywgMHgyNWVhZWFjZixcbiAgICAweGFmNjU2NWNhLCAweDhlN2E3YWY0LCAweGU5YWVhZTQ3LCAweDE4MDgwODEwLFxuICAgIDB4ZDViYWJhNmYsIDB4ODg3ODc4ZjAsIDB4NmYyNTI1NGEsIDB4NzIyZTJlNWMsXG4gICAgMHgyNDFjMWMzOCwgMHhmMWE2YTY1NywgMHhjN2I0YjQ3MywgMHg1MWM2YzY5NyxcbiAgICAweDIzZThlOGNiLCAweDdjZGRkZGExLCAweDljNzQ3NGU4LCAweDIxMWYxZjNlLFxuICAgIDB4ZGQ0YjRiOTYsIDB4ZGNiZGJkNjEsIDB4ODY4YjhiMGQsIDB4ODU4YThhMGYsXG4gICAgMHg5MDcwNzBlMCwgMHg0MjNlM2U3YywgMHhjNGI1YjU3MSwgMHhhYTY2NjZjYyxcbiAgICAweGQ4NDg0ODkwLCAweDA1MDMwMzA2LCAweDAxZjZmNmY3LCAweDEyMGUwZTFjLFxuICAgIDB4YTM2MTYxYzIsIDB4NWYzNTM1NmEsIDB4Zjk1NzU3YWUsIDB4ZDBiOWI5NjksXG4gICAgMHg5MTg2ODYxNywgMHg1OGMxYzE5OSwgMHgyNzFkMWQzYSwgMHhiOTllOWUyNyxcbiAgICAweDM4ZTFlMWQ5LCAweDEzZjhmOGViLCAweGIzOTg5ODJiLCAweDMzMTExMTIyLFxuICAgIDB4YmI2OTY5ZDIsIDB4NzBkOWQ5YTksIDB4ODk4ZThlMDcsIDB4YTc5NDk0MzMsXG4gICAgMHhiNjliOWIyZCwgMHgyMjFlMWUzYywgMHg5Mjg3ODcxNSwgMHgyMGU5ZTljOSxcbiAgICAweDQ5Y2VjZTg3LCAweGZmNTU1NWFhLCAweDc4MjgyODUwLCAweDdhZGZkZmE1LFxuICAgIDB4OGY4YzhjMDMsIDB4ZjhhMWExNTksIDB4ODA4OTg5MDksIDB4MTcwZDBkMWEsXG4gICAgMHhkYWJmYmY2NSwgMHgzMWU2ZTZkNywgMHhjNjQyNDI4NCwgMHhiODY4NjhkMCxcbiAgICAweGMzNDE0MTgyLCAweGIwOTk5OTI5LCAweDc3MmQyZDVhLCAweDExMGYwZjFlLFxuICAgIDB4Y2JiMGIwN2IsIDB4ZmM1NDU0YTgsIDB4ZDZiYmJiNmQsIDB4M2ExNjE2MmNcbl07XG5cbnZhciBUMiA9IFtcbiAgICAweDYzNjNjNmE1LCAweDdjN2NmODg0LCAweDc3NzdlZTk5LCAweDdiN2JmNjhkLFxuICAgIDB4ZjJmMmZmMGQsIDB4NmI2YmQ2YmQsIDB4NmY2ZmRlYjEsIDB4YzVjNTkxNTQsXG4gICAgMHgzMDMwNjA1MCwgMHgwMTAxMDIwMywgMHg2NzY3Y2VhOSwgMHgyYjJiNTY3ZCxcbiAgICAweGZlZmVlNzE5LCAweGQ3ZDdiNTYyLCAweGFiYWI0ZGU2LCAweDc2NzZlYzlhLFxuICAgIDB4Y2FjYThmNDUsIDB4ODI4MjFmOWQsIDB4YzljOTg5NDAsIDB4N2Q3ZGZhODcsXG4gICAgMHhmYWZhZWYxNSwgMHg1OTU5YjJlYiwgMHg0NzQ3OGVjOSwgMHhmMGYwZmIwYixcbiAgICAweGFkYWQ0MWVjLCAweGQ0ZDRiMzY3LCAweGEyYTI1ZmZkLCAweGFmYWY0NWVhLFxuICAgIDB4OWM5YzIzYmYsIDB4YTRhNDUzZjcsIDB4NzI3MmU0OTYsIDB4YzBjMDliNWIsXG4gICAgMHhiN2I3NzVjMiwgMHhmZGZkZTExYywgMHg5MzkzM2RhZSwgMHgyNjI2NGM2YSxcbiAgICAweDM2MzY2YzVhLCAweDNmM2Y3ZTQxLCAweGY3ZjdmNTAyLCAweGNjY2M4MzRmLFxuICAgIDB4MzQzNDY4NWMsIDB4YTVhNTUxZjQsIDB4ZTVlNWQxMzQsIDB4ZjFmMWY5MDgsXG4gICAgMHg3MTcxZTI5MywgMHhkOGQ4YWI3MywgMHgzMTMxNjI1MywgMHgxNTE1MmEzZixcbiAgICAweDA0MDQwODBjLCAweGM3Yzc5NTUyLCAweDIzMjM0NjY1LCAweGMzYzM5ZDVlLFxuICAgIDB4MTgxODMwMjgsIDB4OTY5NjM3YTEsIDB4MDUwNTBhMGYsIDB4OWE5YTJmYjUsXG4gICAgMHgwNzA3MGUwOSwgMHgxMjEyMjQzNiwgMHg4MDgwMWI5YiwgMHhlMmUyZGYzZCxcbiAgICAweGViZWJjZDI2LCAweDI3Mjc0ZTY5LCAweGIyYjI3ZmNkLCAweDc1NzVlYTlmLFxuICAgIDB4MDkwOTEyMWIsIDB4ODM4MzFkOWUsIDB4MmMyYzU4NzQsIDB4MWExYTM0MmUsXG4gICAgMHgxYjFiMzYyZCwgMHg2ZTZlZGNiMiwgMHg1YTVhYjRlZSwgMHhhMGEwNWJmYixcbiAgICAweDUyNTJhNGY2LCAweDNiM2I3NjRkLCAweGQ2ZDZiNzYxLCAweGIzYjM3ZGNlLFxuICAgIDB4MjkyOTUyN2IsIDB4ZTNlM2RkM2UsIDB4MmYyZjVlNzEsIDB4ODQ4NDEzOTcsXG4gICAgMHg1MzUzYTZmNSwgMHhkMWQxYjk2OCwgMHgwMDAwMDAwMCwgMHhlZGVkYzEyYyxcbiAgICAweDIwMjA0MDYwLCAweGZjZmNlMzFmLCAweGIxYjE3OWM4LCAweDViNWJiNmVkLFxuICAgIDB4NmE2YWQ0YmUsIDB4Y2JjYjhkNDYsIDB4YmViZTY3ZDksIDB4MzkzOTcyNGIsXG4gICAgMHg0YTRhOTRkZSwgMHg0YzRjOThkNCwgMHg1ODU4YjBlOCwgMHhjZmNmODU0YSxcbiAgICAweGQwZDBiYjZiLCAweGVmZWZjNTJhLCAweGFhYWE0ZmU1LCAweGZiZmJlZDE2LFxuICAgIDB4NDM0Mzg2YzUsIDB4NGQ0ZDlhZDcsIDB4MzMzMzY2NTUsIDB4ODU4NTExOTQsXG4gICAgMHg0NTQ1OGFjZiwgMHhmOWY5ZTkxMCwgMHgwMjAyMDQwNiwgMHg3ZjdmZmU4MSxcbiAgICAweDUwNTBhMGYwLCAweDNjM2M3ODQ0LCAweDlmOWYyNWJhLCAweGE4YTg0YmUzLFxuICAgIDB4NTE1MWEyZjMsIDB4YTNhMzVkZmUsIDB4NDA0MDgwYzAsIDB4OGY4ZjA1OGEsXG4gICAgMHg5MjkyM2ZhZCwgMHg5ZDlkMjFiYywgMHgzODM4NzA0OCwgMHhmNWY1ZjEwNCxcbiAgICAweGJjYmM2M2RmLCAweGI2YjY3N2MxLCAweGRhZGFhZjc1LCAweDIxMjE0MjYzLFxuICAgIDB4MTAxMDIwMzAsIDB4ZmZmZmU1MWEsIDB4ZjNmM2ZkMGUsIDB4ZDJkMmJmNmQsXG4gICAgMHhjZGNkODE0YywgMHgwYzBjMTgxNCwgMHgxMzEzMjYzNSwgMHhlY2VjYzMyZixcbiAgICAweDVmNWZiZWUxLCAweDk3OTczNWEyLCAweDQ0NDQ4OGNjLCAweDE3MTcyZTM5LFxuICAgIDB4YzRjNDkzNTcsIDB4YTdhNzU1ZjIsIDB4N2U3ZWZjODIsIDB4M2QzZDdhNDcsXG4gICAgMHg2NDY0YzhhYywgMHg1ZDVkYmFlNywgMHgxOTE5MzIyYiwgMHg3MzczZTY5NSxcbiAgICAweDYwNjBjMGEwLCAweDgxODExOTk4LCAweDRmNGY5ZWQxLCAweGRjZGNhMzdmLFxuICAgIDB4MjIyMjQ0NjYsIDB4MmEyYTU0N2UsIDB4OTA5MDNiYWIsIDB4ODg4ODBiODMsXG4gICAgMHg0NjQ2OGNjYSwgMHhlZWVlYzcyOSwgMHhiOGI4NmJkMywgMHgxNDE0MjgzYyxcbiAgICAweGRlZGVhNzc5LCAweDVlNWViY2UyLCAweDBiMGIxNjFkLCAweGRiZGJhZDc2LFxuICAgIDB4ZTBlMGRiM2IsIDB4MzIzMjY0NTYsIDB4M2EzYTc0NGUsIDB4MGEwYTE0MWUsXG4gICAgMHg0OTQ5OTJkYiwgMHgwNjA2MGMwYSwgMHgyNDI0NDg2YywgMHg1YzVjYjhlNCxcbiAgICAweGMyYzI5ZjVkLCAweGQzZDNiZDZlLCAweGFjYWM0M2VmLCAweDYyNjJjNGE2LFxuICAgIDB4OTE5MTM5YTgsIDB4OTU5NTMxYTQsIDB4ZTRlNGQzMzcsIDB4Nzk3OWYyOGIsXG4gICAgMHhlN2U3ZDUzMiwgMHhjOGM4OGI0MywgMHgzNzM3NmU1OSwgMHg2ZDZkZGFiNyxcbiAgICAweDhkOGQwMThjLCAweGQ1ZDViMTY0LCAweDRlNGU5Y2QyLCAweGE5YTk0OWUwLFxuICAgIDB4NmM2Y2Q4YjQsIDB4NTY1NmFjZmEsIDB4ZjRmNGYzMDcsIDB4ZWFlYWNmMjUsXG4gICAgMHg2NTY1Y2FhZiwgMHg3YTdhZjQ4ZSwgMHhhZWFlNDdlOSwgMHgwODA4MTAxOCxcbiAgICAweGJhYmE2ZmQ1LCAweDc4NzhmMDg4LCAweDI1MjU0YTZmLCAweDJlMmU1YzcyLFxuICAgIDB4MWMxYzM4MjQsIDB4YTZhNjU3ZjEsIDB4YjRiNDczYzcsIDB4YzZjNjk3NTEsXG4gICAgMHhlOGU4Y2IyMywgMHhkZGRkYTE3YywgMHg3NDc0ZTg5YywgMHgxZjFmM2UyMSxcbiAgICAweDRiNGI5NmRkLCAweGJkYmQ2MWRjLCAweDhiOGIwZDg2LCAweDhhOGEwZjg1LFxuICAgIDB4NzA3MGUwOTAsIDB4M2UzZTdjNDIsIDB4YjViNTcxYzQsIDB4NjY2NmNjYWEsXG4gICAgMHg0ODQ4OTBkOCwgMHgwMzAzMDYwNSwgMHhmNmY2ZjcwMSwgMHgwZTBlMWMxMixcbiAgICAweDYxNjFjMmEzLCAweDM1MzU2YTVmLCAweDU3NTdhZWY5LCAweGI5Yjk2OWQwLFxuICAgIDB4ODY4NjE3OTEsIDB4YzFjMTk5NTgsIDB4MWQxZDNhMjcsIDB4OWU5ZTI3YjksXG4gICAgMHhlMWUxZDkzOCwgMHhmOGY4ZWIxMywgMHg5ODk4MmJiMywgMHgxMTExMjIzMyxcbiAgICAweDY5NjlkMmJiLCAweGQ5ZDlhOTcwLCAweDhlOGUwNzg5LCAweDk0OTQzM2E3LFxuICAgIDB4OWI5YjJkYjYsIDB4MWUxZTNjMjIsIDB4ODc4NzE1OTIsIDB4ZTllOWM5MjAsXG4gICAgMHhjZWNlODc0OSwgMHg1NTU1YWFmZiwgMHgyODI4NTA3OCwgMHhkZmRmYTU3YSxcbiAgICAweDhjOGMwMzhmLCAweGExYTE1OWY4LCAweDg5ODkwOTgwLCAweDBkMGQxYTE3LFxuICAgIDB4YmZiZjY1ZGEsIDB4ZTZlNmQ3MzEsIDB4NDI0Mjg0YzYsIDB4Njg2OGQwYjgsXG4gICAgMHg0MTQxODJjMywgMHg5OTk5MjliMCwgMHgyZDJkNWE3NywgMHgwZjBmMWUxMSxcbiAgICAweGIwYjA3YmNiLCAweDU0NTRhOGZjLCAweGJiYmI2ZGQ2LCAweDE2MTYyYzNhXG5dO1xuXG52YXIgVDMgPSBbXG4gICAgMHg2M2M2YTU2MywgMHg3Y2Y4ODQ3YywgMHg3N2VlOTk3NywgMHg3YmY2OGQ3YixcbiAgICAweGYyZmYwZGYyLCAweDZiZDZiZDZiLCAweDZmZGViMTZmLCAweGM1OTE1NGM1LFxuICAgIDB4MzA2MDUwMzAsIDB4MDEwMjAzMDEsIDB4NjdjZWE5NjcsIDB4MmI1NjdkMmIsXG4gICAgMHhmZWU3MTlmZSwgMHhkN2I1NjJkNywgMHhhYjRkZTZhYiwgMHg3NmVjOWE3NixcbiAgICAweGNhOGY0NWNhLCAweDgyMWY5ZDgyLCAweGM5ODk0MGM5LCAweDdkZmE4NzdkLFxuICAgIDB4ZmFlZjE1ZmEsIDB4NTliMmViNTksIDB4NDc4ZWM5NDcsIDB4ZjBmYjBiZjAsXG4gICAgMHhhZDQxZWNhZCwgMHhkNGIzNjdkNCwgMHhhMjVmZmRhMiwgMHhhZjQ1ZWFhZixcbiAgICAweDljMjNiZjljLCAweGE0NTNmN2E0LCAweDcyZTQ5NjcyLCAweGMwOWI1YmMwLFxuICAgIDB4Yjc3NWMyYjcsIDB4ZmRlMTFjZmQsIDB4OTMzZGFlOTMsIDB4MjY0YzZhMjYsXG4gICAgMHgzNjZjNWEzNiwgMHgzZjdlNDEzZiwgMHhmN2Y1MDJmNywgMHhjYzgzNGZjYyxcbiAgICAweDM0Njg1YzM0LCAweGE1NTFmNGE1LCAweGU1ZDEzNGU1LCAweGYxZjkwOGYxLFxuICAgIDB4NzFlMjkzNzEsIDB4ZDhhYjczZDgsIDB4MzE2MjUzMzEsIDB4MTUyYTNmMTUsXG4gICAgMHgwNDA4MGMwNCwgMHhjNzk1NTJjNywgMHgyMzQ2NjUyMywgMHhjMzlkNWVjMyxcbiAgICAweDE4MzAyODE4LCAweDk2MzdhMTk2LCAweDA1MGEwZjA1LCAweDlhMmZiNTlhLFxuICAgIDB4MDcwZTA5MDcsIDB4MTIyNDM2MTIsIDB4ODAxYjliODAsIDB4ZTJkZjNkZTIsXG4gICAgMHhlYmNkMjZlYiwgMHgyNzRlNjkyNywgMHhiMjdmY2RiMiwgMHg3NWVhOWY3NSxcbiAgICAweDA5MTIxYjA5LCAweDgzMWQ5ZTgzLCAweDJjNTg3NDJjLCAweDFhMzQyZTFhLFxuICAgIDB4MWIzNjJkMWIsIDB4NmVkY2IyNmUsIDB4NWFiNGVlNWEsIDB4YTA1YmZiYTAsXG4gICAgMHg1MmE0ZjY1MiwgMHgzYjc2NGQzYiwgMHhkNmI3NjFkNiwgMHhiMzdkY2ViMyxcbiAgICAweDI5NTI3YjI5LCAweGUzZGQzZWUzLCAweDJmNWU3MTJmLCAweDg0MTM5Nzg0LFxuICAgIDB4NTNhNmY1NTMsIDB4ZDFiOTY4ZDEsIDB4MDAwMDAwMDAsIDB4ZWRjMTJjZWQsXG4gICAgMHgyMDQwNjAyMCwgMHhmY2UzMWZmYywgMHhiMTc5YzhiMSwgMHg1YmI2ZWQ1YixcbiAgICAweDZhZDRiZTZhLCAweGNiOGQ0NmNiLCAweGJlNjdkOWJlLCAweDM5NzI0YjM5LFxuICAgIDB4NGE5NGRlNGEsIDB4NGM5OGQ0NGMsIDB4NThiMGU4NTgsIDB4Y2Y4NTRhY2YsXG4gICAgMHhkMGJiNmJkMCwgMHhlZmM1MmFlZiwgMHhhYTRmZTVhYSwgMHhmYmVkMTZmYixcbiAgICAweDQzODZjNTQzLCAweDRkOWFkNzRkLCAweDMzNjY1NTMzLCAweDg1MTE5NDg1LFxuICAgIDB4NDU4YWNmNDUsIDB4ZjllOTEwZjksIDB4MDIwNDA2MDIsIDB4N2ZmZTgxN2YsXG4gICAgMHg1MGEwZjA1MCwgMHgzYzc4NDQzYywgMHg5ZjI1YmE5ZiwgMHhhODRiZTNhOCxcbiAgICAweDUxYTJmMzUxLCAweGEzNWRmZWEzLCAweDQwODBjMDQwLCAweDhmMDU4YThmLFxuICAgIDB4OTIzZmFkOTIsIDB4OWQyMWJjOWQsIDB4Mzg3MDQ4MzgsIDB4ZjVmMTA0ZjUsXG4gICAgMHhiYzYzZGZiYywgMHhiNjc3YzFiNiwgMHhkYWFmNzVkYSwgMHgyMTQyNjMyMSxcbiAgICAweDEwMjAzMDEwLCAweGZmZTUxYWZmLCAweGYzZmQwZWYzLCAweGQyYmY2ZGQyLFxuICAgIDB4Y2Q4MTRjY2QsIDB4MGMxODE0MGMsIDB4MTMyNjM1MTMsIDB4ZWNjMzJmZWMsXG4gICAgMHg1ZmJlZTE1ZiwgMHg5NzM1YTI5NywgMHg0NDg4Y2M0NCwgMHgxNzJlMzkxNyxcbiAgICAweGM0OTM1N2M0LCAweGE3NTVmMmE3LCAweDdlZmM4MjdlLCAweDNkN2E0NzNkLFxuICAgIDB4NjRjOGFjNjQsIDB4NWRiYWU3NWQsIDB4MTkzMjJiMTksIDB4NzNlNjk1NzMsXG4gICAgMHg2MGMwYTA2MCwgMHg4MTE5OTg4MSwgMHg0ZjllZDE0ZiwgMHhkY2EzN2ZkYyxcbiAgICAweDIyNDQ2NjIyLCAweDJhNTQ3ZTJhLCAweDkwM2JhYjkwLCAweDg4MGI4Mzg4LFxuICAgIDB4NDY4Y2NhNDYsIDB4ZWVjNzI5ZWUsIDB4Yjg2YmQzYjgsIDB4MTQyODNjMTQsXG4gICAgMHhkZWE3NzlkZSwgMHg1ZWJjZTI1ZSwgMHgwYjE2MWQwYiwgMHhkYmFkNzZkYixcbiAgICAweGUwZGIzYmUwLCAweDMyNjQ1NjMyLCAweDNhNzQ0ZTNhLCAweDBhMTQxZTBhLFxuICAgIDB4NDk5MmRiNDksIDB4MDYwYzBhMDYsIDB4MjQ0ODZjMjQsIDB4NWNiOGU0NWMsXG4gICAgMHhjMjlmNWRjMiwgMHhkM2JkNmVkMywgMHhhYzQzZWZhYywgMHg2MmM0YTY2MixcbiAgICAweDkxMzlhODkxLCAweDk1MzFhNDk1LCAweGU0ZDMzN2U0LCAweDc5ZjI4Yjc5LFxuICAgIDB4ZTdkNTMyZTcsIDB4Yzg4YjQzYzgsIDB4Mzc2ZTU5MzcsIDB4NmRkYWI3NmQsXG4gICAgMHg4ZDAxOGM4ZCwgMHhkNWIxNjRkNSwgMHg0ZTljZDI0ZSwgMHhhOTQ5ZTBhOSxcbiAgICAweDZjZDhiNDZjLCAweDU2YWNmYTU2LCAweGY0ZjMwN2Y0LCAweGVhY2YyNWVhLFxuICAgIDB4NjVjYWFmNjUsIDB4N2FmNDhlN2EsIDB4YWU0N2U5YWUsIDB4MDgxMDE4MDgsXG4gICAgMHhiYTZmZDViYSwgMHg3OGYwODg3OCwgMHgyNTRhNmYyNSwgMHgyZTVjNzIyZSxcbiAgICAweDFjMzgyNDFjLCAweGE2NTdmMWE2LCAweGI0NzNjN2I0LCAweGM2OTc1MWM2LFxuICAgIDB4ZThjYjIzZTgsIDB4ZGRhMTdjZGQsIDB4NzRlODljNzQsIDB4MWYzZTIxMWYsXG4gICAgMHg0Yjk2ZGQ0YiwgMHhiZDYxZGNiZCwgMHg4YjBkODY4YiwgMHg4YTBmODU4YSxcbiAgICAweDcwZTA5MDcwLCAweDNlN2M0MjNlLCAweGI1NzFjNGI1LCAweDY2Y2NhYTY2LFxuICAgIDB4NDg5MGQ4NDgsIDB4MDMwNjA1MDMsIDB4ZjZmNzAxZjYsIDB4MGUxYzEyMGUsXG4gICAgMHg2MWMyYTM2MSwgMHgzNTZhNWYzNSwgMHg1N2FlZjk1NywgMHhiOTY5ZDBiOSxcbiAgICAweDg2MTc5MTg2LCAweGMxOTk1OGMxLCAweDFkM2EyNzFkLCAweDllMjdiOTllLFxuICAgIDB4ZTFkOTM4ZTEsIDB4ZjhlYjEzZjgsIDB4OTgyYmIzOTgsIDB4MTEyMjMzMTEsXG4gICAgMHg2OWQyYmI2OSwgMHhkOWE5NzBkOSwgMHg4ZTA3ODk4ZSwgMHg5NDMzYTc5NCxcbiAgICAweDliMmRiNjliLCAweDFlM2MyMjFlLCAweDg3MTU5Mjg3LCAweGU5YzkyMGU5LFxuICAgIDB4Y2U4NzQ5Y2UsIDB4NTVhYWZmNTUsIDB4Mjg1MDc4MjgsIDB4ZGZhNTdhZGYsXG4gICAgMHg4YzAzOGY4YywgMHhhMTU5ZjhhMSwgMHg4OTA5ODA4OSwgMHgwZDFhMTcwZCxcbiAgICAweGJmNjVkYWJmLCAweGU2ZDczMWU2LCAweDQyODRjNjQyLCAweDY4ZDBiODY4LFxuICAgIDB4NDE4MmMzNDEsIDB4OTkyOWIwOTksIDB4MmQ1YTc3MmQsIDB4MGYxZTExMGYsXG4gICAgMHhiMDdiY2JiMCwgMHg1NGE4ZmM1NCwgMHhiYjZkZDZiYiwgMHgxNjJjM2ExNlxuXTtcblxudmFyIFQ0ID0gW1xuICAgIDB4YzZhNTYzNjMsIDB4Zjg4NDdjN2MsIDB4ZWU5OTc3NzcsIDB4ZjY4ZDdiN2IsXG4gICAgMHhmZjBkZjJmMiwgMHhkNmJkNmI2YiwgMHhkZWIxNmY2ZiwgMHg5MTU0YzVjNSxcbiAgICAweDYwNTAzMDMwLCAweDAyMDMwMTAxLCAweGNlYTk2NzY3LCAweDU2N2QyYjJiLFxuICAgIDB4ZTcxOWZlZmUsIDB4YjU2MmQ3ZDcsIDB4NGRlNmFiYWIsIDB4ZWM5YTc2NzYsXG4gICAgMHg4ZjQ1Y2FjYSwgMHgxZjlkODI4MiwgMHg4OTQwYzljOSwgMHhmYTg3N2Q3ZCxcbiAgICAweGVmMTVmYWZhLCAweGIyZWI1OTU5LCAweDhlYzk0NzQ3LCAweGZiMGJmMGYwLFxuICAgIDB4NDFlY2FkYWQsIDB4YjM2N2Q0ZDQsIDB4NWZmZGEyYTIsIDB4NDVlYWFmYWYsXG4gICAgMHgyM2JmOWM5YywgMHg1M2Y3YTRhNCwgMHhlNDk2NzI3MiwgMHg5YjViYzBjMCxcbiAgICAweDc1YzJiN2I3LCAweGUxMWNmZGZkLCAweDNkYWU5MzkzLCAweDRjNmEyNjI2LFxuICAgIDB4NmM1YTM2MzYsIDB4N2U0MTNmM2YsIDB4ZjUwMmY3ZjcsIDB4ODM0ZmNjY2MsXG4gICAgMHg2ODVjMzQzNCwgMHg1MWY0YTVhNSwgMHhkMTM0ZTVlNSwgMHhmOTA4ZjFmMSxcbiAgICAweGUyOTM3MTcxLCAweGFiNzNkOGQ4LCAweDYyNTMzMTMxLCAweDJhM2YxNTE1LFxuICAgIDB4MDgwYzA0MDQsIDB4OTU1MmM3YzcsIDB4NDY2NTIzMjMsIDB4OWQ1ZWMzYzMsXG4gICAgMHgzMDI4MTgxOCwgMHgzN2ExOTY5NiwgMHgwYTBmMDUwNSwgMHgyZmI1OWE5YSxcbiAgICAweDBlMDkwNzA3LCAweDI0MzYxMjEyLCAweDFiOWI4MDgwLCAweGRmM2RlMmUyLFxuICAgIDB4Y2QyNmViZWIsIDB4NGU2OTI3MjcsIDB4N2ZjZGIyYjIsIDB4ZWE5Zjc1NzUsXG4gICAgMHgxMjFiMDkwOSwgMHgxZDllODM4MywgMHg1ODc0MmMyYywgMHgzNDJlMWExYSxcbiAgICAweDM2MmQxYjFiLCAweGRjYjI2ZTZlLCAweGI0ZWU1YTVhLCAweDViZmJhMGEwLFxuICAgIDB4YTRmNjUyNTIsIDB4NzY0ZDNiM2IsIDB4Yjc2MWQ2ZDYsIDB4N2RjZWIzYjMsXG4gICAgMHg1MjdiMjkyOSwgMHhkZDNlZTNlMywgMHg1ZTcxMmYyZiwgMHgxMzk3ODQ4NCxcbiAgICAweGE2ZjU1MzUzLCAweGI5NjhkMWQxLCAweDAwMDAwMDAwLCAweGMxMmNlZGVkLFxuICAgIDB4NDA2MDIwMjAsIDB4ZTMxZmZjZmMsIDB4NzljOGIxYjEsIDB4YjZlZDViNWIsXG4gICAgMHhkNGJlNmE2YSwgMHg4ZDQ2Y2JjYiwgMHg2N2Q5YmViZSwgMHg3MjRiMzkzOSxcbiAgICAweDk0ZGU0YTRhLCAweDk4ZDQ0YzRjLCAweGIwZTg1ODU4LCAweDg1NGFjZmNmLFxuICAgIDB4YmI2YmQwZDAsIDB4YzUyYWVmZWYsIDB4NGZlNWFhYWEsIDB4ZWQxNmZiZmIsXG4gICAgMHg4NmM1NDM0MywgMHg5YWQ3NGQ0ZCwgMHg2NjU1MzMzMywgMHgxMTk0ODU4NSxcbiAgICAweDhhY2Y0NTQ1LCAweGU5MTBmOWY5LCAweDA0MDYwMjAyLCAweGZlODE3ZjdmLFxuICAgIDB4YTBmMDUwNTAsIDB4Nzg0NDNjM2MsIDB4MjViYTlmOWYsIDB4NGJlM2E4YTgsXG4gICAgMHhhMmYzNTE1MSwgMHg1ZGZlYTNhMywgMHg4MGMwNDA0MCwgMHgwNThhOGY4ZixcbiAgICAweDNmYWQ5MjkyLCAweDIxYmM5ZDlkLCAweDcwNDgzODM4LCAweGYxMDRmNWY1LFxuICAgIDB4NjNkZmJjYmMsIDB4NzdjMWI2YjYsIDB4YWY3NWRhZGEsIDB4NDI2MzIxMjEsXG4gICAgMHgyMDMwMTAxMCwgMHhlNTFhZmZmZiwgMHhmZDBlZjNmMywgMHhiZjZkZDJkMixcbiAgICAweDgxNGNjZGNkLCAweDE4MTQwYzBjLCAweDI2MzUxMzEzLCAweGMzMmZlY2VjLFxuICAgIDB4YmVlMTVmNWYsIDB4MzVhMjk3OTcsIDB4ODhjYzQ0NDQsIDB4MmUzOTE3MTcsXG4gICAgMHg5MzU3YzRjNCwgMHg1NWYyYTdhNywgMHhmYzgyN2U3ZSwgMHg3YTQ3M2QzZCxcbiAgICAweGM4YWM2NDY0LCAweGJhZTc1ZDVkLCAweDMyMmIxOTE5LCAweGU2OTU3MzczLFxuICAgIDB4YzBhMDYwNjAsIDB4MTk5ODgxODEsIDB4OWVkMTRmNGYsIDB4YTM3ZmRjZGMsXG4gICAgMHg0NDY2MjIyMiwgMHg1NDdlMmEyYSwgMHgzYmFiOTA5MCwgMHgwYjgzODg4OCxcbiAgICAweDhjY2E0NjQ2LCAweGM3MjllZWVlLCAweDZiZDNiOGI4LCAweDI4M2MxNDE0LFxuICAgIDB4YTc3OWRlZGUsIDB4YmNlMjVlNWUsIDB4MTYxZDBiMGIsIDB4YWQ3NmRiZGIsXG4gICAgMHhkYjNiZTBlMCwgMHg2NDU2MzIzMiwgMHg3NDRlM2EzYSwgMHgxNDFlMGEwYSxcbiAgICAweDkyZGI0OTQ5LCAweDBjMGEwNjA2LCAweDQ4NmMyNDI0LCAweGI4ZTQ1YzVjLFxuICAgIDB4OWY1ZGMyYzIsIDB4YmQ2ZWQzZDMsIDB4NDNlZmFjYWMsIDB4YzRhNjYyNjIsXG4gICAgMHgzOWE4OTE5MSwgMHgzMWE0OTU5NSwgMHhkMzM3ZTRlNCwgMHhmMjhiNzk3OSxcbiAgICAweGQ1MzJlN2U3LCAweDhiNDNjOGM4LCAweDZlNTkzNzM3LCAweGRhYjc2ZDZkLFxuICAgIDB4MDE4YzhkOGQsIDB4YjE2NGQ1ZDUsIDB4OWNkMjRlNGUsIDB4NDllMGE5YTksXG4gICAgMHhkOGI0NmM2YywgMHhhY2ZhNTY1NiwgMHhmMzA3ZjRmNCwgMHhjZjI1ZWFlYSxcbiAgICAweGNhYWY2NTY1LCAweGY0OGU3YTdhLCAweDQ3ZTlhZWFlLCAweDEwMTgwODA4LFxuICAgIDB4NmZkNWJhYmEsIDB4ZjA4ODc4NzgsIDB4NGE2ZjI1MjUsIDB4NWM3MjJlMmUsXG4gICAgMHgzODI0MWMxYywgMHg1N2YxYTZhNiwgMHg3M2M3YjRiNCwgMHg5NzUxYzZjNixcbiAgICAweGNiMjNlOGU4LCAweGExN2NkZGRkLCAweGU4OWM3NDc0LCAweDNlMjExZjFmLFxuICAgIDB4OTZkZDRiNGIsIDB4NjFkY2JkYmQsIDB4MGQ4NjhiOGIsIDB4MGY4NThhOGEsXG4gICAgMHhlMDkwNzA3MCwgMHg3YzQyM2UzZSwgMHg3MWM0YjViNSwgMHhjY2FhNjY2NixcbiAgICAweDkwZDg0ODQ4LCAweDA2MDUwMzAzLCAweGY3MDFmNmY2LCAweDFjMTIwZTBlLFxuICAgIDB4YzJhMzYxNjEsIDB4NmE1ZjM1MzUsIDB4YWVmOTU3NTcsIDB4NjlkMGI5YjksXG4gICAgMHgxNzkxODY4NiwgMHg5OTU4YzFjMSwgMHgzYTI3MWQxZCwgMHgyN2I5OWU5ZSxcbiAgICAweGQ5MzhlMWUxLCAweGViMTNmOGY4LCAweDJiYjM5ODk4LCAweDIyMzMxMTExLFxuICAgIDB4ZDJiYjY5NjksIDB4YTk3MGQ5ZDksIDB4MDc4OThlOGUsIDB4MzNhNzk0OTQsXG4gICAgMHgyZGI2OWI5YiwgMHgzYzIyMWUxZSwgMHgxNTkyODc4NywgMHhjOTIwZTllOSxcbiAgICAweDg3NDljZWNlLCAweGFhZmY1NTU1LCAweDUwNzgyODI4LCAweGE1N2FkZmRmLFxuICAgIDB4MDM4ZjhjOGMsIDB4NTlmOGExYTEsIDB4MDk4MDg5ODksIDB4MWExNzBkMGQsXG4gICAgMHg2NWRhYmZiZiwgMHhkNzMxZTZlNiwgMHg4NGM2NDI0MiwgMHhkMGI4Njg2OCxcbiAgICAweDgyYzM0MTQxLCAweDI5YjA5OTk5LCAweDVhNzcyZDJkLCAweDFlMTEwZjBmLFxuICAgIDB4N2JjYmIwYjAsIDB4YThmYzU0NTQsIDB4NmRkNmJiYmIsIDB4MmMzYTE2MTZcbl07XG5cbmZ1bmN0aW9uIEIwKHgpIHtcbiAgcmV0dXJuICh4ICYgMjU1KTtcbn1cblxuZnVuY3Rpb24gQjEoeCkge1xuICByZXR1cm4gKCh4ID4+IDgpICYgMjU1KTtcbn1cblxuZnVuY3Rpb24gQjIoeCkge1xuICByZXR1cm4gKCh4ID4+IDE2KSAmIDI1NSk7XG59XG5cbmZ1bmN0aW9uIEIzKHgpIHtcbiAgcmV0dXJuICgoeCA+PiAyNCkgJiAyNTUpO1xufVxuXG5mdW5jdGlvbiBGMSh4MCwgeDEsIHgyLCB4Mykge1xuICByZXR1cm4gQjEoVDFbeDAgJiAyNTVdKSB8IChCMShUMVsoeDEgPj4gOCkgJiAyNTVdKSA8PCA4KSB8IChCMShUMVsoeDIgPj4gMTYpICYgMjU1XSkgPDwgMTYpIHwgKEIxKFQxW3gzID4+PiAyNF0pIDw8XG4gICAgMjQpO1xufVxuXG5mdW5jdGlvbiBwYWNrQnl0ZXMob2N0ZXRzKSB7XG4gIHZhciBpLCBqO1xuICB2YXIgbGVuID0gb2N0ZXRzLmxlbmd0aDtcbiAgdmFyIGIgPSBuZXcgQXJyYXkobGVuIC8gNCk7XG5cbiAgaWYgKCFvY3RldHMgfHwgbGVuICUgNCkgcmV0dXJuO1xuXG4gIGZvciAoaSA9IDAsIGogPSAwOyBqIDwgbGVuOyBqICs9IDQpXG4gICAgYltpKytdID0gb2N0ZXRzW2pdIHwgKG9jdGV0c1tqICsgMV0gPDwgOCkgfCAob2N0ZXRzW2ogKyAyXSA8PCAxNikgfCAob2N0ZXRzW2ogKyAzXSA8PCAyNCk7XG5cbiAgcmV0dXJuIGI7XG59XG5cbmZ1bmN0aW9uIHVucGFja0J5dGVzKHBhY2tlZCkge1xuICB2YXIgajtcbiAgdmFyIGkgPSAwLFxuICAgIGwgPSBwYWNrZWQubGVuZ3RoO1xuICB2YXIgciA9IG5ldyBBcnJheShsICogNCk7XG5cbiAgZm9yIChqID0gMDsgaiA8IGw7IGorKykge1xuICAgIHJbaSsrXSA9IEIwKHBhY2tlZFtqXSk7XG4gICAgcltpKytdID0gQjEocGFja2VkW2pdKTtcbiAgICByW2krK10gPSBCMihwYWNrZWRbal0pO1xuICAgIHJbaSsrXSA9IEIzKHBhY2tlZFtqXSk7XG4gIH1cbiAgcmV0dXJuIHI7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG52YXIgbWF4a2MgPSA4O1xudmFyIG1heHJrID0gMTQ7XG5cbmZ1bmN0aW9uIGtleUV4cGFuc2lvbihrZXkpIHtcbiAgdmFyIGtjLCBpLCBqLCByLCB0O1xuICB2YXIgcm91bmRzO1xuICB2YXIga2V5U2NoZWQgPSBuZXcgQXJyYXkobWF4cmsgKyAxKTtcbiAgdmFyIGtleWxlbiA9IGtleS5sZW5ndGg7XG4gIHZhciBrID0gbmV3IEFycmF5KG1heGtjKTtcbiAgdmFyIHRrID0gbmV3IEFycmF5KG1heGtjKTtcbiAgdmFyIHJjb25wb2ludGVyID0gMDtcblxuICBpZiAoa2V5bGVuID09IDE2KSB7XG4gICAgcm91bmRzID0gMTA7XG4gICAga2MgPSA0O1xuICB9IGVsc2UgaWYgKGtleWxlbiA9PSAyNCkge1xuICAgIHJvdW5kcyA9IDEyO1xuICAgIGtjID0gNjtcbiAgfSBlbHNlIGlmIChrZXlsZW4gPT0gMzIpIHtcbiAgICByb3VuZHMgPSAxNDtcbiAgICBrYyA9IDg7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGtleS1sZW5ndGggZm9yIEFFUyBrZXk6JyArIGtleWxlbik7XG4gIH1cblxuICBmb3IgKGkgPSAwOyBpIDwgbWF4cmsgKyAxOyBpKyspIGtleVNjaGVkW2ldID0gbmV3IEFycmF5KDQpO1xuXG4gIGZvciAoaSA9IDAsIGogPSAwOyBqIDwga2V5bGVuOyBqKyssIGkgKz0gNClcbiAgICBrW2pdID0ga2V5LmNoYXJDb2RlQXQoaSkgfCAoa2V5LmNoYXJDb2RlQXQoaSArIDEpIDw8IDgpIHwgKGtleS5jaGFyQ29kZUF0KGkgKyAyKSA8PCAxNikgfCAoa2V5LmNoYXJDb2RlQXQoaSArIDMpIDw8XG4gICAgICAyNCk7XG5cbiAgZm9yIChqID0ga2MgLSAxOyBqID49IDA7IGotLSkgdGtbal0gPSBrW2pdO1xuXG4gIHIgPSAwO1xuICB0ID0gMDtcbiAgZm9yIChqID0gMDtcbiAgKGogPCBrYykgJiYgKHIgPCByb3VuZHMgKyAxKTspIHtcbiAgICBmb3IgKDtcbiAgICAoaiA8IGtjKSAmJiAodCA8IDQpOyBqKyssIHQrKykge1xuICAgICAga2V5U2NoZWRbcl1bdF0gPSB0a1tqXTtcbiAgICB9XG4gICAgaWYgKHQgPT0gNCkge1xuICAgICAgcisrO1xuICAgICAgdCA9IDA7XG4gICAgfVxuICB9XG5cbiAgd2hpbGUgKHIgPCByb3VuZHMgKyAxKSB7XG4gICAgdmFyIHRlbXAgPSB0a1trYyAtIDFdO1xuXG4gICAgdGtbMF0gXj0gU1tCMSh0ZW1wKV0gfCAoU1tCMih0ZW1wKV0gPDwgOCkgfCAoU1tCMyh0ZW1wKV0gPDwgMTYpIHwgKFNbQjAodGVtcCldIDw8IDI0KTtcbiAgICB0a1swXSBePSBSY29uW3Jjb25wb2ludGVyKytdO1xuXG4gICAgaWYgKGtjICE9IDgpIHtcbiAgICAgIGZvciAoaiA9IDE7IGogPCBrYzsgaisrKSB0a1tqXSBePSB0a1tqIC0gMV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGZvciAoaiA9IDE7IGogPCBrYyAvIDI7IGorKykgdGtbal0gXj0gdGtbaiAtIDFdO1xuXG4gICAgICB0ZW1wID0gdGtba2MgLyAyIC0gMV07XG4gICAgICB0a1trYyAvIDJdIF49IFNbQjAodGVtcCldIHwgKFNbQjEodGVtcCldIDw8IDgpIHwgKFNbQjIodGVtcCldIDw8IDE2KSB8IChTW0IzKHRlbXApXSA8PCAyNCk7XG5cbiAgICAgIGZvciAoaiA9IGtjIC8gMiArIDE7IGogPCBrYzsgaisrKSB0a1tqXSBePSB0a1tqIC0gMV07XG4gICAgfVxuXG4gICAgZm9yIChqID0gMDtcbiAgICAoaiA8IGtjKSAmJiAociA8IHJvdW5kcyArIDEpOykge1xuICAgICAgZm9yICg7XG4gICAgICAoaiA8IGtjKSAmJiAodCA8IDQpOyBqKyssIHQrKykge1xuICAgICAgICBrZXlTY2hlZFtyXVt0XSA9IHRrW2pdO1xuICAgICAgfVxuICAgICAgaWYgKHQgPT0gNCkge1xuICAgICAgICByKys7XG4gICAgICAgIHQgPSAwO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICB0aGlzLnJvdW5kcyA9IHJvdW5kcztcbiAgdGhpcy5yayA9IGtleVNjaGVkO1xuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gQUVTZW5jcnlwdChibG9jaywgY3R4KSB7XG4gIHZhciByO1xuICB2YXIgdDAsIHQxLCB0MiwgdDM7XG5cbiAgdmFyIGIgPSBwYWNrQnl0ZXMoYmxvY2spO1xuICB2YXIgcm91bmRzID0gY3R4LnJvdW5kcztcbiAgdmFyIGIwID0gYlswXTtcbiAgdmFyIGIxID0gYlsxXTtcbiAgdmFyIGIyID0gYlsyXTtcbiAgdmFyIGIzID0gYlszXTtcblxuICBmb3IgKHIgPSAwOyByIDwgcm91bmRzIC0gMTsgcisrKSB7XG4gICAgdDAgPSBiMCBeIGN0eC5ya1tyXVswXTtcbiAgICB0MSA9IGIxIF4gY3R4LnJrW3JdWzFdO1xuICAgIHQyID0gYjIgXiBjdHgucmtbcl1bMl07XG4gICAgdDMgPSBiMyBeIGN0eC5ya1tyXVszXTtcblxuICAgIGIwID0gVDFbdDAgJiAyNTVdIF4gVDJbKHQxID4+IDgpICYgMjU1XSBeIFQzWyh0MiA+PiAxNikgJiAyNTVdIF4gVDRbdDMgPj4+IDI0XTtcbiAgICBiMSA9IFQxW3QxICYgMjU1XSBeIFQyWyh0MiA+PiA4KSAmIDI1NV0gXiBUM1sodDMgPj4gMTYpICYgMjU1XSBeIFQ0W3QwID4+PiAyNF07XG4gICAgYjIgPSBUMVt0MiAmIDI1NV0gXiBUMlsodDMgPj4gOCkgJiAyNTVdIF4gVDNbKHQwID4+IDE2KSAmIDI1NV0gXiBUNFt0MSA+Pj4gMjRdO1xuICAgIGIzID0gVDFbdDMgJiAyNTVdIF4gVDJbKHQwID4+IDgpICYgMjU1XSBeIFQzWyh0MSA+PiAxNikgJiAyNTVdIF4gVDRbdDIgPj4+IDI0XTtcbiAgfVxuXG4gIC8vIGxhc3Qgcm91bmQgaXMgc3BlY2lhbFxuICByID0gcm91bmRzIC0gMTtcblxuICB0MCA9IGIwIF4gY3R4LnJrW3JdWzBdO1xuICB0MSA9IGIxIF4gY3R4LnJrW3JdWzFdO1xuICB0MiA9IGIyIF4gY3R4LnJrW3JdWzJdO1xuICB0MyA9IGIzIF4gY3R4LnJrW3JdWzNdO1xuXG4gIGJbMF0gPSBGMSh0MCwgdDEsIHQyLCB0MykgXiBjdHgucmtbcm91bmRzXVswXTtcbiAgYlsxXSA9IEYxKHQxLCB0MiwgdDMsIHQwKSBeIGN0eC5ya1tyb3VuZHNdWzFdO1xuICBiWzJdID0gRjEodDIsIHQzLCB0MCwgdDEpIF4gY3R4LnJrW3JvdW5kc11bMl07XG4gIGJbM10gPSBGMSh0MywgdDAsIHQxLCB0MikgXiBjdHgucmtbcm91bmRzXVszXTtcblxuICByZXR1cm4gdW5wYWNrQnl0ZXMoYik7XG59XG5cbmZ1bmN0aW9uIG1ha2VDbGFzcyhsZW5ndGgpIHtcblxuICB2YXIgYyA9IGZ1bmN0aW9uKGtleSkge1xuICAgIHRoaXMua2V5ID0ga2V5RXhwYW5zaW9uKGtleSk7XG5cbiAgICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihibG9jaykge1xuICAgICAgcmV0dXJuIEFFU2VuY3J5cHQoYmxvY2ssIHRoaXMua2V5KTtcbiAgICB9XG4gIH1cblxuICBjLmJsb2NrU2l6ZSA9IGMucHJvdG90eXBlLmJsb2NrU2l6ZSA9IDE2O1xuICBjLmtleVNpemUgPSBjLnByb3RvdHlwZS5rZXlTaXplID0gbGVuZ3RoIC8gODtcblxuICByZXR1cm4gYztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7fVxuXG52YXIgdHlwZXMgPSBbMTI4LCAxOTIsIDI1Nl07XG5cbmZvciAodmFyIGkgaW4gdHlwZXMpIHtcbiAgbW9kdWxlLmV4cG9ydHNbdHlwZXNbaV1dID0gbWFrZUNsYXNzKHR5cGVzW2ldKTtcbn1cbiIsIi8qIE1vZGlmaWVkIGJ5IFJlY3VyaXR5IExhYnMgR21iSCBcbiAqIFxuICogT3JpZ2luYWxseSB3cml0dGVuIGJ5IG5rbGVpbiBzb2Z0d2FyZSAobmtsZWluLmNvbSlcbiAqL1xuXG4vKipcbiAqICBAbW9kdWxlIGNyeXB0by9jaXBoZXIvYmxvd2Zpc2hcbiAqL1xuXG4vKiBcbiAqIEphdmFzY3JpcHQgaW1wbGVtZW50YXRpb24gYmFzZWQgb24gQnJ1Y2UgU2NobmVpZXIncyByZWZlcmVuY2UgaW1wbGVtZW50YXRpb24uXG4gKlxuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciBkb2Vzbid0IGRvIG11Y2ggb2YgYW55dGhpbmcuICBJdCdzIGp1c3QgaGVyZVxuICogc28gd2UgY2FuIHN0YXJ0IGRlZmluaW5nIHByb3BlcnRpZXMgYW5kIG1ldGhvZHMgYW5kIHN1Y2guXG4gKi9cbmZ1bmN0aW9uIEJsb3dmaXNoKCkge307XG5cbi8qXG4gKiBEZWNsYXJlIHRoZSBibG9jayBzaXplIHNvIHRoYXQgcHJvdG9jb2xzIGtub3cgd2hhdCBzaXplXG4gKiBJbml0aWFsaXphdGlvbiBWZWN0b3IgKElWKSB0aGV5IHdpbGwgbmVlZC5cbiAqL1xuQmxvd2Zpc2gucHJvdG90eXBlLkJMT0NLU0laRSA9IDg7XG5cbi8qXG4gKiBUaGVzZSBhcmUgdGhlIGRlZmF1bHQgU0JPWEVTLlxuICovXG5CbG93ZmlzaC5wcm90b3R5cGUuU0JPWEVTID0gW1xuICBbXG4gICAgICAweGQxMzEwYmE2LCAweDk4ZGZiNWFjLCAweDJmZmQ3MmRiLCAweGQwMWFkZmI3LCAweGI4ZTFhZmVkLCAweDZhMjY3ZTk2LFxuICAgICAgMHhiYTdjOTA0NSwgMHhmMTJjN2Y5OSwgMHgyNGExOTk0NywgMHhiMzkxNmNmNywgMHgwODAxZjJlMiwgMHg4NThlZmMxNixcbiAgICAgIDB4NjM2OTIwZDgsIDB4NzE1NzRlNjksIDB4YTQ1OGZlYTMsIDB4ZjQ5MzNkN2UsIDB4MGQ5NTc0OGYsIDB4NzI4ZWI2NTgsXG4gICAgICAweDcxOGJjZDU4LCAweDgyMTU0YWVlLCAweDdiNTRhNDFkLCAweGMyNWE1OWI1LCAweDljMzBkNTM5LCAweDJhZjI2MDEzLFxuICAgICAgMHhjNWQxYjAyMywgMHgyODYwODVmMCwgMHhjYTQxNzkxOCwgMHhiOGRiMzhlZiwgMHg4ZTc5ZGNiMCwgMHg2MDNhMTgwZSxcbiAgICAgIDB4NmM5ZTBlOGIsIDB4YjAxZThhM2UsIDB4ZDcxNTc3YzEsIDB4YmQzMTRiMjcsIDB4NzhhZjJmZGEsIDB4NTU2MDVjNjAsXG4gICAgICAweGU2NTUyNWYzLCAweGFhNTVhYjk0LCAweDU3NDg5ODYyLCAweDYzZTgxNDQwLCAweDU1Y2EzOTZhLCAweDJhYWIxMGI2LFxuICAgICAgMHhiNGNjNWMzNCwgMHgxMTQxZThjZSwgMHhhMTU0ODZhZiwgMHg3YzcyZTk5MywgMHhiM2VlMTQxMSwgMHg2MzZmYmMyYSxcbiAgICAgIDB4MmJhOWM1NWQsIDB4NzQxODMxZjYsIDB4Y2U1YzNlMTYsIDB4OWI4NzkzMWUsIDB4YWZkNmJhMzMsIDB4NmMyNGNmNWMsXG4gICAgICAweDdhMzI1MzgxLCAweDI4OTU4Njc3LCAweDNiOGY0ODk4LCAweDZiNGJiOWFmLCAweGM0YmZlODFiLCAweDY2MjgyMTkzLFxuICAgICAgMHg2MWQ4MDljYywgMHhmYjIxYTk5MSwgMHg0ODdjYWM2MCwgMHg1ZGVjODAzMiwgMHhlZjg0NWQ1ZCwgMHhlOTg1NzViMSxcbiAgICAgIDB4ZGMyNjIzMDIsIDB4ZWI2NTFiODgsIDB4MjM4OTNlODEsIDB4ZDM5NmFjYzUsIDB4MGY2ZDZmZjMsIDB4ODNmNDQyMzksXG4gICAgICAweDJlMGI0NDgyLCAweGE0ODQyMDA0LCAweDY5YzhmMDRhLCAweDllMWY5YjVlLCAweDIxYzY2ODQyLCAweGY2ZTk2YzlhLFxuICAgICAgMHg2NzBjOWM2MSwgMHhhYmQzODhmMCwgMHg2YTUxYTBkMiwgMHhkODU0MmY2OCwgMHg5NjBmYTcyOCwgMHhhYjUxMzNhMyxcbiAgICAgIDB4NmVlZjBiNmMsIDB4MTM3YTNiZTQsIDB4YmEzYmYwNTAsIDB4N2VmYjJhOTgsIDB4YTFmMTY1MWQsIDB4MzlhZjAxNzYsXG4gICAgICAweDY2Y2E1OTNlLCAweDgyNDMwZTg4LCAweDhjZWU4NjE5LCAweDQ1NmY5ZmI0LCAweDdkODRhNWMzLCAweDNiOGI1ZWJlLFxuICAgICAgMHhlMDZmNzVkOCwgMHg4NWMxMjA3MywgMHg0MDFhNDQ5ZiwgMHg1NmMxNmFhNiwgMHg0ZWQzYWE2MiwgMHgzNjNmNzcwNixcbiAgICAgIDB4MWJmZWRmNzIsIDB4NDI5YjAyM2QsIDB4MzdkMGQ3MjQsIDB4ZDAwYTEyNDgsIDB4ZGIwZmVhZDMsIDB4NDlmMWMwOWIsXG4gICAgICAweDA3NTM3MmM5LCAweDgwOTkxYjdiLCAweDI1ZDQ3OWQ4LCAweGY2ZThkZWY3LCAweGUzZmU1MDFhLCAweGI2Nzk0YzNiLFxuICAgICAgMHg5NzZjZTBiZCwgMHgwNGMwMDZiYSwgMHhjMWE5NGZiNiwgMHg0MDlmNjBjNCwgMHg1ZTVjOWVjMiwgMHgxOTZhMjQ2MyxcbiAgICAgIDB4NjhmYjZmYWYsIDB4M2U2YzUzYjUsIDB4MTMzOWIyZWIsIDB4M2I1MmVjNmYsIDB4NmRmYzUxMWYsIDB4OWIzMDk1MmMsXG4gICAgICAweGNjODE0NTQ0LCAweGFmNWViZDA5LCAweGJlZTNkMDA0LCAweGRlMzM0YWZkLCAweDY2MGYyODA3LCAweDE5MmU0YmIzLFxuICAgICAgMHhjMGNiYTg1NywgMHg0NWM4NzQwZiwgMHhkMjBiNWYzOSwgMHhiOWQzZmJkYiwgMHg1NTc5YzBiZCwgMHgxYTYwMzIwYSxcbiAgICAgIDB4ZDZhMTAwYzYsIDB4NDAyYzcyNzksIDB4Njc5ZjI1ZmUsIDB4ZmIxZmEzY2MsIDB4OGVhNWU5ZjgsIDB4ZGIzMjIyZjgsXG4gICAgICAweDNjNzUxNmRmLCAweGZkNjE2YjE1LCAweDJmNTAxZWM4LCAweGFkMDU1MmFiLCAweDMyM2RiNWZhLCAweGZkMjM4NzYwLFxuICAgICAgMHg1MzMxN2I0OCwgMHgzZTAwZGY4MiwgMHg5ZTVjNTdiYiwgMHhjYTZmOGNhMCwgMHgxYTg3NTYyZSwgMHhkZjE3NjlkYixcbiAgICAgIDB4ZDU0MmE4ZjYsIDB4Mjg3ZWZmYzMsIDB4YWM2NzMyYzYsIDB4OGM0ZjU1NzMsIDB4Njk1YjI3YjAsIDB4YmJjYTU4YzgsXG4gICAgICAweGUxZmZhMzVkLCAweGI4ZjAxMWEwLCAweDEwZmEzZDk4LCAweGZkMjE4M2I4LCAweDRhZmNiNTZjLCAweDJkZDFkMzViLFxuICAgICAgMHg5YTUzZTQ3OSwgMHhiNmY4NDU2NSwgMHhkMjhlNDliYywgMHg0YmZiOTc5MCwgMHhlMWRkZjJkYSwgMHhhNGNiN2UzMyxcbiAgICAgIDB4NjJmYjEzNDEsIDB4Y2VlNGM2ZTgsIDB4ZWYyMGNhZGEsIDB4MzY3NzRjMDEsIDB4ZDA3ZTllZmUsIDB4MmJmMTFmYjQsXG4gICAgICAweDk1ZGJkYTRkLCAweGFlOTA5MTk4LCAweGVhYWQ4ZTcxLCAweDZiOTNkNWEwLCAweGQwOGVkMWQwLCAweGFmYzcyNWUwLFxuICAgICAgMHg4ZTNjNWIyZiwgMHg4ZTc1OTRiNywgMHg4ZmY2ZTJmYiwgMHhmMjEyMmI2NCwgMHg4ODg4YjgxMiwgMHg5MDBkZjAxYyxcbiAgICAgIDB4NGZhZDVlYTAsIDB4Njg4ZmMzMWMsIDB4ZDFjZmYxOTEsIDB4YjNhOGMxYWQsIDB4MmYyZjIyMTgsIDB4YmUwZTE3NzcsXG4gICAgICAweGVhNzUyZGZlLCAweDhiMDIxZmExLCAweGU1YTBjYzBmLCAweGI1NmY3NGU4LCAweDE4YWNmM2Q2LCAweGNlODllMjk5LFxuICAgICAgMHhiNGE4NGZlMCwgMHhmZDEzZTBiNywgMHg3Y2M0M2I4MSwgMHhkMmFkYThkOSwgMHgxNjVmYTI2NiwgMHg4MDk1NzcwNSxcbiAgICAgIDB4OTNjYzczMTQsIDB4MjExYTE0NzcsIDB4ZTZhZDIwNjUsIDB4NzdiNWZhODYsIDB4Yzc1NDQyZjUsIDB4ZmI5ZDM1Y2YsXG4gICAgICAweGViY2RhZjBjLCAweDdiM2U4OWEwLCAweGQ2NDExYmQzLCAweGFlMWU3ZTQ5LCAweDAwMjUwZTJkLCAweDIwNzFiMzVlLFxuICAgICAgMHgyMjY4MDBiYiwgMHg1N2I4ZTBhZiwgMHgyNDY0MzY5YiwgMHhmMDA5YjkxZSwgMHg1NTYzOTExZCwgMHg1OWRmYTZhYSxcbiAgICAgIDB4NzhjMTQzODksIDB4ZDk1YTUzN2YsIDB4MjA3ZDViYTIsIDB4MDJlNWI5YzUsIDB4ODMyNjAzNzYsIDB4NjI5NWNmYTksXG4gICAgICAweDExYzgxOTY4LCAweDRlNzM0YTQxLCAweGIzNDcyZGNhLCAweDdiMTRhOTRhLCAweDFiNTEwMDUyLCAweDlhNTMyOTE1LFxuICAgICAgMHhkNjBmNTczZiwgMHhiYzliYzZlNCwgMHgyYjYwYTQ3NiwgMHg4MWU2NzQwMCwgMHgwOGJhNmZiNSwgMHg1NzFiZTkxZixcbiAgICAgIDB4ZjI5NmVjNmIsIDB4MmEwZGQ5MTUsIDB4YjY2MzY1MjEsIDB4ZTdiOWY5YjYsIDB4ZmYzNDA1MmUsIDB4YzU4NTU2NjQsXG4gICAgICAweDUzYjAyZDVkLCAweGE5OWY4ZmExLCAweDA4YmE0Nzk5LCAweDZlODUwNzZhXG4gIF0sXG4gIFtcbiAgICAgIDB4NGI3YTcwZTksIDB4YjViMzI5NDQsIDB4ZGI3NTA5MmUsIDB4YzQxOTI2MjMsIDB4YWQ2ZWE2YjAsIDB4NDlhN2RmN2QsXG4gICAgICAweDljZWU2MGI4LCAweDhmZWRiMjY2LCAweGVjYWE4YzcxLCAweDY5OWExN2ZmLCAweDU2NjQ1MjZjLCAweGMyYjE5ZWUxLFxuICAgICAgMHgxOTM2MDJhNSwgMHg3NTA5NGMyOSwgMHhhMDU5MTM0MCwgMHhlNDE4M2EzZSwgMHgzZjU0OTg5YSwgMHg1YjQyOWQ2NSxcbiAgICAgIDB4NmI4ZmU0ZDYsIDB4OTlmNzNmZDYsIDB4YTFkMjljMDcsIDB4ZWZlODMwZjUsIDB4NGQyZDM4ZTYsIDB4ZjAyNTVkYzEsXG4gICAgICAweDRjZGQyMDg2LCAweDg0NzBlYjI2LCAweDYzODJlOWM2LCAweDAyMWVjYzVlLCAweDA5Njg2YjNmLCAweDNlYmFlZmM5LFxuICAgICAgMHgzYzk3MTgxNCwgMHg2YjZhNzBhMSwgMHg2ODdmMzU4NCwgMHg1MmEwZTI4NiwgMHhiNzljNTMwNSwgMHhhYTUwMDczNyxcbiAgICAgIDB4M2UwNzg0MWMsIDB4N2ZkZWFlNWMsIDB4OGU3ZDQ0ZWMsIDB4NTcxNmYyYjgsIDB4YjAzYWRhMzcsIDB4ZjA1MDBjMGQsXG4gICAgICAweGYwMWMxZjA0LCAweDAyMDBiM2ZmLCAweGFlMGNmNTFhLCAweDNjYjU3NGIyLCAweDI1ODM3YTU4LCAweGRjMDkyMWJkLFxuICAgICAgMHhkMTkxMTNmOSwgMHg3Y2E5MmZmNiwgMHg5NDMyNDc3MywgMHgyMmY1NDcwMSwgMHgzYWU1ZTU4MSwgMHgzN2MyZGFkYyxcbiAgICAgIDB4YzhiNTc2MzQsIDB4OWFmM2RkYTcsIDB4YTk0NDYxNDYsIDB4MGZkMDAzMGUsIDB4ZWNjOGM3M2UsIDB4YTQ3NTFlNDEsXG4gICAgICAweGUyMzhjZDk5LCAweDNiZWEwZTJmLCAweDMyODBiYmExLCAweDE4M2ViMzMxLCAweDRlNTQ4YjM4LCAweDRmNmRiOTA4LFxuICAgICAgMHg2ZjQyMGQwMywgMHhmNjBhMDRiZiwgMHgyY2I4MTI5MCwgMHgyNDk3N2M3OSwgMHg1Njc5YjA3MiwgMHhiY2FmODlhZixcbiAgICAgIDB4ZGU5YTc3MWYsIDB4ZDk5MzA4MTAsIDB4YjM4YmFlMTIsIDB4ZGNjZjNmMmUsIDB4NTUxMjcyMWYsIDB4MmU2YjcxMjQsXG4gICAgICAweDUwMWFkZGU2LCAweDlmODRjZDg3LCAweDdhNTg0NzE4LCAweDc0MDhkYTE3LCAweGJjOWY5YWJjLCAweGU5NGI3ZDhjLFxuICAgICAgMHhlYzdhZWMzYSwgMHhkYjg1MWRmYSwgMHg2MzA5NDM2NiwgMHhjNDY0YzNkMiwgMHhlZjFjMTg0NywgMHgzMjE1ZDkwOCxcbiAgICAgIDB4ZGQ0MzNiMzcsIDB4MjRjMmJhMTYsIDB4MTJhMTRkNDMsIDB4MmE2NWM0NTEsIDB4NTA5NDAwMDIsIDB4MTMzYWU0ZGQsXG4gICAgICAweDcxZGZmODllLCAweDEwMzE0ZTU1LCAweDgxYWM3N2Q2LCAweDVmMTExOTliLCAweDA0MzU1NmYxLCAweGQ3YTNjNzZiLFxuICAgICAgMHgzYzExMTgzYiwgMHg1OTI0YTUwOSwgMHhmMjhmZTZlZCwgMHg5N2YxZmJmYSwgMHg5ZWJhYmYyYywgMHgxZTE1M2M2ZSxcbiAgICAgIDB4ODZlMzQ1NzAsIDB4ZWFlOTZmYjEsIDB4ODYwZTVlMGEsIDB4NWEzZTJhYjMsIDB4NzcxZmU3MWMsIDB4NGUzZDA2ZmEsXG4gICAgICAweDI5NjVkY2I5LCAweDk5ZTcxZDBmLCAweDgwM2U4OWQ2LCAweDUyNjZjODI1LCAweDJlNGNjOTc4LCAweDljMTBiMzZhLFxuICAgICAgMHhjNjE1MGViYSwgMHg5NGUyZWE3OCwgMHhhNWZjM2M1MywgMHgxZTBhMmRmNCwgMHhmMmY3NGVhNywgMHgzNjFkMmIzZCxcbiAgICAgIDB4MTkzOTI2MGYsIDB4MTljMjc5NjAsIDB4NTIyM2E3MDgsIDB4ZjcxMzEyYjYsIDB4ZWJhZGZlNmUsIDB4ZWFjMzFmNjYsXG4gICAgICAweGUzYmM0NTk1LCAweGE2N2JjODgzLCAweGIxN2YzN2QxLCAweDAxOGNmZjI4LCAweGMzMzJkZGVmLCAweGJlNmM1YWE1LFxuICAgICAgMHg2NTU4MjE4NSwgMHg2OGFiOTgwMiwgMHhlZWNlYTUwZiwgMHhkYjJmOTUzYiwgMHgyYWVmN2RhZCwgMHg1YjZlMmY4NCxcbiAgICAgIDB4MTUyMWI2MjgsIDB4MjkwNzYxNzAsIDB4ZWNkZDQ3NzUsIDB4NjE5ZjE1MTAsIDB4MTNjY2E4MzAsIDB4ZWI2MWJkOTYsXG4gICAgICAweDAzMzRmZTFlLCAweGFhMDM2M2NmLCAweGI1NzM1YzkwLCAweDRjNzBhMjM5LCAweGQ1OWU5ZTBiLCAweGNiYWFkZTE0LFxuICAgICAgMHhlZWNjODZiYywgMHg2MDYyMmNhNywgMHg5Y2FiNWNhYiwgMHhiMmYzODQ2ZSwgMHg2NDhiMWVhZiwgMHgxOWJkZjBjYSxcbiAgICAgIDB4YTAyMzY5YjksIDB4NjU1YWJiNTAsIDB4NDA2ODVhMzIsIDB4M2MyYWI0YjMsIDB4MzE5ZWU5ZDUsIDB4YzAyMWI4ZjcsXG4gICAgICAweDliNTQwYjE5LCAweDg3NWZhMDk5LCAweDk1Zjc5OTdlLCAweDYyM2Q3ZGE4LCAweGY4Mzc4ODlhLCAweDk3ZTMyZDc3LFxuICAgICAgMHgxMWVkOTM1ZiwgMHgxNjY4MTI4MSwgMHgwZTM1ODgyOSwgMHhjN2U2MWZkNiwgMHg5NmRlZGZhMSwgMHg3ODU4YmE5OSxcbiAgICAgIDB4NTdmNTg0YTUsIDB4MWIyMjcyNjMsIDB4OWI4M2MzZmYsIDB4MWFjMjQ2OTYsIDB4Y2RiMzBhZWIsIDB4NTMyZTMwNTQsXG4gICAgICAweDhmZDk0OGU0LCAweDZkYmMzMTI4LCAweDU4ZWJmMmVmLCAweDM0YzZmZmVhLCAweGZlMjhlZDYxLCAweGVlN2MzYzczLFxuICAgICAgMHg1ZDRhMTRkOSwgMHhlODY0YjdlMywgMHg0MjEwNWQxNCwgMHgyMDNlMTNlMCwgMHg0NWVlZTJiNiwgMHhhM2FhYWJlYSxcbiAgICAgIDB4ZGI2YzRmMTUsIDB4ZmFjYjRmZDAsIDB4Yzc0MmY0NDIsIDB4ZWY2YWJiYjUsIDB4NjU0ZjNiMWQsIDB4NDFjZDIxMDUsXG4gICAgICAweGQ4MWU3OTllLCAweDg2ODU0ZGM3LCAweGU0NGI0NzZhLCAweDNkODE2MjUwLCAweGNmNjJhMWYyLCAweDViOGQyNjQ2LFxuICAgICAgMHhmYzg4ODNhMCwgMHhjMWM3YjZhMywgMHg3ZjE1MjRjMywgMHg2OWNiNzQ5MiwgMHg0Nzg0OGEwYiwgMHg1NjkyYjI4NSxcbiAgICAgIDB4MDk1YmJmMDAsIDB4YWQxOTQ4OWQsIDB4MTQ2MmIxNzQsIDB4MjM4MjBlMDAsIDB4NTg0MjhkMmEsIDB4MGM1NWY1ZWEsXG4gICAgICAweDFkYWRmNDNlLCAweDIzM2Y3MDYxLCAweDMzNzJmMDkyLCAweDhkOTM3ZTQxLCAweGQ2NWZlY2YxLCAweDZjMjIzYmRiLFxuICAgICAgMHg3Y2RlMzc1OSwgMHhjYmVlNzQ2MCwgMHg0MDg1ZjJhNywgMHhjZTc3MzI2ZSwgMHhhNjA3ODA4NCwgMHgxOWY4NTA5ZSxcbiAgICAgIDB4ZThlZmQ4NTUsIDB4NjFkOTk3MzUsIDB4YTk2OWE3YWEsIDB4YzUwYzA2YzIsIDB4NWEwNGFiZmMsIDB4ODAwYmNhZGMsXG4gICAgICAweDllNDQ3YTJlLCAweGMzNDUzNDg0LCAweGZkZDU2NzA1LCAweDBlMWU5ZWM5LCAweGRiNzNkYmQzLCAweDEwNTU4OGNkLFxuICAgICAgMHg2NzVmZGE3OSwgMHhlMzY3NDM0MCwgMHhjNWM0MzQ2NSwgMHg3MTNlMzhkOCwgMHgzZDI4Zjg5ZSwgMHhmMTZkZmYyMCxcbiAgICAgIDB4MTUzZTIxZTcsIDB4OGZiMDNkNGEsIDB4ZTZlMzlmMmIsIDB4ZGI4M2FkZjdcbiAgXSxcbiAgW1xuICAgICAgMHhlOTNkNWE2OCwgMHg5NDgxNDBmNywgMHhmNjRjMjYxYywgMHg5NDY5MjkzNCwgMHg0MTE1MjBmNywgMHg3NjAyZDRmNyxcbiAgICAgIDB4YmNmNDZiMmUsIDB4ZDRhMjAwNjgsIDB4ZDQwODI0NzEsIDB4MzMyMGY0NmEsIDB4NDNiN2Q0YjcsIDB4NTAwMDYxYWYsXG4gICAgICAweDFlMzlmNjJlLCAweDk3MjQ0NTQ2LCAweDE0MjE0Zjc0LCAweGJmOGI4ODQwLCAweDRkOTVmYzFkLCAweDk2YjU5MWFmLFxuICAgICAgMHg3MGY0ZGRkMywgMHg2NmEwMmY0NSwgMHhiZmJjMDllYywgMHgwM2JkOTc4NSwgMHg3ZmFjNmRkMCwgMHgzMWNiODUwNCxcbiAgICAgIDB4OTZlYjI3YjMsIDB4NTVmZDM5NDEsIDB4ZGEyNTQ3ZTYsIDB4YWJjYTBhOWEsIDB4Mjg1MDc4MjUsIDB4NTMwNDI5ZjQsXG4gICAgICAweDBhMmM4NmRhLCAweGU5YjY2ZGZiLCAweDY4ZGMxNDYyLCAweGQ3NDg2OTAwLCAweDY4MGVjMGE0LCAweDI3YTE4ZGVlLFxuICAgICAgMHg0ZjNmZmVhMiwgMHhlODg3YWQ4YywgMHhiNThjZTAwNiwgMHg3YWY0ZDZiNiwgMHhhYWNlMWU3YywgMHhkMzM3NWZlYyxcbiAgICAgIDB4Y2U3OGEzOTksIDB4NDA2YjJhNDIsIDB4MjBmZTllMzUsIDB4ZDlmMzg1YjksIDB4ZWUzOWQ3YWIsIDB4M2IxMjRlOGIsXG4gICAgICAweDFkYzlmYWY3LCAweDRiNmQxODU2LCAweDI2YTM2NjMxLCAweGVhZTM5N2IyLCAweDNhNmVmYTc0LCAweGRkNWI0MzMyLFxuICAgICAgMHg2ODQxZTdmNywgMHhjYTc4MjBmYiwgMHhmYjBhZjU0ZSwgMHhkOGZlYjM5NywgMHg0NTQwNTZhYywgMHhiYTQ4OTUyNyxcbiAgICAgIDB4NTU1MzNhM2EsIDB4MjA4MzhkODcsIDB4ZmU2YmE5YjcsIDB4ZDA5Njk1NGIsIDB4NTVhODY3YmMsIDB4YTExNTlhNTgsXG4gICAgICAweGNjYTkyOTYzLCAweDk5ZTFkYjMzLCAweGE2MmE0YTU2LCAweDNmMzEyNWY5LCAweDVlZjQ3ZTFjLCAweDkwMjkzMTdjLFxuICAgICAgMHhmZGY4ZTgwMiwgMHgwNDI3MmY3MCwgMHg4MGJiMTU1YywgMHgwNTI4MmNlMywgMHg5NWMxMTU0OCwgMHhlNGM2NmQyMixcbiAgICAgIDB4NDhjMTEzM2YsIDB4YzcwZjg2ZGMsIDB4MDdmOWM5ZWUsIDB4NDEwNDFmMGYsIDB4NDA0Nzc5YTQsIDB4NWQ4ODZlMTcsXG4gICAgICAweDMyNWY1MWViLCAweGQ1OWJjMGQxLCAweGYyYmNjMThmLCAweDQxMTEzNTY0LCAweDI1N2I3ODM0LCAweDYwMmE5YzYwLFxuICAgICAgMHhkZmY4ZThhMywgMHgxZjYzNmMxYiwgMHgwZTEyYjRjMiwgMHgwMmUxMzI5ZSwgMHhhZjY2NGZkMSwgMHhjYWQxODExNSxcbiAgICAgIDB4NmIyMzk1ZTAsIDB4MzMzZTkyZTEsIDB4M2IyNDBiNjIsIDB4ZWViZWI5MjIsIDB4ODViMmEyMGUsIDB4ZTZiYTBkOTksXG4gICAgICAweGRlNzIwYzhjLCAweDJkYTJmNzI4LCAweGQwMTI3ODQ1LCAweDk1Yjc5NGZkLCAweDY0N2QwODYyLCAweGU3Y2NmNWYwLFxuICAgICAgMHg1NDQ5YTM2ZiwgMHg4NzdkNDhmYSwgMHhjMzlkZmQyNywgMHhmMzNlOGQxZSwgMHgwYTQ3NjM0MSwgMHg5OTJlZmY3NCxcbiAgICAgIDB4M2E2ZjZlYWIsIDB4ZjRmOGZkMzcsIDB4YTgxMmRjNjAsIDB4YTFlYmRkZjgsIDB4OTkxYmUxNGMsIDB4ZGI2ZTZiMGQsXG4gICAgICAweGM2N2I1NTEwLCAweDZkNjcyYzM3LCAweDI3NjVkNDNiLCAweGRjZDBlODA0LCAweGYxMjkwZGM3LCAweGNjMDBmZmEzLFxuICAgICAgMHhiNTM5MGY5MiwgMHg2OTBmZWQwYiwgMHg2NjdiOWZmYiwgMHhjZWRiN2Q5YywgMHhhMDkxY2YwYiwgMHhkOTE1NWVhMyxcbiAgICAgIDB4YmIxMzJmODgsIDB4NTE1YmFkMjQsIDB4N2I5NDc5YmYsIDB4NzYzYmQ2ZWIsIDB4MzczOTJlYjMsIDB4Y2MxMTU5NzksXG4gICAgICAweDgwMjZlMjk3LCAweGY0MmUzMTJkLCAweDY4NDJhZGE3LCAweGM2NmEyYjNiLCAweDEyNzU0Y2NjLCAweDc4MmVmMTFjLFxuICAgICAgMHg2YTEyNDIzNywgMHhiNzkyNTFlNywgMHgwNmExYmJlNiwgMHg0YmZiNjM1MCwgMHgxYTZiMTAxOCwgMHgxMWNhZWRmYSxcbiAgICAgIDB4M2QyNWJkZDgsIDB4ZTJlMWMzYzksIDB4NDQ0MjE2NTksIDB4MGExMjEzODYsIDB4ZDkwY2VjNmUsIDB4ZDVhYmVhMmEsXG4gICAgICAweDY0YWY2NzRlLCAweGRhODZhODVmLCAweGJlYmZlOTg4LCAweDY0ZTRjM2ZlLCAweDlkYmM4MDU3LCAweGYwZjdjMDg2LFxuICAgICAgMHg2MDc4N2JmOCwgMHg2MDAzNjA0ZCwgMHhkMWZkODM0NiwgMHhmNjM4MWZiMCwgMHg3NzQ1YWUwNCwgMHhkNzM2ZmNjYyxcbiAgICAgIDB4ODM0MjZiMzMsIDB4ZjAxZWFiNzEsIDB4YjA4MDQxODcsIDB4M2MwMDVlNWYsIDB4NzdhMDU3YmUsIDB4YmRlOGFlMjQsXG4gICAgICAweDU1NDY0Mjk5LCAweGJmNTgyZTYxLCAweDRlNThmNDhmLCAweGYyZGRmZGEyLCAweGY0NzRlZjM4LCAweDg3ODliZGMyLFxuICAgICAgMHg1MzY2ZjljMywgMHhjOGIzOGU3NCwgMHhiNDc1ZjI1NSwgMHg0NmZjZDliOSwgMHg3YWViMjY2MSwgMHg4YjFkZGY4NCxcbiAgICAgIDB4ODQ2YTBlNzksIDB4OTE1Zjk1ZTIsIDB4NDY2ZTU5OGUsIDB4MjBiNDU3NzAsIDB4OGNkNTU1OTEsIDB4YzkwMmRlNGMsXG4gICAgICAweGI5MGJhY2UxLCAweGJiODIwNWQwLCAweDExYTg2MjQ4LCAweDc1NzRhOTllLCAweGI3N2YxOWI2LCAweGUwYTlkYzA5LFxuICAgICAgMHg2NjJkMDlhMSwgMHhjNDMyNDYzMywgMHhlODVhMWYwMiwgMHgwOWYwYmU4YywgMHg0YTk5YTAyNSwgMHgxZDZlZmUxMCxcbiAgICAgIDB4MWFiOTNkMWQsIDB4MGJhNWE0ZGYsIDB4YTE4NmYyMGYsIDB4Mjg2OGYxNjksIDB4ZGNiN2RhODMsIDB4NTczOTA2ZmUsXG4gICAgICAweGExZTJjZTliLCAweDRmY2Q3ZjUyLCAweDUwMTE1ZTAxLCAweGE3MDY4M2ZhLCAweGEwMDJiNWM0LCAweDBkZTZkMDI3LFxuICAgICAgMHg5YWY4OGMyNywgMHg3NzNmODY0MSwgMHhjMzYwNGMwNiwgMHg2MWE4MDZiNSwgMHhmMDE3N2EyOCwgMHhjMGY1ODZlMCxcbiAgICAgIDB4MDA2MDU4YWEsIDB4MzBkYzdkNjIsIDB4MTFlNjllZDcsIDB4MjMzOGVhNjMsIDB4NTNjMmRkOTQsIDB4YzJjMjE2MzQsXG4gICAgICAweGJiY2JlZTU2LCAweDkwYmNiNmRlLCAweGViZmM3ZGExLCAweGNlNTkxZDc2LCAweDZmMDVlNDA5LCAweDRiN2MwMTg4LFxuICAgICAgMHgzOTcyMGEzZCwgMHg3YzkyN2MyNCwgMHg4NmUzNzI1ZiwgMHg3MjRkOWRiOSwgMHgxYWMxNWJiNCwgMHhkMzllYjhmYyxcbiAgICAgIDB4ZWQ1NDU1NzgsIDB4MDhmY2E1YjUsIDB4ZDgzZDdjZDMsIDB4NGRhZDBmYzQsIDB4MWU1MGVmNWUsIDB4YjE2MWU2ZjgsXG4gICAgICAweGEyODUxNGQ5LCAweDZjNTExMzNjLCAweDZmZDVjN2U3LCAweDU2ZTE0ZWM0LCAweDM2MmFiZmNlLCAweGRkYzZjODM3LFxuICAgICAgMHhkNzlhMzIzNCwgMHg5MjYzODIxMiwgMHg2NzBlZmE4ZSwgMHg0MDYwMDBlMFxuICBdLFxuICBbXG4gICAgICAweDNhMzljZTM3LCAweGQzZmFmNWNmLCAweGFiYzI3NzM3LCAweDVhYzUyZDFiLCAweDVjYjA2NzllLCAweDRmYTMzNzQyLFxuICAgICAgMHhkMzgyMjc0MCwgMHg5OWJjOWJiZSwgMHhkNTExOGU5ZCwgMHhiZjBmNzMxNSwgMHhkNjJkMWM3ZSwgMHhjNzAwYzQ3YixcbiAgICAgIDB4Yjc4YzFiNmIsIDB4MjFhMTkwNDUsIDB4YjI2ZWIxYmUsIDB4NmEzNjZlYjQsIDB4NTc0OGFiMmYsIDB4YmM5NDZlNzksXG4gICAgICAweGM2YTM3NmQyLCAweDY1NDljMmM4LCAweDUzMGZmOGVlLCAweDQ2OGRkZTdkLCAweGQ1NzMwYTFkLCAweDRjZDA0ZGM2LFxuICAgICAgMHgyOTM5YmJkYiwgMHhhOWJhNDY1MCwgMHhhYzk1MjZlOCwgMHhiZTVlZTMwNCwgMHhhMWZhZDVmMCwgMHg2YTJkNTE5YSxcbiAgICAgIDB4NjNlZjhjZTIsIDB4OWE4NmVlMjIsIDB4YzA4OWMyYjgsIDB4NDMyNDJlZjYsIDB4YTUxZTAzYWEsIDB4OWNmMmQwYTQsXG4gICAgICAweDgzYzA2MWJhLCAweDliZTk2YTRkLCAweDhmZTUxNTUwLCAweGJhNjQ1YmQ2LCAweDI4MjZhMmY5LCAweGE3M2EzYWUxLFxuICAgICAgMHg0YmE5OTU4NiwgMHhlZjU1NjJlOSwgMHhjNzJmZWZkMywgMHhmNzUyZjdkYSwgMHgzZjA0NmY2OSwgMHg3N2ZhMGE1OSxcbiAgICAgIDB4ODBlNGE5MTUsIDB4ODdiMDg2MDEsIDB4OWIwOWU2YWQsIDB4M2IzZWU1OTMsIDB4ZTk5MGZkNWEsIDB4OWUzNGQ3OTcsXG4gICAgICAweDJjZjBiN2Q5LCAweDAyMmI4YjUxLCAweDk2ZDVhYzNhLCAweDAxN2RhNjdkLCAweGQxY2YzZWQ2LCAweDdjN2QyZDI4LFxuICAgICAgMHgxZjlmMjVjZiwgMHhhZGYyYjg5YiwgMHg1YWQ2YjQ3MiwgMHg1YTg4ZjU0YywgMHhlMDI5YWM3MSwgMHhlMDE5YTVlNixcbiAgICAgIDB4NDdiMGFjZmQsIDB4ZWQ5M2ZhOWIsIDB4ZThkM2M0OGQsIDB4MjgzYjU3Y2MsIDB4ZjhkNTY2MjksIDB4NzkxMzJlMjgsXG4gICAgICAweDc4NWYwMTkxLCAweGVkNzU2MDU1LCAweGY3OTYwZTQ0LCAweGUzZDM1ZThjLCAweDE1MDU2ZGQ0LCAweDg4ZjQ2ZGJhLFxuICAgICAgMHgwM2ExNjEyNSwgMHgwNTY0ZjBiZCwgMHhjM2ViOWUxNSwgMHgzYzkwNTdhMiwgMHg5NzI3MWFlYywgMHhhOTNhMDcyYSxcbiAgICAgIDB4MWIzZjZkOWIsIDB4MWU2MzIxZjUsIDB4ZjU5YzY2ZmIsIDB4MjZkY2YzMTksIDB4NzUzM2Q5MjgsIDB4YjE1NWZkZjUsXG4gICAgICAweDAzNTYzNDgyLCAweDhhYmEzY2JiLCAweDI4NTE3NzExLCAweGMyMGFkOWY4LCAweGFiY2M1MTY3LCAweGNjYWQ5MjVmLFxuICAgICAgMHg0ZGU4MTc1MSwgMHgzODMwZGM4ZSwgMHgzNzlkNTg2MiwgMHg5MzIwZjk5MSwgMHhlYTdhOTBjMiwgMHhmYjNlN2JjZSxcbiAgICAgIDB4NTEyMWNlNjQsIDB4Nzc0ZmJlMzIsIDB4YThiNmUzN2UsIDB4YzMyOTNkNDYsIDB4NDhkZTUzNjksIDB4NjQxM2U2ODAsXG4gICAgICAweGEyYWUwODEwLCAweGRkNmRiMjI0LCAweDY5ODUyZGZkLCAweDA5MDcyMTY2LCAweGIzOWE0NjBhLCAweDY0NDVjMGRkLFxuICAgICAgMHg1ODZjZGVjZiwgMHgxYzIwYzhhZSwgMHg1YmJlZjdkZCwgMHgxYjU4OGQ0MCwgMHhjY2QyMDE3ZiwgMHg2YmI0ZTNiYixcbiAgICAgIDB4ZGRhMjZhN2UsIDB4M2E1OWZmNDUsIDB4M2UzNTBhNDQsIDB4YmNiNGNkZDUsIDB4NzJlYWNlYTgsIDB4ZmE2NDg0YmIsXG4gICAgICAweDhkNjYxMmFlLCAweGJmM2M2ZjQ3LCAweGQyOWJlNDYzLCAweDU0MmY1ZDllLCAweGFlYzI3NzFiLCAweGY2NGU2MzcwLFxuICAgICAgMHg3NDBlMGQ4ZCwgMHhlNzViMTM1NywgMHhmODcyMTY3MSwgMHhhZjUzN2Q1ZCwgMHg0MDQwY2IwOCwgMHg0ZWI0ZTJjYyxcbiAgICAgIDB4MzRkMjQ2NmEsIDB4MDExNWFmODQsIDB4ZTFiMDA0MjgsIDB4OTU5ODNhMWQsIDB4MDZiODlmYjQsIDB4Y2U2ZWEwNDgsXG4gICAgICAweDZmM2YzYjgyLCAweDM1MjBhYjgyLCAweDAxMWExZDRiLCAweDI3NzIyN2Y4LCAweDYxMTU2MGIxLCAweGU3OTMzZmRjLFxuICAgICAgMHhiYjNhNzkyYiwgMHgzNDQ1MjViZCwgMHhhMDg4MzllMSwgMHg1MWNlNzk0YiwgMHgyZjMyYzliNywgMHhhMDFmYmFjOSxcbiAgICAgIDB4ZTAxY2M4N2UsIDB4YmNjN2QxZjYsIDB4Y2YwMTExYzMsIDB4YTFlOGFhYzcsIDB4MWE5MDg3NDksIDB4ZDQ0ZmJkOWEsXG4gICAgICAweGQwZGFkZWNiLCAweGQ1MGFkYTM4LCAweDAzMzljMzJhLCAweGM2OTEzNjY3LCAweDhkZjkzMTdjLCAweGUwYjEyYjRmLFxuICAgICAgMHhmNzllNTliNywgMHg0M2Y1YmIzYSwgMHhmMmQ1MTlmZiwgMHgyN2Q5NDU5YywgMHhiZjk3MjIyYywgMHgxNWU2ZmMyYSxcbiAgICAgIDB4MGY5MWZjNzEsIDB4OWI5NDE1MjUsIDB4ZmFlNTkzNjEsIDB4Y2ViNjljZWIsIDB4YzJhODY0NTksIDB4MTJiYWE4ZDEsXG4gICAgICAweGI2YzEwNzVlLCAweGUzMDU2YTBjLCAweDEwZDI1MDY1LCAweGNiMDNhNDQyLCAweGUwZWM2ZTBlLCAweDE2OThkYjNiLFxuICAgICAgMHg0Yzk4YTBiZSwgMHgzMjc4ZTk2NCwgMHg5ZjFmOTUzMiwgMHhlMGQzOTJkZiwgMHhkM2EwMzQyYiwgMHg4OTcxZjIxZSxcbiAgICAgIDB4MWIwYTc0NDEsIDB4NGJhMzM0OGMsIDB4YzViZTcxMjAsIDB4YzM3NjMyZDgsIDB4ZGYzNTlmOGQsIDB4OWI5OTJmMmUsXG4gICAgICAweGU2MGI2ZjQ3LCAweDBmZTNmMTFkLCAweGU1NGNkYTU0LCAweDFlZGFkODkxLCAweGNlNjI3OWNmLCAweGNkM2U3ZTZmLFxuICAgICAgMHgxNjE4YjE2NiwgMHhmZDJjMWQwNSwgMHg4NDhmZDJjNSwgMHhmNmZiMjI5OSwgMHhmNTIzZjM1NywgMHhhNjMyNzYyMyxcbiAgICAgIDB4OTNhODM1MzEsIDB4NTZjY2NkMDIsIDB4YWNmMDgxNjIsIDB4NWE3NWViYjUsIDB4NmUxNjM2OTcsIDB4ODhkMjczY2MsXG4gICAgICAweGRlOTY2MjkyLCAweDgxYjk0OWQwLCAweDRjNTA5MDFiLCAweDcxYzY1NjE0LCAweGU2YzZjN2JkLCAweDMyN2ExNDBhLFxuICAgICAgMHg0NWUxZDAwNiwgMHhjM2YyN2I5YSwgMHhjOWFhNTNmZCwgMHg2MmE4MGYwMCwgMHhiYjI1YmZlMiwgMHgzNWJkZDJmNixcbiAgICAgIDB4NzExMjY5MDUsIDB4YjIwNDAyMjIsIDB4YjZjYmNmN2MsIDB4Y2Q3NjljMmIsIDB4NTMxMTNlYzAsIDB4MTY0MGUzZDMsXG4gICAgICAweDM4YWJiZDYwLCAweDI1NDdhZGYwLCAweGJhMzgyMDljLCAweGY3NDZjZTc2LCAweDc3YWZhMWM1LCAweDIwNzU2MDYwLFxuICAgICAgMHg4NWNiZmU0ZSwgMHg4YWU4OGRkOCwgMHg3YWFhZjliMCwgMHg0Y2Y5YWE3ZSwgMHgxOTQ4YzI1YywgMHgwMmZiOGE4YyxcbiAgICAgIDB4MDFjMzZhZTQsIDB4ZDZlYmUxZjksIDB4OTBkNGY4NjksIDB4YTY1Y2RlYTAsIDB4M2YwOTI1MmQsIDB4YzIwOGU2OWYsXG4gICAgICAweGI3NGU2MTMyLCAweGNlNzdlMjViLCAweDU3OGZkZmUzLCAweDNhYzM3MmU2XG4gIF1cbl07XG5cbi8vKlxuLy8qIFRoaXMgaXMgdGhlIGRlZmF1bHQgUEFSUkFZXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5QQVJSQVkgPSBbXG4gICAgMHgyNDNmNmE4OCwgMHg4NWEzMDhkMywgMHgxMzE5OGEyZSwgMHgwMzcwNzM0NCwgMHhhNDA5MzgyMiwgMHgyOTlmMzFkMCxcbiAgICAweDA4MmVmYTk4LCAweGVjNGU2Yzg5LCAweDQ1MjgyMWU2LCAweDM4ZDAxMzc3LCAweGJlNTQ2NmNmLCAweDM0ZTkwYzZjLFxuICAgIDB4YzBhYzI5YjcsIDB4Yzk3YzUwZGQsIDB4M2Y4NGQ1YjUsIDB4YjU0NzA5MTcsIDB4OTIxNmQ1ZDksIDB4ODk3OWZiMWJcbl07XG5cbi8vKlxuLy8qIFRoaXMgaXMgdGhlIG51bWJlciBvZiByb3VuZHMgdGhlIGNpcGhlciB3aWxsIGdvXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5OTiA9IDE2O1xuXG4vLypcbi8vKiBUaGlzIGZ1bmN0aW9uIGlzIG5lZWRlZCB0byBnZXQgcmlkIG9mIHByb2JsZW1zXG4vLyogd2l0aCB0aGUgaGlnaC1iaXQgZ2V0dGluZyBzZXQuICBJZiB3ZSBkb24ndCBkb1xuLy8qIHRoaXMsIHRoZW4gc29tZXRpbWVzICggYWEgJiAweDAwRkZGRkZGRkYgKSBpcyBub3Rcbi8vKiBlcXVhbCB0byAoIGJiICYgMHgwMEZGRkZGRkZGICkgZXZlbiB3aGVuIHRoZXlcbi8vKiBhZ3JlZSBiaXQtZm9yLWJpdCBmb3IgdGhlIGZpcnN0IDMyIGJpdHMuXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5fY2xlYW4gPSBmdW5jdGlvbih4eCkge1xuICBpZiAoeHggPCAwKSB7XG4gICAgdmFyIHl5ID0geHggJiAweDdGRkZGRkZGO1xuICAgIHh4ID0geXkgKyAweDgwMDAwMDAwO1xuICB9XG4gIHJldHVybiB4eDtcbn07XG5cbi8vKlxuLy8qIFRoaXMgaXMgdGhlIG1peGluZyBmdW5jdGlvbiB0aGF0IHVzZXMgdGhlIHNib3hlc1xuLy8qXG5CbG93ZmlzaC5wcm90b3R5cGUuX0YgPSBmdW5jdGlvbih4eCkge1xuICB2YXIgYWE7XG4gIHZhciBiYjtcbiAgdmFyIGNjO1xuICB2YXIgZGQ7XG4gIHZhciB5eTtcblxuICBkZCA9IHh4ICYgMHgwMEZGO1xuICB4eCA+Pj49IDg7XG4gIGNjID0geHggJiAweDAwRkY7XG4gIHh4ID4+Pj0gODtcbiAgYmIgPSB4eCAmIDB4MDBGRjtcbiAgeHggPj4+PSA4O1xuICBhYSA9IHh4ICYgMHgwMEZGO1xuXG4gIHl5ID0gdGhpcy5zYm94ZXNbMF1bYWFdICsgdGhpcy5zYm94ZXNbMV1bYmJdO1xuICB5eSA9IHl5IF4gdGhpcy5zYm94ZXNbMl1bY2NdO1xuICB5eSA9IHl5ICsgdGhpcy5zYm94ZXNbM11bZGRdO1xuXG4gIHJldHVybiB5eTtcbn07XG5cbi8vKlxuLy8qIFRoaXMgbWV0aG9kIHRha2VzIGFuIGFycmF5IHdpdGggdHdvIHZhbHVlcywgbGVmdCBhbmQgcmlnaHRcbi8vKiBhbmQgZG9lcyBOTiByb3VuZHMgb2YgQmxvd2Zpc2ggb24gdGhlbS5cbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLl9lbmNyeXB0X2Jsb2NrID0gZnVuY3Rpb24odmFscykge1xuICB2YXIgZGF0YUwgPSB2YWxzWzBdO1xuICB2YXIgZGF0YVIgPSB2YWxzWzFdO1xuXG4gIHZhciBpaTtcblxuICBmb3IgKGlpID0gMDsgaWkgPCB0aGlzLk5OOyArK2lpKSB7XG4gICAgZGF0YUwgPSBkYXRhTCBeIHRoaXMucGFycmF5W2lpXTtcbiAgICBkYXRhUiA9IHRoaXMuX0YoZGF0YUwpIF4gZGF0YVI7XG5cbiAgICB2YXIgdG1wID0gZGF0YUw7XG4gICAgZGF0YUwgPSBkYXRhUjtcbiAgICBkYXRhUiA9IHRtcDtcbiAgfVxuXG4gIGRhdGFMID0gZGF0YUwgXiB0aGlzLnBhcnJheVt0aGlzLk5OICsgMF07XG4gIGRhdGFSID0gZGF0YVIgXiB0aGlzLnBhcnJheVt0aGlzLk5OICsgMV07XG5cbiAgdmFsc1swXSA9IHRoaXMuX2NsZWFuKGRhdGFSKTtcbiAgdmFsc1sxXSA9IHRoaXMuX2NsZWFuKGRhdGFMKTtcbn07XG5cbi8vKlxuLy8qIFRoaXMgbWV0aG9kIHRha2VzIGEgdmVjdG9yIG9mIG51bWJlcnMgYW5kIHR1cm5zIHRoZW1cbi8vKiBpbnRvIGxvbmcgd29yZHMgc28gdGhhdCB0aGV5IGNhbiBiZSBwcm9jZXNzZWQgYnkgdGhlXG4vLyogcmVhbCBhbGdvcml0aG0uXG4vLypcbi8vKiBNYXliZSBJIHNob3VsZCBtYWtlIHRoZSByZWFsIGFsZ29yaXRobSBhYm92ZSB0YWtlIGEgdmVjdG9yXG4vLyogaW5zdGVhZC4gIFRoYXQgd2lsbCBpbnZvbHZlIG1vcmUgbG9vcGluZywgYnV0IGl0IHdvbid0IHJlcXVpcmVcbi8vKiB0aGUgRigpIG1ldGhvZCB0byBkZWNvbnN0cnVjdCB0aGUgdmVjdG9yLlxuLy8qXG5CbG93ZmlzaC5wcm90b3R5cGUuZW5jcnlwdF9ibG9jayA9IGZ1bmN0aW9uKHZlY3Rvcikge1xuICB2YXIgaWk7XG4gIHZhciB2YWxzID0gWzAsIDBdO1xuICB2YXIgb2ZmID0gdGhpcy5CTE9DS1NJWkUgLyAyO1xuICBmb3IgKGlpID0gMDsgaWkgPCB0aGlzLkJMT0NLU0laRSAvIDI7ICsraWkpIHtcbiAgICB2YWxzWzBdID0gKHZhbHNbMF0gPDwgOCkgfCAodmVjdG9yW2lpICsgMF0gJiAweDAwRkYpO1xuICAgIHZhbHNbMV0gPSAodmFsc1sxXSA8PCA4KSB8ICh2ZWN0b3JbaWkgKyBvZmZdICYgMHgwMEZGKTtcbiAgfVxuXG4gIHRoaXMuX2VuY3J5cHRfYmxvY2sodmFscyk7XG5cbiAgdmFyIHJldCA9IFtdO1xuICBmb3IgKGlpID0gMDsgaWkgPCB0aGlzLkJMT0NLU0laRSAvIDI7ICsraWkpIHtcbiAgICByZXRbaWkgKyAwXSA9ICh2YWxzWzBdID4+PiAoMjQgLSA4ICogKGlpKSkgJiAweDAwRkYpO1xuICAgIHJldFtpaSArIG9mZl0gPSAodmFsc1sxXSA+Pj4gKDI0IC0gOCAqIChpaSkpICYgMHgwMEZGKTtcbiAgICAvLyB2YWxzWyAwIF0gPSAoIHZhbHNbIDAgXSA+Pj4gOCApO1xuICAgIC8vIHZhbHNbIDEgXSA9ICggdmFsc1sgMSBdID4+PiA4ICk7XG4gIH1cblxuICByZXR1cm4gcmV0O1xufTtcblxuLy8qXG4vLyogVGhpcyBtZXRob2QgdGFrZXMgYW4gYXJyYXkgd2l0aCB0d28gdmFsdWVzLCBsZWZ0IGFuZCByaWdodFxuLy8qIGFuZCB1bmRvZXMgTk4gcm91bmRzIG9mIEJsb3dmaXNoIG9uIHRoZW0uXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5fZGVjcnlwdF9ibG9jayA9IGZ1bmN0aW9uKHZhbHMpIHtcbiAgdmFyIGRhdGFMID0gdmFsc1swXTtcbiAgdmFyIGRhdGFSID0gdmFsc1sxXTtcblxuICB2YXIgaWk7XG5cbiAgZm9yIChpaSA9IHRoaXMuTk4gKyAxOyBpaSA+IDE7IC0taWkpIHtcbiAgICBkYXRhTCA9IGRhdGFMIF4gdGhpcy5wYXJyYXlbaWldO1xuICAgIGRhdGFSID0gdGhpcy5fRihkYXRhTCkgXiBkYXRhUjtcblxuICAgIHZhciB0bXAgPSBkYXRhTDtcbiAgICBkYXRhTCA9IGRhdGFSO1xuICAgIGRhdGFSID0gdG1wO1xuICB9XG5cbiAgZGF0YUwgPSBkYXRhTCBeIHRoaXMucGFycmF5WzFdO1xuICBkYXRhUiA9IGRhdGFSIF4gdGhpcy5wYXJyYXlbMF07XG5cbiAgdmFsc1swXSA9IHRoaXMuX2NsZWFuKGRhdGFSKTtcbiAgdmFsc1sxXSA9IHRoaXMuX2NsZWFuKGRhdGFMKTtcbn07XG5cbi8vKlxuLy8qIFRoaXMgbWV0aG9kIHRha2VzIGEga2V5IGFycmF5IGFuZCBpbml0aWFsaXplcyB0aGVcbi8vKiBzYm94ZXMgYW5kIHBhcnJheSBmb3IgdGhpcyBlbmNyeXB0aW9uLlxuLy8qXG5CbG93ZmlzaC5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uKGtleSkge1xuICB2YXIgaWk7XG4gIHZhciBqaiA9IDA7XG5cbiAgdGhpcy5wYXJyYXkgPSBbXTtcbiAgZm9yIChpaSA9IDA7IGlpIDwgdGhpcy5OTiArIDI7ICsraWkpIHtcbiAgICB2YXIgZGF0YSA9IDB4MDAwMDAwMDA7XG4gICAgdmFyIGtrO1xuICAgIGZvciAoa2sgPSAwOyBrayA8IDQ7ICsra2spIHtcbiAgICAgIGRhdGEgPSAoZGF0YSA8PCA4KSB8IChrZXlbampdICYgMHgwMEZGKTtcbiAgICAgIGlmICgrK2pqID49IGtleS5sZW5ndGgpIHtcbiAgICAgICAgamogPSAwO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnBhcnJheVtpaV0gPSB0aGlzLlBBUlJBWVtpaV0gXiBkYXRhO1xuICB9XG5cbiAgdGhpcy5zYm94ZXMgPSBbXTtcbiAgZm9yIChpaSA9IDA7IGlpIDwgNDsgKytpaSkge1xuICAgIHRoaXMuc2JveGVzW2lpXSA9IFtdO1xuICAgIGZvciAoamogPSAwOyBqaiA8IDI1NjsgKytqaikge1xuICAgICAgdGhpcy5zYm94ZXNbaWldW2pqXSA9IHRoaXMuU0JPWEVTW2lpXVtqal07XG4gICAgfVxuICB9XG5cbiAgdmFyIHZhbHMgPSBbMHgwMDAwMDAwMCwgMHgwMDAwMDAwMF07XG5cbiAgZm9yIChpaSA9IDA7IGlpIDwgdGhpcy5OTiArIDI7IGlpICs9IDIpIHtcbiAgICB0aGlzLl9lbmNyeXB0X2Jsb2NrKHZhbHMpO1xuICAgIHRoaXMucGFycmF5W2lpICsgMF0gPSB2YWxzWzBdO1xuICAgIHRoaXMucGFycmF5W2lpICsgMV0gPSB2YWxzWzFdO1xuICB9XG5cbiAgZm9yIChpaSA9IDA7IGlpIDwgNDsgKytpaSkge1xuICAgIGZvciAoamogPSAwOyBqaiA8IDI1NjsgamogKz0gMikge1xuICAgICAgdGhpcy5fZW5jcnlwdF9ibG9jayh2YWxzKTtcbiAgICAgIHRoaXMuc2JveGVzW2lpXVtqaiArIDBdID0gdmFsc1swXTtcbiAgICAgIHRoaXMuc2JveGVzW2lpXVtqaiArIDFdID0gdmFsc1sxXTtcbiAgICB9XG4gIH1cbn07XG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG4vLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cbmZ1bmN0aW9uIEJGZW5jcnlwdChibG9jaywga2V5KSB7XG4gIHZhciBiZiA9IG5ldyBCbG93ZmlzaCgpO1xuICBiZi5pbml0KHV0aWwuc3RyMmJpbihrZXkpKTtcbiAgcmV0dXJuIGJmLmVuY3J5cHRfYmxvY2soYmxvY2spO1xufVxuXG5mdW5jdGlvbiBCRihrZXkpIHtcbiAgdGhpcy5iZiA9IG5ldyBCbG93ZmlzaCgpO1xuICB0aGlzLmJmLmluaXQodXRpbC5zdHIyYmluKGtleSkpO1xuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKGJsb2NrKSB7XG4gICAgcmV0dXJuIHRoaXMuYmYuZW5jcnlwdF9ibG9jayhibG9jayk7XG4gIH1cbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IEJGO1xubW9kdWxlLmV4cG9ydHMua2V5U2l6ZSA9IEJGLnByb3RvdHlwZS5rZXlTaXplID0gMTY7XG5tb2R1bGUuZXhwb3J0cy5ibG9ja1NpemUgPSBCRi5wcm90b3R5cGUuYmxvY2tTaXplID0gMTY7XG4iLCIvLyBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZVxuLy8gbGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlLlxuXG4vLyBDb3B5cmlnaHQgMjAxMCBwamFjb2JzQHhlZWtyLmNvbSAuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG5cbi8vIE1vZGlmaWVkIGJ5IFJlY3VyaXR5IExhYnMgR21iSFxuXG4vLyBmaXhlZC9tb2RpZmllZCBieSBIZXJiZXJ0IEhhbmV3aW5rZWwsIHd3dy5oYW5lV0lOLmRlXG4vLyBjaGVjayB3d3cuaGFuZVdJTi5kZSBmb3IgdGhlIGxhdGVzdCB2ZXJzaW9uXG5cbi8vIGNhc3Q1LmpzIGlzIGEgSmF2YXNjcmlwdCBpbXBsZW1lbnRhdGlvbiBvZiBDQVNULTEyOCwgYXMgZGVmaW5lZCBpbiBSRkMgMjE0NC5cbi8vIENBU1QtMTI4IGlzIGEgY29tbW9uIE9wZW5QR1AgY2lwaGVyLlxuXG5cbi8vIENBU1Q1IGNvbnN0cnVjdG9yXG5cbi8qKiBAbW9kdWxlIGNyeXB0by9jaXBoZXIvY2FzdDUgKi9cblxuXG5cbmZ1bmN0aW9uIG9wZW5wZ3Bfc3ltZW5jX2Nhc3Q1KCkge1xuICB0aGlzLkJsb2NrU2l6ZSA9IDg7XG4gIHRoaXMuS2V5U2l6ZSA9IDE2O1xuXG4gIHRoaXMuc2V0S2V5ID0gZnVuY3Rpb24oa2V5KSB7XG4gICAgdGhpcy5tYXNraW5nID0gbmV3IEFycmF5KDE2KTtcbiAgICB0aGlzLnJvdGF0ZSA9IG5ldyBBcnJheSgxNik7XG5cbiAgICB0aGlzLnJlc2V0KCk7XG5cbiAgICBpZiAoa2V5Lmxlbmd0aCA9PSB0aGlzLktleVNpemUpIHtcbiAgICAgIHRoaXMua2V5U2NoZWR1bGUoa2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDQVNULTEyODoga2V5cyBtdXN0IGJlIDE2IGJ5dGVzJyk7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG4gIHRoaXMucmVzZXQgPSBmdW5jdGlvbigpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IDE2OyBpKyspIHtcbiAgICAgIHRoaXMubWFza2luZ1tpXSA9IDA7XG4gICAgICB0aGlzLnJvdGF0ZVtpXSA9IDA7XG4gICAgfVxuICB9O1xuXG4gIHRoaXMuZ2V0QmxvY2tTaXplID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIEJsb2NrU2l6ZTtcbiAgfTtcblxuICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihzcmMpIHtcbiAgICB2YXIgZHN0ID0gbmV3IEFycmF5KHNyYy5sZW5ndGgpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzcmMubGVuZ3RoOyBpICs9IDgpIHtcbiAgICAgIHZhciBsID0gc3JjW2ldIDw8IDI0IHwgc3JjW2kgKyAxXSA8PCAxNiB8IHNyY1tpICsgMl0gPDwgOCB8IHNyY1tpICsgM107XG4gICAgICB2YXIgciA9IHNyY1tpICsgNF0gPDwgMjQgfCBzcmNbaSArIDVdIDw8IDE2IHwgc3JjW2kgKyA2XSA8PCA4IHwgc3JjW2kgKyA3XTtcbiAgICAgIHZhciB0O1xuXG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjEociwgdGhpcy5tYXNraW5nWzBdLCB0aGlzLnJvdGF0ZVswXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMihyLCB0aGlzLm1hc2tpbmdbMV0sIHRoaXMucm90YXRlWzFdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYzKHIsIHRoaXMubWFza2luZ1syXSwgdGhpcy5yb3RhdGVbMl0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjEociwgdGhpcy5tYXNraW5nWzNdLCB0aGlzLnJvdGF0ZVszXSk7XG4gICAgICBsID0gdDtcblxuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYyKHIsIHRoaXMubWFza2luZ1s0XSwgdGhpcy5yb3RhdGVbNF0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjMociwgdGhpcy5tYXNraW5nWzVdLCB0aGlzLnJvdGF0ZVs1XSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbNl0sIHRoaXMucm90YXRlWzZdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYyKHIsIHRoaXMubWFza2luZ1s3XSwgdGhpcy5yb3RhdGVbN10pO1xuICAgICAgbCA9IHQ7XG5cbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMyhyLCB0aGlzLm1hc2tpbmdbOF0sIHRoaXMucm90YXRlWzhdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1s5XSwgdGhpcy5yb3RhdGVbOV0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzEwXSwgdGhpcy5yb3RhdGVbMTBdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYzKHIsIHRoaXMubWFza2luZ1sxMV0sIHRoaXMucm90YXRlWzExXSk7XG4gICAgICBsID0gdDtcblxuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1sxMl0sIHRoaXMucm90YXRlWzEyXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMihyLCB0aGlzLm1hc2tpbmdbMTNdLCB0aGlzLnJvdGF0ZVsxM10pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjMociwgdGhpcy5tYXNraW5nWzE0XSwgdGhpcy5yb3RhdGVbMTRdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1sxNV0sIHRoaXMucm90YXRlWzE1XSk7XG4gICAgICBsID0gdDtcblxuICAgICAgZHN0W2ldID0gKHIgPj4+IDI0KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgMV0gPSAociA+Pj4gMTYpICYgMjU1O1xuICAgICAgZHN0W2kgKyAyXSA9IChyID4+PiA4KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgM10gPSByICYgMjU1O1xuICAgICAgZHN0W2kgKyA0XSA9IChsID4+PiAyNCkgJiAyNTU7XG4gICAgICBkc3RbaSArIDVdID0gKGwgPj4+IDE2KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgNl0gPSAobCA+Pj4gOCkgJiAyNTU7XG4gICAgICBkc3RbaSArIDddID0gbCAmIDI1NTtcbiAgICB9XG5cbiAgICByZXR1cm4gZHN0O1xuICB9O1xuXG4gIHRoaXMuZGVjcnlwdCA9IGZ1bmN0aW9uKHNyYykge1xuICAgIHZhciBkc3QgPSBuZXcgQXJyYXkoc3JjLmxlbmd0aCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNyYy5sZW5ndGg7IGkgKz0gOCkge1xuICAgICAgdmFyIGwgPSBzcmNbaV0gPDwgMjQgfCBzcmNbaSArIDFdIDw8IDE2IHwgc3JjW2kgKyAyXSA8PCA4IHwgc3JjW2kgKyAzXTtcbiAgICAgIHZhciByID0gc3JjW2kgKyA0XSA8PCAyNCB8IHNyY1tpICsgNV0gPDwgMTYgfCBzcmNbaSArIDZdIDw8IDggfCBzcmNbaSArIDddO1xuICAgICAgdmFyIHQ7XG5cbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbMTVdLCB0aGlzLnJvdGF0ZVsxNV0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjMociwgdGhpcy5tYXNraW5nWzE0XSwgdGhpcy5yb3RhdGVbMTRdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYyKHIsIHRoaXMubWFza2luZ1sxM10sIHRoaXMucm90YXRlWzEzXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbMTJdLCB0aGlzLnJvdGF0ZVsxMl0pO1xuICAgICAgbCA9IHQ7XG5cbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMyhyLCB0aGlzLm1hc2tpbmdbMTFdLCB0aGlzLnJvdGF0ZVsxMV0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzEwXSwgdGhpcy5yb3RhdGVbMTBdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1s5XSwgdGhpcy5yb3RhdGVbOV0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjMociwgdGhpcy5tYXNraW5nWzhdLCB0aGlzLnJvdGF0ZVs4XSk7XG4gICAgICBsID0gdDtcblxuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYyKHIsIHRoaXMubWFza2luZ1s3XSwgdGhpcy5yb3RhdGVbN10pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjEociwgdGhpcy5tYXNraW5nWzZdLCB0aGlzLnJvdGF0ZVs2XSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMyhyLCB0aGlzLm1hc2tpbmdbNV0sIHRoaXMucm90YXRlWzVdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYyKHIsIHRoaXMubWFza2luZ1s0XSwgdGhpcy5yb3RhdGVbNF0pO1xuICAgICAgbCA9IHQ7XG5cbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbM10sIHRoaXMucm90YXRlWzNdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYzKHIsIHRoaXMubWFza2luZ1syXSwgdGhpcy5yb3RhdGVbMl0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzFdLCB0aGlzLnJvdGF0ZVsxXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbMF0sIHRoaXMucm90YXRlWzBdKTtcbiAgICAgIGwgPSB0O1xuXG4gICAgICBkc3RbaV0gPSAociA+Pj4gMjQpICYgMjU1O1xuICAgICAgZHN0W2kgKyAxXSA9IChyID4+PiAxNikgJiAyNTU7XG4gICAgICBkc3RbaSArIDJdID0gKHIgPj4+IDgpICYgMjU1O1xuICAgICAgZHN0W2kgKyAzXSA9IHIgJiAyNTU7XG4gICAgICBkc3RbaSArIDRdID0gKGwgPj4+IDI0KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgNV0gPSAobCA+PiAxNikgJiAyNTU7XG4gICAgICBkc3RbaSArIDZdID0gKGwgPj4gOCkgJiAyNTU7XG4gICAgICBkc3RbaSArIDddID0gbCAmIDI1NTtcbiAgICB9XG5cbiAgICByZXR1cm4gZHN0O1xuICB9O1xuICB2YXIgc2NoZWR1bGVBID0gbmV3IEFycmF5KDQpO1xuXG4gIHNjaGVkdWxlQVswXSA9IG5ldyBBcnJheSg0KTtcbiAgc2NoZWR1bGVBWzBdWzBdID0gbmV3IEFycmF5KDQsIDAsIDB4ZCwgMHhmLCAweGMsIDB4ZSwgMHg4KTtcbiAgc2NoZWR1bGVBWzBdWzFdID0gbmV3IEFycmF5KDUsIDIsIDE2ICsgMCwgMTYgKyAyLCAxNiArIDEsIDE2ICsgMywgMHhhKTtcbiAgc2NoZWR1bGVBWzBdWzJdID0gbmV3IEFycmF5KDYsIDMsIDE2ICsgNywgMTYgKyA2LCAxNiArIDUsIDE2ICsgNCwgOSk7XG4gIHNjaGVkdWxlQVswXVszXSA9IG5ldyBBcnJheSg3LCAxLCAxNiArIDB4YSwgMTYgKyA5LCAxNiArIDB4YiwgMTYgKyA4LCAweGIpO1xuXG4gIHNjaGVkdWxlQVsxXSA9IG5ldyBBcnJheSg0KTtcbiAgc2NoZWR1bGVBWzFdWzBdID0gbmV3IEFycmF5KDAsIDYsIDE2ICsgNSwgMTYgKyA3LCAxNiArIDQsIDE2ICsgNiwgMTYgKyAwKTtcbiAgc2NoZWR1bGVBWzFdWzFdID0gbmV3IEFycmF5KDEsIDQsIDAsIDIsIDEsIDMsIDE2ICsgMik7XG4gIHNjaGVkdWxlQVsxXVsyXSA9IG5ldyBBcnJheSgyLCA1LCA3LCA2LCA1LCA0LCAxNiArIDEpO1xuICBzY2hlZHVsZUFbMV1bM10gPSBuZXcgQXJyYXkoMywgNywgMHhhLCA5LCAweGIsIDgsIDE2ICsgMyk7XG5cbiAgc2NoZWR1bGVBWzJdID0gbmV3IEFycmF5KDQpO1xuICBzY2hlZHVsZUFbMl1bMF0gPSBuZXcgQXJyYXkoNCwgMCwgMHhkLCAweGYsIDB4YywgMHhlLCA4KTtcbiAgc2NoZWR1bGVBWzJdWzFdID0gbmV3IEFycmF5KDUsIDIsIDE2ICsgMCwgMTYgKyAyLCAxNiArIDEsIDE2ICsgMywgMHhhKTtcbiAgc2NoZWR1bGVBWzJdWzJdID0gbmV3IEFycmF5KDYsIDMsIDE2ICsgNywgMTYgKyA2LCAxNiArIDUsIDE2ICsgNCwgOSk7XG4gIHNjaGVkdWxlQVsyXVszXSA9IG5ldyBBcnJheSg3LCAxLCAxNiArIDB4YSwgMTYgKyA5LCAxNiArIDB4YiwgMTYgKyA4LCAweGIpO1xuXG5cbiAgc2NoZWR1bGVBWzNdID0gbmV3IEFycmF5KDQpO1xuICBzY2hlZHVsZUFbM11bMF0gPSBuZXcgQXJyYXkoMCwgNiwgMTYgKyA1LCAxNiArIDcsIDE2ICsgNCwgMTYgKyA2LCAxNiArIDApO1xuICBzY2hlZHVsZUFbM11bMV0gPSBuZXcgQXJyYXkoMSwgNCwgMCwgMiwgMSwgMywgMTYgKyAyKTtcbiAgc2NoZWR1bGVBWzNdWzJdID0gbmV3IEFycmF5KDIsIDUsIDcsIDYsIDUsIDQsIDE2ICsgMSk7XG4gIHNjaGVkdWxlQVszXVszXSA9IG5ldyBBcnJheSgzLCA3LCAweGEsIDksIDB4YiwgOCwgMTYgKyAzKTtcblxuICB2YXIgc2NoZWR1bGVCID0gbmV3IEFycmF5KDQpO1xuXG4gIHNjaGVkdWxlQlswXSA9IG5ldyBBcnJheSg0KTtcbiAgc2NoZWR1bGVCWzBdWzBdID0gbmV3IEFycmF5KDE2ICsgOCwgMTYgKyA5LCAxNiArIDcsIDE2ICsgNiwgMTYgKyAyKTtcbiAgc2NoZWR1bGVCWzBdWzFdID0gbmV3IEFycmF5KDE2ICsgMHhhLCAxNiArIDB4YiwgMTYgKyA1LCAxNiArIDQsIDE2ICsgNik7XG4gIHNjaGVkdWxlQlswXVsyXSA9IG5ldyBBcnJheSgxNiArIDB4YywgMTYgKyAweGQsIDE2ICsgMywgMTYgKyAyLCAxNiArIDkpO1xuICBzY2hlZHVsZUJbMF1bM10gPSBuZXcgQXJyYXkoMTYgKyAweGUsIDE2ICsgMHhmLCAxNiArIDEsIDE2ICsgMCwgMTYgKyAweGMpO1xuXG4gIHNjaGVkdWxlQlsxXSA9IG5ldyBBcnJheSg0KTtcbiAgc2NoZWR1bGVCWzFdWzBdID0gbmV3IEFycmF5KDMsIDIsIDB4YywgMHhkLCA4KTtcbiAgc2NoZWR1bGVCWzFdWzFdID0gbmV3IEFycmF5KDEsIDAsIDB4ZSwgMHhmLCAweGQpO1xuICBzY2hlZHVsZUJbMV1bMl0gPSBuZXcgQXJyYXkoNywgNiwgOCwgOSwgMyk7XG4gIHNjaGVkdWxlQlsxXVszXSA9IG5ldyBBcnJheSg1LCA0LCAweGEsIDB4YiwgNyk7XG5cblxuICBzY2hlZHVsZUJbMl0gPSBuZXcgQXJyYXkoNCk7XG4gIHNjaGVkdWxlQlsyXVswXSA9IG5ldyBBcnJheSgxNiArIDMsIDE2ICsgMiwgMTYgKyAweGMsIDE2ICsgMHhkLCAxNiArIDkpO1xuICBzY2hlZHVsZUJbMl1bMV0gPSBuZXcgQXJyYXkoMTYgKyAxLCAxNiArIDAsIDE2ICsgMHhlLCAxNiArIDB4ZiwgMTYgKyAweGMpO1xuICBzY2hlZHVsZUJbMl1bMl0gPSBuZXcgQXJyYXkoMTYgKyA3LCAxNiArIDYsIDE2ICsgOCwgMTYgKyA5LCAxNiArIDIpO1xuICBzY2hlZHVsZUJbMl1bM10gPSBuZXcgQXJyYXkoMTYgKyA1LCAxNiArIDQsIDE2ICsgMHhhLCAxNiArIDB4YiwgMTYgKyA2KTtcblxuXG4gIHNjaGVkdWxlQlszXSA9IG5ldyBBcnJheSg0KTtcbiAgc2NoZWR1bGVCWzNdWzBdID0gbmV3IEFycmF5KDgsIDksIDcsIDYsIDMpO1xuICBzY2hlZHVsZUJbM11bMV0gPSBuZXcgQXJyYXkoMHhhLCAweGIsIDUsIDQsIDcpO1xuICBzY2hlZHVsZUJbM11bMl0gPSBuZXcgQXJyYXkoMHhjLCAweGQsIDMsIDIsIDgpO1xuICBzY2hlZHVsZUJbM11bM10gPSBuZXcgQXJyYXkoMHhlLCAweGYsIDEsIDAsIDB4ZCk7XG5cbiAgLy8gY2hhbmdlZCAnaW4nIHRvICdpbm4nIChpbiBqYXZhc2NyaXB0ICdpbicgaXMgYSByZXNlcnZlZCB3b3JkKVxuICB0aGlzLmtleVNjaGVkdWxlID0gZnVuY3Rpb24oaW5uKSB7XG4gICAgdmFyIHQgPSBuZXcgQXJyYXkoOCk7XG4gICAgdmFyIGsgPSBuZXcgQXJyYXkoMzIpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCA0OyBpKyspIHtcbiAgICAgIHZhciBqID0gaSAqIDQ7XG4gICAgICB0W2ldID0gaW5uW2pdIDw8IDI0IHwgaW5uW2ogKyAxXSA8PCAxNiB8IGlubltqICsgMl0gPDwgOCB8IGlubltqICsgM107XG4gICAgfVxuXG4gICAgdmFyIHggPSBbNiwgNywgNCwgNV07XG4gICAgdmFyIGtpID0gMDtcblxuICAgIGZvciAodmFyIGhhbGYgPSAwOyBoYWxmIDwgMjsgaGFsZisrKSB7XG4gICAgICBmb3IgKHZhciByb3VuZCA9IDA7IHJvdW5kIDwgNDsgcm91bmQrKykge1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IDQ7IGorKykge1xuICAgICAgICAgIHZhciBhID0gc2NoZWR1bGVBW3JvdW5kXVtqXTtcbiAgICAgICAgICB2YXIgdyA9IHRbYVsxXV07XG5cbiAgICAgICAgICB3IF49IHNCb3hbNF1bKHRbYVsyXSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYVsyXSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB3IF49IHNCb3hbNV1bKHRbYVszXSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYVszXSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB3IF49IHNCb3hbNl1bKHRbYVs0XSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYVs0XSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB3IF49IHNCb3hbN11bKHRbYVs1XSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYVs1XSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB3IF49IHNCb3hbeFtqXV1bKHRbYVs2XSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYVs2XSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB0W2FbMF1dID0gdztcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgNDsgaisrKSB7XG4gICAgICAgICAgdmFyIGIgPSBzY2hlZHVsZUJbcm91bmRdW2pdO1xuICAgICAgICAgIHZhciB3ID0gc0JveFs0XVsodFtiWzBdID4+PiAyXSA+Pj4gKDI0IC0gOCAqIChiWzBdICYgMykpKSAmIDB4ZmZdO1xuXG4gICAgICAgICAgdyBePSBzQm94WzVdWyh0W2JbMV0gPj4+IDJdID4+PiAoMjQgLSA4ICogKGJbMV0gJiAzKSkpICYgMHhmZl07XG4gICAgICAgICAgdyBePSBzQm94WzZdWyh0W2JbMl0gPj4+IDJdID4+PiAoMjQgLSA4ICogKGJbMl0gJiAzKSkpICYgMHhmZl07XG4gICAgICAgICAgdyBePSBzQm94WzddWyh0W2JbM10gPj4+IDJdID4+PiAoMjQgLSA4ICogKGJbM10gJiAzKSkpICYgMHhmZl07XG4gICAgICAgICAgdyBePSBzQm94WzQgKyBqXVsodFtiWzRdID4+PiAyXSA+Pj4gKDI0IC0gOCAqIChiWzRdICYgMykpKSAmIDB4ZmZdO1xuICAgICAgICAgIGtba2ldID0gdztcbiAgICAgICAgICBraSsrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XG4gICAgICB0aGlzLm1hc2tpbmdbaV0gPSBrW2ldO1xuICAgICAgdGhpcy5yb3RhdGVbaV0gPSBrWzE2ICsgaV0gJiAweDFmO1xuICAgIH1cbiAgfTtcblxuICAvLyBUaGVzZSBhcmUgdGhlIHRocmVlICdmJyBmdW5jdGlvbnMuIFNlZSBSRkMgMjE0NCwgc2VjdGlvbiAyLjIuXG5cbiAgZnVuY3Rpb24gZjEoZCwgbSwgcikge1xuICAgIHZhciB0ID0gbSArIGQ7XG4gICAgdmFyIEkgPSAodCA8PCByKSB8ICh0ID4+PiAoMzIgLSByKSk7XG4gICAgcmV0dXJuICgoc0JveFswXVtJID4+PiAyNF0gXiBzQm94WzFdWyhJID4+PiAxNikgJiAyNTVdKSAtIHNCb3hbMl1bKEkgPj4+IDgpICYgMjU1XSkgKyBzQm94WzNdW0kgJiAyNTVdO1xuICB9XG5cbiAgZnVuY3Rpb24gZjIoZCwgbSwgcikge1xuICAgIHZhciB0ID0gbSBeIGQ7XG4gICAgdmFyIEkgPSAodCA8PCByKSB8ICh0ID4+PiAoMzIgLSByKSk7XG4gICAgcmV0dXJuICgoc0JveFswXVtJID4+PiAyNF0gLSBzQm94WzFdWyhJID4+PiAxNikgJiAyNTVdKSArIHNCb3hbMl1bKEkgPj4+IDgpICYgMjU1XSkgXiBzQm94WzNdW0kgJiAyNTVdO1xuICB9XG5cbiAgZnVuY3Rpb24gZjMoZCwgbSwgcikge1xuICAgIHZhciB0ID0gbSAtIGQ7XG4gICAgdmFyIEkgPSAodCA8PCByKSB8ICh0ID4+PiAoMzIgLSByKSk7XG4gICAgcmV0dXJuICgoc0JveFswXVtJID4+PiAyNF0gKyBzQm94WzFdWyhJID4+PiAxNikgJiAyNTVdKSBeIHNCb3hbMl1bKEkgPj4+IDgpICYgMjU1XSkgLSBzQm94WzNdW0kgJiAyNTVdO1xuICB9XG5cbiAgdmFyIHNCb3ggPSBuZXcgQXJyYXkoOCk7XG4gIHNCb3hbMF0gPSBuZXcgQXJyYXkoXG4gICAgMHgzMGZiNDBkNCwgMHg5ZmEwZmYwYiwgMHg2YmVjY2QyZiwgMHgzZjI1OGM3YSwgMHgxZTIxM2YyZiwgMHg5YzAwNGRkMywgMHg2MDAzZTU0MCwgMHhjZjlmYzk0OSxcbiAgICAweGJmZDRhZjI3LCAweDg4YmJiZGI1LCAweGUyMDM0MDkwLCAweDk4ZDA5Njc1LCAweDZlNjNhMGUwLCAweDE1YzM2MWQyLCAweGMyZTc2NjFkLCAweDIyZDRmZjhlLFxuICAgIDB4Mjg2ODNiNmYsIDB4YzA3ZmQwNTksIDB4ZmYyMzc5YzgsIDB4Nzc1ZjUwZTIsIDB4NDNjMzQwZDMsIDB4ZGYyZjg2NTYsIDB4ODg3Y2E0MWEsIDB4YTJkMmJkMmQsXG4gICAgMHhhMWM5ZTBkNiwgMHgzNDZjNDgxOSwgMHg2MWI3NmQ4NywgMHgyMjU0MGYyZiwgMHgyYWJlMzJlMSwgMHhhYTU0MTY2YiwgMHgyMjU2OGUzYSwgMHhhMmQzNDFkMCxcbiAgICAweDY2ZGI0MGM4LCAweGE3ODQzOTJmLCAweDAwNGRmZjJmLCAweDJkYjlkMmRlLCAweDk3OTQzZmFjLCAweDRhOTdjMWQ4LCAweDUyNzY0NGI3LCAweGI1ZjQzN2E3LFxuICAgIDB4YjgyY2JhZWYsIDB4ZDc1MWQxNTksIDB4NmZmN2YwZWQsIDB4NWEwOTdhMWYsIDB4ODI3YjY4ZDAsIDB4OTBlY2Y1MmUsIDB4MjJiMGMwNTQsIDB4YmM4ZTU5MzUsXG4gICAgMHg0YjZkMmY3ZiwgMHg1MGJiNjRhMiwgMHhkMjY2NDkxMCwgMHhiZWU1ODEyZCwgMHhiNzMzMjI5MCwgMHhlOTNiMTU5ZiwgMHhiNDhlZTQxMSwgMHg0YmZmMzQ1ZCxcbiAgICAweGZkNDVjMjQwLCAweGFkMzE5NzNmLCAweGM0ZjZkMDJlLCAweDU1ZmM4MTY1LCAweGQ1YjFjYWFkLCAweGExYWMyZGFlLCAweGEyZDRiNzZkLCAweGMxOWIwYzUwLFxuICAgIDB4ODgyMjQwZjIsIDB4MGM2ZTRmMzgsIDB4YTRlNGJmZDcsIDB4NGY1YmEyNzIsIDB4NTY0YzFkMmYsIDB4YzU5YzUzMTksIDB4Yjk0OWUzNTQsIDB4YjA0NjY5ZmUsXG4gICAgMHhiMWI2YWI4YSwgMHhjNzEzNThkZCwgMHg2Mzg1YzU0NSwgMHgxMTBmOTM1ZCwgMHg1NzUzOGFkNSwgMHg2YTM5MDQ5MywgMHhlNjNkMzdlMCwgMHgyYTU0ZjZiMyxcbiAgICAweDNhNzg3ZDVmLCAweDYyNzZhMGI1LCAweDE5YTZmY2RmLCAweDdhNDIyMDZhLCAweDI5ZjlkNGQ1LCAweGY2MWIxODkxLCAweGJiNzIyNzVlLCAweGFhNTA4MTY3LFxuICAgIDB4Mzg5MDEwOTEsIDB4YzZiNTA1ZWIsIDB4ODRjN2NiOGMsIDB4MmFkNzVhMGYsIDB4ODc0YTE0MjcsIDB4YTJkMTkzNmIsIDB4MmFkMjg2YWYsIDB4YWE1NmQyOTEsXG4gICAgMHhkNzg5NDM2MCwgMHg0MjVjNzUwZCwgMHg5M2IzOWUyNiwgMHgxODcxODRjOSwgMHg2YzAwYjMyZCwgMHg3M2UyYmIxNCwgMHhhMGJlYmMzYywgMHg1NDYyMzc3OSxcbiAgICAweDY0NDU5ZWFiLCAweDNmMzI4YjgyLCAweDc3MThjZjgyLCAweDU5YTJjZWE2LCAweDA0ZWUwMDJlLCAweDg5ZmU3OGU2LCAweDNmYWIwOTUwLCAweDMyNWZmNmMyLFxuICAgIDB4ODEzODNmMDUsIDB4Njk2M2M1YzgsIDB4NzZjYjVhZDYsIDB4ZDQ5OTc0YzksIDB4Y2ExODBkY2YsIDB4MzgwNzgyZDUsIDB4YzdmYTVjZjYsIDB4OGFjMzE1MTEsXG4gICAgMHgzNWU3OWUxMywgMHg0N2RhOTFkMCwgMHhmNDBmOTA4NiwgMHhhN2UyNDE5ZSwgMHgzMTM2NjI0MSwgMHgwNTFlZjQ5NSwgMHhhYTU3M2IwNCwgMHg0YTgwNWQ4ZCxcbiAgICAweDU0ODMwMGQwLCAweDAwMzIyYTNjLCAweGJmNjRjZGRmLCAweGJhNTdhNjhlLCAweDc1YzYzNzJiLCAweDUwYWZkMzQxLCAweGE3YzEzMjc1LCAweDkxNWEwYmY1LFxuICAgIDB4NmI1NGJmYWIsIDB4MmIwYjE0MjYsIDB4YWI0Y2M5ZDcsIDB4NDQ5Y2NkODIsIDB4ZjdmYmYyNjUsIDB4YWI4NWM1ZjMsIDB4MWI1NWRiOTQsIDB4YWFkNGUzMjQsXG4gICAgMHhjZmE0YmQzZiwgMHgyZGVhYTNlMiwgMHg5ZTIwNGQwMiwgMHhjOGJkMjVhYywgMHhlYWRmNTViMywgMHhkNWJkOWU5OCwgMHhlMzEyMzFiMiwgMHgyYWQ1YWQ2YyxcbiAgICAweDk1NDMyOWRlLCAweGFkYmU0NTI4LCAweGQ4NzEwZjY5LCAweGFhNTFjOTBmLCAweGFhNzg2YmY2LCAweDIyNTEzZjFlLCAweGFhNTFhNzliLCAweDJhZDM0NGNjLFxuICAgIDB4N2I1YTQxZjAsIDB4ZDM3Y2ZiYWQsIDB4MWIwNjk1MDUsIDB4NDFlY2U0OTEsIDB4YjRjMzMyZTYsIDB4MDMyMjY4ZDQsIDB4Yzk2MDBhY2MsIDB4Y2UzODdlNmQsXG4gICAgMHhiZjZiYjE2YywgMHg2YTcwZmI3OCwgMHgwZDAzZDljOSwgMHhkNGRmMzlkZSwgMHhlMDEwNjNkYSwgMHg0NzM2ZjQ2NCwgMHg1YWQzMjhkOCwgMHhiMzQ3Y2M5NixcbiAgICAweDc1YmIwZmMzLCAweDk4NTExYmZiLCAweDRmZmJjYzM1LCAweGI1OGJjZjZhLCAweGUxMWYwYWJjLCAweGJmYzVmZTRhLCAweGE3MGFlYzEwLCAweGFjMzk1NzBhLFxuICAgIDB4M2YwNDQ0MmYsIDB4NjE4OGIxNTMsIDB4ZTAzOTdhMmUsIDB4NTcyN2NiNzksIDB4OWNlYjQxOGYsIDB4MWNhY2Q2OGQsIDB4MmFkMzdjOTYsIDB4MDE3NWNiOWQsXG4gICAgMHhjNjlkZmYwOSwgMHhjNzViNjVmMCwgMHhkOWRiNDBkOCwgMHhlYzBlNzc3OSwgMHg0NzQ0ZWFkNCwgMHhiMTFjMzI3NCwgMHhkZDI0Y2I5ZSwgMHg3ZTFjNTRiZCxcbiAgICAweGYwMTE0NGY5LCAweGQyMjQwZWIxLCAweDk2NzViM2ZkLCAweGEzYWMzNzU1LCAweGQ0N2MyN2FmLCAweDUxYzg1ZjRkLCAweDU2OTA3NTk2LCAweGE1YmIxNWU2LFxuICAgIDB4NTgwMzA0ZjAsIDB4Y2EwNDJjZjEsIDB4MDExYTM3ZWEsIDB4OGRiZmFhZGIsIDB4MzViYTNlNGEsIDB4MzUyNmZmYTAsIDB4YzM3YjRkMDksIDB4YmMzMDZlZDksXG4gICAgMHg5OGE1MjY2NiwgMHg1NjQ4ZjcyNSwgMHhmZjVlNTY5ZCwgMHgwY2VkNjNkMCwgMHg3YzYzYjJjZiwgMHg3MDBiNDVlMSwgMHhkNWVhNTBmMSwgMHg4NWE5Mjg3MixcbiAgICAweGFmMWZiZGE3LCAweGQ0MjM0ODcwLCAweGE3ODcwYmYzLCAweDJkM2I0ZDc5LCAweDQyZTA0MTk4LCAweDBjZDBlZGU3LCAweDI2NDcwZGI4LCAweGY4ODE4MTRjLFxuICAgIDB4NDc0ZDZhZDcsIDB4N2MwYzVlNWMsIDB4ZDEyMzE5NTksIDB4MzgxYjcyOTgsIDB4ZjVkMmY0ZGIsIDB4YWI4Mzg2NTMsIDB4NmUyZjFlMjMsIDB4ODM3MTljOWUsXG4gICAgMHhiZDkxZTA0NiwgMHg5YTU2NDU2ZSwgMHhkYzM5MjAwYywgMHgyMGM4YzU3MSwgMHg5NjJiZGExYywgMHhlMWU2OTZmZiwgMHhiMTQxYWIwOCwgMHg3Y2NhODliOSxcbiAgICAweDFhNjllNzgzLCAweDAyY2M0ODQzLCAweGEyZjdjNTc5LCAweDQyOWVmNDdkLCAweDQyN2IxNjljLCAweDVhYzlmMDQ5LCAweGRkOGYwZjAwLCAweDVjODE2NWJmKTtcblxuICBzQm94WzFdID0gbmV3IEFycmF5KFxuICAgIDB4MWYyMDEwOTQsIDB4ZWYwYmE3NWIsIDB4NjllM2NmN2UsIDB4MzkzZjQzODAsIDB4ZmU2MWNmN2EsIDB4ZWVjNTIwN2EsIDB4NTU4ODljOTQsIDB4NzJmYzA2NTEsXG4gICAgMHhhZGE3ZWY3OSwgMHg0ZTFkNzIzNSwgMHhkNTVhNjNjZSwgMHhkZTA0MzZiYSwgMHg5OWM0MzBlZiwgMHg1ZjBjMDc5NCwgMHgxOGRjZGI3ZCwgMHhhMWQ2ZWZmMyxcbiAgICAweGEwYjUyZjdiLCAweDU5ZTgzNjA1LCAweGVlMTViMDk0LCAweGU5ZmZkOTA5LCAweGRjNDQwMDg2LCAweGVmOTQ0NDU5LCAweGJhODNjY2IzLCAweGUwYzNjZGZiLFxuICAgIDB4ZDFkYTQxODEsIDB4M2IwOTJhYjEsIDB4Zjk5N2YxYzEsIDB4YTVlNmNmN2IsIDB4MDE0MjBkZGIsIDB4ZTRlN2VmNWIsIDB4MjVhMWZmNDEsIDB4ZTE4MGY4MDYsXG4gICAgMHgxZmM0MTA4MCwgMHgxNzliZWU3YSwgMHhkMzdhYzZhOSwgMHhmZTU4MzBhNCwgMHg5OGRlOGI3ZiwgMHg3N2U4M2Y0ZSwgMHg3OTkyOTI2OSwgMHgyNGZhOWY3YixcbiAgICAweGUxMTNjODViLCAweGFjYzQwMDgzLCAweGQ3NTAzNTI1LCAweGY3ZWE2MTVmLCAweDYyMTQzMTU0LCAweDBkNTU0YjYzLCAweDVkNjgxMTIxLCAweGM4NjZjMzU5LFxuICAgIDB4M2Q2M2NmNzMsIDB4Y2VlMjM0YzAsIDB4ZDRkODdlODcsIDB4NWM2NzJiMjEsIDB4MDcxZjYxODEsIDB4MzlmNzYyN2YsIDB4MzYxZTMwODQsIDB4ZTRlYjU3M2IsXG4gICAgMHg2MDJmNjRhNCwgMHhkNjNhY2Q5YywgMHgxYmJjNDYzNSwgMHg5ZTgxMDMyZCwgMHgyNzAxZjUwYywgMHg5OTg0N2FiNCwgMHhhMGUzZGY3OSwgMHhiYTZjZjM4YyxcbiAgICAweDEwODQzMDk0LCAweDI1MzdhOTVlLCAweGY0NmY2ZmZlLCAweGExZmYzYjFmLCAweDIwOGNmYjZhLCAweDhmNDU4Yzc0LCAweGQ5ZTBhMjI3LCAweDRlYzczYTM0LFxuICAgIDB4ZmM4ODRmNjksIDB4M2U0ZGU4ZGYsIDB4ZWYwZTAwODgsIDB4MzU1OTY0OGQsIDB4OGE0NTM4OGMsIDB4MWQ4MDQzNjYsIDB4NzIxZDliZmQsIDB4YTU4Njg0YmIsXG4gICAgMHhlODI1NjMzMywgMHg4NDRlODIxMiwgMHgxMjhkODA5OCwgMHhmZWQzM2ZiNCwgMHhjZTI4MGFlMSwgMHgyN2UxOWJhNSwgMHhkNWE2YzI1MiwgMHhlNDk3NTRiZCxcbiAgICAweGM1ZDY1NWRkLCAweGViNjY3MDY0LCAweDc3ODQwYjRkLCAweGExYjZhODAxLCAweDg0ZGIyNmE5LCAweGUwYjU2NzE0LCAweDIxZjA0M2I3LCAweGU1ZDA1ODYwLFxuICAgIDB4NTRmMDMwODQsIDB4MDY2ZmY0NzIsIDB4YTMxYWExNTMsIDB4ZGFkYzQ3NTUsIDB4YjU2MjVkYmYsIDB4Njg1NjFiZTYsIDB4ODNjYTZiOTQsIDB4MmQ2ZWQyM2IsXG4gICAgMHhlY2NmMDFkYiwgMHhhNmQzZDBiYSwgMHhiNjgwM2Q1YywgMHhhZjc3YTcwOSwgMHgzM2I0YTM0YywgMHgzOTdiYzhkNiwgMHg1ZWUyMmI5NSwgMHg1ZjBlNTMwNCxcbiAgICAweDgxZWQ2ZjYxLCAweDIwZTc0MzY0LCAweGI0NWUxMzc4LCAweGRlMTg2MzliLCAweDg4MWNhMTIyLCAweGI5NjcyNmQxLCAweDgwNDlhN2U4LCAweDIyYjdkYTdiLFxuICAgIDB4NWU1NTJkMjUsIDB4NTI3MmQyMzcsIDB4NzlkMjk1MWMsIDB4YzYwZDg5NGMsIDB4NDg4Y2I0MDIsIDB4MWJhNGZlNWIsIDB4YTRiMDlmNmIsIDB4MWNhODE1Y2YsXG4gICAgMHhhMjBjMzAwNSwgMHg4ODcxZGY2MywgMHhiOWRlMmZjYiwgMHgwY2M2YzllOSwgMHgwYmVlZmY1MywgMHhlMzIxNDUxNywgMHhiNDU0MjgzNSwgMHg5ZjYzMjkzYyxcbiAgICAweGVlNDFlNzI5LCAweDZlMWQyZDdjLCAweDUwMDQ1Mjg2LCAweDFlNjY4NWYzLCAweGYzMzQwMWM2LCAweDMwYTIyYzk1LCAweDMxYTcwODUwLCAweDYwOTMwZjEzLFxuICAgIDB4NzNmOTg0MTcsIDB4YTEyNjk4NTksIDB4ZWM2NDVjNDQsIDB4NTJjODc3YTksIDB4Y2RmZjMzYTYsIDB4YTAyYjE3NDEsIDB4N2NiYWQ5YTIsIDB4MjE4MDAzNmYsXG4gICAgMHg1MGQ5OWMwOCwgMHhjYjNmNDg2MSwgMHhjMjZiZDc2NSwgMHg2NGEzZjZhYiwgMHg4MDM0MjY3NiwgMHgyNWE3NWU3YiwgMHhlNGU2ZDFmYywgMHgyMGM3MTBlNixcbiAgICAweGNkZjBiNjgwLCAweDE3ODQ0ZDNiLCAweDMxZWVmODRkLCAweDdlMDgyNGU0LCAweDJjY2I0OWViLCAweDg0NmEzYmFlLCAweDhmZjc3ODg4LCAweGVlNWQ2MGY2LFxuICAgIDB4N2FmNzU2NzMsIDB4MmZkZDVjZGIsIDB4YTExNjMxYzEsIDB4MzBmNjZmNDMsIDB4YjNmYWVjNTQsIDB4MTU3ZmQ3ZmEsIDB4ZWY4NTc5Y2MsIDB4ZDE1MmRlNTgsXG4gICAgMHhkYjJmZmQ1ZSwgMHg4ZjMyY2UxOSwgMHgzMDZhZjk3YSwgMHgwMmYwM2VmOCwgMHg5OTMxOWFkNSwgMHhjMjQyZmEwZiwgMHhhN2UzZWJiMCwgMHhjNjhlNDkwNixcbiAgICAweGI4ZGEyMzBjLCAweDgwODIzMDI4LCAweGRjZGVmM2M4LCAweGQzNWZiMTcxLCAweDA4OGExYmM4LCAweGJlYzBjNTYwLCAweDYxYTNjOWU4LCAweGJjYThmNTRkLFxuICAgIDB4YzcyZmVmZmEsIDB4MjI4MjJlOTksIDB4ODJjNTcwYjQsIDB4ZDhkOTRlODksIDB4OGIxYzM0YmMsIDB4MzAxZTE2ZTYsIDB4MjczYmU5NzksIDB4YjBmZmVhYTYsXG4gICAgMHg2MWQ5YjhjNiwgMHgwMGIyNDg2OSwgMHhiN2ZmY2UzZiwgMHgwOGRjMjgzYiwgMHg0M2RhZjY1YSwgMHhmN2UxOTc5OCwgMHg3NjE5YjcyZiwgMHg4ZjFjOWJhNCxcbiAgICAweGRjODYzN2EwLCAweDE2YTdkM2IxLCAweDlmYzM5M2I3LCAweGE3MTM2ZWViLCAweGM2YmNjNjNlLCAweDFhNTEzNzQyLCAweGVmNjgyOGJjLCAweDUyMDM2NWQ2LFxuICAgIDB4MmQ2YTc3YWIsIDB4MzUyN2VkNGIsIDB4ODIxZmQyMTYsIDB4MDk1YzZlMmUsIDB4ZGI5MmYyZmIsIDB4NWVlYTI5Y2IsIDB4MTQ1ODkyZjUsIDB4OTE1ODRmN2YsXG4gICAgMHg1NDgzNjk3YiwgMHgyNjY3YThjYywgMHg4NTE5NjA0OCwgMHg4YzRiYWNlYSwgMHg4MzM4NjBkNCwgMHgwZDIzZTBmOSwgMHg2YzM4N2U4YSwgMHgwYWU2ZDI0OSxcbiAgICAweGIyODQ2MDBjLCAweGQ4MzU3MzFkLCAweGRjYjFjNjQ3LCAweGFjNGM1NmVhLCAweDNlYmQ4MWIzLCAweDIzMGVhYmIwLCAweDY0MzhiYzg3LCAweGYwYjViMWZhLFxuICAgIDB4OGY1ZWEyYjMsIDB4ZmMxODQ2NDIsIDB4MGEwMzZiN2EsIDB4NGZiMDg5YmQsIDB4NjQ5ZGE1ODksIDB4YTM0NTQxNWUsIDB4NWMwMzgzMjMsIDB4M2U1ZDNiYjksXG4gICAgMHg0M2Q3OTU3MiwgMHg3ZTZkZDA3YywgMHgwNmRmZGYxZSwgMHg2YzZjYzRlZiwgMHg3MTYwYTUzOSwgMHg3M2JmYmU3MCwgMHg4Mzg3NzYwNSwgMHg0NTIzZWNmMSk7XG5cbiAgc0JveFsyXSA9IG5ldyBBcnJheShcbiAgICAweDhkZWZjMjQwLCAweDI1ZmE1ZDlmLCAweGViOTAzZGJmLCAweGU4MTBjOTA3LCAweDQ3NjA3ZmZmLCAweDM2OWZlNDRiLCAweDhjMWZjNjQ0LCAweGFlY2VjYTkwLFxuICAgIDB4YmViMWY5YmYsIDB4ZWVmYmNhZWEsIDB4ZThjZjE5NTAsIDB4NTFkZjA3YWUsIDB4OTIwZTg4MDYsIDB4ZjBhZDA1NDgsIDB4ZTEzYzhkODMsIDB4OTI3MDEwZDUsXG4gICAgMHgxMTEwN2Q5ZiwgMHgwNzY0N2RiOSwgMHhiMmUzZTRkNCwgMHgzZDRmMjg1ZSwgMHhiOWFmYTgyMCwgMHhmYWRlODJlMCwgMHhhMDY3MjY4YiwgMHg4MjcyNzkyZSxcbiAgICAweDU1M2ZiMmMwLCAweDQ4OWFlMjJiLCAweGQ0ZWY5Nzk0LCAweDEyNWUzZmJjLCAweDIxZmZmY2VlLCAweDgyNWIxYmZkLCAweDkyNTVjNWVkLCAweDEyNTdhMjQwLFxuICAgIDB4NGUxYTgzMDIsIDB4YmFlMDdmZmYsIDB4NTI4MjQ2ZTcsIDB4OGU1NzE0MGUsIDB4MzM3M2Y3YmYsIDB4OGM5ZjgxODgsIDB4YTZmYzRlZTgsIDB4Yzk4MmI1YTUsXG4gICAgMHhhOGMwMWRiNywgMHg1NzlmYzI2NCwgMHg2NzA5NGYzMSwgMHhmMmJkM2Y1ZiwgMHg0MGZmZjdjMSwgMHgxZmI3OGRmYywgMHg4ZTZiZDJjMSwgMHg0MzdiZTU5YixcbiAgICAweDk5YjAzZGJmLCAweGI1ZGJjNjRiLCAweDYzOGRjMGU2LCAweDU1ODE5ZDk5LCAweGExOTdjODFjLCAweDRhMDEyZDZlLCAweGM1ODg0YTI4LCAweGNjYzM2ZjcxLFxuICAgIDB4Yjg0M2MyMTMsIDB4NmMwNzQzZjEsIDB4ODMwOTg5M2MsIDB4MGZlZGRkNWYsIDB4MmY3ZmU4NTAsIDB4ZDdjMDdmN2UsIDB4MDI1MDdmYmYsIDB4NWFmYjlhMDQsXG4gICAgMHhhNzQ3ZDJkMCwgMHgxNjUxMTkyZSwgMHhhZjcwYmYzZSwgMHg1OGMzMTM4MCwgMHg1Zjk4MzAyZSwgMHg3MjdjYzNjNCwgMHgwYTBmYjQwMiwgMHgwZjdmZWY4MixcbiAgICAweDhjOTZmZGFkLCAweDVkMmMyYWFlLCAweDhlZTk5YTQ5LCAweDUwZGE4OGI4LCAweDg0MjdmNGEwLCAweDFlYWM1NzkwLCAweDc5NmZiNDQ5LCAweDgyNTJkYzE1LFxuICAgIDB4ZWZiZDdkOWIsIDB4YTY3MjU5N2QsIDB4YWRhODQwZDgsIDB4NDVmNTQ1MDQsIDB4ZmE1ZDc0MDMsIDB4ZTgzZWMzMDUsIDB4NGY5MTc1MWEsIDB4OTI1NjY5YzIsXG4gICAgMHgyM2VmZTk0MSwgMHhhOTAzZjEyZSwgMHg2MDI3MGRmMiwgMHgwMjc2ZTRiNiwgMHg5NGZkNjU3NCwgMHg5Mjc5ODViMiwgMHg4Mjc2ZGJjYiwgMHgwMjc3ODE3NixcbiAgICAweGY4YWY5MThkLCAweDRlNDhmNzllLCAweDhmNjE2ZGRmLCAweGUyOWQ4NDBlLCAweDg0MmY3ZDgzLCAweDM0MGNlNWM4LCAweDk2YmJiNjgyLCAweDkzYjRiMTQ4LFxuICAgIDB4ZWYzMDNjYWIsIDB4OTg0ZmFmMjgsIDB4Nzc5ZmFmOWIsIDB4OTJkYzU2MGQsIDB4MjI0ZDFlMjAsIDB4ODQzN2FhODgsIDB4N2QyOWRjOTYsIDB4Mjc1NmQzZGMsXG4gICAgMHg4YjkwN2NlZSwgMHhiNTFmZDI0MCwgMHhlN2MwN2NlMywgMHhlNTY2YjRhMSwgMHhjM2U5NjE1ZSwgMHgzY2Y4MjA5ZCwgMHg2MDk0ZDFlMywgMHhjZDljYTM0MSxcbiAgICAweDVjNzY0NjBlLCAweDAwZWE5ODNiLCAweGQ0ZDY3ODgxLCAweGZkNDc1NzJjLCAweGY3NmNlZGQ5LCAweGJkYTgyMjljLCAweDEyN2RhZGFhLCAweDQzOGEwNzRlLFxuICAgIDB4MWY5N2MwOTAsIDB4MDgxYmRiOGEsIDB4OTNhMDdlYmUsIDB4YjkzOGNhMTUsIDB4OTdiMDNjZmYsIDB4M2RjMmMwZjgsIDB4OGQxYWIyZWMsIDB4NjQzODBlNTEsXG4gICAgMHg2OGNjN2JmYiwgMHhkOTBmMjc4OCwgMHgxMjQ5MDE4MSwgMHg1ZGU1ZmZkNCwgMHhkZDdlZjg2YSwgMHg3NmEyZTIxNCwgMHhiOWE0MDM2OCwgMHg5MjVkOTU4ZixcbiAgICAweDRiMzlmZmZhLCAweGJhMzlhZWU5LCAweGE0ZmZkMzBiLCAweGZhZjc5MzNiLCAweDZkNDk4NjIzLCAweDE5M2NiY2ZhLCAweDI3NjI3NTQ1LCAweDgyNWNmNDdhLFxuICAgIDB4NjFiZDhiYTAsIDB4ZDExZTQyZDEsIDB4Y2VhZDA0ZjQsIDB4MTI3ZWEzOTIsIDB4MTA0MjhkYjcsIDB4ODI3MmE5NzIsIDB4OTI3MGM0YTgsIDB4MTI3ZGU1MGIsXG4gICAgMHgyODViYTFjOCwgMHgzYzYyZjQ0ZiwgMHgzNWMwZWFhNSwgMHhlODA1ZDIzMSwgMHg0Mjg5MjlmYiwgMHhiNGZjZGY4MiwgMHg0ZmI2NmE1MywgMHgwZTdkYzE1YixcbiAgICAweDFmMDgxZmFiLCAweDEwODYxOGFlLCAweGZjZmQwODZkLCAweGY5ZmYyODg5LCAweDY5NGJjYzExLCAweDIzNmE1Y2FlLCAweDEyZGVjYTRkLCAweDJjM2Y4Y2M1LFxuICAgIDB4ZDJkMDJkZmUsIDB4ZjhlZjU4OTYsIDB4ZTRjZjUyZGEsIDB4OTUxNTViNjcsIDB4NDk0YTQ4OGMsIDB4YjliNmE4MGMsIDB4NWM4ZjgyYmMsIDB4ODlkMzZiNDUsXG4gICAgMHgzYTYwOTQzNywgMHhlYzAwYzlhOSwgMHg0NDcxNTI1MywgMHgwYTg3NGI0OSwgMHhkNzczYmM0MCwgMHg3YzM0NjcxYywgMHgwMjcxN2VmNiwgMHg0ZmViNTUzNixcbiAgICAweGEyZDAyZmZmLCAweGQyYmY2MGM0LCAweGQ0M2YwM2MwLCAweDUwYjRlZjZkLCAweDA3NDc4Y2QxLCAweDAwNmUxODg4LCAweGEyZTUzZjU1LCAweGI5ZTZkNGJjLFxuICAgIDB4YTIwNDgwMTYsIDB4OTc1NzM4MzMsIDB4ZDcyMDdkNjcsIDB4ZGUwZjhmM2QsIDB4NzJmODdiMzMsIDB4YWJjYzRmMzMsIDB4NzY4OGM1NWQsIDB4N2IwMGE2YjAsXG4gICAgMHg5NDdiMDAwMSwgMHg1NzAwNzVkMiwgMHhmOWJiODhmOCwgMHg4OTQyMDE5ZSwgMHg0MjY0YTVmZiwgMHg4NTYzMDJlMCwgMHg3MmRiZDkyYiwgMHhlZTk3MWI2OSxcbiAgICAweDZlYTIyZmRlLCAweDVmMDhhZTJiLCAweGFmN2E2MTZkLCAweGU1Yzk4NzY3LCAweGNmMWZlYmQyLCAweDYxZWZjOGMyLCAweGYxYWMyNTcxLCAweGNjODIzOWMyLFxuICAgIDB4NjcyMTRjYjgsIDB4YjFlNTgzZDEsIDB4YjdkYzNlNjIsIDB4N2YxMGJkY2UsIDB4ZjkwYTVjMzgsIDB4MGZmMDQ0M2QsIDB4NjA2ZTZkYzYsIDB4NjA1NDNhNDksXG4gICAgMHg1NzI3YzE0OCwgMHgyYmU5OGExZCwgMHg4YWI0MTczOCwgMHgyMGUxYmUyNCwgMHhhZjk2ZGEwZiwgMHg2ODQ1ODQyNSwgMHg5OTgzM2JlNSwgMHg2MDBkNDU3ZCxcbiAgICAweDI4MmY5MzUwLCAweDgzMzRiMzYyLCAweGQ5MWQxMTIwLCAweDJiNmQ4ZGEwLCAweDY0MmIxZTMxLCAweDljMzA1YTAwLCAweDUyYmNlNjg4LCAweDFiMDM1ODhhLFxuICAgIDB4ZjdiYWVmZDUsIDB4NDE0MmVkOWMsIDB4YTQzMTVjMTEsIDB4ODMzMjNlYzUsIDB4ZGZlZjQ2MzYsIDB4YTEzM2M1MDEsIDB4ZTlkMzUzMWMsIDB4ZWUzNTM3ODMpO1xuXG4gIHNCb3hbM10gPSBuZXcgQXJyYXkoXG4gICAgMHg5ZGIzMDQyMCwgMHgxZmI2ZTlkZSwgMHhhN2JlN2JlZiwgMHhkMjczYTI5OCwgMHg0YTRmN2JkYiwgMHg2NGFkOGM1NywgMHg4NTUxMDQ0MywgMHhmYTAyMGVkMSxcbiAgICAweDdlMjg3YWZmLCAweGU2MGZiNjYzLCAweDA5NWYzNWExLCAweDc5ZWJmMTIwLCAweGZkMDU5ZDQzLCAweDY0OTdiN2IxLCAweGYzNjQxZjYzLCAweDI0MWU0YWRmLFxuICAgIDB4MjgxNDdmNWYsIDB4NGZhMmI4Y2QsIDB4Yzk0MzAwNDAsIDB4MGNjMzIyMjAsIDB4ZmRkMzBiMzAsIDB4YzBhNTM3NGYsIDB4MWQyZDAwZDksIDB4MjQxNDdiMTUsXG4gICAgMHhlZTRkMTExYSwgMHgwZmNhNTE2NywgMHg3MWZmOTA0YywgMHgyZDE5NWZmZSwgMHgxYTA1NjQ1ZiwgMHgwYzEzZmVmZSwgMHgwODFiMDhjYSwgMHgwNTE3MDEyMSxcbiAgICAweDgwNTMwMTAwLCAweGU4M2U1ZWZlLCAweGFjOWFmNGY4LCAweDdmZTcyNzAxLCAweGQyYjhlZTVmLCAweDA2ZGY0MjYxLCAweGJiOWU5YjhhLCAweDcyOTNlYTI1LFxuICAgIDB4Y2U4NGZmZGYsIDB4ZjU3MTg4MDEsIDB4M2RkNjRiMDQsIDB4YTI2ZjI2M2IsIDB4N2VkNDg0MDAsIDB4NTQ3ZWViZTYsIDB4NDQ2ZDRjYTAsIDB4NmNmM2Q2ZjUsXG4gICAgMHgyNjQ5YWJkZiwgMHhhZWEwYzdmNSwgMHgzNjMzOGNjMSwgMHg1MDNmN2U5MywgMHhkMzc3MjA2MSwgMHgxMWI2MzhlMSwgMHg3MjUwMGUwMywgMHhmODBlYjJiYixcbiAgICAweGFiZTA1MDJlLCAweGVjOGQ3N2RlLCAweDU3OTcxZTgxLCAweGUxNGY2NzQ2LCAweGM5MzM1NDAwLCAweDY5MjAzMThmLCAweDA4MWRiYjk5LCAweGZmYzMwNGE1LFxuICAgIDB4NGQzNTE4MDUsIDB4N2YzZDVjZTMsIDB4YTZjODY2YzYsIDB4NWQ1YmNjYTksIDB4ZGFlYzZmZWEsIDB4OWY5MjZmOTEsIDB4OWY0NjIyMmYsIDB4Mzk5MTQ2N2QsXG4gICAgMHhhNWJmNmQ4ZSwgMHgxMTQzYzQ0ZiwgMHg0Mzk1ODMwMiwgMHhkMDIxNGVlYiwgMHgwMjIwODNiOCwgMHgzZmI2MTgwYywgMHgxOGY4OTMxZSwgMHgyODE2NThlNixcbiAgICAweDI2NDg2ZTNlLCAweDhiZDc4YTcwLCAweDc0NzdlNGMxLCAweGI1MDZlMDdjLCAweGYzMmQwYTI1LCAweDc5MDk4YjAyLCAweGU0ZWFiYjgxLCAweDI4MTIzYjIzLFxuICAgIDB4NjlkZWFkMzgsIDB4MTU3NGNhMTYsIDB4ZGY4NzFiNjIsIDB4MjExYzQwYjcsIDB4YTUxYTllZjksIDB4MDAxNDM3N2IsIDB4MDQxZThhYzgsIDB4MDkxMTQwMDMsXG4gICAgMHhiZDU5ZTRkMiwgMHhlM2QxNTZkNSwgMHg0ZmU4NzZkNSwgMHgyZjkxYTM0MCwgMHg1NTdiZThkZSwgMHgwMGVhZTRhNywgMHgwY2U1YzJlYywgMHg0ZGI0YmJhNixcbiAgICAweGU3NTZiZGZmLCAweGRkMzM2OWFjLCAweGVjMTdiMDM1LCAweDA2NTcyMzI3LCAweDk5YWZjOGIwLCAweDU2YzhjMzkxLCAweDZiNjU4MTFjLCAweDVlMTQ2MTE5LFxuICAgIDB4NmU4NWNiNzUsIDB4YmUwN2MwMDIsIDB4YzIzMjU1NzcsIDB4ODkzZmY0ZWMsIDB4NWJiZmM5MmQsIDB4ZDBlYzNiMjUsIDB4Yjc4MDFhYjcsIDB4OGQ2ZDNiMjQsXG4gICAgMHgyMGM3NjNlZiwgMHhjMzY2YTVmYywgMHg5YzM4Mjg4MCwgMHgwYWNlMzIwNSwgMHhhYWM5NTQ4YSwgMHhlY2ExZDdjNywgMHgwNDFhZmEzMiwgMHgxZDE2NjI1YSxcbiAgICAweDY3MDE5MDJjLCAweDliNzU3YTU0LCAweDMxZDQ3N2Y3LCAweDkxMjZiMDMxLCAweDM2Y2M2ZmRiLCAweGM3MGI4YjQ2LCAweGQ5ZTY2YTQ4LCAweDU2ZTU1YTc5LFxuICAgIDB4MDI2YTRjZWIsIDB4NTI0MzdlZmYsIDB4MmY4Zjc2YjQsIDB4MGRmOTgwYTUsIDB4ODY3NGNkZTMsIDB4ZWRkYTA0ZWIsIDB4MTdhOWJlMDQsIDB4MmMxOGY0ZGYsXG4gICAgMHhiNzc0N2Y5ZCwgMHhhYjJhZjdiNCwgMHhlZmMzNGQyMCwgMHgyZTA5NmI3YywgMHgxNzQxYTI1NCwgMHhlNWI2YTAzNSwgMHgyMTNkNDJmNiwgMHgyYzFjN2MyNixcbiAgICAweDYxYzJmNTBmLCAweDY1NTJkYWY5LCAweGQyYzIzMWY4LCAweDI1MTMwZjY5LCAweGQ4MTY3ZmEyLCAweDA0MThmMmM4LCAweDAwMWE5NmE2LCAweDBkMTUyNmFiLFxuICAgIDB4NjMzMTVjMjEsIDB4NWUwYTcyZWMsIDB4NDliYWZlZmQsIDB4MTg3OTA4ZDksIDB4OGQwZGJkODYsIDB4MzExMTcwYTcsIDB4M2U5YjY0MGMsIDB4Y2MzZTEwZDcsXG4gICAgMHhkNWNhZDNiNiwgMHgwY2FlYzM4OCwgMHhmNzMwMDFlMSwgMHg2YzcyOGFmZiwgMHg3MWVhZTJhMSwgMHgxZjlhZjM2ZSwgMHhjZmNiZDEyZiwgMHhjMWRlODQxNyxcbiAgICAweGFjMDdiZTZiLCAweGNiNDRhMWQ4LCAweDhiOWIwZjU2LCAweDAxMzk4OGMzLCAweGIxYzUyZmNhLCAweGI0YmUzMWNkLCAweGQ4NzgyODA2LCAweDEyYTNhNGUyLFxuICAgIDB4NmY3ZGU1MzIsIDB4NThmZDdlYjYsIDB4ZDAxZWU5MDAsIDB4MjRhZGZmYzIsIDB4ZjQ5OTBmYzUsIDB4OTcxMWFhYzUsIDB4MDAxZDdiOTUsIDB4ODJlNWU3ZDIsXG4gICAgMHgxMDk4NzNmNiwgMHgwMDYxMzA5NiwgMHhjMzJkOTUyMSwgMHhhZGExMjFmZiwgMHgyOTkwODQxNSwgMHg3ZmJiOTc3ZiwgMHhhZjllYjNkYiwgMHgyOWM5ZWQyYSxcbiAgICAweDVjZTJhNDY1LCAweGE3MzBmMzJjLCAweGQwYWEzZmU4LCAweDhhNWNjMDkxLCAweGQ0OWUyY2U3LCAweDBjZTQ1NGE5LCAweGQ2MGFjZDg2LCAweDAxNWYxOTE5LFxuICAgIDB4NzcwNzkxMDMsIDB4ZGVhMDNhZjYsIDB4NzhhODU2NWUsIDB4ZGVlMzU2ZGYsIDB4MjFmMDVjYmUsIDB4OGI3NWUzODcsIDB4YjNjNTA2NTEsIDB4YjhhNWMzZWYsXG4gICAgMHhkOGVlYjZkMiwgMHhlNTIzYmU3NywgMHhjMjE1NDUyOSwgMHgyZjY5ZWZkZiwgMHhhZmU2N2FmYiwgMHhmNDcwYzRiMiwgMHhmM2UwZWI1YiwgMHhkNmNjOTg3NixcbiAgICAweDM5ZTQ0NjBjLCAweDFmZGE4NTM4LCAweDE5ODc4MzJmLCAweGNhMDA3MzY3LCAweGE5OTE0NGY4LCAweDI5NmIyOTllLCAweDQ5MmZjMjk1LCAweDkyNjZiZWFiLFxuICAgIDB4YjU2NzZlNjksIDB4OWJkM2RkZGEsIDB4ZGY3ZTA1MmYsIDB4ZGIyNTcwMWMsIDB4MWI1ZTUxZWUsIDB4ZjY1MzI0ZTYsIDB4NmFmY2UzNmMsIDB4MDMxNmNjMDQsXG4gICAgMHg4NjQ0MjEzZSwgMHhiN2RjNTlkMCwgMHg3OTY1MjkxZiwgMHhjY2Q2ZmQ0MywgMHg0MTgyMzk3OSwgMHg5MzJiY2RmNiwgMHhiNjU3YzM0ZCwgMHg0ZWRmZDI4MixcbiAgICAweDdhZTUyOTBjLCAweDNjYjk1MzZiLCAweDg1MWUyMGZlLCAweDk4MzM1NTdlLCAweDEzZWNmMGIwLCAweGQzZmZiMzcyLCAweDNmODVjNWMxLCAweDBhZWY3ZWQyKTtcblxuICBzQm94WzRdID0gbmV3IEFycmF5KFxuICAgIDB4N2VjOTBjMDQsIDB4MmM2ZTc0YjksIDB4OWIwZTY2ZGYsIDB4YTYzMzc5MTEsIDB4Yjg2YTdmZmYsIDB4MWRkMzU4ZjUsIDB4NDRkZDlkNDQsIDB4MTczMTE2N2YsXG4gICAgMHgwOGZiZjFmYSwgMHhlN2Y1MTFjYywgMHhkMjA1MWIwMCwgMHg3MzVhYmEwMCwgMHgyYWI3MjJkOCwgMHgzODYzODFjYiwgMHhhY2Y2MjQzYSwgMHg2OWJlZmQ3YSxcbiAgICAweGU2YTJlNzdmLCAweGYwYzcyMGNkLCAweGM0NDk0ODE2LCAweGNjZjVjMTgwLCAweDM4ODUxNjQwLCAweDE1YjBhODQ4LCAweGU2OGIxOGNiLCAweDRjYWFkZWZmLFxuICAgIDB4NWY0ODBhMDEsIDB4MDQxMmIyYWEsIDB4MjU5ODE0ZmMsIDB4NDFkMGVmZTIsIDB4NGU0MGI0OGQsIDB4MjQ4ZWI2ZmIsIDB4OGRiYTFjZmUsIDB4NDFhOTliMDIsXG4gICAgMHgxYTU1MGEwNCwgMHhiYThmNjVjYiwgMHg3MjUxZjRlNywgMHg5NWE1MTcyNSwgMHhjMTA2ZWNkNywgMHg5N2E1OTgwYSwgMHhjNTM5YjlhYSwgMHg0ZDc5ZmU2YSxcbiAgICAweGYyZjNmNzYzLCAweDY4YWY4MDQwLCAweGVkMGM5ZTU2LCAweDExYjQ5NThiLCAweGUxZWI1YTg4LCAweDg3MDllNmIwLCAweGQ3ZTA3MTU2LCAweDRlMjlmZWE3LFxuICAgIDB4NjM2NmU1MmQsIDB4MDJkMWMwMDAsIDB4YzRhYzhlMDUsIDB4OTM3N2Y1NzEsIDB4MGMwNTM3MmEsIDB4NTc4NTM1ZjIsIDB4MjI2MWJlMDIsIDB4ZDY0MmEwYzksXG4gICAgMHhkZjEzYTI4MCwgMHg3NGI1NWJkMiwgMHg2ODIxOTljMCwgMHhkNDIxZTVlYywgMHg1M2ZiM2NlOCwgMHhjOGFkZWRiMywgMHgyOGE4N2ZjOSwgMHgzZDk1OTk4MSxcbiAgICAweDVjMWZmOTAwLCAweGZlMzhkMzk5LCAweDBjNGVmZjBiLCAweDA2MjQwN2VhLCAweGFhMmY0ZmIxLCAweDRmYjk2OTc2LCAweDkwYzc5NTA1LCAweGIwYThhNzc0LFxuICAgIDB4ZWY1NWExZmYsIDB4ZTU5Y2EyYzIsIDB4YTZiNjJkMjcsIDB4ZTY2YTQyNjMsIDB4ZGY2NTAwMWYsIDB4MGVjNTA5NjYsIDB4ZGZkZDU1YmMsIDB4MjlkZTA2NTUsXG4gICAgMHg5MTFlNzM5YSwgMHgxN2FmODk3NSwgMHgzMmM3OTExYywgMHg4OWY4OTQ2OCwgMHgwZDAxZTk4MCwgMHg1MjQ3NTVmNCwgMHgwM2I2M2NjOSwgMHgwY2M4NDRiMixcbiAgICAweGJjZjNmMGFhLCAweDg3YWMzNmU5LCAweGU1M2E3NDI2LCAweDAxYjNkODJiLCAweDFhOWU3NDQ5LCAweDY0ZWUyZDdlLCAweGNkZGJiMWRhLCAweDAxYzk0OTEwLFxuICAgIDB4Yjg2OGJmODAsIDB4MGQyNmYzZmQsIDB4OTM0MmVkZTcsIDB4MDRhNWMyODQsIDB4NjM2NzM3YjYsIDB4NTBmNWI2MTYsIDB4ZjI0NzY2ZTMsIDB4OGVjYTM2YzEsXG4gICAgMHgxMzZlMDVkYiwgMHhmZWYxODM5MSwgMHhmYjg4N2EzNywgMHhkNmU3ZjdkNCwgMHhjN2ZiN2RjOSwgMHgzMDYzZmNkZiwgMHhiNmY1ODlkZSwgMHhlYzI5NDFkYSxcbiAgICAweDI2ZTQ2Njk1LCAweGI3NTY2NDE5LCAweGY2NTRlZmM1LCAweGQwOGQ1OGI3LCAweDQ4OTI1NDAxLCAweGMxYmFjYjdmLCAweGU1ZmY1NTBmLCAweGI2MDgzMDQ5LFxuICAgIDB4NWJiNWQwZTgsIDB4ODdkNzJlNWEsIDB4YWI2YTZlZTEsIDB4MjIzYTY2Y2UsIDB4YzYyYmYzY2QsIDB4OWUwODg1ZjksIDB4NjhjYjNlNDcsIDB4MDg2YzAxMGYsXG4gICAgMHhhMjFkZTgyMCwgMHhkMThiNjlkZSwgMHhmM2Y2NTc3NywgMHhmYTAyYzNmNiwgMHg0MDdlZGFjMywgMHhjYmIzZDU1MCwgMHgxNzkzMDg0ZCwgMHhiMGQ3MGViYSxcbiAgICAweDBhYjM3OGQ1LCAweGQ5NTFmYjBjLCAweGRlZDdkYTU2LCAweDQxMjRiYmU0LCAweDk0Y2EwYjU2LCAweDBmNTc1NWQxLCAweGUwZTFlNTZlLCAweDYxODRiNWJlLFxuICAgIDB4NTgwYTI0OWYsIDB4OTRmNzRiYzAsIDB4ZTMyNzg4OGUsIDB4OWY3YjU1NjEsIDB4YzNkYzAyODAsIDB4MDU2ODc3MTUsIDB4NjQ2YzZiZDcsIDB4NDQ5MDRkYjMsXG4gICAgMHg2NmI0ZjBhMywgMHhjMGYxNjQ4YSwgMHg2OTdlZDVhZiwgMHg0OWU5MmZmNiwgMHgzMDllMzc0ZiwgMHgyY2I2MzU2YSwgMHg4NTgwODU3MywgMHg0OTkxZjg0MCxcbiAgICAweDc2ZjBhZTAyLCAweDA4M2JlODRkLCAweDI4NDIxYzlhLCAweDQ0NDg5NDA2LCAweDczNmU0Y2I4LCAweGMxMDkyOTEwLCAweDhiYzk1ZmM2LCAweDdkODY5Y2Y0LFxuICAgIDB4MTM0ZjYxNmYsIDB4MmU3NzExOGQsIDB4YjMxYjJiZTEsIDB4YWE5MGI0NzIsIDB4M2NhNWQ3MTcsIDB4N2QxNjFiYmEsIDB4OWNhZDkwMTAsIDB4YWY0NjJiYTIsXG4gICAgMHg5ZmU0NTlkMiwgMHg0NWQzNDU1OSwgMHhkOWYyZGExMywgMHhkYmM2NTQ4NywgMHhmM2U0Zjk0ZSwgMHgxNzZkNDg2ZiwgMHgwOTdjMTNlYSwgMHg2MzFkYTVjNyxcbiAgICAweDQ0NWY3MzgyLCAweDE3NTY4M2Y0LCAweGNkYzY2YTk3LCAweDcwYmUwMjg4LCAweGIzY2RjZjcyLCAweDZlNWRkMmYzLCAweDIwOTM2MDc5LCAweDQ1OWI4MGE1LFxuICAgIDB4YmU2MGUyZGIsIDB4YTljMjMxMDEsIDB4ZWJhNTMxNWMsIDB4MjI0ZTQyZjIsIDB4MWM1YzE1NzIsIDB4ZjY3MjFiMmMsIDB4MWFkMmZmZjMsIDB4OGMyNTQwNGUsXG4gICAgMHgzMjRlZDcyZiwgMHg0MDY3YjdmZCwgMHgwNTIzMTM4ZSwgMHg1Y2EzYmM3OCwgMHhkYzBmZDY2ZSwgMHg3NTkyMjI4MywgMHg3ODRkNmIxNywgMHg1OGViYjE2ZSxcbiAgICAweDQ0MDk0Zjg1LCAweDNmNDgxZDg3LCAweGZjZmVhZTdiLCAweDc3YjVmZjc2LCAweDhjMjMwMmJmLCAweGFhZjQ3NTU2LCAweDVmNDZiMDJhLCAweDJiMDkyODAxLFxuICAgIDB4M2QzOGY1ZjcsIDB4MGNhODFmMzYsIDB4NTJhZjRhOGEsIDB4NjZkNWU3YzAsIDB4ZGYzYjA4NzQsIDB4OTUwNTUxMTAsIDB4MWI1YWQ3YTgsIDB4ZjYxZWQ1YWQsXG4gICAgMHg2Y2Y2ZTQ3OSwgMHgyMDc1ODE4NCwgMHhkMGNlZmE2NSwgMHg4OGY3YmU1OCwgMHg0YTA0NjgyNiwgMHgwZmY2ZjhmMywgMHhhMDljN2Y3MCwgMHg1MzQ2YWJhMCxcbiAgICAweDVjZTk2YzI4LCAweGUxNzZlZGEzLCAweDZiYWMzMDdmLCAweDM3NjgyOWQyLCAweDg1MzYwZmE5LCAweDE3ZTNmZTJhLCAweDI0Yjc5NzY3LCAweGY1YTk2YjIwLFxuICAgIDB4ZDZjZDI1OTUsIDB4NjhmZjFlYmYsIDB4NzU1NTQ0MmMsIDB4ZjE5ZjA2YmUsIDB4ZjllMDY1OWEsIDB4ZWViOTQ5MWQsIDB4MzQwMTA3MTgsIDB4YmIzMGNhYjgsXG4gICAgMHhlODIyZmUxNSwgMHg4ODU3MDk4MywgMHg3NTBlNjI0OSwgMHhkYTYyN2U1NSwgMHg1ZTc2ZmZhOCwgMHhiMTUzNDU0NiwgMHg2ZDQ3ZGUwOCwgMHhlZmU5ZTdkNCk7XG5cbiAgc0JveFs1XSA9IG5ldyBBcnJheShcbiAgICAweGY2ZmE4ZjlkLCAweDJjYWM2Y2UxLCAweDRjYTM0ODY3LCAweGUyMzM3ZjdjLCAweDk1ZGIwOGU3LCAweDAxNjg0M2I0LCAweGVjZWQ1Y2JjLCAweDMyNTU1M2FjLFxuICAgIDB4YmY5ZjA5NjAsIDB4ZGZhMWUyZWQsIDB4ODNmMDU3OWQsIDB4NjNlZDg2YjksIDB4MWFiNmE2YjgsIDB4ZGU1ZWJlMzksIDB4ZjM4ZmY3MzIsIDB4ODk4OWIxMzgsXG4gICAgMHgzM2YxNDk2MSwgMHhjMDE5MzdiZCwgMHhmNTA2YzZkYSwgMHhlNDYyNWU3ZSwgMHhhMzA4ZWE5OSwgMHg0ZTIzZTMzYywgMHg3OWNiZDdjYywgMHg0OGExNDM2NyxcbiAgICAweGEzMTQ5NjE5LCAweGZlYzk0YmQ1LCAweGExMTQxNzRhLCAweGVhYTAxODY2LCAweGEwODRkYjJkLCAweDA5YTg0ODZmLCAweGE4ODg2MTRhLCAweDI5MDBhZjk4LFxuICAgIDB4MDE2NjU5OTEsIDB4ZTE5OTI4NjMsIDB4YzhmMzBjNjAsIDB4MmU3OGVmM2MsIDB4ZDBkNTE5MzIsIDB4Y2YwZmVjMTQsIDB4ZjdjYTA3ZDIsIDB4ZDBhODIwNzIsXG4gICAgMHhmZDQxMTk3ZSwgMHg5MzA1YTZiMCwgMHhlODZiZTNkYSwgMHg3NGJlZDNjZCwgMHgzNzJkYTUzYywgMHg0YzdmNDQ0OCwgMHhkYWI1ZDQ0MCwgMHg2ZGJhMGVjMyxcbiAgICAweDA4MzkxOWE3LCAweDlmYmFlZWQ5LCAweDQ5ZGJjZmIwLCAweDRlNjcwYzUzLCAweDVjM2Q5YzAxLCAweDY0YmRiOTQxLCAweDJjMGU2MzZhLCAweGJhN2RkOWNkLFxuICAgIDB4ZWE2ZjczODgsIDB4ZTcwYmM3NjIsIDB4MzVmMjlhZGIsIDB4NWM0Y2RkOGQsIDB4ZjBkNDhkOGMsIDB4Yjg4MTUzZTIsIDB4MDhhMTk4NjYsIDB4MWFlMmVhYzgsXG4gICAgMHgyODRjYWY4OSwgMHhhYTkyODIyMywgMHg5MzM0YmU1MywgMHgzYjNhMjFiZiwgMHgxNjQzNGJlMywgMHg5YWVhMzkwNiwgMHhlZmU4YzM2ZSwgMHhmODkwY2RkOSxcbiAgICAweDgwMjI2ZGFlLCAweGMzNDBhNGEzLCAweGRmN2U5YzA5LCAweGE2OTRhODA3LCAweDViN2M1ZWNjLCAweDIyMWRiM2E2LCAweDlhNjlhMDJmLCAweDY4ODE4YTU0LFxuICAgIDB4Y2ViMjI5NmYsIDB4NTNjMDg0M2EsIDB4ZmU4OTM2NTUsIDB4MjViZmU2OGEsIDB4YjQ2MjhhYmMsIDB4Y2YyMjJlYmYsIDB4MjVhYzZmNDgsIDB4YTlhOTkzODcsXG4gICAgMHg1M2JkZGI2NSwgMHhlNzZmZmJlNywgMHhlOTY3ZmQ3OCwgMHgwYmE5MzU2MywgMHg4ZTM0MmJjMSwgMHhlOGExMWJlOSwgMHg0OTgwNzQwZCwgMHhjODA4N2RmYyxcbiAgICAweDhkZTRiZjk5LCAweGExMTEwMWEwLCAweDdmZDM3OTc1LCAweGRhNWEyNmMwLCAweGU4MWY5OTRmLCAweDk1MjhjZDg5LCAweGZkMzM5ZmVkLCAweGI4NzgzNGJmLFxuICAgIDB4NWYwNDQ1NmQsIDB4MjIyNTg2OTgsIDB4YzljNGM4M2IsIDB4MmRjMTU2YmUsIDB4NGY2MjhkYWEsIDB4NTdmNTVlYzUsIDB4ZTIyMjBhYmUsIDB4ZDI5MTZlYmYsXG4gICAgMHg0ZWM3NWI5NSwgMHgyNGYyYzNjMCwgMHg0MmQxNWQ5OSwgMHhjZDBkN2ZhMCwgMHg3YjZlMjdmZiwgMHhhOGRjOGFmMCwgMHg3MzQ1YzEwNiwgMHhmNDFlMjMyZixcbiAgICAweDM1MTYyMzg2LCAweGU2ZWE4OTI2LCAweDMzMzNiMDk0LCAweDE1N2VjNmYyLCAweDM3MmI3NGFmLCAweDY5MjU3M2U0LCAweGU5YTlkODQ4LCAweGYzMTYwMjg5LFxuICAgIDB4M2E2MmVmMWQsIDB4YTc4N2UyMzgsIDB4ZjNhNWY2NzYsIDB4NzQzNjQ4NTMsIDB4MjA5NTEwNjMsIDB4NDU3NjY5OGQsIDB4YjZmYWQ0MDcsIDB4NTkyYWY5NTAsXG4gICAgMHgzNmY3MzUyMywgMHg0Y2ZiNmU4NywgMHg3ZGE0Y2VjMCwgMHg2YzE1MmRhYSwgMHhjYjAzOTZhOCwgMHhjNTBkZmU1ZCwgMHhmY2Q3MDdhYiwgMHgwOTIxYzQyZixcbiAgICAweDg5ZGZmMGJiLCAweDVmZTJiZTc4LCAweDQ0OGY0ZjMzLCAweDc1NDYxM2M5LCAweDJiMDVkMDhkLCAweDQ4YjlkNTg1LCAweGRjMDQ5NDQxLCAweGM4MDk4ZjliLFxuICAgIDB4N2RlZGU3ODYsIDB4YzM5YTMzNzMsIDB4NDI0MTAwMDUsIDB4NmEwOTE3NTEsIDB4MGVmM2M4YTYsIDB4ODkwMDcyZDYsIDB4MjgyMDc2ODIsIDB4YTlhOWY3YmUsXG4gICAgMHhiZjMyNjc5ZCwgMHhkNDViNWI3NSwgMHhiMzUzZmQwMCwgMHhjYmIwZTM1OCwgMHg4MzBmMjIwYSwgMHgxZjhmYjIxNCwgMHhkMzcyY2YwOCwgMHhjYzNjNGExMyxcbiAgICAweDhjZjYzMTY2LCAweDA2MWM4N2JlLCAweDg4Yzk4Zjg4LCAweDYwNjJlMzk3LCAweDQ3Y2Y4ZTdhLCAweGI2Yzg1MjgzLCAweDNjYzJhY2ZiLCAweDNmYzA2OTc2LFxuICAgIDB4NGU4ZjAyNTIsIDB4NjRkODMxNGQsIDB4ZGEzODcwZTMsIDB4MWU2NjU0NTksIDB4YzEwOTA4ZjAsIDB4NTEzMDIxYTUsIDB4NmM1YjY4YjcsIDB4ODIyZjhhYTAsXG4gICAgMHgzMDA3Y2QzZSwgMHg3NDcxOWVlZiwgMHhkYzg3MjY4MSwgMHgwNzMzNDBkNCwgMHg3ZTQzMmZkOSwgMHgwYzVlYzI0MSwgMHg4ODA5Mjg2YywgMHhmNTkyZDg5MSxcbiAgICAweDA4YTkzMGY2LCAweDk1N2VmMzA1LCAweGI3ZmJmZmJkLCAweGMyNjZlOTZmLCAweDZmZTRhYzk4LCAweGIxNzNlY2MwLCAweGJjNjBiNDJhLCAweDk1MzQ5OGRhLFxuICAgIDB4ZmJhMWFlMTIsIDB4MmQ0YmQ3MzYsIDB4MGYyNWZhYWIsIDB4YTRmM2ZjZWIsIDB4ZTI5NjkxMjMsIDB4MjU3ZjBjM2QsIDB4OTM0OGFmNDksIDB4MzYxNDAwYmMsXG4gICAgMHhlODgxNmY0YSwgMHgzODE0ZjIwMCwgMHhhM2Y5NDA0MywgMHg5YzdhNTRjMiwgMHhiYzcwNGY1NywgMHhkYTQxZTdmOSwgMHhjMjVhZDMzYSwgMHg1NGY0YTA4NCxcbiAgICAweGIxN2Y1NTA1LCAweDU5MzU3Y2JlLCAweGVkYmQxNWM4LCAweDdmOTdjNWFiLCAweGJhNWFjN2I1LCAweGI2ZjZkZWFmLCAweDNhNDc5YzNhLCAweDUzMDJkYTI1LFxuICAgIDB4NjUzZDdlNmEsIDB4NTQyNjhkNDksIDB4NTFhNDc3ZWEsIDB4NTAxN2Q1NWIsIDB4ZDdkMjVkODgsIDB4NDQxMzZjNzYsIDB4MDQwNGE4YzgsIDB4YjhlNWExMjEsXG4gICAgMHhiODFhOTI4YSwgMHg2MGVkNTg2OSwgMHg5N2M1NWI5NiwgMHhlYWVjOTkxYiwgMHgyOTkzNTkxMywgMHgwMWZkYjdmMSwgMHgwODhlOGRmYSwgMHg5YWI2ZjZmNSxcbiAgICAweDNiNGNiZjlmLCAweDRhNWRlM2FiLCAweGU2MDUxZDM1LCAweGEwZTFkODU1LCAweGQzNmI0Y2YxLCAweGY1NDRlZGViLCAweGIwZTkzNTI0LCAweGJlYmI4ZmJkLFxuICAgIDB4YTJkNzYyY2YsIDB4NDljOTJmNTQsIDB4MzhiNWYzMzEsIDB4NzEyOGE0NTQsIDB4NDgzOTI5MDUsIDB4YTY1YjFkYjgsIDB4ODUxYzk3YmQsIDB4ZDY3NWNmMmYpO1xuXG4gIHNCb3hbNl0gPSBuZXcgQXJyYXkoXG4gICAgMHg4NWUwNDAxOSwgMHgzMzJiZjU2NywgMHg2NjJkYmZmZiwgMHhjZmM2NTY5MywgMHgyYThkN2Y2ZiwgMHhhYjliYzkxMiwgMHhkZTYwMDhhMSwgMHgyMDI4ZGExZixcbiAgICAweDAyMjdiY2U3LCAweDRkNjQyOTE2LCAweDE4ZmFjMzAwLCAweDUwZjE4YjgyLCAweDJjYjJjYjExLCAweGIyMzJlNzVjLCAweDRiMzY5NWYyLCAweGIyODcwN2RlLFxuICAgIDB4YTA1ZmJjZjYsIDB4Y2Q0MTgxZTksIDB4ZTE1MDIxMGMsIDB4ZTI0ZWYxYmQsIDB4YjE2OGMzODEsIDB4ZmRlNGU3ODksIDB4NWM3OWIwZDgsIDB4MWU4YmZkNDMsXG4gICAgMHg0ZDQ5NTAwMSwgMHgzOGJlNDM0MSwgMHg5MTNjZWUxZCwgMHg5MmE3OWMzZiwgMHgwODk3NjZiZSwgMHhiYWVlYWRmNCwgMHgxMjg2YmVjZiwgMHhiNmVhY2IxOSxcbiAgICAweDI2NjBjMjAwLCAweDc1NjViZGU0LCAweDY0MjQxZjdhLCAweDgyNDhkY2E5LCAweGMzYjNhZDY2LCAweDI4MTM2MDg2LCAweDBiZDhkZmE4LCAweDM1NmQxY2YyLFxuICAgIDB4MTA3Nzg5YmUsIDB4YjNiMmU5Y2UsIDB4MDUwMmFhOGYsIDB4MGJjMDM1MWUsIDB4MTY2YmY1MmEsIDB4ZWIxMmZmODIsIDB4ZTM0ODY5MTEsIDB4ZDM0ZDc1MTYsXG4gICAgMHg0ZTdiM2FmZiwgMHg1ZjQzNjcxYiwgMHg5Y2Y2ZTAzNywgMHg0OTgxYWM4MywgMHgzMzQyNjZjZSwgMHg4YzkzNDFiNywgMHhkMGQ4NTRjMCwgMHhjYjNhNmM4OCxcbiAgICAweDQ3YmMyODI5LCAweDQ3MjViYTM3LCAweGE2NmFkMjJiLCAweDdhZDYxZjFlLCAweDBjNWNiYWZhLCAweDQ0MzdmMTA3LCAweGI2ZTc5OTYyLCAweDQyZDJkODE2LFxuICAgIDB4MGE5NjEyODgsIDB4ZTFhNWMwNmUsIDB4MTM3NDllNjcsIDB4NzJmYzA4MWEsIDB4YjFkMTM5ZjcsIDB4Zjk1ODM3NDUsIDB4Y2YxOWRmNTgsIDB4YmVjM2Y3NTYsXG4gICAgMHhjMDZlYmEzMCwgMHgwNzIxMWIyNCwgMHg0NWMyODgyOSwgMHhjOTVlMzE3ZiwgMHhiYzhlYzUxMSwgMHgzOGJjNDZlOSwgMHhjNmU2ZmExNCwgMHhiYWU4NTg0YSxcbiAgICAweGFkNGViYzQ2LCAweDQ2OGY1MDhiLCAweDc4Mjk0MzVmLCAweGYxMjQxODNiLCAweDgyMWRiYTlmLCAweGFmZjYwZmY0LCAweGVhMmM0ZTZkLCAweDE2ZTM5MjY0LFxuICAgIDB4OTI1NDRhOGIsIDB4MDA5YjRmYzMsIDB4YWJhNjhjZWQsIDB4OWFjOTZmNzgsIDB4MDZhNWI3OWEsIDB4YjI4NTZlNmUsIDB4MWFlYzNjYTksIDB4YmU4Mzg2ODgsXG4gICAgMHgwZTA4MDRlOSwgMHg1NWYxYmU1NiwgMHhlN2U1MzYzYiwgMHhiM2ExZjI1ZCwgMHhmN2RlYmI4NSwgMHg2MWZlMDMzYywgMHgxNjc0NjIzMywgMHgzYzAzNGMyOCxcbiAgICAweGRhNmQwYzc0LCAweDc5YWFjNTZjLCAweDNjZTRlMWFkLCAweDUxZjBjODAyLCAweDk4ZjhmMzVhLCAweDE2MjZhNDlmLCAweGVlZDgyYjI5LCAweDFkMzgyZmUzLFxuICAgIDB4MGM0ZmI5OWEsIDB4YmIzMjU3NzgsIDB4M2VjNmQ5N2IsIDB4NmU3N2E2YTksIDB4Y2I2NThiNWMsIDB4ZDQ1MjMwYzcsIDB4MmJkMTQwOGIsIDB4NjBjMDNlYjcsXG4gICAgMHhiOTA2OGQ3OCwgMHhhMzM3NTRmNCwgMHhmNDMwYzg3ZCwgMHhjOGE3MTMwMiwgMHhiOTZkOGMzMiwgMHhlYmQ0ZTdiZSwgMHhiZThiOWQyZCwgMHg3OTc5ZmIwNixcbiAgICAweGU3MjI1MzA4LCAweDhiNzVjZjc3LCAweDExZWY4ZGE0LCAweGUwODNjODU4LCAweDhkNmI3ODZmLCAweDVhNjMxN2E2LCAweGZhNWNmN2EwLCAweDVkZGEwMDMzLFxuICAgIDB4ZjI4ZWJmYjAsIDB4ZjViOWMzMTAsIDB4YTBlYWMyODAsIDB4MDhiOTc2N2EsIDB4YTNkOWQyYjAsIDB4NzlkMzQyMTcsIDB4MDIxYTcxOGQsIDB4OWFjNjMzNmEsXG4gICAgMHgyNzExZmQ2MCwgMHg0MzgwNTBlMywgMHgwNjk5MDhhOCwgMHgzZDdmZWRjNCwgMHg4MjZkMmJlZiwgMHg0ZWViODQ3NiwgMHg0ODhkY2YyNSwgMHgzNmM5ZDU2NixcbiAgICAweDI4ZTc0ZTQxLCAweGMyNjEwYWNhLCAweDNkNDlhOWNmLCAweGJhZTNiOWRmLCAweGI2NWY4ZGU2LCAweDkyYWVhZjY0LCAweDNhYzdkNWU2LCAweDllYTgwNTA5LFxuICAgIDB4ZjIyYjAxN2QsIDB4YTQxNzNmNzAsIDB4ZGQxZTE2YzMsIDB4MTVlMGQ3ZjksIDB4NTBiMWI4ODcsIDB4MmI5ZjRmZDUsIDB4NjI1YWJhODIsIDB4NmEwMTc5NjIsXG4gICAgMHgyZWMwMWI5YywgMHgxNTQ4OGFhOSwgMHhkNzE2ZTc0MCwgMHg0MDA1NWEyYywgMHg5M2QyOWEyMiwgMHhlMzJkYmY5YSwgMHgwNTg3NDViOSwgMHgzNDUzZGMxZSxcbiAgICAweGQ2OTkyOTZlLCAweDQ5NmNmZjZmLCAweDFjOWY0OTg2LCAweGRmZTJlZDA3LCAweGI4NzI0MmQxLCAweDE5ZGU3ZWFlLCAweDA1M2U1NjFhLCAweDE1YWQ2ZjhjLFxuICAgIDB4NjY2MjZjMWMsIDB4NzE1NGMyNGMsIDB4ZWEwODJiMmEsIDB4OTNlYjI5MzksIDB4MTdkY2IwZjAsIDB4NThkNGYyYWUsIDB4OWVhMjk0ZmIsIDB4NTJjZjU2NGMsXG4gICAgMHg5ODgzZmU2NiwgMHgyZWM0MDU4MSwgMHg3NjM5NTNjMywgMHgwMWQ2NjkyZSwgMHhkM2EwYzEwOCwgMHhhMWU3MTYwZSwgMHhlNGYyZGZhNiwgMHg2OTNlZDI4NSxcbiAgICAweDc0OTA0Njk4LCAweDRjMmIwZWRkLCAweDRmNzU3NjU2LCAweDVkMzkzMzc4LCAweGExMzIyMzRmLCAweDNkMzIxYzVkLCAweGMzZjVlMTk0LCAweDRiMjY5MzAxLFxuICAgIDB4Yzc5ZjAyMmYsIDB4M2M5OTdlN2UsIDB4NWU0Zjk1MDQsIDB4M2ZmYWZiYmQsIDB4NzZmN2FkMGUsIDB4Mjk2NjkzZjQsIDB4M2QxZmNlNmYsIDB4YzYxZTQ1YmUsXG4gICAgMHhkM2I1YWIzNCwgMHhmNzJiZjliNywgMHgxYjA0MzRjMCwgMHg0ZTcyYjU2NywgMHg1NTkyYTMzZCwgMHhiNTIyOTMwMSwgMHhjZmQyYTg3ZiwgMHg2MGFlYjc2NyxcbiAgICAweDE4MTQzODZiLCAweDMwYmNjMzNkLCAweDM4YTBjMDdkLCAweGZkMTYwNmYyLCAweGMzNjM1MTliLCAweDU4OWRkMzkwLCAweDU0NzlmOGU2LCAweDFjYjhkNjQ3LFxuICAgIDB4OTdmZDYxYTksIDB4ZWE3NzU5ZjQsIDB4MmQ1NzUzOWQsIDB4NTY5YTU4Y2YsIDB4ZTg0ZTYzYWQsIDB4NDYyZTFiNzgsIDB4NjU4MGY4N2UsIDB4ZjM4MTc5MTQsXG4gICAgMHg5MWRhNTVmNCwgMHg0MGEyMzBmMywgMHhkMTk4OGYzNSwgMHhiNmUzMThkMiwgMHgzZmZhNTBiYywgMHgzZDQwZjAyMSwgMHhjM2MwYmRhZSwgMHg0OTU4YzI0YyxcbiAgICAweDUxOGYzNmIyLCAweDg0YjFkMzcwLCAweDBmZWRjZTgzLCAweDg3OGRkYWRhLCAweGYyYTI3OWM3LCAweDk0ZTAxYmU4LCAweDkwNzE2ZjRiLCAweDk1NGI4YWEzKTtcblxuICBzQm94WzddID0gbmV3IEFycmF5KFxuICAgIDB4ZTIxNjMwMGQsIDB4YmJkZGZmZmMsIDB4YTdlYmRhYmQsIDB4MzU2NDgwOTUsIDB4Nzc4OWY4YjcsIDB4ZTZjMTEyMWIsIDB4MGUyNDE2MDAsIDB4MDUyY2U4YjUsXG4gICAgMHgxMWE5Y2ZiMCwgMHhlNTk1MmYxMSwgMHhlY2U3OTkwYSwgMHg5Mzg2ZDE3NCwgMHgyYTQyOTMxYywgMHg3NmUzODExMSwgMHhiMTJkZWYzYSwgMHgzN2RkZGRmYyxcbiAgICAweGRlOWFkZWIxLCAweDBhMGNjMzJjLCAweGJlMTk3MDI5LCAweDg0YTAwOTQwLCAweGJiMjQzYTBmLCAweGI0ZDEzN2NmLCAweGI0NGU3OWYwLCAweDA0OWVlZGZkLFxuICAgIDB4MGIxNWExNWQsIDB4NDgwZDMxNjgsIDB4OGJiYmRlNWEsIDB4NjY5ZGVkNDIsIDB4YzdlY2U4MzEsIDB4M2Y4Zjk1ZTcsIDB4NzJkZjE5MWIsIDB4NzU4MDMzMGQsXG4gICAgMHg5NDA3NDI1MSwgMHg1YzdkY2RmYSwgMHhhYmJlNmQ2MywgMHhhYTQwMjE2NCwgMHhiMzAxZDQwYSwgMHgwMmU3ZDFjYSwgMHg1MzU3MWRhZSwgMHg3YTMxODJhMixcbiAgICAweDEyYThkZGVjLCAweGZkYWEzMzVkLCAweDE3NmY0M2U4LCAweDcxZmI0NmQ0LCAweDM4MTI5MDIyLCAweGNlOTQ5YWQ0LCAweGI4NDc2OWFkLCAweDk2NWJkODYyLFxuICAgIDB4ODJmM2QwNTUsIDB4NjZmYjk3NjcsIDB4MTViODBiNGUsIDB4MWQ1YjQ3YTAsIDB4NGNmZGUwNmYsIDB4YzI4ZWM0YjgsIDB4NTdlODcyNmUsIDB4NjQ3YTc4ZmMsXG4gICAgMHg5OTg2NWQ0NCwgMHg2MDhiZDU5MywgMHg2YzIwMGUwMywgMHgzOWRjNWZmNiwgMHg1ZDBiMDBhMywgMHhhZTYzYWZmMiwgMHg3ZThiZDYzMiwgMHg3MDEwOGMwYyxcbiAgICAweGJiZDM1MDQ5LCAweDI5OThkZjA0LCAweDk4MGNmNDJhLCAweDliNmRmNDkxLCAweDllN2VkZDUzLCAweDA2OTE4NTQ4LCAweDU4Y2I3ZTA3LCAweDNiNzRlZjJlLFxuICAgIDB4NTIyZmZmYjEsIDB4ZDI0NzA4Y2MsIDB4MWM3ZTI3Y2QsIDB4YTRlYjIxNWIsIDB4M2NmMWQyZTIsIDB4MTliNDdhMzgsIDB4NDI0Zjc2MTgsIDB4MzU4NTYwMzksXG4gICAgMHg5ZDE3ZGVlNywgMHgyN2ViMzVlNiwgMHhjOWFmZjY3YiwgMHgzNmJhZjViOCwgMHgwOWM0NjdjZCwgMHhjMTg5MTBiMSwgMHhlMTFkYmY3YiwgMHgwNmNkMWFmOCxcbiAgICAweDcxNzBjNjA4LCAweDJkNWUzMzU0LCAweGQ0ZGU0OTVhLCAweDY0YzZkMDA2LCAweGJjYzBjNjJjLCAweDNkZDAwZGIzLCAweDcwOGY4ZjM0LCAweDc3ZDUxYjQyLFxuICAgIDB4MjY0ZjYyMGYsIDB4MjRiOGQyYmYsIDB4MTVjMWI3OWUsIDB4NDZhNTI1NjQsIDB4ZjhkN2U1NGUsIDB4M2UzNzgxNjAsIDB4Nzg5NWNkYTUsIDB4ODU5YzE1YTUsXG4gICAgMHhlNjQ1OTc4OCwgMHhjMzdiYzc1ZiwgMHhkYjA3YmEwYywgMHgwNjc2YTNhYiwgMHg3ZjIyOWIxZSwgMHgzMTg0MmU3YiwgMHgyNDI1OWZkNywgMHhmOGJlZjQ3MixcbiAgICAweDgzNWZmY2I4LCAweDZkZjRjMWYyLCAweDk2ZjViMTk1LCAweGZkMGFmMGZjLCAweGIwZmUxMzRjLCAweGUyNTA2ZDNkLCAweDRmOWIxMmVhLCAweGYyMTVmMjI1LFxuICAgIDB4YTIyMzczNmYsIDB4OWZiNGM0MjgsIDB4MjVkMDQ5NzksIDB4MzRjNzEzZjgsIDB4YzQ2MTgxODcsIDB4ZWE3YTZlOTgsIDB4N2NkMTZlZmMsIDB4MTQzNjg3NmMsXG4gICAgMHhmMTU0NDEwNywgMHhiZWRlZWUxNCwgMHg1NmU5YWYyNywgMHhhMDRhYTQ0MSwgMHgzY2Y3Yzg5OSwgMHg5MmVjYmFlNiwgMHhkZDY3MDE2ZCwgMHgxNTE2ODJlYixcbiAgICAweGE4NDJlZWRmLCAweGZkYmE2MGI0LCAweGYxOTA3Yjc1LCAweDIwZTMwMzBmLCAweDI0ZDhjMjllLCAweGUxMzk2NzNiLCAweGVmYTYzZmI4LCAweDcxODczMDU0LFxuICAgIDB4YjZmMmNmM2IsIDB4OWYzMjY0NDIsIDB4Y2IxNWE0Y2MsIDB4YjAxYTQ1MDQsIDB4ZjFlNDdkOGQsIDB4ODQ0YTFiZTUsIDB4YmFlN2RmZGMsIDB4NDJjYmRhNzAsXG4gICAgMHhjZDdkYWUwYSwgMHg1N2U4NWI3YSwgMHhkNTNmNWFmNiwgMHgyMGNmNGQ4YywgMHhjZWE0ZDQyOCwgMHg3OWQxMzBhNCwgMHgzNDg2ZWJmYiwgMHgzM2QzY2RkYyxcbiAgICAweDc3ODUzYjUzLCAweDM3ZWZmY2I1LCAweGM1MDY4Nzc4LCAweGU1ODBiM2U2LCAweDRlNjhiOGY0LCAweGM1YzhiMzdlLCAweDBkODA5ZWEyLCAweDM5OGZlYjdjLFxuICAgIDB4MTMyYTRmOTQsIDB4NDNiNzk1MGUsIDB4MmZlZTdkMWMsIDB4MjIzNjEzYmQsIDB4ZGQwNmNhYTIsIDB4MzdkZjkzMmIsIDB4YzQyNDgyODksIDB4YWNmM2ViYzMsXG4gICAgMHg1NzE1ZjZiNywgMHhlZjM0NzhkZCwgMHhmMjY3NjE2ZiwgMHhjMTQ4Y2JlNCwgMHg5MDUyODE1ZSwgMHg1ZTQxMGZhYiwgMHhiNDhhMjQ2NSwgMHgyZWRhN2ZhNCxcbiAgICAweGU4N2I0MGU0LCAweGU5OGVhMDg0LCAweDU4ODllOWUxLCAweGVmZDM5MGZjLCAweGRkMDdkMzViLCAweGRiNDg1Njk0LCAweDM4ZDdlNWIyLCAweDU3NzIwMTAxLFxuICAgIDB4NzMwZWRlYmMsIDB4NWI2NDMxMTMsIDB4OTQ5MTdlNGYsIDB4NTAzYzJmYmEsIDB4NjQ2ZjEyODIsIDB4NzUyM2QyNGEsIDB4ZTA3Nzk2OTUsIDB4ZjljMTdhOGYsXG4gICAgMHg3YTViMjEyMSwgMHhkMTg3Yjg5NiwgMHgyOTI2M2E0ZCwgMHhiYTUxMGNkZiwgMHg4MWY0N2M5ZiwgMHhhZDExNjNlZCwgMHhlYTdiNTk2NSwgMHgxYTAwNzI2ZSxcbiAgICAweDExNDAzMDkyLCAweDAwZGE2ZDc3LCAweDRhMGNkZDYxLCAweGFkMWY0NjAzLCAweDYwNWJkZmIwLCAweDllZWRjMzY0LCAweDIyZWJlNmE4LCAweGNlZTdkMjhhLFxuICAgIDB4YTBlNzM2YTAsIDB4NTU2NGE2YjksIDB4MTA4NTMyMDksIDB4YzdlYjhmMzcsIDB4MmRlNzA1Y2EsIDB4ODk1MTU3MGYsIDB4ZGYwOTgyMmIsIDB4YmQ2OTFhNmMsXG4gICAgMHhhYTEyZTRmMiwgMHg4NzQ1MWMwZiwgMHhlMGY2YTI3YSwgMHgzYWRhNDgxOSwgMHg0Y2YxNzY0ZiwgMHgwZDc3MWMyYiwgMHg2N2NkYjE1NiwgMHgzNTBkODM4NCxcbiAgICAweDU5MzhmYTBmLCAweDQyMzk5ZWYzLCAweDM2OTk3YjA3LCAweDBlODQwOTNkLCAweDRhYTkzZTYxLCAweDgzNjBkODdiLCAweDFmYTk4YjBjLCAweDExNDkzODJjLFxuICAgIDB4ZTk3NjI1YTUsIDB4MDYxNGQxYjcsIDB4MGUyNTI0NGIsIDB4MGM3NjgzNDcsIDB4NTg5ZThkODIsIDB4MGQyMDU5ZDEsIDB4YTQ2NmJiMWUsIDB4ZjhkYTBhODIsXG4gICAgMHgwNGYxOTEzMCwgMHhiYTZlNGVjMCwgMHg5OTI2NTE2NCwgMHgxZWU3MjMwZCwgMHg1MGIyYWQ4MCwgMHhlYWVlNjgwMSwgMHg4ZGIyYTI4MywgMHhlYThiZjU5ZSk7XG5cbn07XG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG5mdW5jdGlvbiBjYXN0NShrZXkpIHtcbiAgdGhpcy5jYXN0NSA9IG5ldyBvcGVucGdwX3N5bWVuY19jYXN0NSgpO1xuICB0aGlzLmNhc3Q1LnNldEtleSh1dGlsLnN0cjJiaW4oa2V5KSk7XG5cbiAgdGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24oYmxvY2spIHtcbiAgICByZXR1cm4gdGhpcy5jYXN0NS5lbmNyeXB0KGJsb2NrKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGNhc3Q1O1xubW9kdWxlLmV4cG9ydHMuYmxvY2tTaXplID0gY2FzdDUucHJvdG90eXBlLmJsb2NrU2l6ZSA9IDg7XG5tb2R1bGUuZXhwb3J0cy5rZXlTaXplID0gY2FzdDUucHJvdG90eXBlLmtleVNpemUgPSAxNjtcbiIsIi8vUGF1bCBUZXJvLCBKdWx5IDIwMDFcbi8vaHR0cDovL3d3dy50ZXJvLmNvLnVrL2Rlcy9cbi8vXG4vL09wdGltaXNlZCBmb3IgcGVyZm9ybWFuY2Ugd2l0aCBsYXJnZSBibG9ja3MgYnkgTWljaGFlbCBIYXl3b3J0aCwgTm92ZW1iZXIgMjAwMVxuLy9odHRwOi8vd3d3Lm5ldGRlYWxpbmcuY29tXG4vL1xuLy8gTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIXG5cbi8vVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIgQU5EXG4vL0FOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRVxuLy9JTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRVxuLy9BUkUgRElTQ0xBSU1FRC4gIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1IgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRVxuLy9GT1IgQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTFxuLy9EQU1BR0VTIChJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EU1xuLy9PUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTilcbi8vSE9XRVZFUiBDQVVTRUQgQU5EIE9OIEFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1Rcbi8vTElBQklMSVRZLCBPUiBUT1JUIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWVxuLy9PVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GXG4vL1NVQ0ggREFNQUdFLlxuXG4vL2Rlc1xuLy90aGlzIHRha2VzIHRoZSBrZXksIHRoZSBtZXNzYWdlLCBhbmQgd2hldGhlciB0byBlbmNyeXB0IG9yIGRlY3J5cHRcblxuLyoqXG4gKiBAbW9kdWxlIGNyeXB0by9jaXBoZXIvZGVzXG4gKi9cblxuXG5mdW5jdGlvbiBkZXMoa2V5cywgbWVzc2FnZSwgZW5jcnlwdCwgbW9kZSwgaXYsIHBhZGRpbmcpIHtcbiAgLy9kZWNsYXJpbmcgdGhpcyBsb2NhbGx5IHNwZWVkcyB0aGluZ3MgdXAgYSBiaXRcbiAgdmFyIHNwZnVuY3Rpb24xID0gbmV3IEFycmF5KDB4MTAxMDQwMCwgMCwgMHgxMDAwMCwgMHgxMDEwNDA0LCAweDEwMTAwMDQsIDB4MTA0MDQsIDB4NCwgMHgxMDAwMCwgMHg0MDAsIDB4MTAxMDQwMCxcbiAgICAweDEwMTA0MDQsIDB4NDAwLCAweDEwMDA0MDQsIDB4MTAxMDAwNCwgMHgxMDAwMDAwLCAweDQsIDB4NDA0LCAweDEwMDA0MDAsIDB4MTAwMDQwMCwgMHgxMDQwMCwgMHgxMDQwMCwgMHgxMDEwMDAwLFxuICAgIDB4MTAxMDAwMCwgMHgxMDAwNDA0LCAweDEwMDA0LCAweDEwMDAwMDQsIDB4MTAwMDAwNCwgMHgxMDAwNCwgMCwgMHg0MDQsIDB4MTA0MDQsIDB4MTAwMDAwMCwgMHgxMDAwMCwgMHgxMDEwNDA0LCAweDQsXG4gICAgMHgxMDEwMDAwLCAweDEwMTA0MDAsIDB4MTAwMDAwMCwgMHgxMDAwMDAwLCAweDQwMCwgMHgxMDEwMDA0LCAweDEwMDAwLCAweDEwNDAwLCAweDEwMDAwMDQsIDB4NDAwLCAweDQsIDB4MTAwMDQwNCxcbiAgICAweDEwNDA0LCAweDEwMTA0MDQsIDB4MTAwMDQsIDB4MTAxMDAwMCwgMHgxMDAwNDA0LCAweDEwMDAwMDQsIDB4NDA0LCAweDEwNDA0LCAweDEwMTA0MDAsIDB4NDA0LCAweDEwMDA0MDAsXG4gICAgMHgxMDAwNDAwLCAwLCAweDEwMDA0LCAweDEwNDAwLCAwLCAweDEwMTAwMDQpO1xuICB2YXIgc3BmdW5jdGlvbjIgPSBuZXcgQXJyYXkoLTB4N2ZlZjdmZTAsIC0weDdmZmY4MDAwLCAweDgwMDAsIDB4MTA4MDIwLCAweDEwMDAwMCwgMHgyMCwgLTB4N2ZlZmZmZTAsIC0weDdmZmY3ZmUwLCAtXG4gICAgMHg3ZmZmZmZlMCwgLTB4N2ZlZjdmZTAsIC0weDdmZWY4MDAwLCAtMHg4MDAwMDAwMCwgLTB4N2ZmZjgwMDAsIDB4MTAwMDAwLCAweDIwLCAtMHg3ZmVmZmZlMCwgMHgxMDgwMDAsIDB4MTAwMDIwLCAtXG4gICAgMHg3ZmZmN2ZlMCwgMCwgLTB4ODAwMDAwMDAsIDB4ODAwMCwgMHgxMDgwMjAsIC0weDdmZjAwMDAwLCAweDEwMDAyMCwgLTB4N2ZmZmZmZTAsIDAsIDB4MTA4MDAwLCAweDgwMjAsIC0weDdmZWY4MDAwLCAtXG4gICAgMHg3ZmYwMDAwMCwgMHg4MDIwLCAwLCAweDEwODAyMCwgLTB4N2ZlZmZmZTAsIDB4MTAwMDAwLCAtMHg3ZmZmN2ZlMCwgLTB4N2ZmMDAwMDAsIC0weDdmZWY4MDAwLCAweDgwMDAsIC0weDdmZjAwMDAwLCAtXG4gICAgMHg3ZmZmODAwMCwgMHgyMCwgLTB4N2ZlZjdmZTAsIDB4MTA4MDIwLCAweDIwLCAweDgwMDAsIC0weDgwMDAwMDAwLCAweDgwMjAsIC0weDdmZWY4MDAwLCAweDEwMDAwMCwgLTB4N2ZmZmZmZTAsXG4gICAgMHgxMDAwMjAsIC0weDdmZmY3ZmUwLCAtMHg3ZmZmZmZlMCwgMHgxMDAwMjAsIDB4MTA4MDAwLCAwLCAtMHg3ZmZmODAwMCwgMHg4MDIwLCAtMHg4MDAwMDAwMCwgLTB4N2ZlZmZmZTAsIC1cbiAgICAweDdmZWY3ZmUwLCAweDEwODAwMCk7XG4gIHZhciBzcGZ1bmN0aW9uMyA9IG5ldyBBcnJheSgweDIwOCwgMHg4MDIwMjAwLCAwLCAweDgwMjAwMDgsIDB4ODAwMDIwMCwgMCwgMHgyMDIwOCwgMHg4MDAwMjAwLCAweDIwMDA4LCAweDgwMDAwMDgsXG4gICAgMHg4MDAwMDA4LCAweDIwMDAwLCAweDgwMjAyMDgsIDB4MjAwMDgsIDB4ODAyMDAwMCwgMHgyMDgsIDB4ODAwMDAwMCwgMHg4LCAweDgwMjAyMDAsIDB4MjAwLCAweDIwMjAwLCAweDgwMjAwMDAsXG4gICAgMHg4MDIwMDA4LCAweDIwMjA4LCAweDgwMDAyMDgsIDB4MjAyMDAsIDB4MjAwMDAsIDB4ODAwMDIwOCwgMHg4LCAweDgwMjAyMDgsIDB4MjAwLCAweDgwMDAwMDAsIDB4ODAyMDIwMCwgMHg4MDAwMDAwLFxuICAgIDB4MjAwMDgsIDB4MjA4LCAweDIwMDAwLCAweDgwMjAyMDAsIDB4ODAwMDIwMCwgMCwgMHgyMDAsIDB4MjAwMDgsIDB4ODAyMDIwOCwgMHg4MDAwMjAwLCAweDgwMDAwMDgsIDB4MjAwLCAwLFxuICAgIDB4ODAyMDAwOCwgMHg4MDAwMjA4LCAweDIwMDAwLCAweDgwMDAwMDAsIDB4ODAyMDIwOCwgMHg4LCAweDIwMjA4LCAweDIwMjAwLCAweDgwMDAwMDgsIDB4ODAyMDAwMCwgMHg4MDAwMjA4LCAweDIwOCxcbiAgICAweDgwMjAwMDAsIDB4MjAyMDgsIDB4OCwgMHg4MDIwMDA4LCAweDIwMjAwKTtcbiAgdmFyIHNwZnVuY3Rpb240ID0gbmV3IEFycmF5KDB4ODAyMDAxLCAweDIwODEsIDB4MjA4MSwgMHg4MCwgMHg4MDIwODAsIDB4ODAwMDgxLCAweDgwMDAwMSwgMHgyMDAxLCAwLCAweDgwMjAwMCxcbiAgICAweDgwMjAwMCwgMHg4MDIwODEsIDB4ODEsIDAsIDB4ODAwMDgwLCAweDgwMDAwMSwgMHgxLCAweDIwMDAsIDB4ODAwMDAwLCAweDgwMjAwMSwgMHg4MCwgMHg4MDAwMDAsIDB4MjAwMSwgMHgyMDgwLFxuICAgIDB4ODAwMDgxLCAweDEsIDB4MjA4MCwgMHg4MDAwODAsIDB4MjAwMCwgMHg4MDIwODAsIDB4ODAyMDgxLCAweDgxLCAweDgwMDA4MCwgMHg4MDAwMDEsIDB4ODAyMDAwLCAweDgwMjA4MSwgMHg4MSwgMCxcbiAgICAwLCAweDgwMjAwMCwgMHgyMDgwLCAweDgwMDA4MCwgMHg4MDAwODEsIDB4MSwgMHg4MDIwMDEsIDB4MjA4MSwgMHgyMDgxLCAweDgwLCAweDgwMjA4MSwgMHg4MSwgMHgxLCAweDIwMDAsIDB4ODAwMDAxLFxuICAgIDB4MjAwMSwgMHg4MDIwODAsIDB4ODAwMDgxLCAweDIwMDEsIDB4MjA4MCwgMHg4MDAwMDAsIDB4ODAyMDAxLCAweDgwLCAweDgwMDAwMCwgMHgyMDAwLCAweDgwMjA4MCk7XG4gIHZhciBzcGZ1bmN0aW9uNSA9IG5ldyBBcnJheSgweDEwMCwgMHgyMDgwMTAwLCAweDIwODAwMDAsIDB4NDIwMDAxMDAsIDB4ODAwMDAsIDB4MTAwLCAweDQwMDAwMDAwLCAweDIwODAwMDAsXG4gICAgMHg0MDA4MDEwMCwgMHg4MDAwMCwgMHgyMDAwMTAwLCAweDQwMDgwMTAwLCAweDQyMDAwMTAwLCAweDQyMDgwMDAwLCAweDgwMTAwLCAweDQwMDAwMDAwLCAweDIwMDAwMDAsIDB4NDAwODAwMDAsXG4gICAgMHg0MDA4MDAwMCwgMCwgMHg0MDAwMDEwMCwgMHg0MjA4MDEwMCwgMHg0MjA4MDEwMCwgMHgyMDAwMTAwLCAweDQyMDgwMDAwLCAweDQwMDAwMTAwLCAwLCAweDQyMDAwMDAwLCAweDIwODAxMDAsXG4gICAgMHgyMDAwMDAwLCAweDQyMDAwMDAwLCAweDgwMTAwLCAweDgwMDAwLCAweDQyMDAwMTAwLCAweDEwMCwgMHgyMDAwMDAwLCAweDQwMDAwMDAwLCAweDIwODAwMDAsIDB4NDIwMDAxMDAsXG4gICAgMHg0MDA4MDEwMCwgMHgyMDAwMTAwLCAweDQwMDAwMDAwLCAweDQyMDgwMDAwLCAweDIwODAxMDAsIDB4NDAwODAxMDAsIDB4MTAwLCAweDIwMDAwMDAsIDB4NDIwODAwMDAsIDB4NDIwODAxMDAsXG4gICAgMHg4MDEwMCwgMHg0MjAwMDAwMCwgMHg0MjA4MDEwMCwgMHgyMDgwMDAwLCAwLCAweDQwMDgwMDAwLCAweDQyMDAwMDAwLCAweDgwMTAwLCAweDIwMDAxMDAsIDB4NDAwMDAxMDAsIDB4ODAwMDAsIDAsXG4gICAgMHg0MDA4MDAwMCwgMHgyMDgwMTAwLCAweDQwMDAwMTAwKTtcbiAgdmFyIHNwZnVuY3Rpb242ID0gbmV3IEFycmF5KDB4MjAwMDAwMTAsIDB4MjA0MDAwMDAsIDB4NDAwMCwgMHgyMDQwNDAxMCwgMHgyMDQwMDAwMCwgMHgxMCwgMHgyMDQwNDAxMCwgMHg0MDAwMDAsXG4gICAgMHgyMDAwNDAwMCwgMHg0MDQwMTAsIDB4NDAwMDAwLCAweDIwMDAwMDEwLCAweDQwMDAxMCwgMHgyMDAwNDAwMCwgMHgyMDAwMDAwMCwgMHg0MDEwLCAwLCAweDQwMDAxMCwgMHgyMDAwNDAxMCxcbiAgICAweDQwMDAsIDB4NDA0MDAwLCAweDIwMDA0MDEwLCAweDEwLCAweDIwNDAwMDEwLCAweDIwNDAwMDEwLCAwLCAweDQwNDAxMCwgMHgyMDQwNDAwMCwgMHg0MDEwLCAweDQwNDAwMCwgMHgyMDQwNDAwMCxcbiAgICAweDIwMDAwMDAwLCAweDIwMDA0MDAwLCAweDEwLCAweDIwNDAwMDEwLCAweDQwNDAwMCwgMHgyMDQwNDAxMCwgMHg0MDAwMDAsIDB4NDAxMCwgMHgyMDAwMDAxMCwgMHg0MDAwMDAsIDB4MjAwMDQwMDAsXG4gICAgMHgyMDAwMDAwMCwgMHg0MDEwLCAweDIwMDAwMDEwLCAweDIwNDA0MDEwLCAweDQwNDAwMCwgMHgyMDQwMDAwMCwgMHg0MDQwMTAsIDB4MjA0MDQwMDAsIDAsIDB4MjA0MDAwMTAsIDB4MTAsIDB4NDAwMCxcbiAgICAweDIwNDAwMDAwLCAweDQwNDAxMCwgMHg0MDAwLCAweDQwMDAxMCwgMHgyMDAwNDAxMCwgMCwgMHgyMDQwNDAwMCwgMHgyMDAwMDAwMCwgMHg0MDAwMTAsIDB4MjAwMDQwMTApO1xuICB2YXIgc3BmdW5jdGlvbjcgPSBuZXcgQXJyYXkoMHgyMDAwMDAsIDB4NDIwMDAwMiwgMHg0MDAwODAyLCAwLCAweDgwMCwgMHg0MDAwODAyLCAweDIwMDgwMiwgMHg0MjAwODAwLCAweDQyMDA4MDIsXG4gICAgMHgyMDAwMDAsIDAsIDB4NDAwMDAwMiwgMHgyLCAweDQwMDAwMDAsIDB4NDIwMDAwMiwgMHg4MDIsIDB4NDAwMDgwMCwgMHgyMDA4MDIsIDB4MjAwMDAyLCAweDQwMDA4MDAsIDB4NDAwMDAwMixcbiAgICAweDQyMDAwMDAsIDB4NDIwMDgwMCwgMHgyMDAwMDIsIDB4NDIwMDAwMCwgMHg4MDAsIDB4ODAyLCAweDQyMDA4MDIsIDB4MjAwODAwLCAweDIsIDB4NDAwMDAwMCwgMHgyMDA4MDAsIDB4NDAwMDAwMCxcbiAgICAweDIwMDgwMCwgMHgyMDAwMDAsIDB4NDAwMDgwMiwgMHg0MDAwODAyLCAweDQyMDAwMDIsIDB4NDIwMDAwMiwgMHgyLCAweDIwMDAwMiwgMHg0MDAwMDAwLCAweDQwMDA4MDAsIDB4MjAwMDAwLFxuICAgIDB4NDIwMDgwMCwgMHg4MDIsIDB4MjAwODAyLCAweDQyMDA4MDAsIDB4ODAyLCAweDQwMDAwMDIsIDB4NDIwMDgwMiwgMHg0MjAwMDAwLCAweDIwMDgwMCwgMCwgMHgyLCAweDQyMDA4MDIsIDAsXG4gICAgMHgyMDA4MDIsIDB4NDIwMDAwMCwgMHg4MDAsIDB4NDAwMDAwMiwgMHg0MDAwODAwLCAweDgwMCwgMHgyMDAwMDIpO1xuICB2YXIgc3BmdW5jdGlvbjggPSBuZXcgQXJyYXkoMHgxMDAwMTA0MCwgMHgxMDAwLCAweDQwMDAwLCAweDEwMDQxMDQwLCAweDEwMDAwMDAwLCAweDEwMDAxMDQwLCAweDQwLCAweDEwMDAwMDAwLFxuICAgIDB4NDAwNDAsIDB4MTAwNDAwMDAsIDB4MTAwNDEwNDAsIDB4NDEwMDAsIDB4MTAwNDEwMDAsIDB4NDEwNDAsIDB4MTAwMCwgMHg0MCwgMHgxMDA0MDAwMCwgMHgxMDAwMDA0MCwgMHgxMDAwMTAwMCxcbiAgICAweDEwNDAsIDB4NDEwMDAsIDB4NDAwNDAsIDB4MTAwNDAwNDAsIDB4MTAwNDEwMDAsIDB4MTA0MCwgMCwgMCwgMHgxMDA0MDA0MCwgMHgxMDAwMDA0MCwgMHgxMDAwMTAwMCwgMHg0MTA0MCxcbiAgICAweDQwMDAwLCAweDQxMDQwLCAweDQwMDAwLCAweDEwMDQxMDAwLCAweDEwMDAsIDB4NDAsIDB4MTAwNDAwNDAsIDB4MTAwMCwgMHg0MTA0MCwgMHgxMDAwMTAwMCwgMHg0MCwgMHgxMDAwMDA0MCxcbiAgICAweDEwMDQwMDAwLCAweDEwMDQwMDQwLCAweDEwMDAwMDAwLCAweDQwMDAwLCAweDEwMDAxMDQwLCAwLCAweDEwMDQxMDQwLCAweDQwMDQwLCAweDEwMDAwMDQwLCAweDEwMDQwMDAwLCAweDEwMDAxMDAwLFxuICAgIDB4MTAwMDEwNDAsIDAsIDB4MTAwNDEwNDAsIDB4NDEwMDAsIDB4NDEwMDAsIDB4MTA0MCwgMHgxMDQwLCAweDQwMDQwLCAweDEwMDAwMDAwLCAweDEwMDQxMDAwKTtcblxuICAvL2NyZWF0ZSB0aGUgMTYgb3IgNDggc3Via2V5cyB3ZSB3aWxsIG5lZWRcbiAgdmFyIG0gPSAwLFxuICAgIGksIGosIHRlbXAsIHRlbXAyLCByaWdodDEsIHJpZ2h0MiwgbGVmdCwgcmlnaHQsIGxvb3Bpbmc7XG4gIHZhciBjYmNsZWZ0LCBjYmNsZWZ0MiwgY2JjcmlnaHQsIGNiY3JpZ2h0MlxuICB2YXIgZW5kbG9vcCwgbG9vcGluYztcbiAgdmFyIGxlbiA9IG1lc3NhZ2UubGVuZ3RoO1xuICB2YXIgY2h1bmsgPSAwO1xuICAvL3NldCB1cCB0aGUgbG9vcHMgZm9yIHNpbmdsZSBhbmQgdHJpcGxlIGRlc1xuICB2YXIgaXRlcmF0aW9ucyA9IGtleXMubGVuZ3RoID09IDMyID8gMyA6IDk7IC8vc2luZ2xlIG9yIHRyaXBsZSBkZXNcbiAgaWYgKGl0ZXJhdGlvbnMgPT0gMykge1xuICAgIGxvb3BpbmcgPSBlbmNyeXB0ID8gbmV3IEFycmF5KDAsIDMyLCAyKSA6IG5ldyBBcnJheSgzMCwgLTIsIC0yKTtcbiAgfSBlbHNlIHtcbiAgICBsb29waW5nID0gZW5jcnlwdCA/IG5ldyBBcnJheSgwLCAzMiwgMiwgNjIsIDMwLCAtMiwgNjQsIDk2LCAyKSA6IG5ldyBBcnJheSg5NCwgNjIsIC0yLCAzMiwgNjQsIDIsIDMwLCAtMiwgLTIpO1xuICB9XG5cbiAgLy9wYWQgdGhlIG1lc3NhZ2UgZGVwZW5kaW5nIG9uIHRoZSBwYWRkaW5nIHBhcmFtZXRlclxuICAvL29ubHkgYWRkIHBhZGRpbmcgaWYgZW5jcnlwdGluZyAtIG5vdGUgdGhhdCB5b3UgbmVlZCB0byB1c2UgdGhlIHNhbWUgcGFkZGluZyBvcHRpb24gZm9yIGJvdGggZW5jcnlwdCBhbmQgZGVjcnlwdFxuICBpZiAoZW5jcnlwdCkge1xuICAgIG1lc3NhZ2UgPSBkZXNfYWRkUGFkZGluZyhtZXNzYWdlLCBwYWRkaW5nKTtcbiAgICBsZW4gPSBtZXNzYWdlLmxlbmd0aDtcbiAgfVxuXG4gIC8vc3RvcmUgdGhlIHJlc3VsdCBoZXJlXG4gIHJlc3VsdCA9IFwiXCI7XG4gIHRlbXByZXN1bHQgPSBcIlwiO1xuXG4gIGlmIChtb2RlID09IDEpIHsgLy9DQkMgbW9kZVxuICAgIGNiY2xlZnQgPSAoaXYuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChpdi5jaGFyQ29kZUF0KG0rKykgPDwgMTYpIHwgKGl2LmNoYXJDb2RlQXQobSsrKSA8PCA4KSB8IGl2LmNoYXJDb2RlQXQobSsrKTtcbiAgICBjYmNyaWdodCA9IChpdi5jaGFyQ29kZUF0KG0rKykgPDwgMjQpIHwgKGl2LmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAoaXYuY2hhckNvZGVBdChtKyspIDw8IDgpIHwgaXYuY2hhckNvZGVBdChtKyspO1xuICAgIG0gPSAwO1xuICB9XG5cbiAgLy9sb29wIHRocm91Z2ggZWFjaCA2NCBiaXQgY2h1bmsgb2YgdGhlIG1lc3NhZ2VcbiAgd2hpbGUgKG0gPCBsZW4pIHtcbiAgICBsZWZ0ID0gKG1lc3NhZ2UuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChtZXNzYWdlLmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAobWVzc2FnZS5jaGFyQ29kZUF0KG0rKykgPDwgOCkgfCBtZXNzYWdlXG4gICAgICAuY2hhckNvZGVBdChtKyspO1xuICAgIHJpZ2h0ID0gKG1lc3NhZ2UuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChtZXNzYWdlLmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAobWVzc2FnZS5jaGFyQ29kZUF0KG0rKykgPDwgOCkgfFxuICAgICAgbWVzc2FnZS5jaGFyQ29kZUF0KG0rKyk7XG5cbiAgICAvL2ZvciBDaXBoZXIgQmxvY2sgQ2hhaW5pbmcgbW9kZSwgeG9yIHRoZSBtZXNzYWdlIHdpdGggdGhlIHByZXZpb3VzIHJlc3VsdFxuICAgIGlmIChtb2RlID09IDEpIHtcbiAgICAgIGlmIChlbmNyeXB0KSB7XG4gICAgICAgIGxlZnQgXj0gY2JjbGVmdDtcbiAgICAgICAgcmlnaHQgXj0gY2JjcmlnaHQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjYmNsZWZ0MiA9IGNiY2xlZnQ7XG4gICAgICAgIGNiY3JpZ2h0MiA9IGNiY3JpZ2h0O1xuICAgICAgICBjYmNsZWZ0ID0gbGVmdDtcbiAgICAgICAgY2JjcmlnaHQgPSByaWdodDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvL2ZpcnN0IGVhY2ggNjQgYnV0IGNodW5rIG9mIHRoZSBtZXNzYWdlIG11c3QgYmUgcGVybXV0ZWQgYWNjb3JkaW5nIHRvIElQXG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gNCkgXiByaWdodCkgJiAweDBmMGYwZjBmO1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCA0KTtcbiAgICB0ZW1wID0gKChsZWZ0ID4+PiAxNikgXiByaWdodCkgJiAweDAwMDBmZmZmO1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAxNik7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IDIpIF4gbGVmdCkgJiAweDMzMzMzMzMzO1xuICAgIGxlZnQgXj0gdGVtcDtcbiAgICByaWdodCBePSAodGVtcCA8PCAyKTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gOCkgXiBsZWZ0KSAmIDB4MDBmZjAwZmY7XG4gICAgbGVmdCBePSB0ZW1wO1xuICAgIHJpZ2h0IF49ICh0ZW1wIDw8IDgpO1xuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDEpIF4gcmlnaHQpICYgMHg1NTU1NTU1NTtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgMSk7XG5cbiAgICBsZWZ0ID0gKChsZWZ0IDw8IDEpIHwgKGxlZnQgPj4+IDMxKSk7XG4gICAgcmlnaHQgPSAoKHJpZ2h0IDw8IDEpIHwgKHJpZ2h0ID4+PiAzMSkpO1xuXG4gICAgLy9kbyB0aGlzIGVpdGhlciAxIG9yIDMgdGltZXMgZm9yIGVhY2ggY2h1bmsgb2YgdGhlIG1lc3NhZ2VcbiAgICBmb3IgKGogPSAwOyBqIDwgaXRlcmF0aW9uczsgaiArPSAzKSB7XG4gICAgICBlbmRsb29wID0gbG9vcGluZ1tqICsgMV07XG4gICAgICBsb29waW5jID0gbG9vcGluZ1tqICsgMl07XG4gICAgICAvL25vdyBnbyB0aHJvdWdoIGFuZCBwZXJmb3JtIHRoZSBlbmNyeXB0aW9uIG9yIGRlY3J5cHRpb24gIFxuICAgICAgZm9yIChpID0gbG9vcGluZ1tqXTsgaSAhPSBlbmRsb29wOyBpICs9IGxvb3BpbmMpIHsgLy9mb3IgZWZmaWNpZW5jeVxuICAgICAgICByaWdodDEgPSByaWdodCBeIGtleXNbaV07XG4gICAgICAgIHJpZ2h0MiA9ICgocmlnaHQgPj4+IDQpIHwgKHJpZ2h0IDw8IDI4KSkgXiBrZXlzW2kgKyAxXTtcbiAgICAgICAgLy90aGUgcmVzdWx0IGlzIGF0dGFpbmVkIGJ5IHBhc3NpbmcgdGhlc2UgYnl0ZXMgdGhyb3VnaCB0aGUgUyBzZWxlY3Rpb24gZnVuY3Rpb25zXG4gICAgICAgIHRlbXAgPSBsZWZ0O1xuICAgICAgICBsZWZ0ID0gcmlnaHQ7XG4gICAgICAgIHJpZ2h0ID0gdGVtcCBeIChzcGZ1bmN0aW9uMlsocmlnaHQxID4+PiAyNCkgJiAweDNmXSB8IHNwZnVuY3Rpb240WyhyaWdodDEgPj4+IDE2KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjZbKHJpZ2h0MSA+Pj5cbiAgICAgICAgICA4KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjhbcmlnaHQxICYgMHgzZl0gfCBzcGZ1bmN0aW9uMVsocmlnaHQyID4+PiAyNCkgJiAweDNmXSB8IHNwZnVuY3Rpb24zWyhyaWdodDIgPj4+IDE2KSAmXG4gICAgICAgICAgMHgzZl0gfCBzcGZ1bmN0aW9uNVsocmlnaHQyID4+PiA4KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjdbcmlnaHQyICYgMHgzZl0pO1xuICAgICAgfVxuICAgICAgdGVtcCA9IGxlZnQ7XG4gICAgICBsZWZ0ID0gcmlnaHQ7XG4gICAgICByaWdodCA9IHRlbXA7IC8vdW5yZXZlcnNlIGxlZnQgYW5kIHJpZ2h0XG4gICAgfSAvL2ZvciBlaXRoZXIgMSBvciAzIGl0ZXJhdGlvbnNcblxuICAgIC8vbW92ZSB0aGVuIGVhY2ggb25lIGJpdCB0byB0aGUgcmlnaHRcbiAgICBsZWZ0ID0gKChsZWZ0ID4+PiAxKSB8IChsZWZ0IDw8IDMxKSk7XG4gICAgcmlnaHQgPSAoKHJpZ2h0ID4+PiAxKSB8IChyaWdodCA8PCAzMSkpO1xuXG4gICAgLy9ub3cgcGVyZm9ybSBJUC0xLCB3aGljaCBpcyBJUCBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uXG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMSkgXiByaWdodCkgJiAweDU1NTU1NTU1O1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAxKTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gOCkgXiBsZWZ0KSAmIDB4MDBmZjAwZmY7XG4gICAgbGVmdCBePSB0ZW1wO1xuICAgIHJpZ2h0IF49ICh0ZW1wIDw8IDgpO1xuICAgIHRlbXAgPSAoKHJpZ2h0ID4+PiAyKSBeIGxlZnQpICYgMHgzMzMzMzMzMztcbiAgICBsZWZ0IF49IHRlbXA7XG4gICAgcmlnaHQgXj0gKHRlbXAgPDwgMik7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMTYpIF4gcmlnaHQpICYgMHgwMDAwZmZmZjtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgMTYpO1xuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDQpIF4gcmlnaHQpICYgMHgwZjBmMGYwZjtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgNCk7XG5cbiAgICAvL2ZvciBDaXBoZXIgQmxvY2sgQ2hhaW5pbmcgbW9kZSwgeG9yIHRoZSBtZXNzYWdlIHdpdGggdGhlIHByZXZpb3VzIHJlc3VsdFxuICAgIGlmIChtb2RlID09IDEpIHtcbiAgICAgIGlmIChlbmNyeXB0KSB7XG4gICAgICAgIGNiY2xlZnQgPSBsZWZ0O1xuICAgICAgICBjYmNyaWdodCA9IHJpZ2h0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGVmdCBePSBjYmNsZWZ0MjtcbiAgICAgICAgcmlnaHQgXj0gY2JjcmlnaHQyO1xuICAgICAgfVxuICAgIH1cbiAgICB0ZW1wcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGxlZnQgPj4+IDI0KSwgKChsZWZ0ID4+PiAxNikgJiAweGZmKSwgKChsZWZ0ID4+PiA4KSAmIDB4ZmYpLCAobGVmdCAmIDB4ZmYpLCAoXG4gICAgICByaWdodCA+Pj4gMjQpLCAoKHJpZ2h0ID4+PiAxNikgJiAweGZmKSwgKChyaWdodCA+Pj4gOCkgJiAweGZmKSwgKHJpZ2h0ICYgMHhmZikpO1xuXG4gICAgY2h1bmsgKz0gODtcbiAgICBpZiAoY2h1bmsgPT0gNTEyKSB7XG4gICAgICByZXN1bHQgKz0gdGVtcHJlc3VsdDtcbiAgICAgIHRlbXByZXN1bHQgPSBcIlwiO1xuICAgICAgY2h1bmsgPSAwO1xuICAgIH1cbiAgfSAvL2ZvciBldmVyeSA4IGNoYXJhY3RlcnMsIG9yIDY0IGJpdHMgaW4gdGhlIG1lc3NhZ2VcblxuICAvL3JldHVybiB0aGUgcmVzdWx0IGFzIGFuIGFycmF5XG4gIHJlc3VsdCArPSB0ZW1wcmVzdWx0O1xuXG4gIC8vb25seSByZW1vdmUgcGFkZGluZyBpZiBkZWNyeXB0aW5nIC0gbm90ZSB0aGF0IHlvdSBuZWVkIHRvIHVzZSB0aGUgc2FtZSBwYWRkaW5nIG9wdGlvbiBmb3IgYm90aCBlbmNyeXB0IGFuZCBkZWNyeXB0XG4gIGlmICghZW5jcnlwdCkge1xuICAgIHJlc3VsdCA9IGRlc19yZW1vdmVQYWRkaW5nKHJlc3VsdCwgcGFkZGluZyk7XG4gIH1cblxuICByZXR1cm4gcmVzdWx0O1xufSAvL2VuZCBvZiBkZXNcblxuXG5cbi8vZGVzX2NyZWF0ZUtleXNcbi8vdGhpcyB0YWtlcyBhcyBpbnB1dCBhIDY0IGJpdCBrZXkgKGV2ZW4gdGhvdWdoIG9ubHkgNTYgYml0cyBhcmUgdXNlZClcbi8vYXMgYW4gYXJyYXkgb2YgMiBpbnRlZ2VycywgYW5kIHJldHVybnMgMTYgNDggYml0IGtleXNcblxuZnVuY3Rpb24gZGVzX2NyZWF0ZUtleXMoa2V5KSB7XG4gIC8vZGVjbGFyaW5nIHRoaXMgbG9jYWxseSBzcGVlZHMgdGhpbmdzIHVwIGEgYml0XG4gIHBjMmJ5dGVzMCA9IG5ldyBBcnJheSgwLCAweDQsIDB4MjAwMDAwMDAsIDB4MjAwMDAwMDQsIDB4MTAwMDAsIDB4MTAwMDQsIDB4MjAwMTAwMDAsIDB4MjAwMTAwMDQsIDB4MjAwLCAweDIwNCxcbiAgICAweDIwMDAwMjAwLCAweDIwMDAwMjA0LCAweDEwMjAwLCAweDEwMjA0LCAweDIwMDEwMjAwLCAweDIwMDEwMjA0KTtcbiAgcGMyYnl0ZXMxID0gbmV3IEFycmF5KDAsIDB4MSwgMHgxMDAwMDAsIDB4MTAwMDAxLCAweDQwMDAwMDAsIDB4NDAwMDAwMSwgMHg0MTAwMDAwLCAweDQxMDAwMDEsIDB4MTAwLCAweDEwMSwgMHgxMDAxMDAsXG4gICAgMHgxMDAxMDEsIDB4NDAwMDEwMCwgMHg0MDAwMTAxLCAweDQxMDAxMDAsIDB4NDEwMDEwMSk7XG4gIHBjMmJ5dGVzMiA9IG5ldyBBcnJheSgwLCAweDgsIDB4ODAwLCAweDgwOCwgMHgxMDAwMDAwLCAweDEwMDAwMDgsIDB4MTAwMDgwMCwgMHgxMDAwODA4LCAwLCAweDgsIDB4ODAwLCAweDgwOCxcbiAgICAweDEwMDAwMDAsIDB4MTAwMDAwOCwgMHgxMDAwODAwLCAweDEwMDA4MDgpO1xuICBwYzJieXRlczMgPSBuZXcgQXJyYXkoMCwgMHgyMDAwMDAsIDB4ODAwMDAwMCwgMHg4MjAwMDAwLCAweDIwMDAsIDB4MjAyMDAwLCAweDgwMDIwMDAsIDB4ODIwMjAwMCwgMHgyMDAwMCwgMHgyMjAwMDAsXG4gICAgMHg4MDIwMDAwLCAweDgyMjAwMDAsIDB4MjIwMDAsIDB4MjIyMDAwLCAweDgwMjIwMDAsIDB4ODIyMjAwMCk7XG4gIHBjMmJ5dGVzNCA9IG5ldyBBcnJheSgwLCAweDQwMDAwLCAweDEwLCAweDQwMDEwLCAwLCAweDQwMDAwLCAweDEwLCAweDQwMDEwLCAweDEwMDAsIDB4NDEwMDAsIDB4MTAxMCwgMHg0MTAxMCwgMHgxMDAwLFxuICAgIDB4NDEwMDAsIDB4MTAxMCwgMHg0MTAxMCk7XG4gIHBjMmJ5dGVzNSA9IG5ldyBBcnJheSgwLCAweDQwMCwgMHgyMCwgMHg0MjAsIDAsIDB4NDAwLCAweDIwLCAweDQyMCwgMHgyMDAwMDAwLCAweDIwMDA0MDAsIDB4MjAwMDAyMCwgMHgyMDAwNDIwLFxuICAgIDB4MjAwMDAwMCwgMHgyMDAwNDAwLCAweDIwMDAwMjAsIDB4MjAwMDQyMCk7XG4gIHBjMmJ5dGVzNiA9IG5ldyBBcnJheSgwLCAweDEwMDAwMDAwLCAweDgwMDAwLCAweDEwMDgwMDAwLCAweDIsIDB4MTAwMDAwMDIsIDB4ODAwMDIsIDB4MTAwODAwMDIsIDAsIDB4MTAwMDAwMDAsXG4gICAgMHg4MDAwMCwgMHgxMDA4MDAwMCwgMHgyLCAweDEwMDAwMDAyLCAweDgwMDAyLCAweDEwMDgwMDAyKTtcbiAgcGMyYnl0ZXM3ID0gbmV3IEFycmF5KDAsIDB4MTAwMDAsIDB4ODAwLCAweDEwODAwLCAweDIwMDAwMDAwLCAweDIwMDEwMDAwLCAweDIwMDAwODAwLCAweDIwMDEwODAwLCAweDIwMDAwLCAweDMwMDAwLFxuICAgIDB4MjA4MDAsIDB4MzA4MDAsIDB4MjAwMjAwMDAsIDB4MjAwMzAwMDAsIDB4MjAwMjA4MDAsIDB4MjAwMzA4MDApO1xuICBwYzJieXRlczggPSBuZXcgQXJyYXkoMCwgMHg0MDAwMCwgMCwgMHg0MDAwMCwgMHgyLCAweDQwMDAyLCAweDIsIDB4NDAwMDIsIDB4MjAwMDAwMCwgMHgyMDQwMDAwLCAweDIwMDAwMDAsIDB4MjA0MDAwMCxcbiAgICAweDIwMDAwMDIsIDB4MjA0MDAwMiwgMHgyMDAwMDAyLCAweDIwNDAwMDIpO1xuICBwYzJieXRlczkgPSBuZXcgQXJyYXkoMCwgMHgxMDAwMDAwMCwgMHg4LCAweDEwMDAwMDA4LCAwLCAweDEwMDAwMDAwLCAweDgsIDB4MTAwMDAwMDgsIDB4NDAwLCAweDEwMDAwNDAwLCAweDQwOCxcbiAgICAweDEwMDAwNDA4LCAweDQwMCwgMHgxMDAwMDQwMCwgMHg0MDgsIDB4MTAwMDA0MDgpO1xuICBwYzJieXRlczEwID0gbmV3IEFycmF5KDAsIDB4MjAsIDAsIDB4MjAsIDB4MTAwMDAwLCAweDEwMDAyMCwgMHgxMDAwMDAsIDB4MTAwMDIwLCAweDIwMDAsIDB4MjAyMCwgMHgyMDAwLCAweDIwMjAsXG4gICAgMHgxMDIwMDAsIDB4MTAyMDIwLCAweDEwMjAwMCwgMHgxMDIwMjApO1xuICBwYzJieXRlczExID0gbmV3IEFycmF5KDAsIDB4MTAwMDAwMCwgMHgyMDAsIDB4MTAwMDIwMCwgMHgyMDAwMDAsIDB4MTIwMDAwMCwgMHgyMDAyMDAsIDB4MTIwMDIwMCwgMHg0MDAwMDAwLCAweDUwMDAwMDAsXG4gICAgMHg0MDAwMjAwLCAweDUwMDAyMDAsIDB4NDIwMDAwMCwgMHg1MjAwMDAwLCAweDQyMDAyMDAsIDB4NTIwMDIwMCk7XG4gIHBjMmJ5dGVzMTIgPSBuZXcgQXJyYXkoMCwgMHgxMDAwLCAweDgwMDAwMDAsIDB4ODAwMTAwMCwgMHg4MDAwMCwgMHg4MTAwMCwgMHg4MDgwMDAwLCAweDgwODEwMDAsIDB4MTAsIDB4MTAxMCxcbiAgICAweDgwMDAwMTAsIDB4ODAwMTAxMCwgMHg4MDAxMCwgMHg4MTAxMCwgMHg4MDgwMDEwLCAweDgwODEwMTApO1xuICBwYzJieXRlczEzID0gbmV3IEFycmF5KDAsIDB4NCwgMHgxMDAsIDB4MTA0LCAwLCAweDQsIDB4MTAwLCAweDEwNCwgMHgxLCAweDUsIDB4MTAxLCAweDEwNSwgMHgxLCAweDUsIDB4MTAxLCAweDEwNSk7XG5cbiAgLy9ob3cgbWFueSBpdGVyYXRpb25zICgxIGZvciBkZXMsIDMgZm9yIHRyaXBsZSBkZXMpXG4gIHZhciBpdGVyYXRpb25zID0ga2V5Lmxlbmd0aCA+IDggPyAzIDogMTsgLy9jaGFuZ2VkIGJ5IFBhdWwgMTYvNi8yMDA3IHRvIHVzZSBUcmlwbGUgREVTIGZvciA5KyBieXRlIGtleXNcbiAgLy9zdG9yZXMgdGhlIHJldHVybiBrZXlzXG4gIHZhciBrZXlzID0gbmV3IEFycmF5KDMyICogaXRlcmF0aW9ucyk7XG4gIC8vbm93IGRlZmluZSB0aGUgbGVmdCBzaGlmdHMgd2hpY2ggbmVlZCB0byBiZSBkb25lXG4gIHZhciBzaGlmdHMgPSBuZXcgQXJyYXkoMCwgMCwgMSwgMSwgMSwgMSwgMSwgMSwgMCwgMSwgMSwgMSwgMSwgMSwgMSwgMCk7XG4gIC8vb3RoZXIgdmFyaWFibGVzXG4gIHZhciBsZWZ0dGVtcCwgcmlnaHR0ZW1wLCBtID0gMCxcbiAgICBuID0gMCxcbiAgICB0ZW1wO1xuXG4gIGZvciAodmFyIGogPSAwOyBqIDwgaXRlcmF0aW9uczsgaisrKSB7IC8vZWl0aGVyIDEgb3IgMyBpdGVyYXRpb25zXG4gICAgbGVmdCA9IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDE2KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDgpIHwga2V5LmNoYXJDb2RlQXQobSsrKTtcbiAgICByaWdodCA9IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDE2KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDgpIHwga2V5LmNoYXJDb2RlQXQobSsrKTtcblxuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDQpIF4gcmlnaHQpICYgMHgwZjBmMGYwZjtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgNCk7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IC0xNikgXiBsZWZ0KSAmIDB4MDAwMGZmZmY7XG4gICAgbGVmdCBePSB0ZW1wO1xuICAgIHJpZ2h0IF49ICh0ZW1wIDw8IC0xNik7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMikgXiByaWdodCkgJiAweDMzMzMzMzMzO1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAyKTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gLTE2KSBeIGxlZnQpICYgMHgwMDAwZmZmZjtcbiAgICBsZWZ0IF49IHRlbXA7XG4gICAgcmlnaHQgXj0gKHRlbXAgPDwgLTE2KTtcbiAgICB0ZW1wID0gKChsZWZ0ID4+PiAxKSBeIHJpZ2h0KSAmIDB4NTU1NTU1NTU7XG4gICAgcmlnaHQgXj0gdGVtcDtcbiAgICBsZWZ0IF49ICh0ZW1wIDw8IDEpO1xuICAgIHRlbXAgPSAoKHJpZ2h0ID4+PiA4KSBeIGxlZnQpICYgMHgwMGZmMDBmZjtcbiAgICBsZWZ0IF49IHRlbXA7XG4gICAgcmlnaHQgXj0gKHRlbXAgPDwgOCk7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMSkgXiByaWdodCkgJiAweDU1NTU1NTU1O1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAxKTtcblxuICAgIC8vdGhlIHJpZ2h0IHNpZGUgbmVlZHMgdG8gYmUgc2hpZnRlZCBhbmQgdG8gZ2V0IHRoZSBsYXN0IGZvdXIgYml0cyBvZiB0aGUgbGVmdCBzaWRlXG4gICAgdGVtcCA9IChsZWZ0IDw8IDgpIHwgKChyaWdodCA+Pj4gMjApICYgMHgwMDAwMDBmMCk7XG4gICAgLy9sZWZ0IG5lZWRzIHRvIGJlIHB1dCB1cHNpZGUgZG93blxuICAgIGxlZnQgPSAocmlnaHQgPDwgMjQpIHwgKChyaWdodCA8PCA4KSAmIDB4ZmYwMDAwKSB8ICgocmlnaHQgPj4+IDgpICYgMHhmZjAwKSB8ICgocmlnaHQgPj4+IDI0KSAmIDB4ZjApO1xuICAgIHJpZ2h0ID0gdGVtcDtcblxuICAgIC8vbm93IGdvIHRocm91Z2ggYW5kIHBlcmZvcm0gdGhlc2Ugc2hpZnRzIG9uIHRoZSBsZWZ0IGFuZCByaWdodCBrZXlzXG4gICAgZm9yIChpID0gMDsgaSA8IHNoaWZ0cy5sZW5ndGg7IGkrKykge1xuICAgICAgLy9zaGlmdCB0aGUga2V5cyBlaXRoZXIgb25lIG9yIHR3byBiaXRzIHRvIHRoZSBsZWZ0XG4gICAgICBpZiAoc2hpZnRzW2ldKSB7XG4gICAgICAgIGxlZnQgPSAobGVmdCA8PCAyKSB8IChsZWZ0ID4+PiAyNik7XG4gICAgICAgIHJpZ2h0ID0gKHJpZ2h0IDw8IDIpIHwgKHJpZ2h0ID4+PiAyNik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZWZ0ID0gKGxlZnQgPDwgMSkgfCAobGVmdCA+Pj4gMjcpO1xuICAgICAgICByaWdodCA9IChyaWdodCA8PCAxKSB8IChyaWdodCA+Pj4gMjcpO1xuICAgICAgfVxuICAgICAgbGVmdCAmPSAtMHhmO1xuICAgICAgcmlnaHQgJj0gLTB4ZjtcblxuICAgICAgLy9ub3cgYXBwbHkgUEMtMiwgaW4gc3VjaCBhIHdheSB0aGF0IEUgaXMgZWFzaWVyIHdoZW4gZW5jcnlwdGluZyBvciBkZWNyeXB0aW5nXG4gICAgICAvL3RoaXMgY29udmVyc2lvbiB3aWxsIGxvb2sgbGlrZSBQQy0yIGV4Y2VwdCBvbmx5IHRoZSBsYXN0IDYgYml0cyBvZiBlYWNoIGJ5dGUgYXJlIHVzZWRcbiAgICAgIC8vcmF0aGVyIHRoYW4gNDggY29uc2VjdXRpdmUgYml0cyBhbmQgdGhlIG9yZGVyIG9mIGxpbmVzIHdpbGwgYmUgYWNjb3JkaW5nIHRvIFxuICAgICAgLy9ob3cgdGhlIFMgc2VsZWN0aW9uIGZ1bmN0aW9ucyB3aWxsIGJlIGFwcGxpZWQ6IFMyLCBTNCwgUzYsIFM4LCBTMSwgUzMsIFM1LCBTN1xuICAgICAgbGVmdHRlbXAgPSBwYzJieXRlczBbbGVmdCA+Pj4gMjhdIHwgcGMyYnl0ZXMxWyhsZWZ0ID4+PiAyNCkgJiAweGZdIHwgcGMyYnl0ZXMyWyhsZWZ0ID4+PiAyMCkgJiAweGZdIHwgcGMyYnl0ZXMzWyhcbiAgICAgICAgbGVmdCA+Pj4gMTYpICYgMHhmXSB8IHBjMmJ5dGVzNFsobGVmdCA+Pj4gMTIpICYgMHhmXSB8IHBjMmJ5dGVzNVsobGVmdCA+Pj4gOCkgJiAweGZdIHwgcGMyYnl0ZXM2WyhsZWZ0ID4+PiA0KSAmXG4gICAgICAgIDB4Zl07XG4gICAgICByaWdodHRlbXAgPSBwYzJieXRlczdbcmlnaHQgPj4+IDI4XSB8IHBjMmJ5dGVzOFsocmlnaHQgPj4+IDI0KSAmIDB4Zl0gfCBwYzJieXRlczlbKHJpZ2h0ID4+PiAyMCkgJiAweGZdIHxcbiAgICAgICAgcGMyYnl0ZXMxMFsocmlnaHQgPj4+IDE2KSAmIDB4Zl0gfCBwYzJieXRlczExWyhyaWdodCA+Pj4gMTIpICYgMHhmXSB8IHBjMmJ5dGVzMTJbKHJpZ2h0ID4+PiA4KSAmIDB4Zl0gfFxuICAgICAgICBwYzJieXRlczEzWyhyaWdodCA+Pj4gNCkgJiAweGZdO1xuICAgICAgdGVtcCA9ICgocmlnaHR0ZW1wID4+PiAxNikgXiBsZWZ0dGVtcCkgJiAweDAwMDBmZmZmO1xuICAgICAga2V5c1tuKytdID0gbGVmdHRlbXAgXiB0ZW1wO1xuICAgICAga2V5c1tuKytdID0gcmlnaHR0ZW1wIF4gKHRlbXAgPDwgMTYpO1xuICAgIH1cbiAgfSAvL2ZvciBlYWNoIGl0ZXJhdGlvbnNcbiAgLy9yZXR1cm4gdGhlIGtleXMgd2UndmUgY3JlYXRlZFxuICByZXR1cm4ga2V5cztcbn0gLy9lbmQgb2YgZGVzX2NyZWF0ZUtleXNcblxuXG5mdW5jdGlvbiBkZXNfYWRkUGFkZGluZyhtZXNzYWdlLCBwYWRkaW5nKSB7XG4gIHZhciBwYWRMZW5ndGggPSA4IC0gKG1lc3NhZ2UubGVuZ3RoICUgOCk7XG4gIGlmICgocGFkZGluZyA9PSAyKSAmJiAocGFkTGVuZ3RoIDwgOCkpIHsgLy9wYWQgdGhlIG1lc3NhZ2Ugd2l0aCBzcGFjZXNcbiAgICBtZXNzYWdlICs9IFwiICAgICAgICBcIi5zdWJzdHIoMCwgcGFkTGVuZ3RoKTtcbiAgfSBlbHNlIGlmIChwYWRkaW5nID09IDEpIHsgLy9QS0NTNyBwYWRkaW5nXG4gICAgbWVzc2FnZSArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHBhZExlbmd0aCwgcGFkTGVuZ3RoLCBwYWRMZW5ndGgsIHBhZExlbmd0aCwgcGFkTGVuZ3RoLCBwYWRMZW5ndGgsIHBhZExlbmd0aCxcbiAgICAgIHBhZExlbmd0aCkuc3Vic3RyKDAsIHBhZExlbmd0aCk7XG4gIH0gZWxzZSBpZiAoIXBhZGRpbmcgJiYgKHBhZExlbmd0aCA8IDgpKSB7IC8vcGFkIHRoZSBtZXNzYWdlIG91dCB3aXRoIG51bGwgYnl0ZXNcbiAgICBtZXNzYWdlICs9IFwiXFwwXFwwXFwwXFwwXFwwXFwwXFwwXFwwXCIuc3Vic3RyKDAsIHBhZExlbmd0aCk7XG4gIH1cbiAgcmV0dXJuIG1lc3NhZ2U7XG59XG5cbmZ1bmN0aW9uIGRlc19yZW1vdmVQYWRkaW5nKG1lc3NhZ2UsIHBhZGRpbmcpIHtcbiAgaWYgKHBhZGRpbmcgPT0gMikgeyAvLyBzcGFjZSBwYWRkZWRcbiAgICBtZXNzYWdlID0gbWVzc2FnZS5yZXBsYWNlKC8gKiQvZywgXCJcIik7XG4gIH0gZWxzZSBpZiAocGFkZGluZyA9PSAxKSB7IC8vIFBLQ1M3XG4gICAgdmFyIHBhZENvdW50ID0gbWVzc2FnZS5jaGFyQ29kZUF0KG1lc3NhZ2UubGVuZ3RoIC0gMSk7XG4gICAgbWVzc2FnZSA9IG1lc3NhZ2Uuc3Vic3RyKDAsIG1lc3NhZ2UubGVuZ3RoIC0gcGFkQ291bnQpO1xuICB9IGVsc2UgaWYgKCFwYWRkaW5nKSB7IC8vIG51bGwgcGFkZGluZ1xuICAgIG1lc3NhZ2UgPSBtZXNzYWdlLnJlcGxhY2UoL1xcMCokL2csIFwiXCIpO1xuICB9XG4gIHJldHVybiBtZXNzYWdlO1xufVxuXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG4vLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cbmZ1bmN0aW9uIERlcyhrZXkpIHtcbiAgdGhpcy5rZXkgPSBbXTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IDM7IGkrKykge1xuICAgIHRoaXMua2V5LnB1c2goa2V5LnN1YnN0cihpICogOCwgOCkpO1xuICB9XG5cbiAgdGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24oYmxvY2spIHtcbiAgICByZXR1cm4gdXRpbC5zdHIyYmluKGRlcyhkZXNfY3JlYXRlS2V5cyh0aGlzLmtleVsyXSksXG4gICAgICBkZXMoZGVzX2NyZWF0ZUtleXModGhpcy5rZXlbMV0pLFxuICAgICAgZGVzKGRlc19jcmVhdGVLZXlzKHRoaXMua2V5WzBdKSxcbiAgICAgIHV0aWwuYmluMnN0cihibG9jayksIHRydWUsIDAsIG51bGwsIG51bGwpLFxuICAgICAgZmFsc2UsIDAsIG51bGwsIG51bGwpLCB0cnVlLCAwLCBudWxsLCBudWxsKSk7XG4gIH1cbn1cblxuRGVzLmtleVNpemUgPSBEZXMucHJvdG90eXBlLmtleVNpemUgPSAyNDtcbkRlcy5ibG9ja1NpemUgPSBEZXMucHJvdG90eXBlLmJsb2NrU2l6ZSA9IDg7XG5cbi8vIFRoaXMgaXMgXCJvcmlnaW5hbFwiIERFUyAtIERlcyBpcyBhY3R1YWxseSBUcmlwbGUgREVTLlxuLy8gVGhpcyBpcyBvbmx5IGV4cG9ydGVkIHNvIHdlIGNhbiB1bml0IHRlc3QuXG5cbmZ1bmN0aW9uIE9yaWdpbmFsRGVzKGtleSkge1xuICB0aGlzLmtleSA9IGtleTtcblxuICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihibG9jaywgcGFkZGluZykge1xuICAgIHZhciBrZXlzID0gZGVzX2NyZWF0ZUtleXModGhpcy5rZXkpO1xuICAgIHJldHVybiB1dGlsLnN0cjJiaW4oZGVzKGtleXMsIHV0aWwuYmluMnN0cihibG9jayksIHRydWUsIDAsIG51bGwsIHBhZGRpbmcpKTtcbiAgfVxuXG4gIHRoaXMuZGVjcnlwdCA9IGZ1bmN0aW9uKGJsb2NrLCBwYWRkaW5nKSB7XG4gICAgdmFyIGtleXMgPSBkZXNfY3JlYXRlS2V5cyh0aGlzLmtleSk7XG4gICAgcmV0dXJuIHV0aWwuc3RyMmJpbihkZXMoa2V5cywgdXRpbC5iaW4yc3RyKGJsb2NrKSwgZmFsc2UsIDAsIG51bGwsIHBhZGRpbmcpKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgLyoqIEBzdGF0aWMgKi9cbiAgZGVzOiBEZXMsXG4gIC8qKiBAc3RhdGljICovXG4gIG9yaWdpbmFsRGVzOiBPcmlnaW5hbERlc1xufVxuIiwiLyoqXG4gKiBAcmVxdWlyZXMgY3J5cHRvL2NpcGhlci9hZXNcbiAqIEByZXF1aXJlcyBjcnlwdG8vY2lwaGVyL2Jsb3dmaXNoXG4gKiBAcmVxdWlyZXMgY3J5cHRvL2NpcGhlci9jYXN0NVxuICogQHJlcXVpcmVzIGNyeXB0by9jaXBoZXIvdHdvZmlzaFxuICogQG1vZHVsZSBjcnlwdG8vY2lwaGVyXG4gKi9cblxudmFyIGRlc01vZHVsZSA9IHJlcXVpcmUoJy4vZGVzLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL2NpcGhlci9kZXMuZGVzICovXG4gIGRlczogZGVzTW9kdWxlWydkZXMnXSxcbiAgLyoqIEBzZWUgbW9kdWxlOmNyeXB0by9jaXBoZXIvZGVzLm9yaWdpbmFsRGVzICovXG4gIG9yaWdpbmFsRGVzOiBkZXNNb2R1bGVbJ29yaWdpbmFsRGVzJ10sXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vY2lwaGVyL2Nhc3Q1ICovXG4gIGNhc3Q1OiByZXF1aXJlKCcuL2Nhc3Q1LmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vY2lwaGVyL3R3b2Zpc2ggKi9cbiAgdHdvZmlzaDogcmVxdWlyZSgnLi90d29maXNoLmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vY2lwaGVyL2Jsb3dmaXNoICovXG4gIGJsb3dmaXNoOiByZXF1aXJlKCcuL2Jsb3dmaXNoLmpzJylcbn1cblxudmFyIGFlcyA9IHJlcXVpcmUoJy4vYWVzLmpzJyk7XG5cbmZvciAodmFyIGkgaW4gYWVzKSB7XG4gIG1vZHVsZS5leHBvcnRzWydhZXMnICsgaV0gPSBhZXNbaV07XG59XG4iLCIvKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkggXG4gKiBcbiAqIENpcGhlci5qc1xuICogQSBibG9jay1jaXBoZXIgYWxnb3JpdGhtIGltcGxlbWVudGF0aW9uIG9uIEphdmFTY3JpcHRcbiAqIFNlZSBDaXBoZXIucmVhZG1lLnR4dCBmb3IgZnVydGhlciBpbmZvcm1hdGlvbi5cbiAqXG4gKiBDb3B5cmlnaHQoYykgMjAwOSBBdHN1c2hpIE9rYSBbIGh0dHA6Ly9va2EubnUvIF1cbiAqIFRoaXMgc2NyaXB0IGZpbGUgaXMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExHUExcbiAqXG4gKiBBQ0tOT1dMRURHTUVOVFxuICpcbiAqICAgICBUaGUgbWFpbiBzdWJyb3V0aW5lcyBhcmUgd3JpdHRlbiBieSBNaWNoaWVsIHZhbiBFdmVyZGluZ2VuLlxuICogXG4gKiAgICAgTWljaGllbCB2YW4gRXZlcmRpbmdlblxuICogICAgIGh0dHA6Ly9ob21lLnZlcnNhdGVsLm5sL01BdmFuRXZlcmRpbmdlbi9pbmRleC5odG1sXG4gKiBcbiAqICAgICBBbGwgcmlnaHRzIGZvciB0aGVzZSByb3V0aW5lcyBhcmUgcmVzZXJ2ZWQgdG8gTWljaGllbCB2YW4gRXZlcmRpbmdlbi5cbiAqXG4gKi9cblxuLyoqXG4gKiBAbW9kdWxlIGNyeXB0by9jaXBoZXIvdHdvZmlzaFxuICovXG5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbi8vTWF0aFxuLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbnZhciBNQVhJTlQgPSAweEZGRkZGRkZGO1xuXG5mdW5jdGlvbiByb3RiKGIsIG4pIHtcbiAgcmV0dXJuIChiIDw8IG4gfCBiID4+PiAoOCAtIG4pKSAmIDB4RkY7XG59XG5cbmZ1bmN0aW9uIHJvdHcodywgbikge1xuICByZXR1cm4gKHcgPDwgbiB8IHcgPj4+ICgzMiAtIG4pKSAmIE1BWElOVDtcbn1cblxuZnVuY3Rpb24gZ2V0VyhhLCBpKSB7XG4gIHJldHVybiBhW2ldIHwgYVtpICsgMV0gPDwgOCB8IGFbaSArIDJdIDw8IDE2IHwgYVtpICsgM10gPDwgMjQ7XG59XG5cbmZ1bmN0aW9uIHNldFcoYSwgaSwgdykge1xuICBhLnNwbGljZShpLCA0LCB3ICYgMHhGRiwgKHcgPj4+IDgpICYgMHhGRiwgKHcgPj4+IDE2KSAmIDB4RkYsICh3ID4+PiAyNCkgJiAweEZGKTtcbn1cblxuZnVuY3Rpb24gc2V0V0ludihhLCBpLCB3KSB7XG4gIGEuc3BsaWNlKGksIDQsICh3ID4+PiAyNCkgJiAweEZGLCAodyA+Pj4gMTYpICYgMHhGRiwgKHcgPj4+IDgpICYgMHhGRiwgdyAmIDB4RkYpO1xufVxuXG5mdW5jdGlvbiBnZXRCKHgsIG4pIHtcbiAgcmV0dXJuICh4ID4+PiAobiAqIDgpKSAmIDB4RkY7XG59XG5cbmZ1bmN0aW9uIGdldE5yQml0cyhpKSB7XG4gIHZhciBuID0gMDtcbiAgd2hpbGUgKGkgPiAwKSB7XG4gICAgbisrO1xuICAgIGkgPj4+PSAxO1xuICB9XG4gIHJldHVybiBuO1xufVxuXG5mdW5jdGlvbiBnZXRNYXNrKG4pIHtcbiAgcmV0dXJuICgxIDw8IG4pIC0gMTtcbn1cblxuLy9hZGRlZCAyMDA4LzExLzEzIFhYWCBNVVNUIFVTRSBPTkUtV0FZIEhBU0ggRlVOQ1RJT04gRk9SIFNFQ1VSSVRZIFJFQVNPTlxuXG5mdW5jdGlvbiByYW5kQnl0ZSgpIHtcbiAgcmV0dXJuIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDI1Nik7XG59XG4vLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBUd29maXNoXG4vLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbmZ1bmN0aW9uIGNyZWF0ZVR3b2Zpc2goKSB7XG4gIC8vXG4gIHZhciBrZXlCeXRlcyA9IG51bGw7XG4gIHZhciBkYXRhQnl0ZXMgPSBudWxsO1xuICB2YXIgZGF0YU9mZnNldCA9IC0xO1xuICAvLyB2YXIgZGF0YUxlbmd0aCA9IC0xO1xuICB2YXIgYWxnb3JpdGhtTmFtZSA9IG51bGw7XG4gIC8vIHZhciBpZHgyID0gLTE7XG4gIC8vXG5cbiAgYWxnb3JpdGhtTmFtZSA9IFwidHdvZmlzaFwiO1xuXG4gIHZhciB0ZnNLZXkgPSBbXTtcbiAgdmFyIHRmc00gPSBbXG4gICAgW10sXG4gICAgW10sXG4gICAgW10sXG4gICAgW11cbiAgXTtcblxuICBmdW5jdGlvbiB0ZnNJbml0KGtleSkge1xuICAgIGtleUJ5dGVzID0ga2V5O1xuICAgIHZhciBpLCBhLCBiLCBjLCBkLCBtZUtleSA9IFtdLFxuICAgICAgbW9LZXkgPSBbXSxcbiAgICAgIGluS2V5ID0gW107XG4gICAgdmFyIGtMZW47XG4gICAgdmFyIHNLZXkgPSBbXTtcbiAgICB2YXIgZjAxLCBmNWIsIGZlZjtcblxuICAgIHZhciBxMCA9IFtcbiAgICAgIFs4LCAxLCA3LCAxMywgNiwgMTUsIDMsIDIsIDAsIDExLCA1LCA5LCAxNCwgMTIsIDEwLCA0XSxcbiAgICAgIFsyLCA4LCAxMSwgMTMsIDE1LCA3LCA2LCAxNCwgMywgMSwgOSwgNCwgMCwgMTAsIDEyLCA1XVxuICAgIF07XG4gICAgdmFyIHExID0gW1xuICAgICAgWzE0LCAxMiwgMTEsIDgsIDEsIDIsIDMsIDUsIDE1LCA0LCAxMCwgNiwgNywgMCwgOSwgMTNdLFxuICAgICAgWzEsIDE0LCAyLCAxMSwgNCwgMTIsIDMsIDcsIDYsIDEzLCAxMCwgNSwgMTUsIDksIDAsIDhdXG4gICAgXTtcbiAgICB2YXIgcTIgPSBbXG4gICAgICBbMTEsIDEwLCA1LCAxNCwgNiwgMTMsIDksIDAsIDEyLCA4LCAxNSwgMywgMiwgNCwgNywgMV0sXG4gICAgICBbNCwgMTIsIDcsIDUsIDEsIDYsIDksIDEwLCAwLCAxNCwgMTMsIDgsIDIsIDExLCAzLCAxNV1cbiAgICBdO1xuICAgIHZhciBxMyA9IFtcbiAgICAgIFsxMywgNywgMTUsIDQsIDEsIDIsIDYsIDE0LCA5LCAxMSwgMywgMCwgOCwgNSwgMTIsIDEwXSxcbiAgICAgIFsxMSwgOSwgNSwgMSwgMTIsIDMsIDEzLCAxNCwgNiwgNCwgNywgMTUsIDIsIDAsIDgsIDEwXVxuICAgIF07XG4gICAgdmFyIHJvcjQgPSBbMCwgOCwgMSwgOSwgMiwgMTAsIDMsIDExLCA0LCAxMiwgNSwgMTMsIDYsIDE0LCA3LCAxNV07XG4gICAgdmFyIGFzaHggPSBbMCwgOSwgMiwgMTEsIDQsIDEzLCA2LCAxNSwgOCwgMSwgMTAsIDMsIDEyLCA1LCAxNCwgN107XG4gICAgdmFyIHEgPSBbXG4gICAgICBbXSxcbiAgICAgIFtdXG4gICAgXTtcbiAgICB2YXIgbSA9IFtcbiAgICAgIFtdLFxuICAgICAgW10sXG4gICAgICBbXSxcbiAgICAgIFtdXG4gICAgXTtcblxuICAgIGZ1bmN0aW9uIGZmbTViKHgpIHtcbiAgICAgIHJldHVybiB4IF4gKHggPj4gMikgXiBbMCwgOTAsIDE4MCwgMjM4XVt4ICYgM107XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZmZtRWYoeCkge1xuICAgICAgcmV0dXJuIHggXiAoeCA+PiAxKSBeICh4ID4+IDIpIF4gWzAsIDIzOCwgMTgwLCA5MF1beCAmIDNdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1kc1JlbShwLCBxKSB7XG4gICAgICB2YXIgaSwgdCwgdTtcbiAgICAgIGZvciAoaSA9IDA7IGkgPCA4OyBpKyspIHtcbiAgICAgICAgdCA9IHEgPj4+IDI0O1xuICAgICAgICBxID0gKChxIDw8IDgpICYgTUFYSU5UKSB8IHAgPj4+IDI0O1xuICAgICAgICBwID0gKHAgPDwgOCkgJiBNQVhJTlQ7XG4gICAgICAgIHUgPSB0IDw8IDE7XG4gICAgICAgIGlmICh0ICYgMTI4KSB7XG4gICAgICAgICAgdSBePSAzMzM7XG4gICAgICAgIH1cbiAgICAgICAgcSBePSB0IF4gKHUgPDwgMTYpO1xuICAgICAgICB1IF49IHQgPj4+IDE7XG4gICAgICAgIGlmICh0ICYgMSkge1xuICAgICAgICAgIHUgXj0gMTY2O1xuICAgICAgICB9XG4gICAgICAgIHEgXj0gdSA8PCAyNCB8IHUgPDwgODtcbiAgICAgIH1cbiAgICAgIHJldHVybiBxO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHFwKG4sIHgpIHtcbiAgICAgIHZhciBhLCBiLCBjLCBkO1xuICAgICAgYSA9IHggPj4gNDtcbiAgICAgIGIgPSB4ICYgMTU7XG4gICAgICBjID0gcTBbbl1bYSBeIGJdO1xuICAgICAgZCA9IHExW25dW3JvcjRbYl0gXiBhc2h4W2FdXTtcbiAgICAgIHJldHVybiBxM1tuXVtyb3I0W2RdIF4gYXNoeFtjXV0gPDwgNCB8IHEyW25dW2MgXiBkXTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBoRnVuKHgsIGtleSkge1xuICAgICAgdmFyIGEgPSBnZXRCKHgsIDApLFxuICAgICAgICBiID0gZ2V0Qih4LCAxKSxcbiAgICAgICAgYyA9IGdldEIoeCwgMiksXG4gICAgICAgIGQgPSBnZXRCKHgsIDMpO1xuICAgICAgc3dpdGNoIChrTGVuKSB7XG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICBhID0gcVsxXVthXSBeIGdldEIoa2V5WzNdLCAwKTtcbiAgICAgICAgICBiID0gcVswXVtiXSBeIGdldEIoa2V5WzNdLCAxKTtcbiAgICAgICAgICBjID0gcVswXVtjXSBeIGdldEIoa2V5WzNdLCAyKTtcbiAgICAgICAgICBkID0gcVsxXVtkXSBeIGdldEIoa2V5WzNdLCAzKTtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIGEgPSBxWzFdW2FdIF4gZ2V0QihrZXlbMl0sIDApO1xuICAgICAgICAgIGIgPSBxWzFdW2JdIF4gZ2V0QihrZXlbMl0sIDEpO1xuICAgICAgICAgIGMgPSBxWzBdW2NdIF4gZ2V0QihrZXlbMl0sIDIpO1xuICAgICAgICAgIGQgPSBxWzBdW2RdIF4gZ2V0QihrZXlbMl0sIDMpO1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgYSA9IHFbMF1bcVswXVthXSBeIGdldEIoa2V5WzFdLCAwKV0gXiBnZXRCKGtleVswXSwgMCk7XG4gICAgICAgICAgYiA9IHFbMF1bcVsxXVtiXSBeIGdldEIoa2V5WzFdLCAxKV0gXiBnZXRCKGtleVswXSwgMSk7XG4gICAgICAgICAgYyA9IHFbMV1bcVswXVtjXSBeIGdldEIoa2V5WzFdLCAyKV0gXiBnZXRCKGtleVswXSwgMik7XG4gICAgICAgICAgZCA9IHFbMV1bcVsxXVtkXSBeIGdldEIoa2V5WzFdLCAzKV0gXiBnZXRCKGtleVswXSwgMyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbVswXVthXSBeIG1bMV1bYl0gXiBtWzJdW2NdIF4gbVszXVtkXTtcbiAgICB9XG5cbiAgICBrZXlCeXRlcyA9IGtleUJ5dGVzLnNsaWNlKDAsIDMyKTtcbiAgICBpID0ga2V5Qnl0ZXMubGVuZ3RoO1xuICAgIHdoaWxlIChpICE9IDE2ICYmIGkgIT0gMjQgJiYgaSAhPSAzMilcbiAgICAgIGtleUJ5dGVzW2krK10gPSAwO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGtleUJ5dGVzLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICBpbktleVtpID4+IDJdID0gZ2V0VyhrZXlCeXRlcywgaSk7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCAyNTY7IGkrKykge1xuICAgICAgcVswXVtpXSA9IHFwKDAsIGkpO1xuICAgICAgcVsxXVtpXSA9IHFwKDEsIGkpO1xuICAgIH1cbiAgICBmb3IgKGkgPSAwOyBpIDwgMjU2OyBpKyspIHtcbiAgICAgIGYwMSA9IHFbMV1baV07XG4gICAgICBmNWIgPSBmZm01YihmMDEpO1xuICAgICAgZmVmID0gZmZtRWYoZjAxKTtcbiAgICAgIG1bMF1baV0gPSBmMDEgKyAoZjViIDw8IDgpICsgKGZlZiA8PCAxNikgKyAoZmVmIDw8IDI0KTtcbiAgICAgIG1bMl1baV0gPSBmNWIgKyAoZmVmIDw8IDgpICsgKGYwMSA8PCAxNikgKyAoZmVmIDw8IDI0KTtcbiAgICAgIGYwMSA9IHFbMF1baV07XG4gICAgICBmNWIgPSBmZm01YihmMDEpO1xuICAgICAgZmVmID0gZmZtRWYoZjAxKTtcbiAgICAgIG1bMV1baV0gPSBmZWYgKyAoZmVmIDw8IDgpICsgKGY1YiA8PCAxNikgKyAoZjAxIDw8IDI0KTtcbiAgICAgIG1bM11baV0gPSBmNWIgKyAoZjAxIDw8IDgpICsgKGZlZiA8PCAxNikgKyAoZjViIDw8IDI0KTtcbiAgICB9XG5cbiAgICBrTGVuID0gaW5LZXkubGVuZ3RoIC8gMjtcbiAgICBmb3IgKGkgPSAwOyBpIDwga0xlbjsgaSsrKSB7XG4gICAgICBhID0gaW5LZXlbaSArIGldO1xuICAgICAgbWVLZXlbaV0gPSBhO1xuICAgICAgYiA9IGluS2V5W2kgKyBpICsgMV07XG4gICAgICBtb0tleVtpXSA9IGI7XG4gICAgICBzS2V5W2tMZW4gLSBpIC0gMV0gPSBtZHNSZW0oYSwgYik7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCA0MDsgaSArPSAyKSB7XG4gICAgICBhID0gMHgxMDEwMTAxICogaTtcbiAgICAgIGIgPSBhICsgMHgxMDEwMTAxO1xuICAgICAgYSA9IGhGdW4oYSwgbWVLZXkpO1xuICAgICAgYiA9IHJvdHcoaEZ1bihiLCBtb0tleSksIDgpO1xuICAgICAgdGZzS2V5W2ldID0gKGEgKyBiKSAmIE1BWElOVDtcbiAgICAgIHRmc0tleVtpICsgMV0gPSByb3R3KGEgKyAyICogYiwgOSk7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCAyNTY7IGkrKykge1xuICAgICAgYSA9IGIgPSBjID0gZCA9IGk7XG4gICAgICBzd2l0Y2ggKGtMZW4pIHtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIGEgPSBxWzFdW2FdIF4gZ2V0QihzS2V5WzNdLCAwKTtcbiAgICAgICAgICBiID0gcVswXVtiXSBeIGdldEIoc0tleVszXSwgMSk7XG4gICAgICAgICAgYyA9IHFbMF1bY10gXiBnZXRCKHNLZXlbM10sIDIpO1xuICAgICAgICAgIGQgPSBxWzFdW2RdIF4gZ2V0QihzS2V5WzNdLCAzKTtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIGEgPSBxWzFdW2FdIF4gZ2V0QihzS2V5WzJdLCAwKTtcbiAgICAgICAgICBiID0gcVsxXVtiXSBeIGdldEIoc0tleVsyXSwgMSk7XG4gICAgICAgICAgYyA9IHFbMF1bY10gXiBnZXRCKHNLZXlbMl0sIDIpO1xuICAgICAgICAgIGQgPSBxWzBdW2RdIF4gZ2V0QihzS2V5WzJdLCAzKTtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHRmc01bMF1baV0gPSBtWzBdW3FbMF1bcVswXVthXSBeIGdldEIoc0tleVsxXSwgMCldIF4gZ2V0QihzS2V5WzBdLCAwKV07XG4gICAgICAgICAgdGZzTVsxXVtpXSA9IG1bMV1bcVswXVtxWzFdW2JdIF4gZ2V0QihzS2V5WzFdLCAxKV0gXiBnZXRCKHNLZXlbMF0sIDEpXTtcbiAgICAgICAgICB0ZnNNWzJdW2ldID0gbVsyXVtxWzFdW3FbMF1bY10gXiBnZXRCKHNLZXlbMV0sIDIpXSBeIGdldEIoc0tleVswXSwgMildO1xuICAgICAgICAgIHRmc01bM11baV0gPSBtWzNdW3FbMV1bcVsxXVtkXSBeIGdldEIoc0tleVsxXSwgMyldIF4gZ2V0QihzS2V5WzBdLCAzKV07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gdGZzRzAoeCkge1xuICAgIHJldHVybiB0ZnNNWzBdW2dldEIoeCwgMCldIF4gdGZzTVsxXVtnZXRCKHgsIDEpXSBeIHRmc01bMl1bZ2V0Qih4LCAyKV0gXiB0ZnNNWzNdW2dldEIoeCwgMyldO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRzEoeCkge1xuICAgIHJldHVybiB0ZnNNWzBdW2dldEIoeCwgMyldIF4gdGZzTVsxXVtnZXRCKHgsIDApXSBeIHRmc01bMl1bZ2V0Qih4LCAxKV0gXiB0ZnNNWzNdW2dldEIoeCwgMildO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRnJuZChyLCBibGspIHtcbiAgICB2YXIgYSA9IHRmc0cwKGJsa1swXSk7XG4gICAgdmFyIGIgPSB0ZnNHMShibGtbMV0pO1xuICAgIGJsa1syXSA9IHJvdHcoYmxrWzJdIF4gKGEgKyBiICsgdGZzS2V5WzQgKiByICsgOF0pICYgTUFYSU5ULCAzMSk7XG4gICAgYmxrWzNdID0gcm90dyhibGtbM10sIDEpIF4gKGEgKyAyICogYiArIHRmc0tleVs0ICogciArIDldKSAmIE1BWElOVDtcbiAgICBhID0gdGZzRzAoYmxrWzJdKTtcbiAgICBiID0gdGZzRzEoYmxrWzNdKTtcbiAgICBibGtbMF0gPSByb3R3KGJsa1swXSBeIChhICsgYiArIHRmc0tleVs0ICogciArIDEwXSkgJiBNQVhJTlQsIDMxKTtcbiAgICBibGtbMV0gPSByb3R3KGJsa1sxXSwgMSkgXiAoYSArIDIgKiBiICsgdGZzS2V5WzQgKiByICsgMTFdKSAmIE1BWElOVDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRmc0lybmQoaSwgYmxrKSB7XG4gICAgdmFyIGEgPSB0ZnNHMChibGtbMF0pO1xuICAgIHZhciBiID0gdGZzRzEoYmxrWzFdKTtcbiAgICBibGtbMl0gPSByb3R3KGJsa1syXSwgMSkgXiAoYSArIGIgKyB0ZnNLZXlbNCAqIGkgKyAxMF0pICYgTUFYSU5UO1xuICAgIGJsa1szXSA9IHJvdHcoYmxrWzNdIF4gKGEgKyAyICogYiArIHRmc0tleVs0ICogaSArIDExXSkgJiBNQVhJTlQsIDMxKTtcbiAgICBhID0gdGZzRzAoYmxrWzJdKTtcbiAgICBiID0gdGZzRzEoYmxrWzNdKTtcbiAgICBibGtbMF0gPSByb3R3KGJsa1swXSwgMSkgXiAoYSArIGIgKyB0ZnNLZXlbNCAqIGkgKyA4XSkgJiBNQVhJTlQ7XG4gICAgYmxrWzFdID0gcm90dyhibGtbMV0gXiAoYSArIDIgKiBiICsgdGZzS2V5WzQgKiBpICsgOV0pICYgTUFYSU5ULCAzMSk7XG4gIH1cblxuICBmdW5jdGlvbiB0ZnNDbG9zZSgpIHtcbiAgICB0ZnNLZXkgPSBbXTtcbiAgICB0ZnNNID0gW1xuICAgICAgW10sXG4gICAgICBbXSxcbiAgICAgIFtdLFxuICAgICAgW11cbiAgICBdO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRW5jcnlwdChkYXRhLCBvZmZzZXQpIHtcbiAgICBkYXRhQnl0ZXMgPSBkYXRhO1xuICAgIGRhdGFPZmZzZXQgPSBvZmZzZXQ7XG4gICAgdmFyIGJsayA9IFtnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCkgXiB0ZnNLZXlbMF0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgNCkgXiB0ZnNLZXlbMV0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgOCkgXiB0ZnNLZXlbMl0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgMTIpIF4gdGZzS2V5WzNdXG4gICAgXTtcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IDg7IGorKykge1xuICAgICAgdGZzRnJuZChqLCBibGspO1xuICAgIH1cbiAgICBzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCwgYmxrWzJdIF4gdGZzS2V5WzRdKTtcbiAgICBzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDQsIGJsa1szXSBeIHRmc0tleVs1XSk7XG4gICAgc2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQgKyA4LCBibGtbMF0gXiB0ZnNLZXlbNl0pO1xuICAgIHNldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgMTIsIGJsa1sxXSBeIHRmc0tleVs3XSk7XG4gICAgZGF0YU9mZnNldCArPSAxNjtcbiAgICByZXR1cm4gZGF0YUJ5dGVzO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRGVjcnlwdChkYXRhLCBvZmZzZXQpIHtcbiAgICBkYXRhQnl0ZXMgPSBkYXRhO1xuICAgIGRhdGFPZmZzZXQgPSBvZmZzZXQ7XG4gICAgdmFyIGJsayA9IFtnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCkgXiB0ZnNLZXlbNF0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgNCkgXiB0ZnNLZXlbNV0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgOCkgXiB0ZnNLZXlbNl0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgMTIpIF4gdGZzS2V5WzddXG4gICAgXTtcbiAgICBmb3IgKHZhciBqID0gNzsgaiA+PSAwOyBqLS0pIHtcbiAgICAgIHRmc0lybmQoaiwgYmxrKTtcbiAgICB9XG4gICAgc2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQsIGJsa1syXSBeIHRmc0tleVswXSk7XG4gICAgc2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQgKyA0LCBibGtbM10gXiB0ZnNLZXlbMV0pO1xuICAgIHNldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgOCwgYmxrWzBdIF4gdGZzS2V5WzJdKTtcbiAgICBzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDEyLCBibGtbMV0gXiB0ZnNLZXlbM10pO1xuICAgIGRhdGFPZmZzZXQgKz0gMTY7XG4gIH1cblxuICAvLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cbiAgZnVuY3Rpb24gdGZzRmluYWwoKSB7XG4gICAgcmV0dXJuIGRhdGFCeXRlcztcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgbmFtZTogXCJ0d29maXNoXCIsXG4gICAgYmxvY2tzaXplOiAxMjggLyA4LFxuICAgIG9wZW46IHRmc0luaXQsXG4gICAgY2xvc2U6IHRmc0Nsb3NlLFxuICAgIGVuY3J5cHQ6IHRmc0VuY3J5cHQsXG4gICAgZGVjcnlwdDogdGZzRGVjcnlwdCxcbiAgICAvLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG4gICAgZmluYWxpemU6IHRmc0ZpbmFsXG4gIH07XG59XG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG4vLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cbmZ1bmN0aW9uIFRGZW5jcnlwdChibG9jaywga2V5KSB7XG4gIHZhciBibG9ja19jb3B5ID0gW10uY29uY2F0KGJsb2NrKTtcbiAgdmFyIHRmID0gY3JlYXRlVHdvZmlzaCgpO1xuICB0Zi5vcGVuKHV0aWwuc3RyMmJpbihrZXkpLCAwKTtcbiAgdmFyIHJlc3VsdCA9IHRmLmVuY3J5cHQoYmxvY2tfY29weSwgMCk7XG4gIHRmLmNsb3NlKCk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIFRGKGtleSkge1xuICB0aGlzLnRmID0gY3JlYXRlVHdvZmlzaCgpO1xuICB0aGlzLnRmLm9wZW4odXRpbC5zdHIyYmluKGtleSksIDApO1xuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKGJsb2NrKSB7XG4gICAgcmV0dXJuIHRoaXMudGYuZW5jcnlwdChbXS5jb25jYXQoYmxvY2spLCAwKTtcbiAgfVxufVxuXG5cbm1vZHVsZS5leHBvcnRzID0gVEY7XG5tb2R1bGUuZXhwb3J0cy5rZXlTaXplID0gVEYucHJvdG90eXBlLmtleVNpemUgPSAzMjtcbm1vZHVsZS5leHBvcnRzLmJsb2NrU2l6ZSA9IFRGLnByb3RvdHlwZS5ibG9ja1NpemUgPSAxNjtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBIFxuXG4vLyBUaGUgR1BHNEJyb3dzZXJzIGNyeXB0byBpbnRlcmZhY2VcblxuLyoqXG4gKiBAcmVxdWlyZXMgY3J5cHRvL2NpcGhlclxuICogQHJlcXVpcmVzIGNyeXB0by9wdWJsaWNfa2V5XG4gKiBAcmVxdWlyZXMgY3J5cHRvL3JhbmRvbVxuICogQHJlcXVpcmVzIHR5cGUvbXBpXG4gKiBAbW9kdWxlIGNyeXB0by9jcnlwdG9cbiAqL1xuXG52YXIgcmFuZG9tID0gcmVxdWlyZSgnLi9yYW5kb20uanMnKSxcbiAgY2lwaGVyID0gcmVxdWlyZSgnLi9jaXBoZXInKSxcbiAgcHVibGljS2V5ID0gcmVxdWlyZSgnLi9wdWJsaWNfa2V5JyksXG4gIHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIC8qKlxuICAgKiBFbmNyeXB0cyBkYXRhIHVzaW5nIHRoZSBzcGVjaWZpZWQgcHVibGljIGtleSBtdWx0aXByZWNpc2lvbiBpbnRlZ2VycyBcbiAgICogYW5kIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtLlxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gQWxnb3JpdGhtIHRvIGJlIHVzZWQgKFNlZSBSRkM0ODgwIDkuMSlcbiAgICogQHBhcmFtIHtBcnJheTxtb2R1bGU6dHlwZS9tcGk+fSBwdWJsaWNNUElzIEFsZ29yaXRobSBkZXBlbmRlbnQgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnNcbiAgICogQHBhcmFtIHttb2R1bGU6dHlwZS9tcGl9IGRhdGEgRGF0YSB0byBiZSBlbmNyeXB0ZWQgYXMgTVBJXG4gICAqIEByZXR1cm4ge0FycmF5PG1vZHVsZTp0eXBlL21waT59IGlmIFJTQSBhbiBtb2R1bGU6dHlwZS9tcGk7IFxuICAgKiBpZiBlbGdhbWFsIGVuY3J5cHRpb24gYW4gYXJyYXkgb2YgdHdvIG1vZHVsZTp0eXBlL21waSBpcyByZXR1cm5lZDsgb3RoZXJ3aXNlIG51bGxcbiAgICovXG4gIHB1YmxpY0tleUVuY3J5cHQ6IGZ1bmN0aW9uKGFsZ28sIHB1YmxpY01QSXMsIGRhdGEpIHtcbiAgICB2YXIgcmVzdWx0ID0gKGZ1bmN0aW9uKCkge1xuICAgICAgc3dpdGNoIChhbGdvKSB7XG4gICAgICAgIGNhc2UgJ3JzYV9lbmNyeXB0JzpcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHRfc2lnbic6XG4gICAgICAgICAgdmFyIHJzYSA9IG5ldyBwdWJsaWNLZXkucnNhKCk7XG4gICAgICAgICAgdmFyIG4gPSBwdWJsaWNNUElzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciBlID0gcHVibGljTVBJc1sxXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICB2YXIgbSA9IGRhdGEudG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgcmV0dXJuIFtyc2EuZW5jcnlwdChtLCBlLCBuKV07XG5cbiAgICAgICAgY2FzZSAnZWxnYW1hbCc6XG4gICAgICAgICAgdmFyIGVsZ2FtYWwgPSBuZXcgcHVibGljS2V5LmVsZ2FtYWwoKTtcbiAgICAgICAgICB2YXIgcCA9IHB1YmxpY01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIGcgPSBwdWJsaWNNUElzWzFdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciB5ID0gcHVibGljTVBJc1syXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICB2YXIgbSA9IGRhdGEudG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgcmV0dXJuIGVsZ2FtYWwuZW5jcnlwdChtLCBnLCBwLCB5KTtcblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICB9KSgpO1xuXG4gICAgcmV0dXJuIHJlc3VsdC5tYXAoZnVuY3Rpb24oYm4pIHtcbiAgICAgIHZhciBtcGkgPSBuZXcgdHlwZV9tcGkoKTtcbiAgICAgIG1waS5mcm9tQmlnSW50ZWdlcihibik7XG4gICAgICByZXR1cm4gbXBpO1xuICAgIH0pO1xuICB9LFxuXG4gIC8qKlxuICAgKiBEZWNyeXB0cyBkYXRhIHVzaW5nIHRoZSBzcGVjaWZpZWQgcHVibGljIGtleSBtdWx0aXByZWNpc2lvbiBpbnRlZ2VycyBvZiB0aGUgcHJpdmF0ZSBrZXksXG4gICAqIHRoZSBzcGVjaWZpZWQgc2VjcmV0TVBJcyBvZiB0aGUgcHJpdmF0ZSBrZXkgYW5kIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtLlxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gQWxnb3JpdGhtIHRvIGJlIHVzZWQgKFNlZSBSRkM0ODgwIDkuMSlcbiAgICogQHBhcmFtIHtBcnJheTxtb2R1bGU6dHlwZS9tcGk+fSBwdWJsaWNNUElzIEFsZ29yaXRobSBkZXBlbmRlbnQgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgXG4gICAqIG9mIHRoZSBwdWJsaWMga2V5IHBhcnQgb2YgdGhlIHByaXZhdGUga2V5XG4gICAqIEBwYXJhbSB7QXJyYXk8bW9kdWxlOnR5cGUvbXBpPn0gc2VjcmV0TVBJcyBBbGdvcml0aG0gZGVwZW5kZW50IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIFxuICAgKiBvZiB0aGUgcHJpdmF0ZSBrZXkgdXNlZFxuICAgKiBAcGFyYW0ge21vZHVsZTp0eXBlL21waX0gZGF0YSBEYXRhIHRvIGJlIGVuY3J5cHRlZCBhcyBNUElcbiAgICogQHJldHVybiB7bW9kdWxlOnR5cGUvbXBpfSByZXR1cm5zIGEgYmlnIGludGVnZXIgY29udGFpbmluZyB0aGUgZGVjcnlwdGVkIGRhdGE7IG90aGVyd2lzZSBudWxsXG4gICAqL1xuXG4gIHB1YmxpY0tleURlY3J5cHQ6IGZ1bmN0aW9uKGFsZ28sIGtleUludGVnZXJzLCBkYXRhSW50ZWdlcnMpIHtcbiAgICB2YXIgYm4gPSAoZnVuY3Rpb24oKSB7XG4gICAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHRfc2lnbic6XG4gICAgICAgIGNhc2UgJ3JzYV9lbmNyeXB0JzpcbiAgICAgICAgICB2YXIgcnNhID0gbmV3IHB1YmxpY0tleS5yc2EoKTtcbiAgICAgICAgICAvLyAwIGFuZCAxIGFyZSB0aGUgcHVibGljIGtleS5cbiAgICAgICAgICB2YXIgZCA9IGtleUludGVnZXJzWzJdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciBwID0ga2V5SW50ZWdlcnNbM10udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIHEgPSBrZXlJbnRlZ2Vyc1s0XS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICB2YXIgdSA9IGtleUludGVnZXJzWzVdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciBtID0gZGF0YUludGVnZXJzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHJldHVybiByc2EuZGVjcnlwdChtLCBkLCBwLCBxLCB1KTtcbiAgICAgICAgY2FzZSAnZWxnYW1hbCc6XG4gICAgICAgICAgdmFyIGVsZ2FtYWwgPSBuZXcgcHVibGljS2V5LmVsZ2FtYWwoKTtcbiAgICAgICAgICB2YXIgeCA9IGtleUludGVnZXJzWzNdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciBjMSA9IGRhdGFJbnRlZ2Vyc1swXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICB2YXIgYzIgPSBkYXRhSW50ZWdlcnNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIHAgPSBrZXlJbnRlZ2Vyc1swXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICByZXR1cm4gZWxnYW1hbC5kZWNyeXB0KGMxLCBjMiwgcCwgeCk7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSkoKTtcblxuICAgIHZhciByZXN1bHQgPSBuZXcgdHlwZV9tcGkoKTtcbiAgICByZXN1bHQuZnJvbUJpZ0ludGVnZXIoYm4pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG5cbiAgLyoqIFJldHVybnMgdGhlIG51bWJlciBvZiBpbnRlZ2VycyBjb21wcmlzaW5nIHRoZSBwcml2YXRlIGtleSBvZiBhbiBhbGdvcml0aG1cbiAgICogQHBhcmFtIHtTdHJpbmd9IGFsZ28gVGhlIHB1YmxpYyBrZXkgYWxnb3JpdGhtXG4gICAqIEByZXR1cm4ge0ludGVnZXJ9IFRoZSBudW1iZXIgb2YgaW50ZWdlcnMuXG4gICAqL1xuICBnZXRQcml2YXRlTXBpQ291bnQ6IGZ1bmN0aW9uKGFsZ28pIHtcbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgJ3JzYV9lbmNyeXB0JzpcbiAgICAgIGNhc2UgJ3JzYV9lbmNyeXB0X3NpZ24nOlxuICAgICAgY2FzZSAncnNhX3NpZ24nOlxuICAgICAgICAvLyAgIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIFJTQSBzZWNyZXQga2V5czpcbiAgICAgICAgLy8gICAtIG11bHRpcHJlY2lzaW9uIGludGVnZXIgKE1QSSkgb2YgUlNBIHNlY3JldCBleHBvbmVudCBkLlxuICAgICAgICAvLyAgIC0gTVBJIG9mIFJTQSBzZWNyZXQgcHJpbWUgdmFsdWUgcC5cbiAgICAgICAgLy8gICAtIE1QSSBvZiBSU0Egc2VjcmV0IHByaW1lIHZhbHVlIHEgKHAgPCBxKS5cbiAgICAgICAgLy8gICAtIE1QSSBvZiB1LCB0aGUgbXVsdGlwbGljYXRpdmUgaW52ZXJzZSBvZiBwLCBtb2QgcS5cbiAgICAgICAgcmV0dXJuIDQ7XG4gICAgICBjYXNlICdlbGdhbWFsJzpcbiAgICAgICAgLy8gQWxnb3JpdGhtLVNwZWNpZmljIEZpZWxkcyBmb3IgRWxnYW1hbCBzZWNyZXQga2V5czpcbiAgICAgICAgLy8gICAtIE1QSSBvZiBFbGdhbWFsIHNlY3JldCBleHBvbmVudCB4LlxuICAgICAgICByZXR1cm4gMTtcbiAgICAgIGNhc2UgJ2RzYSc6XG4gICAgICAgIC8vIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIERTQSBzZWNyZXQga2V5czpcbiAgICAgICAgLy8gICAtIE1QSSBvZiBEU0Egc2VjcmV0IGV4cG9uZW50IHguXG4gICAgICAgIHJldHVybiAxO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmtub3duIGFsZ29yaXRobScpO1xuICAgIH1cbiAgfSxcblxuICBnZXRQdWJsaWNNcGlDb3VudDogZnVuY3Rpb24oYWxnbykge1xuICAgIC8vIC0gQSBzZXJpZXMgb2YgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgY29tcHJpc2luZyB0aGUga2V5IG1hdGVyaWFsOlxuICAgIC8vICAgQWxnb3JpdGhtLVNwZWNpZmljIEZpZWxkcyBmb3IgUlNBIHB1YmxpYyBrZXlzOlxuICAgIC8vICAgICAgIC0gYSBtdWx0aXByZWNpc2lvbiBpbnRlZ2VyIChNUEkpIG9mIFJTQSBwdWJsaWMgbW9kdWx1cyBuO1xuICAgIC8vICAgICAgIC0gYW4gTVBJIG9mIFJTQSBwdWJsaWMgZW5jcnlwdGlvbiBleHBvbmVudCBlLlxuICAgIHN3aXRjaCAoYWxnbykge1xuICAgICAgY2FzZSAncnNhX2VuY3J5cHQnOlxuICAgICAgY2FzZSAncnNhX2VuY3J5cHRfc2lnbic6XG4gICAgICBjYXNlICdyc2Ffc2lnbic6XG4gICAgICAgIHJldHVybiAyO1xuXG4gICAgICAgIC8vICAgQWxnb3JpdGhtLVNwZWNpZmljIEZpZWxkcyBmb3IgRWxnYW1hbCBwdWJsaWMga2V5czpcbiAgICAgICAgLy8gICAgIC0gTVBJIG9mIEVsZ2FtYWwgcHJpbWUgcDtcbiAgICAgICAgLy8gICAgIC0gTVBJIG9mIEVsZ2FtYWwgZ3JvdXAgZ2VuZXJhdG9yIGc7XG4gICAgICAgIC8vICAgICAtIE1QSSBvZiBFbGdhbWFsIHB1YmxpYyBrZXkgdmFsdWUgeSAoPSBnKip4IG1vZCBwIHdoZXJlIHggIGlzIHNlY3JldCkuXG4gICAgICBjYXNlICdlbGdhbWFsJzpcbiAgICAgICAgcmV0dXJuIDM7XG5cbiAgICAgICAgLy8gICBBbGdvcml0aG0tU3BlY2lmaWMgRmllbGRzIGZvciBEU0EgcHVibGljIGtleXM6XG4gICAgICAgIC8vICAgICAgIC0gTVBJIG9mIERTQSBwcmltZSBwO1xuICAgICAgICAvLyAgICAgICAtIE1QSSBvZiBEU0EgZ3JvdXAgb3JkZXIgcSAocSBpcyBhIHByaW1lIGRpdmlzb3Igb2YgcC0xKTtcbiAgICAgICAgLy8gICAgICAgLSBNUEkgb2YgRFNBIGdyb3VwIGdlbmVyYXRvciBnO1xuICAgICAgICAvLyAgICAgICAtIE1QSSBvZiBEU0EgcHVibGljLWtleSB2YWx1ZSB5ICg9IGcqKnggbW9kIHAgd2hlcmUgeCAgaXMgc2VjcmV0KS5cbiAgICAgIGNhc2UgJ2RzYSc6XG4gICAgICAgIHJldHVybiA0O1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gYWxnb3JpdGhtLicpO1xuICAgIH1cbiAgfSxcblxuICBnZW5lcmF0ZU1waTogZnVuY3Rpb24oYWxnbywgYml0cykge1xuICAgIHZhciByZXN1bHQgPSAoZnVuY3Rpb24oKSB7XG4gICAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHQnOlxuICAgICAgICBjYXNlICdyc2FfZW5jcnlwdF9zaWduJzpcbiAgICAgICAgY2FzZSAncnNhX3NpZ24nOlxuICAgICAgICAgIC8vcmVtZW1iZXIgXCJwdWJsaWNLZXlcIiByZWZlcnMgdG8gdGhlIGNyeXB0by9wdWJsaWNfa2V5IGRpclxuICAgICAgICAgIHZhciByc2EgPSBuZXcgcHVibGljS2V5LnJzYSgpO1xuICAgICAgICAgIHZhciBrZXlPYmplY3QgPSByc2EuZ2VuZXJhdGUoYml0cywgXCIxMDAwMVwiKTtcbiAgICAgICAgICB2YXIgb3V0cHV0ID0gW107XG4gICAgICAgICAgb3V0cHV0LnB1c2goa2V5T2JqZWN0Lm4pO1xuICAgICAgICAgIG91dHB1dC5wdXNoKGtleU9iamVjdC5lZSk7XG4gICAgICAgICAgb3V0cHV0LnB1c2goa2V5T2JqZWN0LmQpO1xuICAgICAgICAgIG91dHB1dC5wdXNoKGtleU9iamVjdC5wKTtcbiAgICAgICAgICBvdXRwdXQucHVzaChrZXlPYmplY3QucSk7XG4gICAgICAgICAgb3V0cHV0LnB1c2goa2V5T2JqZWN0LnUpO1xuICAgICAgICAgIHJldHVybiBvdXRwdXQ7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbnN1cHBvcnRlZCBhbGdvcml0aG0gZm9yIGtleSBnZW5lcmF0aW9uLicpO1xuICAgICAgfVxuICAgIH0pKCk7XG5cbiAgICByZXR1cm4gcmVzdWx0Lm1hcChmdW5jdGlvbihibikge1xuICAgICAgdmFyIG1waSA9IG5ldyB0eXBlX21waSgpO1xuICAgICAgbXBpLmZyb21CaWdJbnRlZ2VyKGJuKTtcbiAgICAgIHJldHVybiBtcGk7XG4gICAgfSk7XG4gIH0sXG5cblxuICAvKipcbiAgICogZ2VuZXJhdGUgcmFuZG9tIGJ5dGUgcHJlZml4IGFzIHN0cmluZyBmb3IgdGhlIHNwZWNpZmllZCBhbGdvcml0aG1cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBhbGdvIEFsZ29yaXRobSB0byB1c2UgKHNlZSBSRkM0ODgwIDkuMilcbiAgICogQHJldHVybiB7U3RyaW5nfSBSYW5kb20gYnl0ZXMgd2l0aCBsZW5ndGggZXF1YWwgdG8gdGhlIGJsb2NrXG4gICAqIHNpemUgb2YgdGhlIGNpcGhlclxuICAgKi9cbiAgZ2V0UHJlZml4UmFuZG9tOiBmdW5jdGlvbihhbGdvKSB7XG4gICAgcmV0dXJuIHJhbmRvbS5nZXRSYW5kb21CeXRlcyhjaXBoZXJbYWxnb10uYmxvY2tTaXplKTtcbiAgfSxcblxuICAvKipcbiAgICogR2VuZXJhdGluZyBhIHNlc3Npb24ga2V5IGZvciB0aGUgc3BlY2lmaWVkIHN5bW1ldHJpYyBhbGdvcml0aG1cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBhbGdvIEFsZ29yaXRobSB0byB1c2UgKHNlZSBSRkM0ODgwIDkuMilcbiAgICogQHJldHVybiB7U3RyaW5nfSBSYW5kb20gYnl0ZXMgYXMgYSBzdHJpbmcgdG8gYmUgdXNlZCBhcyBhIGtleVxuICAgKi9cbiAgZ2VuZXJhdGVTZXNzaW9uS2V5OiBmdW5jdGlvbihhbGdvKSB7XG4gICAgcmV0dXJuIHJhbmRvbS5nZXRSYW5kb21CeXRlcyhjaXBoZXJbYWxnb10ua2V5U2l6ZSk7XG4gIH1cbn07XG4iLCIvKipcbiAqIEByZXF1aXJlcyBjcnlwdG8vaGFzaC9zaGFcbiAqIEBtb2R1bGUgY3J5cHRvL2hhc2hcbiAqL1xudmFyIHNoYSA9IHJlcXVpcmUoJy4vc2hhLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL2hhc2gvbWQ1ICovXG4gIG1kNTogcmVxdWlyZSgnLi9tZDUuanMnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOmNyeXB0by9oYXNoL3NoYS5zaGExICovXG4gIHNoYTE6IHNoYS5zaGExLFxuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL2hhc2gvc2hhLnNoYTIyNCAqL1xuICBzaGEyMjQ6IHNoYS5zaGEyMjQsXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vaGFzaC9zaGEuc2hhMjU2ICovXG4gIHNoYTI1Njogc2hhLnNoYTI1NixcbiAgLyoqIEBzZWUgbW9kdWxlOmNyeXB0by9oYXNoL3NoYS5zaGEzODQgKi9cbiAgc2hhMzg0OiBzaGEuc2hhMzg0LFxuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL2hhc2gvc2hhLnNoYTUxMiAqL1xuICBzaGE1MTI6IHNoYS5zaGE1MTIsXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vaGFzaC9yaXBlLW1kICovXG4gIHJpcGVtZDogcmVxdWlyZSgnLi9yaXBlLW1kLmpzJyksXG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIGhhc2ggb24gdGhlIHNwZWNpZmllZCBkYXRhIHVzaW5nIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBIYXNoIGFsZ29yaXRobSB0eXBlIChzZWUgUkZDNDg4MCA5LjQpXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgdG8gYmUgaGFzaGVkXG4gICAqIEByZXR1cm4ge1N0cmluZ30gaGFzaCB2YWx1ZVxuICAgKi9cbiAgZGlnZXN0OiBmdW5jdGlvbihhbGdvLCBkYXRhKSB7XG4gICAgc3dpdGNoIChhbGdvKSB7XG4gICAgICBjYXNlIDE6XG4gICAgICAgIC8vIC0gTUQ1IFtIQUNdXG4gICAgICAgIHJldHVybiB0aGlzLm1kNShkYXRhKTtcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgLy8gLSBTSEEtMSBbRklQUzE4MF1cbiAgICAgICAgcmV0dXJuIHRoaXMuc2hhMShkYXRhKTtcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgLy8gLSBSSVBFLU1ELzE2MCBbSEFDXVxuICAgICAgICByZXR1cm4gdGhpcy5yaXBlbWQoZGF0YSk7XG4gICAgICBjYXNlIDg6XG4gICAgICAgIC8vIC0gU0hBMjU2IFtGSVBTMTgwXVxuICAgICAgICByZXR1cm4gdGhpcy5zaGEyNTYoZGF0YSk7XG4gICAgICBjYXNlIDk6XG4gICAgICAgIC8vIC0gU0hBMzg0IFtGSVBTMTgwXVxuICAgICAgICByZXR1cm4gdGhpcy5zaGEzODQoZGF0YSk7XG4gICAgICBjYXNlIDEwOlxuICAgICAgICAvLyAtIFNIQTUxMiBbRklQUzE4MF1cbiAgICAgICAgcmV0dXJuIHRoaXMuc2hhNTEyKGRhdGEpO1xuICAgICAgY2FzZSAxMTpcbiAgICAgICAgLy8gLSBTSEEyMjQgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiB0aGlzLnNoYTIyNChkYXRhKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoYXNoIGZ1bmN0aW9uLicpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgaGFzaCBzaXplIGluIGJ5dGVzIG9mIHRoZSBzcGVjaWZpZWQgaGFzaCBhbGdvcml0aG0gdHlwZVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gSGFzaCBhbGdvcml0aG0gdHlwZSAoU2VlIFJGQzQ4ODAgOS40KVxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBTaXplIGluIGJ5dGVzIG9mIHRoZSByZXN1bHRpbmcgaGFzaFxuICAgKi9cbiAgZ2V0SGFzaEJ5dGVMZW5ndGg6IGZ1bmN0aW9uKGFsZ28pIHtcbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgLy8gLSBNRDUgW0hBQ11cbiAgICAgICAgcmV0dXJuIDE2O1xuICAgICAgY2FzZSAyOlxuICAgICAgICAvLyAtIFNIQS0xIFtGSVBTMTgwXVxuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyAtIFJJUEUtTUQvMTYwIFtIQUNdXG4gICAgICAgIHJldHVybiAyMDtcbiAgICAgIGNhc2UgODpcbiAgICAgICAgLy8gLSBTSEEyNTYgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiAzMjtcbiAgICAgIGNhc2UgOTpcbiAgICAgICAgLy8gLSBTSEEzODQgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiA0OFxuICAgICAgY2FzZSAxMDpcbiAgICAgICAgLy8gLSBTSEE1MTIgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiA2NDtcbiAgICAgIGNhc2UgMTE6XG4gICAgICAgIC8vIC0gU0hBMjI0IFtGSVBTMTgwXVxuICAgICAgICByZXR1cm4gMjg7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGFzaCBhbGdvcml0aG0uJyk7XG4gICAgfVxuICB9XG59XG4iLCIvKipcbiAqIEEgZmFzdCBNRDUgSmF2YVNjcmlwdCBpbXBsZW1lbnRhdGlvblxuICogQ29weXJpZ2h0IChjKSAyMDEyIEpvc2VwaCBNeWVyc1xuICogaHR0cDovL3d3dy5teWVyc2RhaWx5Lm9yZy9qb3NlcGgvamF2YXNjcmlwdC9tZDUtdGV4dC5odG1sXG4gKlxuICogUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZVxuICogYW5kIGl0cyBkb2N1bWVudGF0aW9uIGZvciBhbnkgcHVycG9zZXMgYW5kIHdpdGhvdXRcbiAqIGZlZSBpcyBoZXJlYnkgZ3JhbnRlZCBwcm92aWRlZCB0aGF0IHRoaXMgY29weXJpZ2h0IG5vdGljZVxuICogYXBwZWFycyBpbiBhbGwgY29waWVzLlxuICpcbiAqIE9mIGNvdXJzZSwgdGhpcyBzb2Z0IGlzIHByb3ZpZGVkIFwiYXMgaXNcIiB3aXRob3V0IGV4cHJlc3Mgb3IgaW1wbGllZFxuICogd2FycmFudHkgb2YgYW55IGtpbmQuXG4gKi9cblxuLyoqXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSBjcnlwdG8vaGFzaC9tZDVcbiAqL1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuLyoqXG4gKiBNRDUgaGFzaFxuICogQHBhcmFtIHtTdHJpbmd9IGVudHJlZSBzdHJpbmcgdG8gaGFzaFxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChlbnRyZWUpIHtcbiAgdmFyIGhleCA9IG1kNShlbnRyZWUpO1xuICB2YXIgYmluID0gdXRpbC5oZXgyYmluKGhleCk7XG4gIHJldHVybiBiaW47XG59XG5cbmZ1bmN0aW9uIG1kNWN5Y2xlKHgsIGspIHtcbiAgdmFyIGEgPSB4WzBdLFxuICAgIGIgPSB4WzFdLFxuICAgIGMgPSB4WzJdLFxuICAgIGQgPSB4WzNdO1xuXG4gIGEgPSBmZihhLCBiLCBjLCBkLCBrWzBdLCA3LCAtNjgwODc2OTM2KTtcbiAgZCA9IGZmKGQsIGEsIGIsIGMsIGtbMV0sIDEyLCAtMzg5NTY0NTg2KTtcbiAgYyA9IGZmKGMsIGQsIGEsIGIsIGtbMl0sIDE3LCA2MDYxMDU4MTkpO1xuICBiID0gZmYoYiwgYywgZCwgYSwga1szXSwgMjIsIC0xMDQ0NTI1MzMwKTtcbiAgYSA9IGZmKGEsIGIsIGMsIGQsIGtbNF0sIDcsIC0xNzY0MTg4OTcpO1xuICBkID0gZmYoZCwgYSwgYiwgYywga1s1XSwgMTIsIDEyMDAwODA0MjYpO1xuICBjID0gZmYoYywgZCwgYSwgYiwga1s2XSwgMTcsIC0xNDczMjMxMzQxKTtcbiAgYiA9IGZmKGIsIGMsIGQsIGEsIGtbN10sIDIyLCAtNDU3MDU5ODMpO1xuICBhID0gZmYoYSwgYiwgYywgZCwga1s4XSwgNywgMTc3MDAzNTQxNik7XG4gIGQgPSBmZihkLCBhLCBiLCBjLCBrWzldLCAxMiwgLTE5NTg0MTQ0MTcpO1xuICBjID0gZmYoYywgZCwgYSwgYiwga1sxMF0sIDE3LCAtNDIwNjMpO1xuICBiID0gZmYoYiwgYywgZCwgYSwga1sxMV0sIDIyLCAtMTk5MDQwNDE2Mik7XG4gIGEgPSBmZihhLCBiLCBjLCBkLCBrWzEyXSwgNywgMTgwNDYwMzY4Mik7XG4gIGQgPSBmZihkLCBhLCBiLCBjLCBrWzEzXSwgMTIsIC00MDM0MTEwMSk7XG4gIGMgPSBmZihjLCBkLCBhLCBiLCBrWzE0XSwgMTcsIC0xNTAyMDAyMjkwKTtcbiAgYiA9IGZmKGIsIGMsIGQsIGEsIGtbMTVdLCAyMiwgMTIzNjUzNTMyOSk7XG5cbiAgYSA9IGdnKGEsIGIsIGMsIGQsIGtbMV0sIDUsIC0xNjU3OTY1MTApO1xuICBkID0gZ2coZCwgYSwgYiwgYywga1s2XSwgOSwgLTEwNjk1MDE2MzIpO1xuICBjID0gZ2coYywgZCwgYSwgYiwga1sxMV0sIDE0LCA2NDM3MTc3MTMpO1xuICBiID0gZ2coYiwgYywgZCwgYSwga1swXSwgMjAsIC0zNzM4OTczMDIpO1xuICBhID0gZ2coYSwgYiwgYywgZCwga1s1XSwgNSwgLTcwMTU1ODY5MSk7XG4gIGQgPSBnZyhkLCBhLCBiLCBjLCBrWzEwXSwgOSwgMzgwMTYwODMpO1xuICBjID0gZ2coYywgZCwgYSwgYiwga1sxNV0sIDE0LCAtNjYwNDc4MzM1KTtcbiAgYiA9IGdnKGIsIGMsIGQsIGEsIGtbNF0sIDIwLCAtNDA1NTM3ODQ4KTtcbiAgYSA9IGdnKGEsIGIsIGMsIGQsIGtbOV0sIDUsIDU2ODQ0NjQzOCk7XG4gIGQgPSBnZyhkLCBhLCBiLCBjLCBrWzE0XSwgOSwgLTEwMTk4MDM2OTApO1xuICBjID0gZ2coYywgZCwgYSwgYiwga1szXSwgMTQsIC0xODczNjM5NjEpO1xuICBiID0gZ2coYiwgYywgZCwgYSwga1s4XSwgMjAsIDExNjM1MzE1MDEpO1xuICBhID0gZ2coYSwgYiwgYywgZCwga1sxM10sIDUsIC0xNDQ0NjgxNDY3KTtcbiAgZCA9IGdnKGQsIGEsIGIsIGMsIGtbMl0sIDksIC01MTQwMzc4NCk7XG4gIGMgPSBnZyhjLCBkLCBhLCBiLCBrWzddLCAxNCwgMTczNTMyODQ3Myk7XG4gIGIgPSBnZyhiLCBjLCBkLCBhLCBrWzEyXSwgMjAsIC0xOTI2NjA3NzM0KTtcblxuICBhID0gaGgoYSwgYiwgYywgZCwga1s1XSwgNCwgLTM3ODU1OCk7XG4gIGQgPSBoaChkLCBhLCBiLCBjLCBrWzhdLCAxMSwgLTIwMjI1NzQ0NjMpO1xuICBjID0gaGgoYywgZCwgYSwgYiwga1sxMV0sIDE2LCAxODM5MDMwNTYyKTtcbiAgYiA9IGhoKGIsIGMsIGQsIGEsIGtbMTRdLCAyMywgLTM1MzA5NTU2KTtcbiAgYSA9IGhoKGEsIGIsIGMsIGQsIGtbMV0sIDQsIC0xNTMwOTkyMDYwKTtcbiAgZCA9IGhoKGQsIGEsIGIsIGMsIGtbNF0sIDExLCAxMjcyODkzMzUzKTtcbiAgYyA9IGhoKGMsIGQsIGEsIGIsIGtbN10sIDE2LCAtMTU1NDk3NjMyKTtcbiAgYiA9IGhoKGIsIGMsIGQsIGEsIGtbMTBdLCAyMywgLTEwOTQ3MzA2NDApO1xuICBhID0gaGgoYSwgYiwgYywgZCwga1sxM10sIDQsIDY4MTI3OTE3NCk7XG4gIGQgPSBoaChkLCBhLCBiLCBjLCBrWzBdLCAxMSwgLTM1ODUzNzIyMik7XG4gIGMgPSBoaChjLCBkLCBhLCBiLCBrWzNdLCAxNiwgLTcyMjUyMTk3OSk7XG4gIGIgPSBoaChiLCBjLCBkLCBhLCBrWzZdLCAyMywgNzYwMjkxODkpO1xuICBhID0gaGgoYSwgYiwgYywgZCwga1s5XSwgNCwgLTY0MDM2NDQ4Nyk7XG4gIGQgPSBoaChkLCBhLCBiLCBjLCBrWzEyXSwgMTEsIC00MjE4MTU4MzUpO1xuICBjID0gaGgoYywgZCwgYSwgYiwga1sxNV0sIDE2LCA1MzA3NDI1MjApO1xuICBiID0gaGgoYiwgYywgZCwgYSwga1syXSwgMjMsIC05OTUzMzg2NTEpO1xuXG4gIGEgPSBpaShhLCBiLCBjLCBkLCBrWzBdLCA2LCAtMTk4NjMwODQ0KTtcbiAgZCA9IGlpKGQsIGEsIGIsIGMsIGtbN10sIDEwLCAxMTI2ODkxNDE1KTtcbiAgYyA9IGlpKGMsIGQsIGEsIGIsIGtbMTRdLCAxNSwgLTE0MTYzNTQ5MDUpO1xuICBiID0gaWkoYiwgYywgZCwgYSwga1s1XSwgMjEsIC01NzQzNDA1NSk7XG4gIGEgPSBpaShhLCBiLCBjLCBkLCBrWzEyXSwgNiwgMTcwMDQ4NTU3MSk7XG4gIGQgPSBpaShkLCBhLCBiLCBjLCBrWzNdLCAxMCwgLTE4OTQ5ODY2MDYpO1xuICBjID0gaWkoYywgZCwgYSwgYiwga1sxMF0sIDE1LCAtMTA1MTUyMyk7XG4gIGIgPSBpaShiLCBjLCBkLCBhLCBrWzFdLCAyMSwgLTIwNTQ5MjI3OTkpO1xuICBhID0gaWkoYSwgYiwgYywgZCwga1s4XSwgNiwgMTg3MzMxMzM1OSk7XG4gIGQgPSBpaShkLCBhLCBiLCBjLCBrWzE1XSwgMTAsIC0zMDYxMTc0NCk7XG4gIGMgPSBpaShjLCBkLCBhLCBiLCBrWzZdLCAxNSwgLTE1NjAxOTgzODApO1xuICBiID0gaWkoYiwgYywgZCwgYSwga1sxM10sIDIxLCAxMzA5MTUxNjQ5KTtcbiAgYSA9IGlpKGEsIGIsIGMsIGQsIGtbNF0sIDYsIC0xNDU1MjMwNzApO1xuICBkID0gaWkoZCwgYSwgYiwgYywga1sxMV0sIDEwLCAtMTEyMDIxMDM3OSk7XG4gIGMgPSBpaShjLCBkLCBhLCBiLCBrWzJdLCAxNSwgNzE4Nzg3MjU5KTtcbiAgYiA9IGlpKGIsIGMsIGQsIGEsIGtbOV0sIDIxLCAtMzQzNDg1NTUxKTtcblxuICB4WzBdID0gYWRkMzIoYSwgeFswXSk7XG4gIHhbMV0gPSBhZGQzMihiLCB4WzFdKTtcbiAgeFsyXSA9IGFkZDMyKGMsIHhbMl0pO1xuICB4WzNdID0gYWRkMzIoZCwgeFszXSk7XG5cbn1cblxuZnVuY3Rpb24gY21uKHEsIGEsIGIsIHgsIHMsIHQpIHtcbiAgYSA9IGFkZDMyKGFkZDMyKGEsIHEpLCBhZGQzMih4LCB0KSk7XG4gIHJldHVybiBhZGQzMigoYSA8PCBzKSB8IChhID4+PiAoMzIgLSBzKSksIGIpO1xufVxuXG5mdW5jdGlvbiBmZihhLCBiLCBjLCBkLCB4LCBzLCB0KSB7XG4gIHJldHVybiBjbW4oKGIgJiBjKSB8ICgofmIpICYgZCksIGEsIGIsIHgsIHMsIHQpO1xufVxuXG5mdW5jdGlvbiBnZyhhLCBiLCBjLCBkLCB4LCBzLCB0KSB7XG4gIHJldHVybiBjbW4oKGIgJiBkKSB8IChjICYgKH5kKSksIGEsIGIsIHgsIHMsIHQpO1xufVxuXG5mdW5jdGlvbiBoaChhLCBiLCBjLCBkLCB4LCBzLCB0KSB7XG4gIHJldHVybiBjbW4oYiBeIGMgXiBkLCBhLCBiLCB4LCBzLCB0KTtcbn1cblxuZnVuY3Rpb24gaWkoYSwgYiwgYywgZCwgeCwgcywgdCkge1xuICByZXR1cm4gY21uKGMgXiAoYiB8ICh+ZCkpLCBhLCBiLCB4LCBzLCB0KTtcbn1cblxuZnVuY3Rpb24gbWQ1MShzKSB7XG4gIHR4dCA9ICcnO1xuICB2YXIgbiA9IHMubGVuZ3RoLFxuICAgIHN0YXRlID0gWzE3MzI1ODQxOTMsIC0yNzE3MzM4NzksIC0xNzMyNTg0MTk0LCAyNzE3MzM4NzhdLFxuICAgIGk7XG4gIGZvciAoaSA9IDY0OyBpIDw9IHMubGVuZ3RoOyBpICs9IDY0KSB7XG4gICAgbWQ1Y3ljbGUoc3RhdGUsIG1kNWJsayhzLnN1YnN0cmluZyhpIC0gNjQsIGkpKSk7XG4gIH1cbiAgcyA9IHMuc3Vic3RyaW5nKGkgLSA2NCk7XG4gIHZhciB0YWlsID0gWzAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDBdO1xuICBmb3IgKGkgPSAwOyBpIDwgcy5sZW5ndGg7IGkrKylcbiAgICB0YWlsW2kgPj4gMl0gfD0gcy5jaGFyQ29kZUF0KGkpIDw8ICgoaSAlIDQpIDw8IDMpO1xuICB0YWlsW2kgPj4gMl0gfD0gMHg4MCA8PCAoKGkgJSA0KSA8PCAzKTtcbiAgaWYgKGkgPiA1NSkge1xuICAgIG1kNWN5Y2xlKHN0YXRlLCB0YWlsKTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgMTY7IGkrKykgdGFpbFtpXSA9IDA7XG4gIH1cbiAgdGFpbFsxNF0gPSBuICogODtcbiAgbWQ1Y3ljbGUoc3RhdGUsIHRhaWwpO1xuICByZXR1cm4gc3RhdGU7XG59XG5cbi8qIHRoZXJlIG5lZWRzIHRvIGJlIHN1cHBvcnQgZm9yIFVuaWNvZGUgaGVyZSxcbiAqIHVubGVzcyB3ZSBwcmV0ZW5kIHRoYXQgd2UgY2FuIHJlZGVmaW5lIHRoZSBNRC01XG4gKiBhbGdvcml0aG0gZm9yIG11bHRpLWJ5dGUgY2hhcmFjdGVycyAocGVyaGFwc1xuICogYnkgYWRkaW5nIGV2ZXJ5IGZvdXIgMTYtYml0IGNoYXJhY3RlcnMgYW5kXG4gKiBzaG9ydGVuaW5nIHRoZSBzdW0gdG8gMzIgYml0cykuIE90aGVyd2lzZVxuICogSSBzdWdnZXN0IHBlcmZvcm1pbmcgTUQtNSBhcyBpZiBldmVyeSBjaGFyYWN0ZXJcbiAqIHdhcyB0d28gYnl0ZXMtLWUuZy4sIDAwNDAgMDAyNSA9IEAlLS1idXQgdGhlblxuICogaG93IHdpbGwgYW4gb3JkaW5hcnkgTUQtNSBzdW0gYmUgbWF0Y2hlZD9cbiAqIFRoZXJlIGlzIG5vIHdheSB0byBzdGFuZGFyZGl6ZSB0ZXh0IHRvIHNvbWV0aGluZ1xuICogbGlrZSBVVEYtOCBiZWZvcmUgdHJhbnNmb3JtYXRpb247IHNwZWVkIGNvc3QgaXNcbiAqIHV0dGVybHkgcHJvaGliaXRpdmUuIFRoZSBKYXZhU2NyaXB0IHN0YW5kYXJkXG4gKiBpdHNlbGYgbmVlZHMgdG8gbG9vayBhdCB0aGlzOiBpdCBzaG91bGQgc3RhcnRcbiAqIHByb3ZpZGluZyBhY2Nlc3MgdG8gc3RyaW5ncyBhcyBwcmVmb3JtZWQgVVRGLThcbiAqIDgtYml0IHVuc2lnbmVkIHZhbHVlIGFycmF5cy5cbiAqL1xuZnVuY3Rpb24gbWQ1YmxrKHMpIHsgLyogSSBmaWd1cmVkIGdsb2JhbCB3YXMgZmFzdGVyLiAgICovXG4gIHZhciBtZDVibGtzID0gW10sXG4gICAgaTsgLyogQW5keSBLaW5nIHNhaWQgZG8gaXQgdGhpcyB3YXkuICovXG4gIGZvciAoaSA9IDA7IGkgPCA2NDsgaSArPSA0KSB7XG4gICAgbWQ1Ymxrc1tpID4+IDJdID0gcy5jaGFyQ29kZUF0KGkpICsgKHMuY2hhckNvZGVBdChpICsgMSkgPDwgOCkgKyAocy5jaGFyQ29kZUF0KGkgKyAyKSA8PCAxNikgKyAocy5jaGFyQ29kZUF0KGkgKyAzKSA8PFxuICAgICAgMjQpO1xuICB9XG4gIHJldHVybiBtZDVibGtzO1xufVxuXG52YXIgaGV4X2NociA9ICcwMTIzNDU2Nzg5YWJjZGVmJy5zcGxpdCgnJyk7XG5cbmZ1bmN0aW9uIHJoZXgobikge1xuICB2YXIgcyA9ICcnLFxuICAgIGogPSAwO1xuICBmb3IgKDsgaiA8IDQ7IGorKylcbiAgICBzICs9IGhleF9jaHJbKG4gPj4gKGogKiA4ICsgNCkpICYgMHgwRl0gKyBoZXhfY2hyWyhuID4+IChqICogOCkpICYgMHgwRl07XG4gIHJldHVybiBzO1xufVxuXG5mdW5jdGlvbiBoZXgoeCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHgubGVuZ3RoOyBpKyspXG4gICAgeFtpXSA9IHJoZXgoeFtpXSk7XG4gIHJldHVybiB4LmpvaW4oJycpO1xufVxuXG5mdW5jdGlvbiBtZDUocykge1xuICByZXR1cm4gaGV4KG1kNTEocykpO1xufVxuXG4vKiB0aGlzIGZ1bmN0aW9uIGlzIG11Y2ggZmFzdGVyLFxuc28gaWYgcG9zc2libGUgd2UgdXNlIGl0LiBTb21lIElFc1xuYXJlIHRoZSBvbmx5IG9uZXMgSSBrbm93IG9mIHRoYXRcbm5lZWQgdGhlIGlkaW90aWMgc2Vjb25kIGZ1bmN0aW9uLFxuZ2VuZXJhdGVkIGJ5IGFuIGlmIGNsYXVzZS4gICovXG5cbmZ1bmN0aW9uIGFkZDMyKGEsIGIpIHtcbiAgcmV0dXJuIChhICsgYikgJiAweEZGRkZGRkZGO1xufVxuXG5pZiAobWQ1KCdoZWxsbycpICE9ICc1ZDQxNDAyYWJjNGIyYTc2Yjk3MTlkOTExMDE3YzU5MicpIHtcbiAgZnVuY3Rpb24gYWRkMzIoeCwgeSkge1xuICAgIHZhciBsc3cgPSAoeCAmIDB4RkZGRikgKyAoeSAmIDB4RkZGRiksXG4gICAgICBtc3cgPSAoeCA+PiAxNikgKyAoeSA+PiAxNikgKyAobHN3ID4+IDE2KTtcbiAgICByZXR1cm4gKG1zdyA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcbiAgfVxufVxuIiwiLypcbiAqIENyeXB0b01YIFRvb2xzXG4gKiBDb3B5cmlnaHQgKEMpIDIwMDQgLSAyMDA2IERlcmVrIEJ1aXRlbmh1aXNcbiAqXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gKiBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICogYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDJcbiAqIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4gKlxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4gKiBGb3VuZGF0aW9uLCBJbmMuLCA1OSBUZW1wbGUgUGxhY2UgLSBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgIDAyMTExLTEzMDcsIFVTQS5cbiAqL1xuXG4vKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcbiAqL1xuXG4vKipcbiAqIEBtb2R1bGUgY3J5cHRvL2hhc2gvcmlwZS1tZFxuICovXG5cbnZhciBSTURzaXplID0gMTYwO1xudmFyIFggPSBuZXcgQXJyYXkoKTtcblxuZnVuY3Rpb24gUk9MKHgsIG4pIHtcbiAgcmV0dXJuIG5ldyBOdW1iZXIoKHggPDwgbikgfCAoeCA+Pj4gKDMyIC0gbikpKTtcbn1cblxuZnVuY3Rpb24gRih4LCB5LCB6KSB7XG4gIHJldHVybiBuZXcgTnVtYmVyKHggXiB5IF4geik7XG59XG5cbmZ1bmN0aW9uIEcoeCwgeSwgeikge1xuICByZXR1cm4gbmV3IE51bWJlcigoeCAmIHkpIHwgKH54ICYgeikpO1xufVxuXG5mdW5jdGlvbiBIKHgsIHksIHopIHtcbiAgcmV0dXJuIG5ldyBOdW1iZXIoKHggfCB+eSkgXiB6KTtcbn1cblxuZnVuY3Rpb24gSSh4LCB5LCB6KSB7XG4gIHJldHVybiBuZXcgTnVtYmVyKCh4ICYgeikgfCAoeSAmIH56KSk7XG59XG5cbmZ1bmN0aW9uIEooeCwgeSwgeikge1xuICByZXR1cm4gbmV3IE51bWJlcih4IF4gKHkgfCB+eikpO1xufVxuXG5mdW5jdGlvbiBtaXhPbmVSb3VuZChhLCBiLCBjLCBkLCBlLCB4LCBzLCByb3VuZE51bWJlcikge1xuICBzd2l0Y2ggKHJvdW5kTnVtYmVyKSB7XG4gICAgY2FzZSAwOlxuICAgICAgYSArPSBGKGIsIGMsIGQpICsgeCArIDB4MDAwMDAwMDA7XG4gICAgICBicmVhaztcbiAgICBjYXNlIDE6XG4gICAgICBhICs9IEcoYiwgYywgZCkgKyB4ICsgMHg1YTgyNzk5OTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgMjpcbiAgICAgIGEgKz0gSChiLCBjLCBkKSArIHggKyAweDZlZDllYmExO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAzOlxuICAgICAgYSArPSBJKGIsIGMsIGQpICsgeCArIDB4OGYxYmJjZGM7XG4gICAgICBicmVhaztcbiAgICBjYXNlIDQ6XG4gICAgICBhICs9IEooYiwgYywgZCkgKyB4ICsgMHhhOTUzZmQ0ZTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgNTpcbiAgICAgIGEgKz0gSihiLCBjLCBkKSArIHggKyAweDUwYTI4YmU2O1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSA2OlxuICAgICAgYSArPSBJKGIsIGMsIGQpICsgeCArIDB4NWM0ZGQxMjQ7XG4gICAgICBicmVhaztcbiAgICBjYXNlIDc6XG4gICAgICBhICs9IEgoYiwgYywgZCkgKyB4ICsgMHg2ZDcwM2VmMztcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgODpcbiAgICAgIGEgKz0gRyhiLCBjLCBkKSArIHggKyAweDdhNmQ3NmU5O1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSA5OlxuICAgICAgYSArPSBGKGIsIGMsIGQpICsgeCArIDB4MDAwMDAwMDA7XG4gICAgICBicmVhaztcblxuICAgIGRlZmF1bHQ6XG4gICAgICBkb2N1bWVudC53cml0ZShcIkJvZ3VzIHJvdW5kIG51bWJlclwiKTtcbiAgICAgIGJyZWFrO1xuICB9XG5cbiAgYSA9IFJPTChhLCBzKSArIGU7XG4gIGMgPSBST0woYywgMTApO1xuXG4gIGEgJj0gMHhmZmZmZmZmZjtcbiAgYiAmPSAweGZmZmZmZmZmO1xuICBjICY9IDB4ZmZmZmZmZmY7XG4gIGQgJj0gMHhmZmZmZmZmZjtcbiAgZSAmPSAweGZmZmZmZmZmO1xuXG4gIHZhciByZXRCbG9jayA9IG5ldyBBcnJheSgpO1xuICByZXRCbG9ja1swXSA9IGE7XG4gIHJldEJsb2NrWzFdID0gYjtcbiAgcmV0QmxvY2tbMl0gPSBjO1xuICByZXRCbG9ja1szXSA9IGQ7XG4gIHJldEJsb2NrWzRdID0gZTtcbiAgcmV0QmxvY2tbNV0gPSB4O1xuICByZXRCbG9ja1s2XSA9IHM7XG5cbiAgcmV0dXJuIHJldEJsb2NrO1xufVxuXG5mdW5jdGlvbiBNRGluaXQoTURidWYpIHtcbiAgTURidWZbMF0gPSAweDY3NDUyMzAxO1xuICBNRGJ1ZlsxXSA9IDB4ZWZjZGFiODk7XG4gIE1EYnVmWzJdID0gMHg5OGJhZGNmZTtcbiAgTURidWZbM10gPSAweDEwMzI1NDc2O1xuICBNRGJ1Zls0XSA9IDB4YzNkMmUxZjA7XG59XG5cbnZhciBST0xzID0gW1xuICBbMTEsIDE0LCAxNSwgMTIsIDUsIDgsIDcsIDksIDExLCAxMywgMTQsIDE1LCA2LCA3LCA5LCA4XSxcbiAgWzcsIDYsIDgsIDEzLCAxMSwgOSwgNywgMTUsIDcsIDEyLCAxNSwgOSwgMTEsIDcsIDEzLCAxMl0sXG4gIFsxMSwgMTMsIDYsIDcsIDE0LCA5LCAxMywgMTUsIDE0LCA4LCAxMywgNiwgNSwgMTIsIDcsIDVdLFxuICBbMTEsIDEyLCAxNCwgMTUsIDE0LCAxNSwgOSwgOCwgOSwgMTQsIDUsIDYsIDgsIDYsIDUsIDEyXSxcbiAgWzksIDE1LCA1LCAxMSwgNiwgOCwgMTMsIDEyLCA1LCAxMiwgMTMsIDE0LCAxMSwgOCwgNSwgNl0sXG4gIFs4LCA5LCA5LCAxMSwgMTMsIDE1LCAxNSwgNSwgNywgNywgOCwgMTEsIDE0LCAxNCwgMTIsIDZdLFxuICBbOSwgMTMsIDE1LCA3LCAxMiwgOCwgOSwgMTEsIDcsIDcsIDEyLCA3LCA2LCAxNSwgMTMsIDExXSxcbiAgWzksIDcsIDE1LCAxMSwgOCwgNiwgNiwgMTQsIDEyLCAxMywgNSwgMTQsIDEzLCAxMywgNywgNV0sXG4gIFsxNSwgNSwgOCwgMTEsIDE0LCAxNCwgNiwgMTQsIDYsIDksIDEyLCA5LCAxMiwgNSwgMTUsIDhdLFxuICBbOCwgNSwgMTIsIDksIDEyLCA1LCAxNCwgNiwgOCwgMTMsIDYsIDUsIDE1LCAxMywgMTEsIDExXVxuXTtcblxudmFyIGluZGV4ZXMgPSBbXG4gIFswLCAxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMCwgMTEsIDEyLCAxMywgMTQsIDE1XSxcbiAgWzcsIDQsIDEzLCAxLCAxMCwgNiwgMTUsIDMsIDEyLCAwLCA5LCA1LCAyLCAxNCwgMTEsIDhdLFxuICBbMywgMTAsIDE0LCA0LCA5LCAxNSwgOCwgMSwgMiwgNywgMCwgNiwgMTMsIDExLCA1LCAxMl0sXG4gIFsxLCA5LCAxMSwgMTAsIDAsIDgsIDEyLCA0LCAxMywgMywgNywgMTUsIDE0LCA1LCA2LCAyXSxcbiAgWzQsIDAsIDUsIDksIDcsIDEyLCAyLCAxMCwgMTQsIDEsIDMsIDgsIDExLCA2LCAxNSwgMTNdLFxuICBbNSwgMTQsIDcsIDAsIDksIDIsIDExLCA0LCAxMywgNiwgMTUsIDgsIDEsIDEwLCAzLCAxMl0sXG4gIFs2LCAxMSwgMywgNywgMCwgMTMsIDUsIDEwLCAxNCwgMTUsIDgsIDEyLCA0LCA5LCAxLCAyXSxcbiAgWzE1LCA1LCAxLCAzLCA3LCAxNCwgNiwgOSwgMTEsIDgsIDEyLCAyLCAxMCwgMCwgNCwgMTNdLFxuICBbOCwgNiwgNCwgMSwgMywgMTEsIDE1LCAwLCA1LCAxMiwgMiwgMTMsIDksIDcsIDEwLCAxNF0sXG4gIFsxMiwgMTUsIDEwLCA0LCAxLCA1LCA4LCA3LCA2LCAyLCAxMywgMTQsIDAsIDMsIDksIDExXVxuXTtcblxuZnVuY3Rpb24gY29tcHJlc3MoTURidWYsIFgpIHtcbiAgYmxvY2tBID0gbmV3IEFycmF5KCk7XG4gIGJsb2NrQiA9IG5ldyBBcnJheSgpO1xuXG4gIHZhciByZXRCbG9jaztcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IDU7IGkrKykge1xuICAgIGJsb2NrQVtpXSA9IG5ldyBOdW1iZXIoTURidWZbaV0pO1xuICAgIGJsb2NrQltpXSA9IG5ldyBOdW1iZXIoTURidWZbaV0pO1xuICB9XG5cbiAgdmFyIHN0ZXAgPSAwO1xuICBmb3IgKHZhciBqID0gMDsgaiA8IDU7IGorKykge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMTY7IGkrKykge1xuICAgICAgcmV0QmxvY2sgPSBtaXhPbmVSb3VuZChcbiAgICAgICAgYmxvY2tBWyhzdGVwICsgMCkgJSA1XSxcbiAgICAgICAgYmxvY2tBWyhzdGVwICsgMSkgJSA1XSxcbiAgICAgICAgYmxvY2tBWyhzdGVwICsgMikgJSA1XSxcbiAgICAgICAgYmxvY2tBWyhzdGVwICsgMykgJSA1XSxcbiAgICAgICAgYmxvY2tBWyhzdGVwICsgNCkgJSA1XSxcbiAgICAgICAgWFtpbmRleGVzW2pdW2ldXSxcbiAgICAgICAgUk9Mc1tqXVtpXSxcbiAgICAgICAgaik7XG5cbiAgICAgIGJsb2NrQVsoc3RlcCArIDApICUgNV0gPSByZXRCbG9ja1swXTtcbiAgICAgIGJsb2NrQVsoc3RlcCArIDEpICUgNV0gPSByZXRCbG9ja1sxXTtcbiAgICAgIGJsb2NrQVsoc3RlcCArIDIpICUgNV0gPSByZXRCbG9ja1syXTtcbiAgICAgIGJsb2NrQVsoc3RlcCArIDMpICUgNV0gPSByZXRCbG9ja1szXTtcbiAgICAgIGJsb2NrQVsoc3RlcCArIDQpICUgNV0gPSByZXRCbG9ja1s0XTtcblxuICAgICAgc3RlcCArPSA0O1xuICAgIH1cbiAgfVxuXG4gIHN0ZXAgPSAwO1xuICBmb3IgKHZhciBqID0gNTsgaiA8IDEwOyBqKyspIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IDE2OyBpKyspIHtcbiAgICAgIHJldEJsb2NrID0gbWl4T25lUm91bmQoXG4gICAgICAgIGJsb2NrQlsoc3RlcCArIDApICUgNV0sXG4gICAgICAgIGJsb2NrQlsoc3RlcCArIDEpICUgNV0sXG4gICAgICAgIGJsb2NrQlsoc3RlcCArIDIpICUgNV0sXG4gICAgICAgIGJsb2NrQlsoc3RlcCArIDMpICUgNV0sXG4gICAgICAgIGJsb2NrQlsoc3RlcCArIDQpICUgNV0sXG4gICAgICAgIFhbaW5kZXhlc1tqXVtpXV0sXG4gICAgICAgIFJPTHNbal1baV0sXG4gICAgICAgIGopO1xuXG4gICAgICBibG9ja0JbKHN0ZXAgKyAwKSAlIDVdID0gcmV0QmxvY2tbMF07XG4gICAgICBibG9ja0JbKHN0ZXAgKyAxKSAlIDVdID0gcmV0QmxvY2tbMV07XG4gICAgICBibG9ja0JbKHN0ZXAgKyAyKSAlIDVdID0gcmV0QmxvY2tbMl07XG4gICAgICBibG9ja0JbKHN0ZXAgKyAzKSAlIDVdID0gcmV0QmxvY2tbM107XG4gICAgICBibG9ja0JbKHN0ZXAgKyA0KSAlIDVdID0gcmV0QmxvY2tbNF07XG5cbiAgICAgIHN0ZXAgKz0gNDtcbiAgICB9XG4gIH1cblxuICBibG9ja0JbM10gKz0gYmxvY2tBWzJdICsgTURidWZbMV07XG4gIE1EYnVmWzFdID0gTURidWZbMl0gKyBibG9ja0FbM10gKyBibG9ja0JbNF07XG4gIE1EYnVmWzJdID0gTURidWZbM10gKyBibG9ja0FbNF0gKyBibG9ja0JbMF07XG4gIE1EYnVmWzNdID0gTURidWZbNF0gKyBibG9ja0FbMF0gKyBibG9ja0JbMV07XG4gIE1EYnVmWzRdID0gTURidWZbMF0gKyBibG9ja0FbMV0gKyBibG9ja0JbMl07XG4gIE1EYnVmWzBdID0gYmxvY2tCWzNdO1xufVxuXG5mdW5jdGlvbiB6ZXJvWChYKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgMTY7IGkrKykge1xuICAgIFhbaV0gPSAwO1xuICB9XG59XG5cbmZ1bmN0aW9uIE1EZmluaXNoKE1EYnVmLCBzdHJwdHIsIGxzd2xlbiwgbXN3bGVuKSB7XG4gIHZhciBYID0gbmV3IEFycmF5KDE2KTtcbiAgemVyb1goWCk7XG5cbiAgdmFyIGogPSAwO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IChsc3dsZW4gJiA2Myk7IGkrKykge1xuICAgIFhbaSA+Pj4gMl0gXj0gKHN0cnB0ci5jaGFyQ29kZUF0KGorKykgJiAyNTUpIDw8ICg4ICogKGkgJiAzKSk7XG4gIH1cblxuICBYWyhsc3dsZW4gPj4+IDIpICYgMTVdIF49IDEgPDwgKDggKiAobHN3bGVuICYgMykgKyA3KTtcblxuICBpZiAoKGxzd2xlbiAmIDYzKSA+IDU1KSB7XG4gICAgY29tcHJlc3MoTURidWYsIFgpO1xuICAgIHZhciBYID0gbmV3IEFycmF5KDE2KTtcbiAgICB6ZXJvWChYKTtcbiAgfVxuXG4gIFhbMTRdID0gbHN3bGVuIDw8IDM7XG4gIFhbMTVdID0gKGxzd2xlbiA+Pj4gMjkpIHwgKG1zd2xlbiA8PCAzKTtcblxuICBjb21wcmVzcyhNRGJ1ZiwgWCk7XG59XG5cbmZ1bmN0aW9uIEJZVEVTX1RPX0RXT1JEKGZvdXJDaGFycykge1xuICB2YXIgdG1wID0gKGZvdXJDaGFycy5jaGFyQ29kZUF0KDMpICYgMjU1KSA8PCAyNDtcbiAgdG1wIHw9IChmb3VyQ2hhcnMuY2hhckNvZGVBdCgyKSAmIDI1NSkgPDwgMTY7XG4gIHRtcCB8PSAoZm91ckNoYXJzLmNoYXJDb2RlQXQoMSkgJiAyNTUpIDw8IDg7XG4gIHRtcCB8PSAoZm91ckNoYXJzLmNoYXJDb2RlQXQoMCkgJiAyNTUpO1xuXG4gIHJldHVybiB0bXA7XG59XG5cbmZ1bmN0aW9uIFJNRChtZXNzYWdlKSB7XG4gIHZhciBNRGJ1ZiA9IG5ldyBBcnJheShSTURzaXplIC8gMzIpO1xuICB2YXIgaGFzaGNvZGUgPSBuZXcgQXJyYXkoUk1Ec2l6ZSAvIDgpO1xuICB2YXIgbGVuZ3RoO1xuICB2YXIgbmJ5dGVzO1xuXG4gIE1EaW5pdChNRGJ1Zik7XG4gIGxlbmd0aCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG4gIHZhciBYID0gbmV3IEFycmF5KDE2KTtcbiAgemVyb1goWCk7XG5cbiAgdmFyIGogPSAwO1xuICBmb3IgKHZhciBuYnl0ZXMgPSBsZW5ndGg7IG5ieXRlcyA+IDYzOyBuYnl0ZXMgLT0gNjQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IDE2OyBpKyspIHtcbiAgICAgIFhbaV0gPSBCWVRFU19UT19EV09SRChtZXNzYWdlLnN1YnN0cihqLCA0KSk7XG4gICAgICBqICs9IDQ7XG4gICAgfVxuICAgIGNvbXByZXNzKE1EYnVmLCBYKTtcbiAgfVxuXG4gIE1EZmluaXNoKE1EYnVmLCBtZXNzYWdlLnN1YnN0cihqKSwgbGVuZ3RoLCAwKTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IFJNRHNpemUgLyA4OyBpICs9IDQpIHtcbiAgICBoYXNoY29kZVtpXSA9IE1EYnVmW2kgPj4+IDJdICYgMjU1O1xuICAgIGhhc2hjb2RlW2kgKyAxXSA9IChNRGJ1ZltpID4+PiAyXSA+Pj4gOCkgJiAyNTU7XG4gICAgaGFzaGNvZGVbaSArIDJdID0gKE1EYnVmW2kgPj4+IDJdID4+PiAxNikgJiAyNTU7XG4gICAgaGFzaGNvZGVbaSArIDNdID0gKE1EYnVmW2kgPj4+IDJdID4+PiAyNCkgJiAyNTU7XG4gIH1cblxuICByZXR1cm4gaGFzaGNvZGU7XG59XG5cblxuZnVuY3Rpb24gUk1Ec3RyaW5nKG1lc3NhZ2UpIHtcbiAgdmFyIGhhc2hjb2RlID0gUk1EKG1lc3NhZ2UpO1xuICB2YXIgcmV0U3RyaW5nID0gXCJcIjtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IFJNRHNpemUgLyA4OyBpKyspIHtcbiAgICByZXRTdHJpbmcgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShoYXNoY29kZVtpXSk7XG4gIH1cblxuICByZXR1cm4gcmV0U3RyaW5nO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFJNRHN0cmluZztcbiIsIi8qIEEgSmF2YVNjcmlwdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgU0hBIGZhbWlseSBvZiBoYXNoZXMsIGFzIGRlZmluZWQgaW4gRklQUyBcbiAqIFBVQiAxODAtMiBhcyB3ZWxsIGFzIHRoZSBjb3JyZXNwb25kaW5nIEhNQUMgaW1wbGVtZW50YXRpb24gYXMgZGVmaW5lZCBpblxuICogRklQUyBQVUIgMTk4YVxuICpcbiAqIFZlcnNpb24gMS4zIENvcHlyaWdodCBCcmlhbiBUdXJlayAyMDA4LTIwMTBcbiAqIERpc3RyaWJ1dGVkIHVuZGVyIHRoZSBCU0QgTGljZW5zZVxuICogU2VlIGh0dHA6Ly9qc3NoYS5zb3VyY2Vmb3JnZS5uZXQvIGZvciBtb3JlIGluZm9ybWF0aW9uXG4gKlxuICogU2V2ZXJhbCBmdW5jdGlvbnMgdGFrZW4gZnJvbSBQYXVsIEpvaG5zb25cbiAqL1xuXG4vKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcbiAqIFxuICogVGhpcyBjb2RlIGhhcyBiZWVuIHNsaWdodGx5IG1vZGlmaWVkIGRpcmVjdCBzdHJpbmcgb3V0cHV0OlxuICogLSBiaW4yYnN0ciBoYXMgYmVlbiBhZGRlZFxuICogLSBmb2xsb3dpbmcgd3JhcHBlcnMgb2YgdGhpcyBsaWJyYXJ5IGhhdmUgYmVlbiBhZGRlZDpcbiAqICAgLSBzdHJfc2hhMVxuICogICAtIHN0cl9zaGEyNTZcbiAqICAgLSBzdHJfc2hhMjI0XG4gKiAgIC0gc3RyX3NoYTM4NFxuICogICAtIHN0cl9zaGE1MTJcbiAqL1xuXG4vKipcbiAqIEBtb2R1bGUgY3J5cHRvL2hhc2gvc2hhXG4gKi9cblxudmFyIGpzU0hBID0gKGZ1bmN0aW9uKCkge1xuXG4gIC8qXG4gICAqIENvbmZpZ3VyYWJsZSB2YXJpYWJsZXMuIERlZmF1bHRzIHR5cGljYWxseSB3b3JrXG4gICAqL1xuICAvKiBOdW1iZXIgb2YgQml0cyBQZXIgY2hhcmFjdGVyICg4IGZvciBBU0NJSSwgMTYgZm9yIFVuaWNvZGUpICovXG4gIHZhciBjaGFyU2l6ZSA9IDgsXG4gICAgLyogYmFzZS02NCBwYWQgY2hhcmFjdGVyLiBcIj1cIiBmb3Igc3RyaWN0IFJGQyBjb21wbGlhbmNlICovXG4gICAgYjY0cGFkID0gXCJcIixcbiAgICAvKiBoZXggb3V0cHV0IGZvcm1hdC4gMCAtIGxvd2VyY2FzZTsgMSAtIHVwcGVyY2FzZSAqL1xuICAgIGhleENhc2UgPSAwLFxuXG4gICAgLypcbiAgICAgKiBJbnRfNjQgaXMgYSBvYmplY3QgZm9yIDIgMzItYml0IG51bWJlcnMgZW11bGF0aW5nIGEgNjQtYml0IG51bWJlclxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IG1zaW50XzMyIFRoZSBtb3N0IHNpZ25pZmljYW50IDMyLWJpdHMgb2YgYSA2NC1iaXQgbnVtYmVyXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IGxzaW50XzMyIFRoZSBsZWFzdCBzaWduaWZpY2FudCAzMi1iaXRzIG9mIGEgNjQtYml0IG51bWJlclxuICAgICAqL1xuICAgIEludF82NCA9IGZ1bmN0aW9uKG1zaW50XzMyLCBsc2ludF8zMikge1xuICAgICAgdGhpcy5oaWdoT3JkZXIgPSBtc2ludF8zMjtcbiAgICAgIHRoaXMubG93T3JkZXIgPSBsc2ludF8zMjtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBDb252ZXJ0IGEgc3RyaW5nIHRvIGFuIGFycmF5IG9mIGJpZy1lbmRpYW4gd29yZHNcbiAgICAgKiBJZiBjaGFyU2l6ZSBpcyBBU0NJSSwgY2hhcmFjdGVycyA+MjU1IGhhdmUgdGhlaXIgaGktYnl0ZSBzaWxlbnRseVxuICAgICAqIGlnbm9yZWQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyB0byBiZSBjb252ZXJ0ZWQgdG8gYmluYXJ5IHJlcHJlc2VudGF0aW9uXG4gICAgICogQHJldHVybiBJbnRlZ2VyIGFycmF5IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwYXJhbWV0ZXJcbiAgICAgKi9cbiAgICBzdHIyYmluYiA9IGZ1bmN0aW9uKHN0cikge1xuICAgICAgdmFyIGJpbiA9IFtdLFxuICAgICAgICBtYXNrID0gKDEgPDwgY2hhclNpemUpIC0gMSxcbiAgICAgICAgbGVuZ3RoID0gc3RyLmxlbmd0aCAqIGNoYXJTaXplLFxuICAgICAgICBpO1xuXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IGNoYXJTaXplKSB7XG4gICAgICAgIGJpbltpID4+IDVdIHw9IChzdHIuY2hhckNvZGVBdChpIC8gY2hhclNpemUpICYgbWFzaykgPDxcbiAgICAgICAgICAoMzIgLSBjaGFyU2l6ZSAtIChpICUgMzIpKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGJpbjtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBDb252ZXJ0IGEgaGV4IHN0cmluZyB0byBhbiBhcnJheSBvZiBiaWctZW5kaWFuIHdvcmRzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyB0byBiZSBjb252ZXJ0ZWQgdG8gYmluYXJ5IHJlcHJlc2VudGF0aW9uXG4gICAgICogQHJldHVybiBJbnRlZ2VyIGFycmF5IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwYXJhbWV0ZXJcbiAgICAgKi9cbiAgICBoZXgyYmluYiA9IGZ1bmN0aW9uKHN0cikge1xuICAgICAgdmFyIGJpbiA9IFtdLFxuICAgICAgICBsZW5ndGggPSBzdHIubGVuZ3RoLFxuICAgICAgICBpLCBudW07XG5cbiAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMikge1xuICAgICAgICBudW0gPSBwYXJzZUludChzdHIuc3Vic3RyKGksIDIpLCAxNik7XG4gICAgICAgIGlmICghaXNOYU4obnVtKSkge1xuICAgICAgICAgIGJpbltpID4+IDNdIHw9IG51bSA8PCAoMjQgLSAoNCAqIChpICUgOCkpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gXCJJTlZBTElEIEhFWCBTVFJJTkdcIjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gYmluO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIENvbnZlcnQgYW4gYXJyYXkgb2YgYmlnLWVuZGlhbiB3b3JkcyB0byBhIGhleCBzdHJpbmcuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7QXJyYXl9IGJpbmFycmF5IEFycmF5IG9mIGludGVnZXJzIHRvIGJlIGNvbnZlcnRlZCB0byBoZXhpZGVjaW1hbFxuICAgICAqXHQgcmVwcmVzZW50YXRpb25cbiAgICAgKiBAcmV0dXJuIEhleGlkZWNpbWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwYXJhbWV0ZXIgaW4gU3RyaW5nIGZvcm1cbiAgICAgKi9cbiAgICBiaW5iMmhleCA9IGZ1bmN0aW9uKGJpbmFycmF5KSB7XG4gICAgICB2YXIgaGV4X3RhYiA9IChoZXhDYXNlKSA/IFwiMDEyMzQ1Njc4OUFCQ0RFRlwiIDogXCIwMTIzNDU2Nzg5YWJjZGVmXCIsXG4gICAgICAgIHN0ciA9IFwiXCIsXG4gICAgICAgIGxlbmd0aCA9IGJpbmFycmF5Lmxlbmd0aCAqIDQsXG4gICAgICAgIGksIHNyY0J5dGU7XG5cbiAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBzcmNCeXRlID0gYmluYXJyYXlbaSA+PiAyXSA+PiAoKDMgLSAoaSAlIDQpKSAqIDgpO1xuICAgICAgICBzdHIgKz0gaGV4X3RhYi5jaGFyQXQoKHNyY0J5dGUgPj4gNCkgJiAweEYpICtcbiAgICAgICAgICBoZXhfdGFiLmNoYXJBdChzcmNCeXRlICYgMHhGKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBDb252ZXJ0IGFuIGFycmF5IG9mIGJpZy1lbmRpYW4gd29yZHMgdG8gYSBiYXNlLTY0IHN0cmluZ1xuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBiaW5hcnJheSBBcnJheSBvZiBpbnRlZ2VycyB0byBiZSBjb252ZXJ0ZWQgdG8gYmFzZS02NFxuICAgICAqXHQgcmVwcmVzZW50YXRpb25cbiAgICAgKiBAcmV0dXJuIEJhc2UtNjQgZW5jb2RlZCByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFyYW1ldGVyIGluIFN0cmluZyBmb3JtXG4gICAgICovXG4gICAgYmluYjJiNjQgPSBmdW5jdGlvbihiaW5hcnJheSkge1xuICAgICAgdmFyIHRhYiA9IFwiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5elwiICtcbiAgICAgICAgXCIwMTIzNDU2Nzg5Ky9cIixcbiAgICAgICAgc3RyID0gXCJcIixcbiAgICAgICAgbGVuZ3RoID0gYmluYXJyYXkubGVuZ3RoICogNCxcbiAgICAgICAgaSwgaixcbiAgICAgICAgdHJpcGxldDtcblxuICAgICAgZm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAzKSB7XG4gICAgICAgIHRyaXBsZXQgPSAoKChiaW5hcnJheVtpID4+IDJdID4+IDggKiAoMyAtIGkgJSA0KSkgJiAweEZGKSA8PCAxNikgfFxuICAgICAgICAgICgoKGJpbmFycmF5W2kgKyAxID4+IDJdID4+IDggKiAoMyAtIChpICsgMSkgJSA0KSkgJiAweEZGKSA8PCA4KSB8XG4gICAgICAgICAgKChiaW5hcnJheVtpICsgMiA+PiAyXSA+PiA4ICogKDMgLSAoaSArIDIpICUgNCkpICYgMHhGRik7XG4gICAgICAgIGZvciAoaiA9IDA7IGogPCA0OyBqICs9IDEpIHtcbiAgICAgICAgICBpZiAoaSAqIDggKyBqICogNiA8PSBiaW5hcnJheS5sZW5ndGggKiAzMikge1xuICAgICAgICAgICAgc3RyICs9IHRhYi5jaGFyQXQoKHRyaXBsZXQgPj4gNiAqICgzIC0gaikpICYgMHgzRik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHN0ciArPSBiNjRwYWQ7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gc3RyO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIENvbnZlcnQgYW4gYXJyYXkgb2YgYmlnLWVuZGlhbiB3b3JkcyB0byBhIHN0cmluZ1xuICAgICAqL1xuICAgIGJpbmIyc3RyID0gZnVuY3Rpb24oYmluKSB7XG4gICAgICB2YXIgc3RyID0gXCJcIjtcbiAgICAgIHZhciBtYXNrID0gKDEgPDwgOCkgLSAxO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBiaW4ubGVuZ3RoICogMzI7IGkgKz0gOClcbiAgICAgICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGJpbltpID4+IDVdID4+PiAoMjQgLSBpICUgMzIpKSAmIG1hc2spO1xuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9LFxuICAgIC8qXG4gICAgICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiBjaXJjdWxhciByb3RhdGUgbGVmdFxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gbiBUaGUgbnVtYmVyIG9mIGJpdHMgdG8gc2hpZnRcbiAgICAgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgY2lyY3VsYXJseSBieSBuIGJpdHNcbiAgICAgKi9cbiAgICByb3RsXzMyID0gZnVuY3Rpb24oeCwgbikge1xuICAgICAgcmV0dXJuICh4IDw8IG4pIHwgKHggPj4+ICgzMiAtIG4pKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIGNpcmN1bGFyIHJvdGF0ZSByaWdodFxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gbiBUaGUgbnVtYmVyIG9mIGJpdHMgdG8gc2hpZnRcbiAgICAgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgY2lyY3VsYXJseSBieSBuIGJpdHNcbiAgICAgKi9cbiAgICByb3RyXzMyID0gZnVuY3Rpb24oeCwgbikge1xuICAgICAgcmV0dXJuICh4ID4+PiBuKSB8ICh4IDw8ICgzMiAtIG4pKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgNjQtYml0IGltcGxlbWVudGF0aW9uIG9mIGNpcmN1bGFyIHJvdGF0ZSByaWdodFxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gbiBUaGUgbnVtYmVyIG9mIGJpdHMgdG8gc2hpZnRcbiAgICAgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgY2lyY3VsYXJseSBieSBuIGJpdHNcbiAgICAgKi9cbiAgICByb3RyXzY0ID0gZnVuY3Rpb24oeCwgbikge1xuICAgICAgaWYgKG4gPD0gMzIpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBJbnRfNjQoXG4gICAgICAgICh4LmhpZ2hPcmRlciA+Pj4gbikgfCAoeC5sb3dPcmRlciA8PCAoMzIgLSBuKSksICh4Lmxvd09yZGVyID4+PiBuKSB8ICh4LmhpZ2hPcmRlciA8PCAoMzIgLSBuKSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIG5ldyBJbnRfNjQoXG4gICAgICAgICh4Lmxvd09yZGVyID4+PiBuKSB8ICh4LmhpZ2hPcmRlciA8PCAoMzIgLSBuKSksICh4LmhpZ2hPcmRlciA+Pj4gbikgfCAoeC5sb3dPcmRlciA8PCAoMzIgLSBuKSkpO1xuICAgICAgfVxuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2Ygc2hpZnQgcmlnaHRcbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0XG4gICAgICogQHJldHVybiBUaGUgeCBzaGlmdGVkIGJ5IG4gYml0c1xuICAgICAqL1xuICAgIHNocl8zMiA9IGZ1bmN0aW9uKHgsIG4pIHtcbiAgICAgIHJldHVybiB4ID4+PiBuO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2Ygc2hpZnQgcmlnaHRcbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0XG4gICAgICogQHJldHVybiBUaGUgeCBzaGlmdGVkIGJ5IG4gYml0c1xuICAgICAqL1xuICAgIHNocl82NCA9IGZ1bmN0aW9uKHgsIG4pIHtcbiAgICAgIGlmIChuIDw9IDMyKSB7XG4gICAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICAgIHguaGlnaE9yZGVyID4+PiBuLFxuICAgICAgICAgIHgubG93T3JkZXIgPj4+IG4gfCAoeC5oaWdoT3JkZXIgPDwgKDMyIC0gbikpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICAgIDAsXG4gICAgICAgICAgeC5oaWdoT3JkZXIgPDwgKDMyIC0gbikpO1xuICAgICAgfVxuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFBhcml0eSBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgZmlyc3QgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geSBUaGUgc2Vjb25kIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHogVGhlIHRoaXJkIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuICAgICAqL1xuICAgIHBhcml0eV8zMiA9IGZ1bmN0aW9uKHgsIHksIHopIHtcbiAgICAgIHJldHVybiB4IF4geSBeIHo7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgQ2ggZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIGZpcnN0IDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHkgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB6IFRoZSB0aGlyZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBjaF8zMiA9IGZ1bmN0aW9uKHgsIHksIHopIHtcbiAgICAgIHJldHVybiAoeCAmIHkpIF4gKH54ICYgeik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgQ2ggZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIGZpcnN0IDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHkgVGhlIHNlY29uZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB6IFRoZSB0aGlyZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBjaF82NCA9IGZ1bmN0aW9uKHgsIHksIHopIHtcbiAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgKHguaGlnaE9yZGVyICYgeS5oaWdoT3JkZXIpIF4gKH54LmhpZ2hPcmRlciAmIHouaGlnaE9yZGVyKSwgKHgubG93T3JkZXIgJiB5Lmxvd09yZGVyKSBeICh+eC5sb3dPcmRlciAmIHoubG93T3JkZXIpKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBNYWogZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIGZpcnN0IDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHkgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB6IFRoZSB0aGlyZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBtYWpfMzIgPSBmdW5jdGlvbih4LCB5LCB6KSB7XG4gICAgICByZXR1cm4gKHggJiB5KSBeICh4ICYgeikgXiAoeSAmIHopO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIE1haiBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgZmlyc3QgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geSBUaGUgc2Vjb25kIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHogVGhlIHRoaXJkIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuICAgICAqL1xuICAgIG1hal82NCA9IGZ1bmN0aW9uKHgsIHksIHopIHtcbiAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgKHguaGlnaE9yZGVyICYgeS5oaWdoT3JkZXIpIF5cbiAgICAgICAgKHguaGlnaE9yZGVyICYgei5oaWdoT3JkZXIpIF5cbiAgICAgICAgKHkuaGlnaE9yZGVyICYgei5oaWdoT3JkZXIpLCAoeC5sb3dPcmRlciAmIHkubG93T3JkZXIpIF5cbiAgICAgICAgKHgubG93T3JkZXIgJiB6Lmxvd09yZGVyKSBeXG4gICAgICAgICh5Lmxvd09yZGVyICYgei5sb3dPcmRlcikpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFNpZ21hMCBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgc2lnbWEwXzMyID0gZnVuY3Rpb24oeCkge1xuICAgICAgcmV0dXJuIHJvdHJfMzIoeCwgMikgXiByb3RyXzMyKHgsIDEzKSBeIHJvdHJfMzIoeCwgMjIpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFNpZ21hMCBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgc2lnbWEwXzY0ID0gZnVuY3Rpb24oeCkge1xuICAgICAgdmFyIHJvdHIyOCA9IHJvdHJfNjQoeCwgMjgpLFxuICAgICAgICByb3RyMzQgPSByb3RyXzY0KHgsIDM0KSxcbiAgICAgICAgcm90cjM5ID0gcm90cl82NCh4LCAzOSk7XG5cbiAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICByb3RyMjguaGlnaE9yZGVyIF4gcm90cjM0LmhpZ2hPcmRlciBeIHJvdHIzOS5oaWdoT3JkZXIsXG4gICAgICAgIHJvdHIyOC5sb3dPcmRlciBeIHJvdHIzNC5sb3dPcmRlciBeIHJvdHIzOS5sb3dPcmRlcik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgU2lnbWExIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBzaWdtYTFfMzIgPSBmdW5jdGlvbih4KSB7XG4gICAgICByZXR1cm4gcm90cl8zMih4LCA2KSBeIHJvdHJfMzIoeCwgMTEpIF4gcm90cl8zMih4LCAyNSk7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgU2lnbWExIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBzaWdtYTFfNjQgPSBmdW5jdGlvbih4KSB7XG4gICAgICB2YXIgcm90cjE0ID0gcm90cl82NCh4LCAxNCksXG4gICAgICAgIHJvdHIxOCA9IHJvdHJfNjQoeCwgMTgpLFxuICAgICAgICByb3RyNDEgPSByb3RyXzY0KHgsIDQxKTtcblxuICAgICAgcmV0dXJuIG5ldyBJbnRfNjQoXG4gICAgICAgIHJvdHIxNC5oaWdoT3JkZXIgXiByb3RyMTguaGlnaE9yZGVyIF4gcm90cjQxLmhpZ2hPcmRlcixcbiAgICAgICAgcm90cjE0Lmxvd09yZGVyIF4gcm90cjE4Lmxvd09yZGVyIF4gcm90cjQxLmxvd09yZGVyKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBHYW1tYTAgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuICAgICAqL1xuICAgIGdhbW1hMF8zMiA9IGZ1bmN0aW9uKHgpIHtcbiAgICAgIHJldHVybiByb3RyXzMyKHgsIDcpIF4gcm90cl8zMih4LCAxOCkgXiBzaHJfMzIoeCwgMyk7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgR2FtbWEwIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBnYW1tYTBfNjQgPSBmdW5jdGlvbih4KSB7XG4gICAgICB2YXIgcm90cjEgPSByb3RyXzY0KHgsIDEpLFxuICAgICAgICByb3RyOCA9IHJvdHJfNjQoeCwgOCksXG4gICAgICAgIHNocjcgPSBzaHJfNjQoeCwgNyk7XG5cbiAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICByb3RyMS5oaWdoT3JkZXIgXiByb3RyOC5oaWdoT3JkZXIgXiBzaHI3LmhpZ2hPcmRlcixcbiAgICAgICAgcm90cjEubG93T3JkZXIgXiByb3RyOC5sb3dPcmRlciBeIHNocjcubG93T3JkZXIpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIEdhbW1hMSBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgZ2FtbWExXzMyID0gZnVuY3Rpb24oeCkge1xuICAgICAgcmV0dXJuIHJvdHJfMzIoeCwgMTcpIF4gcm90cl8zMih4LCAxOSkgXiBzaHJfMzIoeCwgMTApO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIEdhbW1hMSBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgZ2FtbWExXzY0ID0gZnVuY3Rpb24oeCkge1xuICAgICAgdmFyIHJvdHIxOSA9IHJvdHJfNjQoeCwgMTkpLFxuICAgICAgICByb3RyNjEgPSByb3RyXzY0KHgsIDYxKSxcbiAgICAgICAgc2hyNiA9IHNocl82NCh4LCA2KTtcblxuICAgICAgcmV0dXJuIG5ldyBJbnRfNjQoXG4gICAgICAgIHJvdHIxOS5oaWdoT3JkZXIgXiByb3RyNjEuaGlnaE9yZGVyIF4gc2hyNi5oaWdoT3JkZXIsXG4gICAgICAgIHJvdHIxOS5sb3dPcmRlciBeIHJvdHI2MS5sb3dPcmRlciBeIHNocjYubG93T3JkZXIpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIEFkZCB0d28gMzItYml0IGludGVnZXJzLCB3cmFwcGluZyBhdCAyXjMyLiBUaGlzIHVzZXMgMTYtYml0IG9wZXJhdGlvbnNcbiAgICAgKiBpbnRlcm5hbGx5IHRvIHdvcmsgYXJvdW5kIGJ1Z3MgaW4gc29tZSBKUyBpbnRlcnByZXRlcnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSBmaXJzdCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB5IFRoZSBzZWNvbmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcmV0dXJuIFRoZSBzdW0gb2YgeCArIHlcbiAgICAgKi9cbiAgICBzYWZlQWRkXzMyXzIgPSBmdW5jdGlvbih4LCB5KSB7XG4gICAgICB2YXIgbHN3ID0gKHggJiAweEZGRkYpICsgKHkgJiAweEZGRkYpLFxuICAgICAgICBtc3cgPSAoeCA+Pj4gMTYpICsgKHkgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcblxuICAgICAgcmV0dXJuICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBBZGQgZm91ciAzMi1iaXQgaW50ZWdlcnMsIHdyYXBwaW5nIGF0IDJeMzIuIFRoaXMgdXNlcyAxNi1iaXQgb3BlcmF0aW9uc1xuICAgICAqIGludGVybmFsbHkgdG8gd29yayBhcm91bmQgYnVncyBpbiBzb21lIEpTIGludGVycHJldGVycy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IGEgVGhlIGZpcnN0IDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IGIgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBjIFRoZSB0aGlyZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBkIFRoZSBmb3VydGggMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcmV0dXJuIFRoZSBzdW0gb2YgYSArIGIgKyBjICsgZFxuICAgICAqL1xuICAgIHNhZmVBZGRfMzJfNCA9IGZ1bmN0aW9uKGEsIGIsIGMsIGQpIHtcbiAgICAgIHZhciBsc3cgPSAoYSAmIDB4RkZGRikgKyAoYiAmIDB4RkZGRikgKyAoYyAmIDB4RkZGRikgKyAoZCAmIDB4RkZGRiksXG4gICAgICAgIG1zdyA9IChhID4+PiAxNikgKyAoYiA+Pj4gMTYpICsgKGMgPj4+IDE2KSArIChkID4+PiAxNikgK1xuICAgICAgICAgIChsc3cgPj4+IDE2KTtcblxuICAgICAgcmV0dXJuICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBBZGQgZml2ZSAzMi1iaXQgaW50ZWdlcnMsIHdyYXBwaW5nIGF0IDJeMzIuIFRoaXMgdXNlcyAxNi1iaXQgb3BlcmF0aW9uc1xuICAgICAqIGludGVybmFsbHkgdG8gd29yayBhcm91bmQgYnVncyBpbiBzb21lIEpTIGludGVycHJldGVycy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IGEgVGhlIGZpcnN0IDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IGIgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBjIFRoZSB0aGlyZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBkIFRoZSBmb3VydGggMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gZSBUaGUgZmlmdGggMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcmV0dXJuIFRoZSBzdW0gb2YgYSArIGIgKyBjICsgZCArIGVcbiAgICAgKi9cbiAgICBzYWZlQWRkXzMyXzUgPSBmdW5jdGlvbihhLCBiLCBjLCBkLCBlKSB7XG4gICAgICB2YXIgbHN3ID0gKGEgJiAweEZGRkYpICsgKGIgJiAweEZGRkYpICsgKGMgJiAweEZGRkYpICsgKGQgJiAweEZGRkYpICtcbiAgICAgICAgKGUgJiAweEZGRkYpLFxuICAgICAgICBtc3cgPSAoYSA+Pj4gMTYpICsgKGIgPj4+IDE2KSArIChjID4+PiAxNikgKyAoZCA+Pj4gMTYpICtcbiAgICAgICAgICAoZSA+Pj4gMTYpICsgKGxzdyA+Pj4gMTYpO1xuXG4gICAgICByZXR1cm4gKChtc3cgJiAweEZGRkYpIDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIEFkZCB0d28gNjQtYml0IGludGVnZXJzLCB3cmFwcGluZyBhdCAyXjY0LiBUaGlzIHVzZXMgMTYtYml0IG9wZXJhdGlvbnNcbiAgICAgKiBpbnRlcm5hbGx5IHRvIHdvcmsgYXJvdW5kIGJ1Z3MgaW4gc29tZSBKUyBpbnRlcnByZXRlcnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSBmaXJzdCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB5IFRoZSBzZWNvbmQgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcmV0dXJuIFRoZSBzdW0gb2YgeCArIHlcbiAgICAgKi9cbiAgICBzYWZlQWRkXzY0XzIgPSBmdW5jdGlvbih4LCB5KSB7XG4gICAgICB2YXIgbHN3LCBtc3csIGxvd09yZGVyLCBoaWdoT3JkZXI7XG5cbiAgICAgIGxzdyA9ICh4Lmxvd09yZGVyICYgMHhGRkZGKSArICh5Lmxvd09yZGVyICYgMHhGRkZGKTtcbiAgICAgIG1zdyA9ICh4Lmxvd09yZGVyID4+PiAxNikgKyAoeS5sb3dPcmRlciA+Pj4gMTYpICsgKGxzdyA+Pj4gMTYpO1xuICAgICAgbG93T3JkZXIgPSAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cbiAgICAgIGxzdyA9ICh4LmhpZ2hPcmRlciAmIDB4RkZGRikgKyAoeS5oaWdoT3JkZXIgJiAweEZGRkYpICsgKG1zdyA+Pj4gMTYpO1xuICAgICAgbXN3ID0gKHguaGlnaE9yZGVyID4+PiAxNikgKyAoeS5oaWdoT3JkZXIgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcbiAgICAgIGhpZ2hPcmRlciA9ICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcblxuICAgICAgcmV0dXJuIG5ldyBJbnRfNjQoaGlnaE9yZGVyLCBsb3dPcmRlcik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQWRkIGZvdXIgNjQtYml0IGludGVnZXJzLCB3cmFwcGluZyBhdCAyXjY0LiBUaGlzIHVzZXMgMTYtYml0IG9wZXJhdGlvbnNcbiAgICAgKiBpbnRlcm5hbGx5IHRvIHdvcmsgYXJvdW5kIGJ1Z3MgaW4gc29tZSBKUyBpbnRlcnByZXRlcnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7SW50XzY0fSBhIFRoZSBmaXJzdCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSBiIFRoZSBzZWNvbmQgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge0ludF82NH0gYyBUaGUgdGhpcmQgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge0ludF82NH0gZCBUaGUgZm91dGggNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcmV0dXJuIFRoZSBzdW0gb2YgYSArIGIgKyBjICsgZFxuICAgICAqL1xuICAgIHNhZmVBZGRfNjRfNCA9IGZ1bmN0aW9uKGEsIGIsIGMsIGQpIHtcbiAgICAgIHZhciBsc3csIG1zdywgbG93T3JkZXIsIGhpZ2hPcmRlcjtcblxuICAgICAgbHN3ID0gKGEubG93T3JkZXIgJiAweEZGRkYpICsgKGIubG93T3JkZXIgJiAweEZGRkYpICtcbiAgICAgICAgKGMubG93T3JkZXIgJiAweEZGRkYpICsgKGQubG93T3JkZXIgJiAweEZGRkYpO1xuICAgICAgbXN3ID0gKGEubG93T3JkZXIgPj4+IDE2KSArIChiLmxvd09yZGVyID4+PiAxNikgK1xuICAgICAgICAoYy5sb3dPcmRlciA+Pj4gMTYpICsgKGQubG93T3JkZXIgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcbiAgICAgIGxvd09yZGVyID0gKChtc3cgJiAweEZGRkYpIDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xuXG4gICAgICBsc3cgPSAoYS5oaWdoT3JkZXIgJiAweEZGRkYpICsgKGIuaGlnaE9yZGVyICYgMHhGRkZGKSArXG4gICAgICAgIChjLmhpZ2hPcmRlciAmIDB4RkZGRikgKyAoZC5oaWdoT3JkZXIgJiAweEZGRkYpICsgKG1zdyA+Pj4gMTYpO1xuICAgICAgbXN3ID0gKGEuaGlnaE9yZGVyID4+PiAxNikgKyAoYi5oaWdoT3JkZXIgPj4+IDE2KSArXG4gICAgICAgIChjLmhpZ2hPcmRlciA+Pj4gMTYpICsgKGQuaGlnaE9yZGVyID4+PiAxNikgKyAobHN3ID4+PiAxNik7XG4gICAgICBoaWdoT3JkZXIgPSAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cbiAgICAgIHJldHVybiBuZXcgSW50XzY0KGhpZ2hPcmRlciwgbG93T3JkZXIpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIEFkZCBmaXZlIDY0LWJpdCBpbnRlZ2Vycywgd3JhcHBpbmcgYXQgMl42NC4gVGhpcyB1c2VzIDE2LWJpdCBvcGVyYXRpb25zXG4gICAgICogaW50ZXJuYWxseSB0byB3b3JrIGFyb3VuZCBidWdzIGluIHNvbWUgSlMgaW50ZXJwcmV0ZXJzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0gYSBUaGUgZmlyc3QgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge0ludF82NH0gYiBUaGUgc2Vjb25kIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IGMgVGhlIHRoaXJkIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IGQgVGhlIGZvdXRoIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IGUgVGhlIGZvdXRoIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHJldHVybiBUaGUgc3VtIG9mIGEgKyBiICsgYyArIGQgKyBlXG4gICAgICovXG4gICAgc2FmZUFkZF82NF81ID0gZnVuY3Rpb24oYSwgYiwgYywgZCwgZSkge1xuICAgICAgdmFyIGxzdywgbXN3LCBsb3dPcmRlciwgaGlnaE9yZGVyO1xuXG4gICAgICBsc3cgPSAoYS5sb3dPcmRlciAmIDB4RkZGRikgKyAoYi5sb3dPcmRlciAmIDB4RkZGRikgK1xuICAgICAgICAoYy5sb3dPcmRlciAmIDB4RkZGRikgKyAoZC5sb3dPcmRlciAmIDB4RkZGRikgK1xuICAgICAgICAoZS5sb3dPcmRlciAmIDB4RkZGRik7XG4gICAgICBtc3cgPSAoYS5sb3dPcmRlciA+Pj4gMTYpICsgKGIubG93T3JkZXIgPj4+IDE2KSArXG4gICAgICAgIChjLmxvd09yZGVyID4+PiAxNikgKyAoZC5sb3dPcmRlciA+Pj4gMTYpICsgKGUubG93T3JkZXIgPj4+IDE2KSArXG4gICAgICAgIChsc3cgPj4+IDE2KTtcbiAgICAgIGxvd09yZGVyID0gKChtc3cgJiAweEZGRkYpIDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xuXG4gICAgICBsc3cgPSAoYS5oaWdoT3JkZXIgJiAweEZGRkYpICsgKGIuaGlnaE9yZGVyICYgMHhGRkZGKSArXG4gICAgICAgIChjLmhpZ2hPcmRlciAmIDB4RkZGRikgKyAoZC5oaWdoT3JkZXIgJiAweEZGRkYpICtcbiAgICAgICAgKGUuaGlnaE9yZGVyICYgMHhGRkZGKSArIChtc3cgPj4+IDE2KTtcbiAgICAgIG1zdyA9IChhLmhpZ2hPcmRlciA+Pj4gMTYpICsgKGIuaGlnaE9yZGVyID4+PiAxNikgK1xuICAgICAgICAoYy5oaWdoT3JkZXIgPj4+IDE2KSArIChkLmhpZ2hPcmRlciA+Pj4gMTYpICtcbiAgICAgICAgKGUuaGlnaE9yZGVyID4+PiAxNikgKyAobHN3ID4+PiAxNik7XG4gICAgICBoaWdoT3JkZXIgPSAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cbiAgICAgIHJldHVybiBuZXcgSW50XzY0KGhpZ2hPcmRlciwgbG93T3JkZXIpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIENhbGN1bGF0ZXMgdGhlIFNIQS0xIGhhc2ggb2YgdGhlIHN0cmluZyBzZXQgYXQgaW5zdGFudGlhdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBtZXNzYWdlIFRoZSBiaW5hcnkgYXJyYXkgcmVwcmVzZW50YXRpb24gb2YgdGhlIHN0cmluZyB0b1xuICAgICAqXHQgaGFzaFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBtZXNzYWdlTGVuIFRoZSBudW1iZXIgb2YgYml0cyBpbiB0aGUgbWVzc2FnZVxuICAgICAqIEByZXR1cm4gVGhlIGFycmF5IG9mIGludGVnZXJzIHJlcHJlc2VudGluZyB0aGUgU0hBLTEgaGFzaCBvZiBtZXNzYWdlXG4gICAgICovXG4gICAgY29yZVNIQTEgPSBmdW5jdGlvbihtZXNzYWdlLCBtZXNzYWdlTGVuKSB7XG4gICAgICB2YXIgVyA9IFtdLFxuICAgICAgICBhLCBiLCBjLCBkLCBlLCBULCBjaCA9IGNoXzMyLFxuICAgICAgICBwYXJpdHkgPSBwYXJpdHlfMzIsXG4gICAgICAgIG1haiA9IG1hal8zMixcbiAgICAgICAgcm90bCA9IHJvdGxfMzIsXG4gICAgICAgIHNhZmVBZGRfMiA9IHNhZmVBZGRfMzJfMixcbiAgICAgICAgaSwgdCxcbiAgICAgICAgc2FmZUFkZF81ID0gc2FmZUFkZF8zMl81LFxuICAgICAgICBhcHBlbmRlZE1lc3NhZ2VMZW5ndGgsXG4gICAgICAgIEggPSBbXG4gICAgICAgICAgICAweDY3NDUyMzAxLCAweGVmY2RhYjg5LCAweDk4YmFkY2ZlLCAweDEwMzI1NDc2LCAweGMzZDJlMWYwXG4gICAgICAgIF0sXG4gICAgICAgIEsgPSBbXG4gICAgICAgICAgICAweDVhODI3OTk5LCAweDVhODI3OTk5LCAweDVhODI3OTk5LCAweDVhODI3OTk5LFxuICAgICAgICAgICAgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSxcbiAgICAgICAgICAgIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG4gICAgICAgICAgICAweDVhODI3OTk5LCAweDVhODI3OTk5LCAweDVhODI3OTk5LCAweDVhODI3OTk5LFxuICAgICAgICAgICAgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSxcbiAgICAgICAgICAgIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG4gICAgICAgICAgICAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLFxuICAgICAgICAgICAgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSxcbiAgICAgICAgICAgIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG4gICAgICAgICAgICAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLFxuICAgICAgICAgICAgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYyxcbiAgICAgICAgICAgIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG4gICAgICAgICAgICAweDhmMWJiY2RjLCAweDhmMWJiY2RjLCAweDhmMWJiY2RjLCAweDhmMWJiY2RjLFxuICAgICAgICAgICAgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYyxcbiAgICAgICAgICAgIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG4gICAgICAgICAgICAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LFxuICAgICAgICAgICAgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNixcbiAgICAgICAgICAgIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsXG4gICAgICAgICAgICAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LFxuICAgICAgICAgICAgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNlxuICAgICAgICBdO1xuXG4gICAgICAvKiBBcHBlbmQgJzEnIGF0IHRoZSBlbmQgb2YgdGhlIGJpbmFyeSBzdHJpbmcgKi9cbiAgICAgIG1lc3NhZ2VbbWVzc2FnZUxlbiA+PiA1XSB8PSAweDgwIDw8ICgyNCAtIChtZXNzYWdlTGVuICUgMzIpKTtcbiAgICAgIC8qIEFwcGVuZCBsZW5ndGggb2YgYmluYXJ5IHN0cmluZyBpbiB0aGUgcG9zaXRpb24gc3VjaCB0aGF0IHRoZSBuZXdcblx0XHRsZW5ndGggaXMgYSBtdWx0aXBsZSBvZiA1MTIuICBMb2dpYyBkb2VzIG5vdCB3b3JrIGZvciBldmVuIG11bHRpcGxlc1xuXHRcdG9mIDUxMiBidXQgdGhlcmUgY2FuIG5ldmVyIGJlIGV2ZW4gbXVsdGlwbGVzIG9mIDUxMiAqL1xuICAgICAgbWVzc2FnZVsoKChtZXNzYWdlTGVuICsgNjUpID4+IDkpIDw8IDQpICsgMTVdID0gbWVzc2FnZUxlbjtcblxuICAgICAgYXBwZW5kZWRNZXNzYWdlTGVuZ3RoID0gbWVzc2FnZS5sZW5ndGg7XG5cbiAgICAgIGZvciAoaSA9IDA7IGkgPCBhcHBlbmRlZE1lc3NhZ2VMZW5ndGg7IGkgKz0gMTYpIHtcbiAgICAgICAgYSA9IEhbMF07XG4gICAgICAgIGIgPSBIWzFdO1xuICAgICAgICBjID0gSFsyXTtcbiAgICAgICAgZCA9IEhbM107XG4gICAgICAgIGUgPSBIWzRdO1xuXG4gICAgICAgIGZvciAodCA9IDA7IHQgPCA4MDsgdCArPSAxKSB7XG4gICAgICAgICAgaWYgKHQgPCAxNikge1xuICAgICAgICAgICAgV1t0XSA9IG1lc3NhZ2VbdCArIGldO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBXW3RdID0gcm90bChXW3QgLSAzXSBeIFdbdCAtIDhdIF4gV1t0IC0gMTRdIF4gV1t0IC0gMTZdLCAxKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAodCA8IDIwKSB7XG4gICAgICAgICAgICBUID0gc2FmZUFkZF81KHJvdGwoYSwgNSksIGNoKGIsIGMsIGQpLCBlLCBLW3RdLCBXW3RdKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHQgPCA0MCkge1xuICAgICAgICAgICAgVCA9IHNhZmVBZGRfNShyb3RsKGEsIDUpLCBwYXJpdHkoYiwgYywgZCksIGUsIEtbdF0sIFdbdF0pO1xuICAgICAgICAgIH0gZWxzZSBpZiAodCA8IDYwKSB7XG4gICAgICAgICAgICBUID0gc2FmZUFkZF81KHJvdGwoYSwgNSksIG1haihiLCBjLCBkKSwgZSwgS1t0XSwgV1t0XSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIFQgPSBzYWZlQWRkXzUocm90bChhLCA1KSwgcGFyaXR5KGIsIGMsIGQpLCBlLCBLW3RdLCBXW3RdKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBlID0gZDtcbiAgICAgICAgICBkID0gYztcbiAgICAgICAgICBjID0gcm90bChiLCAzMCk7XG4gICAgICAgICAgYiA9IGE7XG4gICAgICAgICAgYSA9IFQ7XG4gICAgICAgIH1cblxuICAgICAgICBIWzBdID0gc2FmZUFkZF8yKGEsIEhbMF0pO1xuICAgICAgICBIWzFdID0gc2FmZUFkZF8yKGIsIEhbMV0pO1xuICAgICAgICBIWzJdID0gc2FmZUFkZF8yKGMsIEhbMl0pO1xuICAgICAgICBIWzNdID0gc2FmZUFkZF8yKGQsIEhbM10pO1xuICAgICAgICBIWzRdID0gc2FmZUFkZF8yKGUsIEhbNF0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gSDtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBDYWxjdWxhdGVzIHRoZSBkZXNpcmVkIFNIQS0yIGhhc2ggb2YgdGhlIHN0cmluZyBzZXQgYXQgaW5zdGFudGlhdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBUaGUgYmluYXJ5IGFycmF5IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBzdHJpbmcgdG8gaGFzaFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBUaGUgbnVtYmVyIG9mIGJpdHMgaW4gbWVzc2FnZVxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSB2YXJpYW50IFRoZSBkZXNpcmVkIFNIQS0yIHZhcmlhbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBhcnJheSBvZiBpbnRlZ2VycyByZXByZXNlbnRpbmcgdGhlIFNIQS0yIGhhc2ggb2YgbWVzc2FnZVxuICAgICAqL1xuICAgIGNvcmVTSEEyID0gZnVuY3Rpb24obWVzc2FnZSwgbWVzc2FnZUxlbiwgdmFyaWFudCkge1xuICAgICAgdmFyIGEsIGIsIGMsIGQsIGUsIGYsIGcsIGgsIFQxLCBUMiwgSCwgbnVtUm91bmRzLCBsZW5ndGhQb3NpdGlvbiwgaSwgdCxcbiAgICAgICAgYmluYXJ5U3RyaW5nSW5jLCBiaW5hcnlTdHJpbmdNdWx0LCBzYWZlQWRkXzIsIHNhZmVBZGRfNCwgc2FmZUFkZF81LFxuICAgICAgICBnYW1tYTAsIGdhbW1hMSwgc2lnbWEwLCBzaWdtYTEsIGNoLCBtYWosIEludCwgSywgVyA9IFtdLFxuICAgICAgICBhcHBlbmRlZE1lc3NhZ2VMZW5ndGg7XG5cbiAgICAgIC8qIFNldCB1cCB0aGUgdmFyaW91cyBmdW5jdGlvbiBoYW5kbGVzIGFuZCB2YXJpYWJsZSBmb3IgdGhlIHNwZWNpZmljIFxuICAgICAgICogdmFyaWFudCAqL1xuICAgICAgaWYgKHZhcmlhbnQgPT09IFwiU0hBLTIyNFwiIHx8IHZhcmlhbnQgPT09IFwiU0hBLTI1NlwiKSB7XG4gICAgICAgIC8qIDMyLWJpdCB2YXJpYW50ICovXG4gICAgICAgIG51bVJvdW5kcyA9IDY0O1xuICAgICAgICBsZW5ndGhQb3NpdGlvbiA9ICgoKG1lc3NhZ2VMZW4gKyA2NSkgPj4gOSkgPDwgNCkgKyAxNTtcbiAgICAgICAgYmluYXJ5U3RyaW5nSW5jID0gMTY7XG4gICAgICAgIGJpbmFyeVN0cmluZ011bHQgPSAxO1xuICAgICAgICBJbnQgPSBOdW1iZXI7XG4gICAgICAgIHNhZmVBZGRfMiA9IHNhZmVBZGRfMzJfMjtcbiAgICAgICAgc2FmZUFkZF80ID0gc2FmZUFkZF8zMl80O1xuICAgICAgICBzYWZlQWRkXzUgPSBzYWZlQWRkXzMyXzU7XG4gICAgICAgIGdhbW1hMCA9IGdhbW1hMF8zMjtcbiAgICAgICAgZ2FtbWExID0gZ2FtbWExXzMyO1xuICAgICAgICBzaWdtYTAgPSBzaWdtYTBfMzI7XG4gICAgICAgIHNpZ21hMSA9IHNpZ21hMV8zMjtcbiAgICAgICAgbWFqID0gbWFqXzMyO1xuICAgICAgICBjaCA9IGNoXzMyO1xuICAgICAgICBLID0gW1xuICAgICAgICAgICAgMHg0MjhBMkY5OCwgMHg3MTM3NDQ5MSwgMHhCNUMwRkJDRiwgMHhFOUI1REJBNSxcbiAgICAgICAgICAgIDB4Mzk1NkMyNUIsIDB4NTlGMTExRjEsIDB4OTIzRjgyQTQsIDB4QUIxQzVFRDUsXG4gICAgICAgICAgICAweEQ4MDdBQTk4LCAweDEyODM1QjAxLCAweDI0MzE4NUJFLCAweDU1MEM3REMzLFxuICAgICAgICAgICAgMHg3MkJFNUQ3NCwgMHg4MERFQjFGRSwgMHg5QkRDMDZBNywgMHhDMTlCRjE3NCxcbiAgICAgICAgICAgIDB4RTQ5QjY5QzEsIDB4RUZCRTQ3ODYsIDB4MEZDMTlEQzYsIDB4MjQwQ0ExQ0MsXG4gICAgICAgICAgICAweDJERTkyQzZGLCAweDRBNzQ4NEFBLCAweDVDQjBBOURDLCAweDc2Rjk4OERBLFxuICAgICAgICAgICAgMHg5ODNFNTE1MiwgMHhBODMxQzY2RCwgMHhCMDAzMjdDOCwgMHhCRjU5N0ZDNyxcbiAgICAgICAgICAgIDB4QzZFMDBCRjMsIDB4RDVBNzkxNDcsIDB4MDZDQTYzNTEsIDB4MTQyOTI5NjcsXG4gICAgICAgICAgICAweDI3QjcwQTg1LCAweDJFMUIyMTM4LCAweDREMkM2REZDLCAweDUzMzgwRDEzLFxuICAgICAgICAgICAgMHg2NTBBNzM1NCwgMHg3NjZBMEFCQiwgMHg4MUMyQzkyRSwgMHg5MjcyMkM4NSxcbiAgICAgICAgICAgIDB4QTJCRkU4QTEsIDB4QTgxQTY2NEIsIDB4QzI0QjhCNzAsIDB4Qzc2QzUxQTMsXG4gICAgICAgICAgICAweEQxOTJFODE5LCAweEQ2OTkwNjI0LCAweEY0MEUzNTg1LCAweDEwNkFBMDcwLFxuICAgICAgICAgICAgMHgxOUE0QzExNiwgMHgxRTM3NkMwOCwgMHgyNzQ4Nzc0QywgMHgzNEIwQkNCNSxcbiAgICAgICAgICAgIDB4MzkxQzBDQjMsIDB4NEVEOEFBNEEsIDB4NUI5Q0NBNEYsIDB4NjgyRTZGRjMsXG4gICAgICAgICAgICAweDc0OEY4MkVFLCAweDc4QTU2MzZGLCAweDg0Qzg3ODE0LCAweDhDQzcwMjA4LFxuICAgICAgICAgICAgMHg5MEJFRkZGQSwgMHhBNDUwNkNFQiwgMHhCRUY5QTNGNywgMHhDNjcxNzhGMlxuICAgICAgICBdO1xuXG4gICAgICAgIGlmICh2YXJpYW50ID09PSBcIlNIQS0yMjRcIikge1xuICAgICAgICAgIEggPSBbXG4gICAgICAgICAgICAgIDB4YzEwNTllZDgsIDB4MzY3Y2Q1MDcsIDB4MzA3MGRkMTcsIDB4ZjcwZTU5MzksXG4gICAgICAgICAgICAgIDB4ZmZjMDBiMzEsIDB4Njg1ODE1MTEsIDB4NjRmOThmYTcsIDB4YmVmYTRmYTRcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIEggPSBbXG4gICAgICAgICAgICAgIDB4NkEwOUU2NjcsIDB4QkI2N0FFODUsIDB4M0M2RUYzNzIsIDB4QTU0RkY1M0EsXG4gICAgICAgICAgICAgIDB4NTEwRTUyN0YsIDB4OUIwNTY4OEMsIDB4MUY4M0Q5QUIsIDB4NUJFMENEMTlcbiAgICAgICAgICBdO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHZhcmlhbnQgPT09IFwiU0hBLTM4NFwiIHx8IHZhcmlhbnQgPT09IFwiU0hBLTUxMlwiKSB7XG4gICAgICAgIC8qIDY0LWJpdCB2YXJpYW50ICovXG4gICAgICAgIG51bVJvdW5kcyA9IDgwO1xuICAgICAgICBsZW5ndGhQb3NpdGlvbiA9ICgoKG1lc3NhZ2VMZW4gKyAxMjgpID4+IDEwKSA8PCA1KSArIDMxO1xuICAgICAgICBiaW5hcnlTdHJpbmdJbmMgPSAzMjtcbiAgICAgICAgYmluYXJ5U3RyaW5nTXVsdCA9IDI7XG4gICAgICAgIEludCA9IEludF82NDtcbiAgICAgICAgc2FmZUFkZF8yID0gc2FmZUFkZF82NF8yO1xuICAgICAgICBzYWZlQWRkXzQgPSBzYWZlQWRkXzY0XzQ7XG4gICAgICAgIHNhZmVBZGRfNSA9IHNhZmVBZGRfNjRfNTtcbiAgICAgICAgZ2FtbWEwID0gZ2FtbWEwXzY0O1xuICAgICAgICBnYW1tYTEgPSBnYW1tYTFfNjQ7XG4gICAgICAgIHNpZ21hMCA9IHNpZ21hMF82NDtcbiAgICAgICAgc2lnbWExID0gc2lnbWExXzY0O1xuICAgICAgICBtYWogPSBtYWpfNjQ7XG4gICAgICAgIGNoID0gY2hfNjQ7XG5cbiAgICAgICAgSyA9IFtcbiAgICAgICAgICAgIG5ldyBJbnQoMHg0MjhhMmY5OCwgMHhkNzI4YWUyMiksIG5ldyBJbnQoMHg3MTM3NDQ5MSwgMHgyM2VmNjVjZCksXG4gICAgICAgICAgICBuZXcgSW50KDB4YjVjMGZiY2YsIDB4ZWM0ZDNiMmYpLCBuZXcgSW50KDB4ZTliNWRiYTUsIDB4ODE4OWRiYmMpLFxuICAgICAgICAgICAgbmV3IEludCgweDM5NTZjMjViLCAweGYzNDhiNTM4KSwgbmV3IEludCgweDU5ZjExMWYxLCAweGI2MDVkMDE5KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg5MjNmODJhNCwgMHhhZjE5NGY5YiksIG5ldyBJbnQoMHhhYjFjNWVkNSwgMHhkYTZkODExOCksXG4gICAgICAgICAgICBuZXcgSW50KDB4ZDgwN2FhOTgsIDB4YTMwMzAyNDIpLCBuZXcgSW50KDB4MTI4MzViMDEsIDB4NDU3MDZmYmUpLFxuICAgICAgICAgICAgbmV3IEludCgweDI0MzE4NWJlLCAweDRlZTRiMjhjKSwgbmV3IEludCgweDU1MGM3ZGMzLCAweGQ1ZmZiNGUyKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg3MmJlNWQ3NCwgMHhmMjdiODk2ZiksIG5ldyBJbnQoMHg4MGRlYjFmZSwgMHgzYjE2OTZiMSksXG4gICAgICAgICAgICBuZXcgSW50KDB4OWJkYzA2YTcsIDB4MjVjNzEyMzUpLCBuZXcgSW50KDB4YzE5YmYxNzQsIDB4Y2Y2OTI2OTQpLFxuICAgICAgICAgICAgbmV3IEludCgweGU0OWI2OWMxLCAweDllZjE0YWQyKSwgbmV3IEludCgweGVmYmU0Nzg2LCAweDM4NGYyNWUzKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgwZmMxOWRjNiwgMHg4YjhjZDViNSksIG5ldyBJbnQoMHgyNDBjYTFjYywgMHg3N2FjOWM2NSksXG4gICAgICAgICAgICBuZXcgSW50KDB4MmRlOTJjNmYsIDB4NTkyYjAyNzUpLCBuZXcgSW50KDB4NGE3NDg0YWEsIDB4NmVhNmU0ODMpLFxuICAgICAgICAgICAgbmV3IEludCgweDVjYjBhOWRjLCAweGJkNDFmYmQ0KSwgbmV3IEludCgweDc2Zjk4OGRhLCAweDgzMTE1M2I1KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg5ODNlNTE1MiwgMHhlZTY2ZGZhYiksIG5ldyBJbnQoMHhhODMxYzY2ZCwgMHgyZGI0MzIxMCksXG4gICAgICAgICAgICBuZXcgSW50KDB4YjAwMzI3YzgsIDB4OThmYjIxM2YpLCBuZXcgSW50KDB4YmY1OTdmYzcsIDB4YmVlZjBlZTQpLFxuICAgICAgICAgICAgbmV3IEludCgweGM2ZTAwYmYzLCAweDNkYTg4ZmMyKSwgbmV3IEludCgweGQ1YTc5MTQ3LCAweDkzMGFhNzI1KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgwNmNhNjM1MSwgMHhlMDAzODI2ZiksIG5ldyBJbnQoMHgxNDI5Mjk2NywgMHgwYTBlNmU3MCksXG4gICAgICAgICAgICBuZXcgSW50KDB4MjdiNzBhODUsIDB4NDZkMjJmZmMpLCBuZXcgSW50KDB4MmUxYjIxMzgsIDB4NWMyNmM5MjYpLFxuICAgICAgICAgICAgbmV3IEludCgweDRkMmM2ZGZjLCAweDVhYzQyYWVkKSwgbmV3IEludCgweDUzMzgwZDEzLCAweDlkOTViM2RmKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg2NTBhNzM1NCwgMHg4YmFmNjNkZSksIG5ldyBJbnQoMHg3NjZhMGFiYiwgMHgzYzc3YjJhOCksXG4gICAgICAgICAgICBuZXcgSW50KDB4ODFjMmM5MmUsIDB4NDdlZGFlZTYpLCBuZXcgSW50KDB4OTI3MjJjODUsIDB4MTQ4MjM1M2IpLFxuICAgICAgICAgICAgbmV3IEludCgweGEyYmZlOGExLCAweDRjZjEwMzY0KSwgbmV3IEludCgweGE4MWE2NjRiLCAweGJjNDIzMDAxKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHhjMjRiOGI3MCwgMHhkMGY4OTc5MSksIG5ldyBJbnQoMHhjNzZjNTFhMywgMHgwNjU0YmUzMCksXG4gICAgICAgICAgICBuZXcgSW50KDB4ZDE5MmU4MTksIDB4ZDZlZjUyMTgpLCBuZXcgSW50KDB4ZDY5OTA2MjQsIDB4NTU2NWE5MTApLFxuICAgICAgICAgICAgbmV3IEludCgweGY0MGUzNTg1LCAweDU3NzEyMDJhKSwgbmV3IEludCgweDEwNmFhMDcwLCAweDMyYmJkMWI4KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgxOWE0YzExNiwgMHhiOGQyZDBjOCksIG5ldyBJbnQoMHgxZTM3NmMwOCwgMHg1MTQxYWI1MyksXG4gICAgICAgICAgICBuZXcgSW50KDB4Mjc0ODc3NGMsIDB4ZGY4ZWViOTkpLCBuZXcgSW50KDB4MzRiMGJjYjUsIDB4ZTE5YjQ4YTgpLFxuICAgICAgICAgICAgbmV3IEludCgweDM5MWMwY2IzLCAweGM1Yzk1YTYzKSwgbmV3IEludCgweDRlZDhhYTRhLCAweGUzNDE4YWNiKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg1YjljY2E0ZiwgMHg3NzYzZTM3MyksIG5ldyBJbnQoMHg2ODJlNmZmMywgMHhkNmIyYjhhMyksXG4gICAgICAgICAgICBuZXcgSW50KDB4NzQ4ZjgyZWUsIDB4NWRlZmIyZmMpLCBuZXcgSW50KDB4NzhhNTYzNmYsIDB4NDMxNzJmNjApLFxuICAgICAgICAgICAgbmV3IEludCgweDg0Yzg3ODE0LCAweGExZjBhYjcyKSwgbmV3IEludCgweDhjYzcwMjA4LCAweDFhNjQzOWVjKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg5MGJlZmZmYSwgMHgyMzYzMWUyOCksIG5ldyBJbnQoMHhhNDUwNmNlYiwgMHhkZTgyYmRlOSksXG4gICAgICAgICAgICBuZXcgSW50KDB4YmVmOWEzZjcsIDB4YjJjNjc5MTUpLCBuZXcgSW50KDB4YzY3MTc4ZjIsIDB4ZTM3MjUzMmIpLFxuICAgICAgICAgICAgbmV3IEludCgweGNhMjczZWNlLCAweGVhMjY2MTljKSwgbmV3IEludCgweGQxODZiOGM3LCAweDIxYzBjMjA3KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHhlYWRhN2RkNiwgMHhjZGUwZWIxZSksIG5ldyBJbnQoMHhmNTdkNGY3ZiwgMHhlZTZlZDE3OCksXG4gICAgICAgICAgICBuZXcgSW50KDB4MDZmMDY3YWEsIDB4NzIxNzZmYmEpLCBuZXcgSW50KDB4MGE2MzdkYzUsIDB4YTJjODk4YTYpLFxuICAgICAgICAgICAgbmV3IEludCgweDExM2Y5ODA0LCAweGJlZjkwZGFlKSwgbmV3IEludCgweDFiNzEwYjM1LCAweDEzMWM0NzFiKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgyOGRiNzdmNSwgMHgyMzA0N2Q4NCksIG5ldyBJbnQoMHgzMmNhYWI3YiwgMHg0MGM3MjQ5MyksXG4gICAgICAgICAgICBuZXcgSW50KDB4M2M5ZWJlMGEsIDB4MTVjOWJlYmMpLCBuZXcgSW50KDB4NDMxZDY3YzQsIDB4OWMxMDBkNGMpLFxuICAgICAgICAgICAgbmV3IEludCgweDRjYzVkNGJlLCAweGNiM2U0MmI2KSwgbmV3IEludCgweDU5N2YyOTljLCAweGZjNjU3ZTJhKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg1ZmNiNmZhYiwgMHgzYWQ2ZmFlYyksIG5ldyBJbnQoMHg2YzQ0MTk4YywgMHg0YTQ3NTgxNylcbiAgICAgICAgXTtcblxuICAgICAgICBpZiAodmFyaWFudCA9PT0gXCJTSEEtMzg0XCIpIHtcbiAgICAgICAgICBIID0gW1xuICAgICAgICAgICAgICBuZXcgSW50KDB4Y2JiYjlkNWQsIDB4YzEwNTllZDgpLCBuZXcgSW50KDB4MDYyOWEyOTJhLCAweDM2N2NkNTA3KSxcbiAgICAgICAgICAgICAgbmV3IEludCgweDkxNTkwMTVhLCAweDMwNzBkZDE3KSwgbmV3IEludCgweDAxNTJmZWNkOCwgMHhmNzBlNTkzOSksXG4gICAgICAgICAgICAgIG5ldyBJbnQoMHg2NzMzMjY2NywgMHhmZmMwMGIzMSksIG5ldyBJbnQoMHg5OGViNDRhODcsIDB4Njg1ODE1MTEpLFxuICAgICAgICAgICAgICBuZXcgSW50KDB4ZGIwYzJlMGQsIDB4NjRmOThmYTcpLCBuZXcgSW50KDB4MDQ3YjU0ODFkLCAweGJlZmE0ZmE0KVxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgSCA9IFtcbiAgICAgICAgICAgICAgbmV3IEludCgweDZhMDllNjY3LCAweGYzYmNjOTA4KSwgbmV3IEludCgweGJiNjdhZTg1LCAweDg0Y2FhNzNiKSxcbiAgICAgICAgICAgICAgbmV3IEludCgweDNjNmVmMzcyLCAweGZlOTRmODJiKSwgbmV3IEludCgweGE1NGZmNTNhLCAweDVmMWQzNmYxKSxcbiAgICAgICAgICAgICAgbmV3IEludCgweDUxMGU1MjdmLCAweGFkZTY4MmQxKSwgbmV3IEludCgweDliMDU2ODhjLCAweDJiM2U2YzFmKSxcbiAgICAgICAgICAgICAgbmV3IEludCgweDFmODNkOWFiLCAweGZiNDFiZDZiKSwgbmV3IEludCgweDViZTBjZDE5LCAweDEzN2UyMTc5KVxuICAgICAgICAgIF07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLyogQXBwZW5kICcxJyBhdCB0aGUgZW5kIG9mIHRoZSBiaW5hcnkgc3RyaW5nICovXG4gICAgICBtZXNzYWdlW21lc3NhZ2VMZW4gPj4gNV0gfD0gMHg4MCA8PCAoMjQgLSBtZXNzYWdlTGVuICUgMzIpO1xuICAgICAgLyogQXBwZW5kIGxlbmd0aCBvZiBiaW5hcnkgc3RyaW5nIGluIHRoZSBwb3NpdGlvbiBzdWNoIHRoYXQgdGhlIG5ld1xuICAgICAgICogbGVuZ3RoIGlzIGNvcnJlY3QgKi9cbiAgICAgIG1lc3NhZ2VbbGVuZ3RoUG9zaXRpb25dID0gbWVzc2FnZUxlbjtcblxuICAgICAgYXBwZW5kZWRNZXNzYWdlTGVuZ3RoID0gbWVzc2FnZS5sZW5ndGg7XG5cbiAgICAgIGZvciAoaSA9IDA7IGkgPCBhcHBlbmRlZE1lc3NhZ2VMZW5ndGg7IGkgKz0gYmluYXJ5U3RyaW5nSW5jKSB7XG4gICAgICAgIGEgPSBIWzBdO1xuICAgICAgICBiID0gSFsxXTtcbiAgICAgICAgYyA9IEhbMl07XG4gICAgICAgIGQgPSBIWzNdO1xuICAgICAgICBlID0gSFs0XTtcbiAgICAgICAgZiA9IEhbNV07XG4gICAgICAgIGcgPSBIWzZdO1xuICAgICAgICBoID0gSFs3XTtcblxuICAgICAgICBmb3IgKHQgPSAwOyB0IDwgbnVtUm91bmRzOyB0ICs9IDEpIHtcbiAgICAgICAgICBpZiAodCA8IDE2KSB7XG4gICAgICAgICAgICAvKiBCaXQgb2YgYSBoYWNrIC0gZm9yIDMyLWJpdCwgdGhlIHNlY29uZCB0ZXJtIGlzIGlnbm9yZWQgKi9cbiAgICAgICAgICAgIFdbdF0gPSBuZXcgSW50KG1lc3NhZ2VbdCAqIGJpbmFyeVN0cmluZ011bHQgKyBpXSxcbiAgICAgICAgICAgICAgbWVzc2FnZVt0ICogYmluYXJ5U3RyaW5nTXVsdCArIGkgKyAxXSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIFdbdF0gPSBzYWZlQWRkXzQoXG4gICAgICAgICAgICAgIGdhbW1hMShXW3QgLSAyXSksIFdbdCAtIDddLFxuICAgICAgICAgICAgICBnYW1tYTAoV1t0IC0gMTVdKSwgV1t0IC0gMTZdKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBUMSA9IHNhZmVBZGRfNShoLCBzaWdtYTEoZSksIGNoKGUsIGYsIGcpLCBLW3RdLCBXW3RdKTtcbiAgICAgICAgICBUMiA9IHNhZmVBZGRfMihzaWdtYTAoYSksIG1haihhLCBiLCBjKSk7XG4gICAgICAgICAgaCA9IGc7XG4gICAgICAgICAgZyA9IGY7XG4gICAgICAgICAgZiA9IGU7XG4gICAgICAgICAgZSA9IHNhZmVBZGRfMihkLCBUMSk7XG4gICAgICAgICAgZCA9IGM7XG4gICAgICAgICAgYyA9IGI7XG4gICAgICAgICAgYiA9IGE7XG4gICAgICAgICAgYSA9IHNhZmVBZGRfMihUMSwgVDIpO1xuICAgICAgICB9XG5cbiAgICAgICAgSFswXSA9IHNhZmVBZGRfMihhLCBIWzBdKTtcbiAgICAgICAgSFsxXSA9IHNhZmVBZGRfMihiLCBIWzFdKTtcbiAgICAgICAgSFsyXSA9IHNhZmVBZGRfMihjLCBIWzJdKTtcbiAgICAgICAgSFszXSA9IHNhZmVBZGRfMihkLCBIWzNdKTtcbiAgICAgICAgSFs0XSA9IHNhZmVBZGRfMihlLCBIWzRdKTtcbiAgICAgICAgSFs1XSA9IHNhZmVBZGRfMihmLCBIWzVdKTtcbiAgICAgICAgSFs2XSA9IHNhZmVBZGRfMihnLCBIWzZdKTtcbiAgICAgICAgSFs3XSA9IHNhZmVBZGRfMihoLCBIWzddKTtcbiAgICAgIH1cblxuICAgICAgc3dpdGNoICh2YXJpYW50KSB7XG4gICAgICAgIGNhc2UgXCJTSEEtMjI0XCI6XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIEhbMF0sIEhbMV0sIEhbMl0sIEhbM10sXG4gICAgICAgICAgICBIWzRdLCBIWzVdLCBIWzZdXTtcbiAgICAgICAgY2FzZSBcIlNIQS0yNTZcIjpcbiAgICAgICAgICByZXR1cm4gSDtcbiAgICAgICAgY2FzZSBcIlNIQS0zODRcIjpcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgSFswXS5oaWdoT3JkZXIsIEhbMF0ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzFdLmhpZ2hPcmRlciwgSFsxXS5sb3dPcmRlcixcbiAgICAgICAgICAgIEhbMl0uaGlnaE9yZGVyLCBIWzJdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFszXS5oaWdoT3JkZXIsIEhbM10ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzRdLmhpZ2hPcmRlciwgSFs0XS5sb3dPcmRlcixcbiAgICAgICAgICAgIEhbNV0uaGlnaE9yZGVyLCBIWzVdLmxvd09yZGVyXTtcbiAgICAgICAgY2FzZSBcIlNIQS01MTJcIjpcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgSFswXS5oaWdoT3JkZXIsIEhbMF0ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzFdLmhpZ2hPcmRlciwgSFsxXS5sb3dPcmRlcixcbiAgICAgICAgICAgIEhbMl0uaGlnaE9yZGVyLCBIWzJdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFszXS5oaWdoT3JkZXIsIEhbM10ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzRdLmhpZ2hPcmRlciwgSFs0XS5sb3dPcmRlcixcbiAgICAgICAgICAgIEhbNV0uaGlnaE9yZGVyLCBIWzVdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFs2XS5oaWdoT3JkZXIsIEhbNl0ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzddLmhpZ2hPcmRlciwgSFs3XS5sb3dPcmRlcl07XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgLyogVGhpcyBzaG91bGQgbmV2ZXIgYmUgcmVhY2hlZCAqL1xuICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBqc1NIQSBpcyB0aGUgd29ya2hvcnNlIG9mIHRoZSBsaWJyYXJ5LiAgSW5zdGFudGlhdGUgaXQgd2l0aCB0aGUgc3RyaW5nIHRvXG4gICAgICogYmUgaGFzaGVkIGFzIHRoZSBwYXJhbWV0ZXJcbiAgICAgKlxuICAgICAqIEBjb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBzcmNTdHJpbmcgVGhlIHN0cmluZyB0byBiZSBoYXNoZWRcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXRGb3JtYXQgVGhlIGZvcm1hdCBvZiBzcmNTdHJpbmcsIEFTQ0lJIG9yIEhFWFxuICAgICAqL1xuICAgIGpzU0hBID0gZnVuY3Rpb24oc3JjU3RyaW5nLCBpbnB1dEZvcm1hdCkge1xuXG4gICAgICB0aGlzLnNoYTEgPSBudWxsO1xuICAgICAgdGhpcy5zaGEyMjQgPSBudWxsO1xuICAgICAgdGhpcy5zaGEyNTYgPSBudWxsO1xuICAgICAgdGhpcy5zaGEzODQgPSBudWxsO1xuICAgICAgdGhpcy5zaGE1MTIgPSBudWxsO1xuXG4gICAgICB0aGlzLnN0ckJpbkxlbiA9IG51bGw7XG4gICAgICB0aGlzLnN0clRvSGFzaCA9IG51bGw7XG5cbiAgICAgIC8qIENvbnZlcnQgdGhlIGlucHV0IHN0cmluZyBpbnRvIHRoZSBjb3JyZWN0IHR5cGUgKi9cbiAgICAgIGlmIChcIkhFWFwiID09PSBpbnB1dEZvcm1hdCkge1xuICAgICAgICBpZiAoMCAhPT0gKHNyY1N0cmluZy5sZW5ndGggJSAyKSkge1xuICAgICAgICAgIHJldHVybiBcIlRFWFQgTVVTVCBCRSBJTiBCWVRFIElOQ1JFTUVOVFNcIjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnN0ckJpbkxlbiA9IHNyY1N0cmluZy5sZW5ndGggKiA0O1xuICAgICAgICB0aGlzLnN0clRvSGFzaCA9IGhleDJiaW5iKHNyY1N0cmluZyk7XG4gICAgICB9IGVsc2UgaWYgKChcIkFTQ0lJXCIgPT09IGlucHV0Rm9ybWF0KSB8fFxuICAgICAgICAoJ3VuZGVmaW5lZCcgPT09IHR5cGVvZihpbnB1dEZvcm1hdCkpKSB7XG4gICAgICAgIHRoaXMuc3RyQmluTGVuID0gc3JjU3RyaW5nLmxlbmd0aCAqIGNoYXJTaXplO1xuICAgICAgICB0aGlzLnN0clRvSGFzaCA9IHN0cjJiaW5iKHNyY1N0cmluZyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gXCJVTktOT1dOIFRFWFQgSU5QVVQgVFlQRVwiO1xuICAgICAgfVxuICAgIH07XG5cbiAganNTSEEucHJvdG90eXBlID0ge1xuICAgIC8qXG4gICAgICogUmV0dXJucyB0aGUgZGVzaXJlZCBTSEEgaGFzaCBvZiB0aGUgc3RyaW5nIHNwZWNpZmllZCBhdCBpbnN0YW50aWF0aW9uXG4gICAgICogdXNpbmcgdGhlIHNwZWNpZmllZCBwYXJhbWV0ZXJzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gdmFyaWFudCBUaGUgZGVzaXJlZCBTSEEgdmFyaWFudCAoU0hBLTEsIFNIQS0yMjQsXG4gICAgICpcdCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyKVxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBmb3JtYXQgVGhlIGRlc2lyZWQgb3V0cHV0IGZvcm1hdHRpbmcgKEI2NCBvciBIRVgpXG4gICAgICogQHJldHVybiBUaGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBoYXNoIGluIHRoZSBmb3JtYXQgc3BlY2lmaWVkXG4gICAgICovXG4gICAgZ2V0SGFzaDogZnVuY3Rpb24odmFyaWFudCwgZm9ybWF0KSB7XG4gICAgICB2YXIgZm9ybWF0RnVuYyA9IG51bGwsXG4gICAgICAgIG1lc3NhZ2UgPSB0aGlzLnN0clRvSGFzaC5zbGljZSgpO1xuXG4gICAgICBzd2l0Y2ggKGZvcm1hdCkge1xuICAgICAgICBjYXNlIFwiSEVYXCI6XG4gICAgICAgICAgZm9ybWF0RnVuYyA9IGJpbmIyaGV4O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiQjY0XCI6XG4gICAgICAgICAgZm9ybWF0RnVuYyA9IGJpbmIyYjY0O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiQVNDSUlcIjpcbiAgICAgICAgICBmb3JtYXRGdW5jID0gYmluYjJzdHI7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIFwiRk9STUFUIE5PVCBSRUNPR05JWkVEXCI7XG4gICAgICB9XG5cbiAgICAgIHN3aXRjaCAodmFyaWFudCkge1xuICAgICAgICBjYXNlIFwiU0hBLTFcIjpcbiAgICAgICAgICBpZiAobnVsbCA9PT0gdGhpcy5zaGExKSB7XG4gICAgICAgICAgICB0aGlzLnNoYTEgPSBjb3JlU0hBMShtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbik7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmb3JtYXRGdW5jKHRoaXMuc2hhMSk7XG4gICAgICAgIGNhc2UgXCJTSEEtMjI0XCI6XG4gICAgICAgICAgaWYgKG51bGwgPT09IHRoaXMuc2hhMjI0KSB7XG4gICAgICAgICAgICB0aGlzLnNoYTIyNCA9IGNvcmVTSEEyKG1lc3NhZ2UsIHRoaXMuc3RyQmluTGVuLCB2YXJpYW50KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGZvcm1hdEZ1bmModGhpcy5zaGEyMjQpO1xuICAgICAgICBjYXNlIFwiU0hBLTI1NlwiOlxuICAgICAgICAgIGlmIChudWxsID09PSB0aGlzLnNoYTI1Nikge1xuICAgICAgICAgICAgdGhpcy5zaGEyNTYgPSBjb3JlU0hBMihtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmb3JtYXRGdW5jKHRoaXMuc2hhMjU2KTtcbiAgICAgICAgY2FzZSBcIlNIQS0zODRcIjpcbiAgICAgICAgICBpZiAobnVsbCA9PT0gdGhpcy5zaGEzODQpIHtcbiAgICAgICAgICAgIHRoaXMuc2hhMzg0ID0gY29yZVNIQTIobWVzc2FnZSwgdGhpcy5zdHJCaW5MZW4sIHZhcmlhbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZm9ybWF0RnVuYyh0aGlzLnNoYTM4NCk7XG4gICAgICAgIGNhc2UgXCJTSEEtNTEyXCI6XG4gICAgICAgICAgaWYgKG51bGwgPT09IHRoaXMuc2hhNTEyKSB7XG4gICAgICAgICAgICB0aGlzLnNoYTUxMiA9IGNvcmVTSEEyKG1lc3NhZ2UsIHRoaXMuc3RyQmluTGVuLCB2YXJpYW50KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGZvcm1hdEZ1bmModGhpcy5zaGE1MTIpO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHJldHVybiBcIkhBU0ggTk9UIFJFQ09HTklaRURcIjtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBSZXR1cm5zIHRoZSBkZXNpcmVkIEhNQUMgb2YgdGhlIHN0cmluZyBzcGVjaWZpZWQgYXQgaW5zdGFudGlhdGlvblxuICAgICAqIHVzaW5nIHRoZSBrZXkgYW5kIHZhcmlhbnQgcGFyYW0uXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30ga2V5IFRoZSBrZXkgdXNlZCB0byBjYWxjdWxhdGUgdGhlIEhNQUNcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXRGb3JtYXQgVGhlIGZvcm1hdCBvZiBrZXksIEFTQ0lJIG9yIEhFWFxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSB2YXJpYW50IFRoZSBkZXNpcmVkIFNIQSB2YXJpYW50IChTSEEtMSwgU0hBLTIyNCxcbiAgICAgKlx0IFNIQS0yNTYsIFNIQS0zODQsIG9yIFNIQS01MTIpXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IG91dHB1dEZvcm1hdCBUaGUgZGVzaXJlZCBvdXRwdXQgZm9ybWF0dGluZ1xuICAgICAqXHQgKEI2NCBvciBIRVgpXG4gICAgICogQHJldHVybiBUaGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBoYXNoIGluIHRoZSBmb3JtYXQgc3BlY2lmaWVkXG4gICAgICovXG4gICAgZ2V0SE1BQzogZnVuY3Rpb24oa2V5LCBpbnB1dEZvcm1hdCwgdmFyaWFudCwgb3V0cHV0Rm9ybWF0KSB7XG4gICAgICB2YXIgZm9ybWF0RnVuYywga2V5VG9Vc2UsIGJsb2NrQnl0ZVNpemUsIGJsb2NrQml0U2l6ZSwgaSxcbiAgICAgICAgcmV0VmFsLCBsYXN0QXJyYXlJbmRleCwga2V5QmluTGVuLCBoYXNoQml0U2l6ZSxcbiAgICAgICAga2V5V2l0aElQYWQgPSBbXSxcbiAgICAgICAga2V5V2l0aE9QYWQgPSBbXTtcblxuICAgICAgLyogVmFsaWRhdGUgdGhlIG91dHB1dCBmb3JtYXQgc2VsZWN0aW9uICovXG4gICAgICBzd2l0Y2ggKG91dHB1dEZvcm1hdCkge1xuICAgICAgICBjYXNlIFwiSEVYXCI6XG4gICAgICAgICAgZm9ybWF0RnVuYyA9IGJpbmIyaGV4O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiQjY0XCI6XG4gICAgICAgICAgZm9ybWF0RnVuYyA9IGJpbmIyYjY0O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiQVNDSUlcIjpcbiAgICAgICAgICBmb3JtYXRGdW5jID0gYmluYjJzdHI7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIFwiRk9STUFUIE5PVCBSRUNPR05JWkVEXCI7XG4gICAgICB9XG5cbiAgICAgIC8qIFZhbGlkYXRlIHRoZSBoYXNoIHZhcmlhbnQgc2VsZWN0aW9uIGFuZCBzZXQgbmVlZGVkIHZhcmlhYmxlcyAqL1xuICAgICAgc3dpdGNoICh2YXJpYW50KSB7XG4gICAgICAgIGNhc2UgXCJTSEEtMVwiOlxuICAgICAgICAgIGJsb2NrQnl0ZVNpemUgPSA2NDtcbiAgICAgICAgICBoYXNoQml0U2l6ZSA9IDE2MDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcIlNIQS0yMjRcIjpcbiAgICAgICAgICBibG9ja0J5dGVTaXplID0gNjQ7XG4gICAgICAgICAgaGFzaEJpdFNpemUgPSAyMjQ7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJTSEEtMjU2XCI6XG4gICAgICAgICAgYmxvY2tCeXRlU2l6ZSA9IDY0O1xuICAgICAgICAgIGhhc2hCaXRTaXplID0gMjU2O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiU0hBLTM4NFwiOlxuICAgICAgICAgIGJsb2NrQnl0ZVNpemUgPSAxMjg7XG4gICAgICAgICAgaGFzaEJpdFNpemUgPSAzODQ7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJTSEEtNTEyXCI6XG4gICAgICAgICAgYmxvY2tCeXRlU2l6ZSA9IDEyODtcbiAgICAgICAgICBoYXNoQml0U2l6ZSA9IDUxMjtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gXCJIQVNIIE5PVCBSRUNPR05JWkVEXCI7XG4gICAgICB9XG5cbiAgICAgIC8qIFZhbGlkYXRlIGlucHV0IGZvcm1hdCBzZWxlY3Rpb24gKi9cbiAgICAgIGlmIChcIkhFWFwiID09PSBpbnB1dEZvcm1hdCkge1xuICAgICAgICAvKiBOaWJibGVzIG11c3QgY29tZSBpbiBwYWlycyAqL1xuICAgICAgICBpZiAoMCAhPT0gKGtleS5sZW5ndGggJSAyKSkge1xuICAgICAgICAgIHJldHVybiBcIktFWSBNVVNUIEJFIElOIEJZVEUgSU5DUkVNRU5UU1wiO1xuICAgICAgICB9XG4gICAgICAgIGtleVRvVXNlID0gaGV4MmJpbmIoa2V5KTtcbiAgICAgICAga2V5QmluTGVuID0ga2V5Lmxlbmd0aCAqIDQ7XG4gICAgICB9IGVsc2UgaWYgKFwiQVNDSUlcIiA9PT0gaW5wdXRGb3JtYXQpIHtcbiAgICAgICAga2V5VG9Vc2UgPSBzdHIyYmluYihrZXkpO1xuICAgICAgICBrZXlCaW5MZW4gPSBrZXkubGVuZ3RoICogY2hhclNpemU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gXCJVTktOT1dOIEtFWSBJTlBVVCBUWVBFXCI7XG4gICAgICB9XG5cbiAgICAgIC8qIFRoZXNlIGFyZSB1c2VkIG11bHRpcGxlIHRpbWVzLCBjYWxjdWxhdGUgYW5kIHN0b3JlIHRoZW0gKi9cbiAgICAgIGJsb2NrQml0U2l6ZSA9IGJsb2NrQnl0ZVNpemUgKiA4O1xuICAgICAgbGFzdEFycmF5SW5kZXggPSAoYmxvY2tCeXRlU2l6ZSAvIDQpIC0gMTtcblxuICAgICAgLyogRmlndXJlIG91dCB3aGF0IHRvIGRvIHdpdGggdGhlIGtleSBiYXNlZCBvbiBpdHMgc2l6ZSByZWxhdGl2ZSB0b1xuICAgICAgICogdGhlIGhhc2gncyBibG9jayBzaXplICovXG4gICAgICBpZiAoYmxvY2tCeXRlU2l6ZSA8IChrZXlCaW5MZW4gLyA4KSkge1xuICAgICAgICBpZiAoXCJTSEEtMVwiID09PSB2YXJpYW50KSB7XG4gICAgICAgICAga2V5VG9Vc2UgPSBjb3JlU0hBMShrZXlUb1VzZSwga2V5QmluTGVuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBrZXlUb1VzZSA9IGNvcmVTSEEyKGtleVRvVXNlLCBrZXlCaW5MZW4sIHZhcmlhbnQpO1xuICAgICAgICB9XG4gICAgICAgIC8qIEZvciBhbGwgdmFyaWFudHMsIHRoZSBibG9jayBzaXplIGlzIGJpZ2dlciB0aGFuIHRoZSBvdXRwdXRcbiAgICAgICAgICogc2l6ZSBzbyB0aGVyZSB3aWxsIG5ldmVyIGJlIGEgdXNlZnVsIGJ5dGUgYXQgdGhlIGVuZCBvZiB0aGVcbiAgICAgICAgICogc3RyaW5nICovXG4gICAgICAgIGtleVRvVXNlW2xhc3RBcnJheUluZGV4XSAmPSAweEZGRkZGRjAwO1xuICAgICAgfSBlbHNlIGlmIChibG9ja0J5dGVTaXplID4gKGtleUJpbkxlbiAvIDgpKSB7XG4gICAgICAgIC8qIElmIHRoZSBibG9ja0J5dGVTaXplIGlzIGdyZWF0ZXIgdGhhbiB0aGUga2V5IGxlbmd0aCwgdGhlcmVcbiAgICAgICAgICogd2lsbCBhbHdheXMgYmUgYXQgTEVBU1Qgb25lIFwidXNlbGVzc1wiIGJ5dGUgYXQgdGhlIGVuZCBvZiB0aGVcbiAgICAgICAgICogc3RyaW5nICovXG4gICAgICAgIGtleVRvVXNlW2xhc3RBcnJheUluZGV4XSAmPSAweEZGRkZGRjAwO1xuICAgICAgfVxuXG4gICAgICAvKiBDcmVhdGUgaXBhZCBhbmQgb3BhZCAqL1xuICAgICAgZm9yIChpID0gMDsgaSA8PSBsYXN0QXJyYXlJbmRleDsgaSArPSAxKSB7XG4gICAgICAgIGtleVdpdGhJUGFkW2ldID0ga2V5VG9Vc2VbaV0gXiAweDM2MzYzNjM2O1xuICAgICAgICBrZXlXaXRoT1BhZFtpXSA9IGtleVRvVXNlW2ldIF4gMHg1QzVDNUM1QztcbiAgICAgIH1cblxuICAgICAgLyogQ2FsY3VsYXRlIHRoZSBITUFDICovXG4gICAgICBpZiAoXCJTSEEtMVwiID09PSB2YXJpYW50KSB7XG4gICAgICAgIHJldFZhbCA9IGNvcmVTSEExKFxuICAgICAgICAgIGtleVdpdGhJUGFkLmNvbmNhdCh0aGlzLnN0clRvSGFzaCksXG4gICAgICAgICAgYmxvY2tCaXRTaXplICsgdGhpcy5zdHJCaW5MZW4pO1xuICAgICAgICByZXRWYWwgPSBjb3JlU0hBMShcbiAgICAgICAgICBrZXlXaXRoT1BhZC5jb25jYXQocmV0VmFsKSxcbiAgICAgICAgICBibG9ja0JpdFNpemUgKyBoYXNoQml0U2l6ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXRWYWwgPSBjb3JlU0hBMihcbiAgICAgICAgICBrZXlXaXRoSVBhZC5jb25jYXQodGhpcy5zdHJUb0hhc2gpLFxuICAgICAgICAgIGJsb2NrQml0U2l6ZSArIHRoaXMuc3RyQmluTGVuLCB2YXJpYW50KTtcbiAgICAgICAgcmV0VmFsID0gY29yZVNIQTIoXG4gICAgICAgICAga2V5V2l0aE9QYWQuY29uY2F0KHJldFZhbCksXG4gICAgICAgICAgYmxvY2tCaXRTaXplICsgaGFzaEJpdFNpemUsIHZhcmlhbnQpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gKGZvcm1hdEZ1bmMocmV0VmFsKSk7XG4gICAgfVxuICB9O1xuXG4gIHJldHVybiBqc1NIQTtcbn0oKSk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAvKiogU0hBMSBoYXNoICovXG4gIHNoYTE6IGZ1bmN0aW9uKHN0cikge1xuICAgIHZhciBzaGFPYmogPSBuZXcganNTSEEoc3RyLCBcIkFTQ0lJXCIpO1xuICAgIHJldHVybiBzaGFPYmouZ2V0SGFzaChcIlNIQS0xXCIsIFwiQVNDSUlcIik7XG4gIH0sXG4gIC8qKiBTSEEyMjQgaGFzaCAqL1xuICBzaGEyMjQ6IGZ1bmN0aW9uKHN0cikge1xuICAgIHZhciBzaGFPYmogPSBuZXcganNTSEEoc3RyLCBcIkFTQ0lJXCIpO1xuICAgIHJldHVybiBzaGFPYmouZ2V0SGFzaChcIlNIQS0yMjRcIiwgXCJBU0NJSVwiKTtcbiAgfSxcbiAgLyoqIFNIQTI1NiBoYXNoICovXG4gIHNoYTI1NjogZnVuY3Rpb24oc3RyKSB7XG4gICAgdmFyIHNoYU9iaiA9IG5ldyBqc1NIQShzdHIsIFwiQVNDSUlcIik7XG4gICAgcmV0dXJuIHNoYU9iai5nZXRIYXNoKFwiU0hBLTI1NlwiLCBcIkFTQ0lJXCIpO1xuICB9LFxuICAvKiogU0hBMzg0IGhhc2ggKi9cbiAgc2hhMzg0OiBmdW5jdGlvbihzdHIpIHtcbiAgICB2YXIgc2hhT2JqID0gbmV3IGpzU0hBKHN0ciwgXCJBU0NJSVwiKTtcbiAgICByZXR1cm4gc2hhT2JqLmdldEhhc2goXCJTSEEtMzg0XCIsIFwiQVNDSUlcIik7XG5cbiAgfSxcbiAgLyoqIFNIQTUxMiBoYXNoICovXG4gIHNoYTUxMjogZnVuY3Rpb24oc3RyKSB7XG4gICAgdmFyIHNoYU9iaiA9IG5ldyBqc1NIQShzdHIsIFwiQVNDSUlcIik7XG4gICAgcmV0dXJuIHNoYU9iai5nZXRIYXNoKFwiU0hBLTUxMlwiLCBcIkFTQ0lJXCIpO1xuICB9XG59XG4iLCIvKipcbiAqIEBzZWUgbW9kdWxlOmNyeXB0by9jcnlwdG9cbiAqIEBtb2R1bGUgY3J5cHRvXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL2NpcGhlciAqL1xuICBjaXBoZXI6IHJlcXVpcmUoJy4vY2lwaGVyJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vaGFzaCAqL1xuICBoYXNoOiByZXF1aXJlKCcuL2hhc2gnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOmNyeXB0by9jZmIgKi9cbiAgY2ZiOiByZXF1aXJlKCcuL2NmYi5qcycpLFxuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL3B1YmxpY19rZXkgKi9cbiAgcHVibGljS2V5OiByZXF1aXJlKCcuL3B1YmxpY19rZXknKSxcbiAgLyoqIEBzZWUgbW9kdWxlOmNyeXB0by9zaWduYXR1cmUgKi9cbiAgc2lnbmF0dXJlOiByZXF1aXJlKCcuL3NpZ25hdHVyZS5qcycpLFxuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL3JhbmRvbSAqL1xuICByYW5kb206IHJlcXVpcmUoJy4vcmFuZG9tLmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vcGtjczEgKi9cbiAgcGtjczE6IHJlcXVpcmUoJy4vcGtjczEuanMnKVxuXG59XG5cbnZhciBjcnlwdG8gPSByZXF1aXJlKCcuL2NyeXB0by5qcycpO1xuXG5mb3IgKHZhciBpIGluIGNyeXB0bylcbiAgbW9kdWxlLmV4cG9ydHNbaV0gPSBjcnlwdG9baV07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIFBLQ1MxIGVuY29kaW5nXG4gKiBAcmVxdWlyZXMgY3J5cHRvL2NyeXB0b1xuICogQHJlcXVpcmVzIGNyeXB0by9oYXNoXG4gKiBAcmVxdWlyZXMgY3J5cHRvL3B1YmxpY19rZXkvanNiblxuICogQHJlcXVpcmVzIGNyeXB0by9yYW5kb21cbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIGNyeXB0by9wa2NzMVxuICovXG5cbi8qKlxuICogQVNOMSBvYmplY3QgaWRlbnRpZmllcnMgZm9yIGhhc2hlcyAoU2VlIFJGQzQ4ODAgNS4yLjIpXG4gKi9cbmhhc2hfaGVhZGVycyA9IG5ldyBBcnJheSgpO1xuaGFzaF9oZWFkZXJzWzFdID0gWzB4MzAsIDB4MjAsIDB4MzAsIDB4MGMsIDB4MDYsIDB4MDgsIDB4MmEsIDB4ODYsIDB4NDgsIDB4ODYsIDB4ZjcsIDB4MGQsIDB4MDIsIDB4MDUsIDB4MDUsIDB4MDAsIDB4MDQsXG4gICAgMHgxMFxuXTtcbmhhc2hfaGVhZGVyc1syXSA9IFsweDMwLCAweDIxLCAweDMwLCAweDA5LCAweDA2LCAweDA1LCAweDJiLCAweDBlLCAweDAzLCAweDAyLCAweDFhLCAweDA1LCAweDAwLCAweDA0LCAweDE0XTtcbmhhc2hfaGVhZGVyc1szXSA9IFsweDMwLCAweDIxLCAweDMwLCAweDA5LCAweDA2LCAweDA1LCAweDJCLCAweDI0LCAweDAzLCAweDAyLCAweDAxLCAweDA1LCAweDAwLCAweDA0LCAweDE0XTtcbmhhc2hfaGVhZGVyc1s4XSA9IFsweDMwLCAweDMxLCAweDMwLCAweDBkLCAweDA2LCAweDA5LCAweDYwLCAweDg2LCAweDQ4LCAweDAxLCAweDY1LCAweDAzLCAweDA0LCAweDAyLCAweDAxLCAweDA1LCAweDAwLFxuICAgIDB4MDQsIDB4MjBcbl07XG5oYXNoX2hlYWRlcnNbOV0gPSBbMHgzMCwgMHg0MSwgMHgzMCwgMHgwZCwgMHgwNiwgMHgwOSwgMHg2MCwgMHg4NiwgMHg0OCwgMHgwMSwgMHg2NSwgMHgwMywgMHgwNCwgMHgwMiwgMHgwMiwgMHgwNSwgMHgwMCxcbiAgICAweDA0LCAweDMwXG5dO1xuaGFzaF9oZWFkZXJzWzEwXSA9IFsweDMwLCAweDUxLCAweDMwLCAweDBkLCAweDA2LCAweDA5LCAweDYwLCAweDg2LCAweDQ4LCAweDAxLCAweDY1LCAweDAzLCAweDA0LCAweDAyLCAweDAzLCAweDA1LFxuICAgIDB4MDAsIDB4MDQsIDB4NDBcbl07XG5oYXNoX2hlYWRlcnNbMTFdID0gWzB4MzAsIDB4MzEsIDB4MzAsIDB4MGQsIDB4MDYsIDB4MDksIDB4NjAsIDB4ODYsIDB4NDgsIDB4MDEsIDB4NjUsIDB4MDMsIDB4MDQsIDB4MDIsIDB4MDQsIDB4MDUsXG4gICAgMHgwMCwgMHgwNCwgMHgxQ1xuXTtcblxudmFyIGNyeXB0byA9IHJlcXVpcmUoJy4vY3J5cHRvLmpzJyksXG4gIHJhbmRvbSA9IHJlcXVpcmUoJy4vcmFuZG9tLmpzJyksXG4gIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIEJpZ0ludGVnZXIgPSByZXF1aXJlKCcuL3B1YmxpY19rZXkvanNibi5qcycpLFxuICBoYXNoID0gcmVxdWlyZSgnLi9oYXNoJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBlbWU6IHtcbiAgICAvKipcbiAgICAgKiBjcmVhdGUgYSBFTUUtUEtDUzEtdjFfNSBwYWRkaW5nIChTZWUgUkZDNDg4MCAxMy4xLjEpXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgbWVzc2FnZSB0byBiZSBwYWRkZWRcbiAgICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlbmd0aCBMZW5ndGggdG8gdGhlIHJlc3VsdGluZyBtZXNzYWdlXG4gICAgICogQHJldHVybiB7U3RyaW5nfSBFTUUtUEtDUzEgcGFkZGVkIG1lc3NhZ2VcbiAgICAgKi9cbiAgICBlbmNvZGU6IGZ1bmN0aW9uKG1lc3NhZ2UsIGxlbmd0aCkge1xuICAgICAgaWYgKG1lc3NhZ2UubGVuZ3RoID4gbGVuZ3RoIC0gMTEpXG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIHZhciByZXN1bHQgPSBcIlwiO1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgyKTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoIC0gbWVzc2FnZS5sZW5ndGggLSAzOyBpKyspIHtcbiAgICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUocmFuZG9tLmdldFBzZXVkb1JhbmRvbSgxLCAyNTUpKTtcbiAgICAgIH1cbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuICAgICAgcmVzdWx0ICs9IG1lc3NhZ2U7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBkZWNvZGVzIGEgRU1FLVBLQ1MxLXYxXzUgcGFkZGluZyAoU2VlIFJGQzQ4ODAgMTMuMS4yKVxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIEVNRS1QS0NTMSBwYWRkZWQgbWVzc2FnZVxuICAgICAqIEByZXR1cm4ge1N0cmluZ30gZGVjb2RlZCBtZXNzYWdlIFxuICAgICAqL1xuICAgIGRlY29kZTogZnVuY3Rpb24obWVzc2FnZSwgbGVuKSB7XG4gICAgICBpZiAobWVzc2FnZS5sZW5ndGggPCBsZW4pXG4gICAgICAgIG1lc3NhZ2UgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApICsgbWVzc2FnZTtcbiAgICAgIGlmIChtZXNzYWdlLmxlbmd0aCA8IDEyIHx8IG1lc3NhZ2UuY2hhckNvZGVBdCgwKSAhPSAwIHx8IG1lc3NhZ2UuY2hhckNvZGVBdCgxKSAhPSAyKVxuICAgICAgICByZXR1cm4gLTE7XG4gICAgICB2YXIgaSA9IDI7XG4gICAgICB3aGlsZSAobWVzc2FnZS5jaGFyQ29kZUF0KGkpICE9IDAgJiYgbWVzc2FnZS5sZW5ndGggPiBpKVxuICAgICAgICBpKys7XG4gICAgICByZXR1cm4gbWVzc2FnZS5zdWJzdHJpbmcoaSArIDEsIG1lc3NhZ2UubGVuZ3RoKTtcbiAgICB9XG4gIH0sXG5cbiAgZW1zYToge1xuXG4gICAgLyoqXG4gICAgICogY3JlYXRlIGEgRU1TQS1QS0NTMS12MV81IHBhZGRpbmcgKFNlZSBSRkM0ODgwIDEzLjEuMylcbiAgICAgKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gSGFzaCBhbGdvcml0aG0gdHlwZSB1c2VkXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgRGF0YSB0byBiZSBoYXNoZWRcbiAgICAgKiBAcGFyYW0ge0ludGVnZXJ9IGtleWxlbmd0aCBLZXkgc2l6ZSBvZiB0aGUgcHVibGljIG1waSBpbiBieXRlc1xuICAgICAqIEByZXR1cm5zIHtTdHJpbmd9IEhhc2hjb2RlIHdpdGggcGtjczFwYWRkaW5nIGFzIHN0cmluZ1xuICAgICAqL1xuICAgIGVuY29kZTogZnVuY3Rpb24oYWxnbywgZGF0YSwga2V5bGVuZ3RoKSB7XG4gICAgICB2YXIgZGF0YTIgPSBcIlwiO1xuICAgICAgZGF0YTIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDAwKTtcbiAgICAgIGRhdGEyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHgwMSk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IChrZXlsZW5ndGggLSBoYXNoX2hlYWRlcnNbYWxnb10ubGVuZ3RoIC0gMyAtXG4gICAgICAgIGhhc2guZ2V0SGFzaEJ5dGVMZW5ndGgoYWxnbykpOyBpKyspXG5cbiAgICAgICAgZGF0YTIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweGZmKTtcblxuICAgICAgZGF0YTIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDAwKTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYXNoX2hlYWRlcnNbYWxnb10ubGVuZ3RoOyBpKyspXG4gICAgICAgIGRhdGEyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoaGFzaF9oZWFkZXJzW2FsZ29dW2ldKTtcblxuICAgICAgZGF0YTIgKz0gaGFzaC5kaWdlc3QoYWxnbywgZGF0YSk7XG4gICAgICByZXR1cm4gbmV3IEJpZ0ludGVnZXIodXRpbC5oZXhzdHJkdW1wKGRhdGEyKSwgMTYpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBleHRyYWN0IHRoZSBoYXNoIG91dCBvZiBhbiBFTVNBLVBLQ1MxLXYxLjUgcGFkZGluZyAoU2VlIFJGQzQ4ODAgMTMuMS4zKSBcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBIYXNoIGluIHBrY3MxIGVuY29kaW5nXG4gICAgICogQHJldHVybnMge1N0cmluZ30gVGhlIGhhc2ggYXMgc3RyaW5nXG4gICAgICovXG4gICAgZGVjb2RlOiBmdW5jdGlvbihhbGdvLCBkYXRhKSB7XG4gICAgICB2YXIgaSA9IDA7XG4gICAgICBpZiAoZGF0YS5jaGFyQ29kZUF0KDApID09IDApIGkrKztcbiAgICAgIGVsc2UgaWYgKGRhdGEuY2hhckNvZGVBdCgwKSAhPSAxKSByZXR1cm4gLTE7XG4gICAgICBlbHNlIGkrKztcblxuICAgICAgd2hpbGUgKGRhdGEuY2hhckNvZGVBdChpKSA9PSAweEZGKSBpKys7XG4gICAgICBpZiAoZGF0YS5jaGFyQ29kZUF0KGkrKykgIT0gMCkgcmV0dXJuIC0xO1xuICAgICAgdmFyIGogPSAwO1xuICAgICAgZm9yIChqID0gMDsgaiA8IGhhc2hfaGVhZGVyc1thbGdvXS5sZW5ndGggJiYgaiArIGkgPCBkYXRhLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmIChkYXRhLmNoYXJDb2RlQXQoaiArIGkpICE9IGhhc2hfaGVhZGVyc1thbGdvXVtqXSkgcmV0dXJuIC0xO1xuICAgICAgfVxuICAgICAgaSArPSBqO1xuICAgICAgaWYgKGRhdGEuc3Vic3RyaW5nKGkpLmxlbmd0aCA8IGhhc2guZ2V0SGFzaEJ5dGVMZW5ndGgoYWxnbykpIHJldHVybiAtMTtcbiAgICAgIHJldHVybiBkYXRhLnN1YnN0cmluZyhpKTtcbiAgICB9XG4gIH1cbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG4vL1xuLy8gQSBEaWdpdGFsIHNpZ25hdHVyZSBhbGdvcml0aG0gaW1wbGVtZW50YXRpb25cblxuLyoqXG4gKiBAcmVxdWlyZXMgY3J5cHRvL2hhc2hcbiAqIEByZXF1aXJlcyBjcnlwdG8vcHVibGljX2tleS9qc2JuXG4gKiBAcmVxdWlyZXMgY3J5cHRvL3JhbmRvbVxuICogQHJlcXVpcmVzIHV0aWxcbiAqIEBtb2R1bGUgY3J5cHRvL3B1YmxpY19rZXkvZHNhXG4gKi9cblxudmFyIEJpZ0ludGVnZXIgPSByZXF1aXJlKCcuL2pzYm4uanMnKSxcbiAgcmFuZG9tID0gcmVxdWlyZSgnLi4vcmFuZG9tLmpzJyksXG4gIGhhc2hNb2R1bGUgPSByZXF1aXJlKCcuLi9oYXNoJyksXG4gIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyksXG4gIGNvbmZpZyA9IHJlcXVpcmUoJy4uLy4uL2NvbmZpZycpO1xuXG5mdW5jdGlvbiBEU0EoKSB7XG4gIC8vIHMxID0gKChnKipzKSBtb2QgcCkgbW9kIHFcbiAgLy8gczEgPSAoKHMqKi0xKSooc2hhLTEobSkrKHMxKngpIG1vZCBxKVxuICBmdW5jdGlvbiBzaWduKGhhc2hhbGdvLCBtLCBnLCBwLCBxLCB4KSB7XG4gICAgLy8gSWYgdGhlIG91dHB1dCBzaXplIG9mIHRoZSBjaG9zZW4gaGFzaCBpcyBsYXJnZXIgdGhhbiB0aGUgbnVtYmVyIG9mXG4gICAgLy8gYml0cyBvZiBxLCB0aGUgaGFzaCByZXN1bHQgaXMgdHJ1bmNhdGVkIHRvIGZpdCBieSB0YWtpbmcgdGhlIG51bWJlclxuICAgIC8vIG9mIGxlZnRtb3N0IGJpdHMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiBiaXRzIG9mIHEuICBUaGlzIChwb3NzaWJseVxuICAgIC8vIHRydW5jYXRlZCkgaGFzaCBmdW5jdGlvbiByZXN1bHQgaXMgdHJlYXRlZCBhcyBhIG51bWJlciBhbmQgdXNlZFxuICAgIC8vIGRpcmVjdGx5IGluIHRoZSBEU0Egc2lnbmF0dXJlIGFsZ29yaXRobS5cbiAgICB2YXIgaGFzaGVkX2RhdGEgPSB1dGlsLmdldExlZnROQml0cyhoYXNoTW9kdWxlLmRpZ2VzdChoYXNoYWxnbywgbSksIHEuYml0TGVuZ3RoKCkpO1xuICAgIHZhciBoYXNoID0gbmV3IEJpZ0ludGVnZXIodXRpbC5oZXhzdHJkdW1wKGhhc2hlZF9kYXRhKSwgMTYpO1xuICAgIHZhciBrID0gcmFuZG9tLmdldFJhbmRvbUJpZ0ludGVnZXJJblJhbmdlKEJpZ0ludGVnZXIuT05FLmFkZChCaWdJbnRlZ2VyLk9ORSksIHEuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpKTtcbiAgICB2YXIgczEgPSAoZy5tb2RQb3coaywgcCkpLm1vZChxKTtcbiAgICB2YXIgczIgPSAoay5tb2RJbnZlcnNlKHEpLm11bHRpcGx5KGhhc2guYWRkKHgubXVsdGlwbHkoczEpKSkpLm1vZChxKTtcbiAgICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KCk7XG4gICAgcmVzdWx0WzBdID0gczEudG9NUEkoKTtcbiAgICByZXN1bHRbMV0gPSBzMi50b01QSSgpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBmdW5jdGlvbiBzZWxlY3RfaGFzaF9hbGdvcml0aG0ocSkge1xuICAgIHZhciB1c2Vyc2V0dGluZyA9IGNvbmZpZy5wcmVmZXJfaGFzaF9hbGdvcml0aG07XG4gICAgLypcbiAgICAgKiAxMDI0LWJpdCBrZXksIDE2MC1iaXQgcSwgU0hBLTEsIFNIQS0yMjQsIFNIQS0yNTYsIFNIQS0zODQsIG9yIFNIQS01MTIgaGFzaFxuICAgICAqIDIwNDgtYml0IGtleSwgMjI0LWJpdCBxLCBTSEEtMjI0LCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyIGhhc2hcbiAgICAgKiAyMDQ4LWJpdCBrZXksIDI1Ni1iaXQgcSwgU0hBLTI1NiwgU0hBLTM4NCwgb3IgU0hBLTUxMiBoYXNoXG4gICAgICogMzA3Mi1iaXQga2V5LCAyNTYtYml0IHEsIFNIQS0yNTYsIFNIQS0zODQsIG9yIFNIQS01MTIgaGFzaFxuICAgICAqL1xuICAgIHN3aXRjaCAoTWF0aC5yb3VuZChxLmJpdExlbmd0aCgpIC8gOCkpIHtcbiAgICAgIGNhc2UgMjA6XG4gICAgICAgIC8vIDEwMjQgYml0XG4gICAgICAgIGlmICh1c2Vyc2V0dGluZyAhPSAyICYmXG4gICAgICAgICAgdXNlcnNldHRpbmcgPiAxMSAmJlxuICAgICAgICAgIHVzZXJzZXR0aW5nICE9IDEwICYmXG4gICAgICAgICAgdXNlcnNldHRpbmcgPCA4KVxuICAgICAgICAgIHJldHVybiAyOyAvLyBwcmVmZXIgc2hhMVxuICAgICAgICByZXR1cm4gdXNlcnNldHRpbmc7XG4gICAgICBjYXNlIDI4OlxuICAgICAgICAvLyAyMDQ4IGJpdFxuICAgICAgICBpZiAodXNlcnNldHRpbmcgPiAxMSAmJlxuICAgICAgICAgIHVzZXJzZXR0aW5nIDwgOClcbiAgICAgICAgICByZXR1cm4gMTE7XG4gICAgICAgIHJldHVybiB1c2Vyc2V0dGluZztcbiAgICAgIGNhc2UgMzI6XG4gICAgICAgIC8vIDQwOTYgYml0IC8vIHByZWZlciBzaGEyMjRcbiAgICAgICAgaWYgKHVzZXJzZXR0aW5nID4gMTAgJiZcbiAgICAgICAgICB1c2Vyc2V0dGluZyA8IDgpXG4gICAgICAgICAgcmV0dXJuIDg7IC8vIHByZWZlciBzaGEyNTZcbiAgICAgICAgcmV0dXJuIHVzZXJzZXR0aW5nO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdXRpbC5wcmludF9kZWJ1ZyhcIkRTQSBzZWxlY3QgaGFzaCBhbGdvcml0aG06IHJldHVybmluZyBudWxsIGZvciBhbiB1bmtub3duIGxlbmd0aCBvZiBxXCIpO1xuICAgICAgICByZXR1cm4gbnVsbDtcblxuICAgIH1cbiAgfVxuICB0aGlzLnNlbGVjdF9oYXNoX2FsZ29yaXRobSA9IHNlbGVjdF9oYXNoX2FsZ29yaXRobTtcblxuICBmdW5jdGlvbiB2ZXJpZnkoaGFzaGFsZ28sIHMxLCBzMiwgbSwgcCwgcSwgZywgeSkge1xuICAgIHZhciBoYXNoZWRfZGF0YSA9IHV0aWwuZ2V0TGVmdE5CaXRzKGhhc2hNb2R1bGUuZGlnZXN0KGhhc2hhbGdvLCBtKSwgcS5iaXRMZW5ndGgoKSk7XG4gICAgdmFyIGhhc2ggPSBuZXcgQmlnSW50ZWdlcih1dGlsLmhleHN0cmR1bXAoaGFzaGVkX2RhdGEpLCAxNik7XG4gICAgaWYgKEJpZ0ludGVnZXIuWkVSTy5jb21wYXJlVG8oczEpID4gMCB8fFxuICAgICAgczEuY29tcGFyZVRvKHEpID4gMCB8fFxuICAgICAgQmlnSW50ZWdlci5aRVJPLmNvbXBhcmVUbyhzMikgPiAwIHx8XG4gICAgICBzMi5jb21wYXJlVG8ocSkgPiAwKSB7XG4gICAgICB1dGlsLnByaW50X2RlYnVnKFwiaW52YWxpZCBEU0EgU2lnbmF0dXJlXCIpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHZhciB3ID0gczIubW9kSW52ZXJzZShxKTtcbiAgICB2YXIgdTEgPSBoYXNoLm11bHRpcGx5KHcpLm1vZChxKTtcbiAgICB2YXIgdTIgPSBzMS5tdWx0aXBseSh3KS5tb2QocSk7XG4gICAgcmV0dXJuIGcubW9kUG93KHUxLCBwKS5tdWx0aXBseSh5Lm1vZFBvdyh1MiwgcCkpLm1vZChwKS5tb2QocSk7XG4gIH1cblxuICAvKlxuXHQgKiB1bnVzZWQgY29kZS4gVGhpcyBjYW4gYmUgdXNlZCBhcyBhIHN0YXJ0IHRvIHdyaXRlIGEga2V5IGdlbmVyYXRvclxuXHQgKiBmdW5jdGlvbi5cblx0XG5cdGZ1bmN0aW9uIGdlbmVyYXRlS2V5KGJpdGNvdW50KSB7XG5cdCAgICB2YXIgcWkgPSBuZXcgQmlnSW50ZWdlcihiaXRjb3VudCwgcHJpbWVDZW50ZXJpZSk7XG5cdCAgICB2YXIgcGkgPSBnZW5lcmF0ZVAocSwgNTEyKTtcblx0ICAgIHZhciBnaSA9IGdlbmVyYXRlRyhwLCBxLCBiaXRjb3VudCk7XG5cdCAgICB2YXIgeGk7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgeGkgPSBuZXcgQmlnSW50ZWdlcihxLmJpdENvdW50KCksIHJhbmQpO1xuXHQgICAgfSB3aGlsZSAoeC5jb21wYXJlVG8oQmlnSW50ZWdlci5aRVJPKSAhPSAxICYmIHguY29tcGFyZVRvKHEpICE9IC0xKTtcblx0ICAgIHZhciB5aSA9IGcubW9kUG93KHgsIHApO1xuXHQgICAgcmV0dXJuIHt4OiB4aSwgcTogcWksIHA6IHBpLCBnOiBnaSwgeTogeWl9O1xuXHR9XG5cblx0ZnVuY3Rpb24gZ2VuZXJhdGVQKHEsIGJpdGxlbmd0aCwgcmFuZG9tZm4pIHtcblx0ICAgIGlmIChiaXRsZW5ndGggJSA2NCAhPSAwKSB7XG5cdCAgICBcdHJldHVybiBmYWxzZTtcblx0ICAgIH1cblx0ICAgIHZhciBwVGVtcDtcblx0ICAgIHZhciBwVGVtcDI7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgcFRlbXAgPSByYW5kb21mbihiaXRjb3VudCwgdHJ1ZSk7XG5cdCAgICAgICAgcFRlbXAyID0gcFRlbXAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpO1xuXHQgICAgICAgIHBUZW1wID0gcFRlbXAuc3VidHJhY3QocFRlbXAyLnJlbWFpbmRlcihxKSk7XG5cdCAgICB9IHdoaWxlICghcFRlbXAuaXNQcm9iYWJsZVByaW1lKHByaW1lQ2VudGVyaWUpIHx8IHBUZW1wLmJpdExlbmd0aCgpICE9IGwpO1xuXHQgICAgcmV0dXJuIHBUZW1wO1xuXHR9XG5cdFxuXHRmdW5jdGlvbiBnZW5lcmF0ZUcocCwgcSwgYml0bGVuZ3RoLCByYW5kb21mbikge1xuXHQgICAgdmFyIGF1eCA9IHAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpO1xuXHQgICAgdmFyIHBvdyA9IGF1eC5kaXZpZGUocSk7XG5cdCAgICB2YXIgZ1RlbXA7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgZ1RlbXAgPSByYW5kb21mbihiaXRsZW5ndGgpO1xuXHQgICAgfSB3aGlsZSAoZ1RlbXAuY29tcGFyZVRvKGF1eCkgIT0gLTEgJiYgZ1RlbXAuY29tcGFyZVRvKEJpZ0ludGVnZXIuT05FKSAhPSAxKTtcblx0ICAgIHJldHVybiBnVGVtcC5tb2RQb3cocG93LCBwKTtcblx0fVxuXG5cdGZ1bmN0aW9uIGdlbmVyYXRlSyhxLCBiaXRsZW5ndGgsIHJhbmRvbWZuKSB7XG5cdCAgICB2YXIgdGVtcEs7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgdGVtcEsgPSByYW5kb21mbihiaXRsZW5ndGgsIGZhbHNlKTtcblx0ICAgIH0gd2hpbGUgKHRlbXBLLmNvbXBhcmVUbyhxKSAhPSAtMSAmJiB0ZW1wSy5jb21wYXJlVG8oQmlnSW50ZWdlci5aRVJPKSAhPSAxKTtcblx0ICAgIHJldHVybiB0ZW1wSztcblx0fVxuXG5cdGZ1bmN0aW9uIGdlbmVyYXRlUihxLHApIHtcblx0ICAgIGsgPSBnZW5lcmF0ZUsocSk7XG5cdCAgICB2YXIgciA9IGcubW9kUG93KGssIHApLm1vZChxKTtcblx0ICAgIHJldHVybiByO1xuXHR9XG5cblx0ZnVuY3Rpb24gZ2VuZXJhdGVTKGhhc2hmbixrLHIsbSxxLHgpIHtcbiAgICAgICAgdmFyIGhhc2ggPSBoYXNoZm4obSk7XG4gICAgICAgIHMgPSAoay5tb2RJbnZlcnNlKHEpLm11bHRpcGx5KGhhc2guYWRkKHgubXVsdGlwbHkocikpKSkubW9kKHEpO1xuXHQgICAgcmV0dXJuIHM7XG5cdH0gKi9cbiAgdGhpcy5zaWduID0gc2lnbjtcbiAgdGhpcy52ZXJpZnkgPSB2ZXJpZnk7XG4gIC8vIHRoaXMuZ2VuZXJhdGUgPSBnZW5lcmF0ZUtleTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBEU0E7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuLy9cbi8vIEVsR2FtYWwgaW1wbGVtZW50YXRpb25cblxuLyoqXG4gKiBAcmVxdWlyZXMgY3J5cHRvL3B1YmxpY19rZXkvanNiblxuICogQHJlcXVpcmVzIGNyeXB0by9yYW5kb21cbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIGNyeXB0by9wdWJsaWNfa2V5L2VsZ2FtYWxcbiAqL1xuXG52YXIgQmlnSW50ZWdlciA9IHJlcXVpcmUoJy4vanNibi5qcycpLFxuICByYW5kb20gPSByZXF1aXJlKCcuLi9yYW5kb20uanMnKSxcbiAgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuZnVuY3Rpb24gRWxnYW1hbCgpIHtcblxuICBmdW5jdGlvbiBlbmNyeXB0KG0sIGcsIHAsIHkpIHtcbiAgICAvLyAgY2hvb3NlIGsgaW4gezIsLi4uLHAtMn1cbiAgICB2YXIgdHdvID0gQmlnSW50ZWdlci5PTkUuYWRkKEJpZ0ludGVnZXIuT05FKTtcbiAgICB2YXIgcE1pbnVzMiA9IHAuc3VidHJhY3QodHdvKTtcbiAgICB2YXIgayA9IHJhbmRvbS5nZXRSYW5kb21CaWdJbnRlZ2VySW5SYW5nZSh0d28sIHBNaW51czIpO1xuICAgIGsgPSBrLm1vZChwTWludXMyKS5hZGQoQmlnSW50ZWdlci5PTkUpO1xuICAgIHZhciBjID0gW107XG4gICAgY1swXSA9IGcubW9kUG93KGssIHApO1xuICAgIGNbMV0gPSB5Lm1vZFBvdyhrLCBwKS5tdWx0aXBseShtKS5tb2QocCk7XG4gICAgcmV0dXJuIGM7XG4gIH1cblxuICBmdW5jdGlvbiBkZWNyeXB0KGMxLCBjMiwgcCwgeCkge1xuICAgIHV0aWwucHJpbnRfZGVidWcoXCJFbGdhbWFsIERlY3J5cHQ6XFxuYzE6XCIgKyB1dGlsLmhleHN0cmR1bXAoYzEudG9NUEkoKSkgKyBcIlxcblwiICtcbiAgICAgIFwiYzI6XCIgKyB1dGlsLmhleHN0cmR1bXAoYzIudG9NUEkoKSkgKyBcIlxcblwiICtcbiAgICAgIFwicDpcIiArIHV0aWwuaGV4c3RyZHVtcChwLnRvTVBJKCkpICsgXCJcXG5cIiArXG4gICAgICBcIng6XCIgKyB1dGlsLmhleHN0cmR1bXAoeC50b01QSSgpKSk7XG4gICAgcmV0dXJuIChjMS5tb2RQb3coeCwgcCkubW9kSW52ZXJzZShwKSkubXVsdGlwbHkoYzIpLm1vZChwKTtcbiAgICAvL3ZhciBjID0gYzEucG93KHgpLm1vZEludmVyc2UocCk7IC8vIGMwXi1hIG1vZCBwXG4gICAgLy9yZXR1cm4gYy5tdWx0aXBseShjMikubW9kKHApO1xuICB9XG5cbiAgLy8gc2lnbmluZyBhbmQgc2lnbmF0dXJlIHZlcmlmaWNhdGlvbiB1c2luZyBFbGdhbWFsIGlzIG5vdCByZXF1aXJlZCBieSBPcGVuUEdQLlxuICB0aGlzLmVuY3J5cHQgPSBlbmNyeXB0O1xuICB0aGlzLmRlY3J5cHQgPSBkZWNyeXB0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IEVsZ2FtYWw7XG4iLCIvKipcbiAqIEByZXF1aXJlcyBjcnlwdG8vcHVibGljX2tleS9kc2FcbiAqIEByZXF1aXJlcyBjcnlwdG8vcHVibGljX2tleS9lbGdhbWFsXG4gKiBAcmVxdWlyZXMgY3J5cHRvL3B1YmxpY19rZXkvcnNhXG4gKiBAbW9kdWxlIGNyeXB0by9wdWJsaWNfa2V5XG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAvKiogQHNlZSBtb2R1bGU6Y3J5cHRvL3B1YmxpY19rZXkvcnNhICovXG4gIHJzYTogcmVxdWlyZSgnLi9yc2EuanMnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOmNyeXB0by9wdWJsaWNfa2V5L2VsZ2FtYWwgKi9cbiAgZWxnYW1hbDogcmVxdWlyZSgnLi9lbGdhbWFsLmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpjcnlwdG8vcHVibGljX2tleS9kc2EgKi9cbiAgZHNhOiByZXF1aXJlKCcuL2RzYS5qcycpXG59XG4iLCIvKlxuICogQ29weXJpZ2h0IChjKSAyMDAzLTIwMDUgIFRvbSBXdSAodGp3QGNzLlN0YW5mb3JkLkVEVSkgXG4gKiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIE1vZGlmaWVkIGJ5IFJlY3VyaXR5IExhYnMgR21iSCBcbiAqIFxuICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nXG4gKiBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGVcbiAqIFwiU29mdHdhcmVcIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZ1xuICogd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLFxuICogZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvXG4gKiBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG9cbiAqIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbiAqXG4gKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZVxuICogaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4gKlxuICogVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMtSVNcIiBBTkQgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgXG4gKiBFWFBSRVNTLCBJTVBMSUVEIE9SIE9USEVSV0lTRSwgSU5DTFVESU5HIFdJVEhPVVQgTElNSVRBVElPTiwgQU5ZIFxuICogV0FSUkFOVFkgT0YgTUVSQ0hBTlRBQklMSVRZIE9SIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgXG4gKlxuICogSU4gTk8gRVZFTlQgU0hBTEwgVE9NIFdVIEJFIExJQUJMRSBGT1IgQU5ZIFNQRUNJQUwsIElOQ0lERU5UQUwsXG4gKiBJTkRJUkVDVCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgT0YgQU5ZIEtJTkQsIE9SIEFOWSBEQU1BR0VTIFdIQVRTT0VWRVJcbiAqIFJFU1VMVElORyBGUk9NIExPU1MgT0YgVVNFLCBEQVRBIE9SIFBST0ZJVFMsIFdIRVRIRVIgT1IgTk9UIEFEVklTRUQgT0ZcbiAqIFRIRSBQT1NTSUJJTElUWSBPRiBEQU1BR0UsIEFORCBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgQVJJU0lORyBPVVRcbiAqIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SIFBFUkZPUk1BTkNFIE9GIFRISVMgU09GVFdBUkUuXG4gKlxuICogSW4gYWRkaXRpb24sIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uIGFwcGxpZXM6XG4gKlxuICogQWxsIHJlZGlzdHJpYnV0aW9ucyBtdXN0IHJldGFpbiBhbiBpbnRhY3QgY29weSBvZiB0aGlzIGNvcHlyaWdodCBub3RpY2VcbiAqIGFuZCBkaXNjbGFpbWVyLlxuICovXG5cblxuLyoqXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSBjcnlwdG8vcHVibGljX2tleS9qc2JuXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyk7XG5cbi8vIEJhc2ljIEphdmFTY3JpcHQgQk4gbGlicmFyeSAtIHN1YnNldCB1c2VmdWwgZm9yIFJTQSBlbmNyeXB0aW9uLlxuXG4vLyBCaXRzIHBlciBkaWdpdFxudmFyIGRiaXRzO1xuXG4vLyBKYXZhU2NyaXB0IGVuZ2luZSBhbmFseXNpc1xudmFyIGNhbmFyeSA9IDB4ZGVhZGJlZWZjYWZlO1xudmFyIGpfbG0gPSAoKGNhbmFyeSAmIDB4ZmZmZmZmKSA9PSAweGVmY2FmZSk7XG5cbi8vIChwdWJsaWMpIENvbnN0cnVjdG9yXG5cbmZ1bmN0aW9uIEJpZ0ludGVnZXIoYSwgYiwgYykge1xuICBpZiAoYSAhPSBudWxsKVxuICAgIGlmIChcIm51bWJlclwiID09IHR5cGVvZiBhKSB0aGlzLmZyb21OdW1iZXIoYSwgYiwgYyk7XG4gICAgZWxzZSBpZiAoYiA9PSBudWxsICYmIFwic3RyaW5nXCIgIT0gdHlwZW9mIGEpIHRoaXMuZnJvbVN0cmluZyhhLCAyNTYpO1xuICBlbHNlIHRoaXMuZnJvbVN0cmluZyhhLCBiKTtcbn1cblxuLy8gcmV0dXJuIG5ldywgdW5zZXQgQmlnSW50ZWdlclxuXG5mdW5jdGlvbiBuYmkoKSB7XG4gIHJldHVybiBuZXcgQmlnSW50ZWdlcihudWxsKTtcbn1cblxuLy8gYW06IENvbXB1dGUgd19qICs9ICh4KnRoaXNfaSksIHByb3BhZ2F0ZSBjYXJyaWVzLFxuLy8gYyBpcyBpbml0aWFsIGNhcnJ5LCByZXR1cm5zIGZpbmFsIGNhcnJ5LlxuLy8gYyA8IDMqZHZhbHVlLCB4IDwgMipkdmFsdWUsIHRoaXNfaSA8IGR2YWx1ZVxuLy8gV2UgbmVlZCB0byBzZWxlY3QgdGhlIGZhc3Rlc3Qgb25lIHRoYXQgd29ya3MgaW4gdGhpcyBlbnZpcm9ubWVudC5cblxuLy8gYW0xOiB1c2UgYSBzaW5nbGUgbXVsdCBhbmQgZGl2aWRlIHRvIGdldCB0aGUgaGlnaCBiaXRzLFxuLy8gbWF4IGRpZ2l0IGJpdHMgc2hvdWxkIGJlIDI2IGJlY2F1c2Vcbi8vIG1heCBpbnRlcm5hbCB2YWx1ZSA9IDIqZHZhbHVlXjItMipkdmFsdWUgKDwgMl41MylcblxuZnVuY3Rpb24gYW0xKGksIHgsIHcsIGosIGMsIG4pIHtcbiAgd2hpbGUgKC0tbiA+PSAwKSB7XG4gICAgdmFyIHYgPSB4ICogdGhpc1tpKytdICsgd1tqXSArIGM7XG4gICAgYyA9IE1hdGguZmxvb3IodiAvIDB4NDAwMDAwMCk7XG4gICAgd1tqKytdID0gdiAmIDB4M2ZmZmZmZjtcbiAgfVxuICByZXR1cm4gYztcbn1cbi8vIGFtMiBhdm9pZHMgYSBiaWcgbXVsdC1hbmQtZXh0cmFjdCBjb21wbGV0ZWx5LlxuLy8gTWF4IGRpZ2l0IGJpdHMgc2hvdWxkIGJlIDw9IDMwIGJlY2F1c2Ugd2UgZG8gYml0d2lzZSBvcHNcbi8vIG9uIHZhbHVlcyB1cCB0byAyKmhkdmFsdWVeMi1oZHZhbHVlLTEgKDwgMl4zMSlcblxuZnVuY3Rpb24gYW0yKGksIHgsIHcsIGosIGMsIG4pIHtcbiAgdmFyIHhsID0geCAmIDB4N2ZmZixcbiAgICB4aCA9IHggPj4gMTU7XG4gIHdoaWxlICgtLW4gPj0gMCkge1xuICAgIHZhciBsID0gdGhpc1tpXSAmIDB4N2ZmZjtcbiAgICB2YXIgaCA9IHRoaXNbaSsrXSA+PiAxNTtcbiAgICB2YXIgbSA9IHhoICogbCArIGggKiB4bDtcbiAgICBsID0geGwgKiBsICsgKChtICYgMHg3ZmZmKSA8PCAxNSkgKyB3W2pdICsgKGMgJiAweDNmZmZmZmZmKTtcbiAgICBjID0gKGwgPj4+IDMwKSArIChtID4+PiAxNSkgKyB4aCAqIGggKyAoYyA+Pj4gMzApO1xuICAgIHdbaisrXSA9IGwgJiAweDNmZmZmZmZmO1xuICB9XG4gIHJldHVybiBjO1xufVxuLy8gQWx0ZXJuYXRlbHksIHNldCBtYXggZGlnaXQgYml0cyB0byAyOCBzaW5jZSBzb21lXG4vLyBicm93c2VycyBzbG93IGRvd24gd2hlbiBkZWFsaW5nIHdpdGggMzItYml0IG51bWJlcnMuXG5cbmZ1bmN0aW9uIGFtMyhpLCB4LCB3LCBqLCBjLCBuKSB7XG4gIHZhciB4bCA9IHggJiAweDNmZmYsXG4gICAgeGggPSB4ID4+IDE0O1xuICB3aGlsZSAoLS1uID49IDApIHtcbiAgICB2YXIgbCA9IHRoaXNbaV0gJiAweDNmZmY7XG4gICAgdmFyIGggPSB0aGlzW2krK10gPj4gMTQ7XG4gICAgdmFyIG0gPSB4aCAqIGwgKyBoICogeGw7XG4gICAgbCA9IHhsICogbCArICgobSAmIDB4M2ZmZikgPDwgMTQpICsgd1tqXSArIGM7XG4gICAgYyA9IChsID4+IDI4KSArIChtID4+IDE0KSArIHhoICogaDtcbiAgICB3W2orK10gPSBsICYgMHhmZmZmZmZmO1xuICB9XG4gIHJldHVybiBjO1xufVxuLyppZihqX2xtICYmIChuYXZpZ2F0b3IgIT0gdW5kZWZpbmVkICYmIFxuXHRuYXZpZ2F0b3IuYXBwTmFtZSA9PSBcIk1pY3Jvc29mdCBJbnRlcm5ldCBFeHBsb3JlclwiKSkge1xuICBCaWdJbnRlZ2VyLnByb3RvdHlwZS5hbSA9IGFtMjtcbiAgZGJpdHMgPSAzMDtcbn1cbmVsc2UgaWYoal9sbSAmJiAobmF2aWdhdG9yICE9IHVuZGVmaW5lZCAmJiBuYXZpZ2F0b3IuYXBwTmFtZSAhPSBcIk5ldHNjYXBlXCIpKSB7Ki9cbkJpZ0ludGVnZXIucHJvdG90eXBlLmFtID0gYW0xO1xuZGJpdHMgPSAyNjtcbi8qfVxuZWxzZSB7IC8vIE1vemlsbGEvTmV0c2NhcGUgc2VlbXMgdG8gcHJlZmVyIGFtM1xuICBCaWdJbnRlZ2VyLnByb3RvdHlwZS5hbSA9IGFtMztcbiAgZGJpdHMgPSAyODtcbn0qL1xuXG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5EQiA9IGRiaXRzO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuRE0gPSAoKDEgPDwgZGJpdHMpIC0gMSk7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5EViA9ICgxIDw8IGRiaXRzKTtcblxudmFyIEJJX0ZQID0gNTI7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5GViA9IE1hdGgucG93KDIsIEJJX0ZQKTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLkYxID0gQklfRlAgLSBkYml0cztcbkJpZ0ludGVnZXIucHJvdG90eXBlLkYyID0gMiAqIGRiaXRzIC0gQklfRlA7XG5cbi8vIERpZ2l0IGNvbnZlcnNpb25zXG52YXIgQklfUk0gPSBcIjAxMjM0NTY3ODlhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5elwiO1xudmFyIEJJX1JDID0gbmV3IEFycmF5KCk7XG52YXIgcnIsIHZ2O1xucnIgPSBcIjBcIi5jaGFyQ29kZUF0KDApO1xuZm9yICh2diA9IDA7IHZ2IDw9IDk7ICsrdnYpIEJJX1JDW3JyKytdID0gdnY7XG5yciA9IFwiYVwiLmNoYXJDb2RlQXQoMCk7XG5mb3IgKHZ2ID0gMTA7IHZ2IDwgMzY7ICsrdnYpIEJJX1JDW3JyKytdID0gdnY7XG5yciA9IFwiQVwiLmNoYXJDb2RlQXQoMCk7XG5mb3IgKHZ2ID0gMTA7IHZ2IDwgMzY7ICsrdnYpIEJJX1JDW3JyKytdID0gdnY7XG5cbmZ1bmN0aW9uIGludDJjaGFyKG4pIHtcbiAgcmV0dXJuIEJJX1JNLmNoYXJBdChuKTtcbn1cblxuZnVuY3Rpb24gaW50QXQocywgaSkge1xuICB2YXIgYyA9IEJJX1JDW3MuY2hhckNvZGVBdChpKV07XG4gIHJldHVybiAoYyA9PSBudWxsKSA/IC0xIDogYztcbn1cblxuLy8gKHByb3RlY3RlZCkgY29weSB0aGlzIHRvIHJcblxuZnVuY3Rpb24gYm5wQ29weVRvKHIpIHtcbiAgZm9yICh2YXIgaSA9IHRoaXMudCAtIDE7IGkgPj0gMDsgLS1pKSByW2ldID0gdGhpc1tpXTtcbiAgci50ID0gdGhpcy50O1xuICByLnMgPSB0aGlzLnM7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHNldCBmcm9tIGludGVnZXIgdmFsdWUgeCwgLURWIDw9IHggPCBEVlxuXG5mdW5jdGlvbiBibnBGcm9tSW50KHgpIHtcbiAgdGhpcy50ID0gMTtcbiAgdGhpcy5zID0gKHggPCAwKSA/IC0xIDogMDtcbiAgaWYgKHggPiAwKSB0aGlzWzBdID0geDtcbiAgZWxzZSBpZiAoeCA8IC0xKSB0aGlzWzBdID0geCArIERWO1xuICBlbHNlIHRoaXMudCA9IDA7XG59XG5cbi8vIHJldHVybiBiaWdpbnQgaW5pdGlhbGl6ZWQgdG8gdmFsdWVcblxuZnVuY3Rpb24gbmJ2KGkpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgci5mcm9tSW50KGkpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHByb3RlY3RlZCkgc2V0IGZyb20gc3RyaW5nIGFuZCByYWRpeFxuXG5mdW5jdGlvbiBibnBGcm9tU3RyaW5nKHMsIGIpIHtcbiAgdmFyIGs7XG4gIGlmIChiID09IDE2KSBrID0gNDtcbiAgZWxzZSBpZiAoYiA9PSA4KSBrID0gMztcbiAgZWxzZSBpZiAoYiA9PSAyNTYpIGsgPSA4OyAvLyBieXRlIGFycmF5XG4gIGVsc2UgaWYgKGIgPT0gMikgayA9IDE7XG4gIGVsc2UgaWYgKGIgPT0gMzIpIGsgPSA1O1xuICBlbHNlIGlmIChiID09IDQpIGsgPSAyO1xuICBlbHNlIHtcbiAgICB0aGlzLmZyb21SYWRpeChzLCBiKTtcbiAgICByZXR1cm47XG4gIH1cbiAgdGhpcy50ID0gMDtcbiAgdGhpcy5zID0gMDtcbiAgdmFyIGkgPSBzLmxlbmd0aCxcbiAgICBtaSA9IGZhbHNlLFxuICAgIHNoID0gMDtcbiAgd2hpbGUgKC0taSA+PSAwKSB7XG4gICAgdmFyIHggPSAoayA9PSA4KSA/IHNbaV0gJiAweGZmIDogaW50QXQocywgaSk7XG4gICAgaWYgKHggPCAwKSB7XG4gICAgICBpZiAocy5jaGFyQXQoaSkgPT0gXCItXCIpIG1pID0gdHJ1ZTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBtaSA9IGZhbHNlO1xuICAgIGlmIChzaCA9PSAwKVxuICAgICAgdGhpc1t0aGlzLnQrK10gPSB4O1xuICAgIGVsc2UgaWYgKHNoICsgayA+IHRoaXMuREIpIHtcbiAgICAgIHRoaXNbdGhpcy50IC0gMV0gfD0gKHggJiAoKDEgPDwgKHRoaXMuREIgLSBzaCkpIC0gMSkpIDw8IHNoO1xuICAgICAgdGhpc1t0aGlzLnQrK10gPSAoeCA+PiAodGhpcy5EQiAtIHNoKSk7XG4gICAgfSBlbHNlXG4gICAgICB0aGlzW3RoaXMudCAtIDFdIHw9IHggPDwgc2g7XG4gICAgc2ggKz0gaztcbiAgICBpZiAoc2ggPj0gdGhpcy5EQikgc2ggLT0gdGhpcy5EQjtcbiAgfVxuICBpZiAoayA9PSA4ICYmIChzWzBdICYgMHg4MCkgIT0gMCkge1xuICAgIHRoaXMucyA9IC0xO1xuICAgIGlmIChzaCA+IDApIHRoaXNbdGhpcy50IC0gMV0gfD0gKCgxIDw8ICh0aGlzLkRCIC0gc2gpKSAtIDEpIDw8IHNoO1xuICB9XG4gIHRoaXMuY2xhbXAoKTtcbiAgaWYgKG1pKSBCaWdJbnRlZ2VyLlpFUk8uc3ViVG8odGhpcywgdGhpcyk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIGNsYW1wIG9mZiBleGNlc3MgaGlnaCB3b3Jkc1xuXG5mdW5jdGlvbiBibnBDbGFtcCgpIHtcbiAgdmFyIGMgPSB0aGlzLnMgJiB0aGlzLkRNO1xuICB3aGlsZSAodGhpcy50ID4gMCAmJiB0aGlzW3RoaXMudCAtIDFdID09IGMpLS10aGlzLnQ7XG59XG5cbi8vIChwdWJsaWMpIHJldHVybiBzdHJpbmcgcmVwcmVzZW50YXRpb24gaW4gZ2l2ZW4gcmFkaXhcblxuZnVuY3Rpb24gYm5Ub1N0cmluZyhiKSB7XG4gIGlmICh0aGlzLnMgPCAwKSByZXR1cm4gXCItXCIgKyB0aGlzLm5lZ2F0ZSgpLnRvU3RyaW5nKGIpO1xuICB2YXIgaztcbiAgaWYgKGIgPT0gMTYpIGsgPSA0O1xuICBlbHNlIGlmIChiID09IDgpIGsgPSAzO1xuICBlbHNlIGlmIChiID09IDIpIGsgPSAxO1xuICBlbHNlIGlmIChiID09IDMyKSBrID0gNTtcbiAgZWxzZSBpZiAoYiA9PSA0KSBrID0gMjtcbiAgZWxzZSByZXR1cm4gdGhpcy50b1JhZGl4KGIpO1xuICB2YXIga20gPSAoMSA8PCBrKSAtIDEsXG4gICAgZCwgbSA9IGZhbHNlLFxuICAgIHIgPSBcIlwiLFxuICAgIGkgPSB0aGlzLnQ7XG4gIHZhciBwID0gdGhpcy5EQiAtIChpICogdGhpcy5EQikgJSBrO1xuICBpZiAoaS0tID4gMCkge1xuICAgIGlmIChwIDwgdGhpcy5EQiAmJiAoZCA9IHRoaXNbaV0gPj4gcCkgPiAwKSB7XG4gICAgICBtID0gdHJ1ZTtcbiAgICAgIHIgPSBpbnQyY2hhcihkKTtcbiAgICB9XG4gICAgd2hpbGUgKGkgPj0gMCkge1xuICAgICAgaWYgKHAgPCBrKSB7XG4gICAgICAgIGQgPSAodGhpc1tpXSAmICgoMSA8PCBwKSAtIDEpKSA8PCAoayAtIHApO1xuICAgICAgICBkIHw9IHRoaXNbLS1pXSA+PiAocCArPSB0aGlzLkRCIC0gayk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkID0gKHRoaXNbaV0gPj4gKHAgLT0gaykpICYga207XG4gICAgICAgIGlmIChwIDw9IDApIHtcbiAgICAgICAgICBwICs9IHRoaXMuREI7XG4gICAgICAgICAgLS1pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoZCA+IDApIG0gPSB0cnVlO1xuICAgICAgaWYgKG0pIHIgKz0gaW50MmNoYXIoZCk7XG4gICAgfVxuICB9XG4gIHJldHVybiBtID8gciA6IFwiMFwiO1xufVxuXG4vLyAocHVibGljKSAtdGhpc1xuXG5mdW5jdGlvbiBibk5lZ2F0ZSgpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHRoaXMsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgfHRoaXN8XG5cbmZ1bmN0aW9uIGJuQWJzKCkge1xuICByZXR1cm4gKHRoaXMucyA8IDApID8gdGhpcy5uZWdhdGUoKSA6IHRoaXM7XG59XG5cbi8vIChwdWJsaWMpIHJldHVybiArIGlmIHRoaXMgPiBhLCAtIGlmIHRoaXMgPCBhLCAwIGlmIGVxdWFsXG5cbmZ1bmN0aW9uIGJuQ29tcGFyZVRvKGEpIHtcbiAgdmFyIHIgPSB0aGlzLnMgLSBhLnM7XG4gIGlmIChyICE9IDApIHJldHVybiByO1xuICB2YXIgaSA9IHRoaXMudDtcbiAgciA9IGkgLSBhLnQ7XG4gIGlmIChyICE9IDApIHJldHVybiByO1xuICB3aGlsZSAoLS1pID49IDApIGlmICgociA9IHRoaXNbaV0gLSBhW2ldKSAhPSAwKSByZXR1cm4gcjtcbiAgcmV0dXJuIDA7XG59XG5cbi8vIHJldHVybnMgYml0IGxlbmd0aCBvZiB0aGUgaW50ZWdlciB4XG5cbmZ1bmN0aW9uIG5iaXRzKHgpIHtcbiAgdmFyIHIgPSAxLFxuICAgIHQ7XG4gIGlmICgodCA9IHggPj4+IDE2KSAhPSAwKSB7XG4gICAgeCA9IHQ7XG4gICAgciArPSAxNjtcbiAgfVxuICBpZiAoKHQgPSB4ID4+IDgpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICByICs9IDg7XG4gIH1cbiAgaWYgKCh0ID0geCA+PiA0KSAhPSAwKSB7XG4gICAgeCA9IHQ7XG4gICAgciArPSA0O1xuICB9XG4gIGlmICgodCA9IHggPj4gMikgIT0gMCkge1xuICAgIHggPSB0O1xuICAgIHIgKz0gMjtcbiAgfVxuICBpZiAoKHQgPSB4ID4+IDEpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICByICs9IDE7XG4gIH1cbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHJldHVybiB0aGUgbnVtYmVyIG9mIGJpdHMgaW4gXCJ0aGlzXCJcblxuZnVuY3Rpb24gYm5CaXRMZW5ndGgoKSB7XG4gIGlmICh0aGlzLnQgPD0gMCkgcmV0dXJuIDA7XG4gIHJldHVybiB0aGlzLkRCICogKHRoaXMudCAtIDEpICsgbmJpdHModGhpc1t0aGlzLnQgLSAxXSBeICh0aGlzLnMgJiB0aGlzLkRNKSk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzIDw8IG4qREJcblxuZnVuY3Rpb24gYm5wRExTaGlmdFRvKG4sIHIpIHtcbiAgdmFyIGk7XG4gIGZvciAoaSA9IHRoaXMudCAtIDE7IGkgPj0gMDsgLS1pKSByW2kgKyBuXSA9IHRoaXNbaV07XG4gIGZvciAoaSA9IG4gLSAxOyBpID49IDA7IC0taSkgcltpXSA9IDA7XG4gIHIudCA9IHRoaXMudCArIG47XG4gIHIucyA9IHRoaXMucztcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgPj4gbipEQlxuXG5mdW5jdGlvbiBibnBEUlNoaWZ0VG8obiwgcikge1xuICBmb3IgKHZhciBpID0gbjsgaSA8IHRoaXMudDsgKytpKSByW2kgLSBuXSA9IHRoaXNbaV07XG4gIHIudCA9IE1hdGgubWF4KHRoaXMudCAtIG4sIDApO1xuICByLnMgPSB0aGlzLnM7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzIDw8IG5cblxuZnVuY3Rpb24gYm5wTFNoaWZ0VG8obiwgcikge1xuICB2YXIgYnMgPSBuICUgdGhpcy5EQjtcbiAgdmFyIGNicyA9IHRoaXMuREIgLSBicztcbiAgdmFyIGJtID0gKDEgPDwgY2JzKSAtIDE7XG4gIHZhciBkcyA9IE1hdGguZmxvb3IobiAvIHRoaXMuREIpLFxuICAgIGMgPSAodGhpcy5zIDw8IGJzKSAmIHRoaXMuRE0sXG4gICAgaTtcbiAgZm9yIChpID0gdGhpcy50IC0gMTsgaSA+PSAwOyAtLWkpIHtcbiAgICByW2kgKyBkcyArIDFdID0gKHRoaXNbaV0gPj4gY2JzKSB8IGM7XG4gICAgYyA9ICh0aGlzW2ldICYgYm0pIDw8IGJzO1xuICB9XG4gIGZvciAoaSA9IGRzIC0gMTsgaSA+PSAwOyAtLWkpIHJbaV0gPSAwO1xuICByW2RzXSA9IGM7XG4gIHIudCA9IHRoaXMudCArIGRzICsgMTtcbiAgci5zID0gdGhpcy5zO1xuICByLmNsYW1wKCk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzID4+IG5cblxuZnVuY3Rpb24gYm5wUlNoaWZ0VG8obiwgcikge1xuICByLnMgPSB0aGlzLnM7XG4gIHZhciBkcyA9IE1hdGguZmxvb3IobiAvIHRoaXMuREIpO1xuICBpZiAoZHMgPj0gdGhpcy50KSB7XG4gICAgci50ID0gMDtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIGJzID0gbiAlIHRoaXMuREI7XG4gIHZhciBjYnMgPSB0aGlzLkRCIC0gYnM7XG4gIHZhciBibSA9ICgxIDw8IGJzKSAtIDE7XG4gIHJbMF0gPSB0aGlzW2RzXSA+PiBicztcbiAgZm9yICh2YXIgaSA9IGRzICsgMTsgaSA8IHRoaXMudDsgKytpKSB7XG4gICAgcltpIC0gZHMgLSAxXSB8PSAodGhpc1tpXSAmIGJtKSA8PCBjYnM7XG4gICAgcltpIC0gZHNdID0gdGhpc1tpXSA+PiBicztcbiAgfVxuICBpZiAoYnMgPiAwKSByW3RoaXMudCAtIGRzIC0gMV0gfD0gKHRoaXMucyAmIGJtKSA8PCBjYnM7XG4gIHIudCA9IHRoaXMudCAtIGRzO1xuICByLmNsYW1wKCk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzIC0gYVxuXG5mdW5jdGlvbiBibnBTdWJUbyhhLCByKSB7XG4gIHZhciBpID0gMCxcbiAgICBjID0gMCxcbiAgICBtID0gTWF0aC5taW4oYS50LCB0aGlzLnQpO1xuICB3aGlsZSAoaSA8IG0pIHtcbiAgICBjICs9IHRoaXNbaV0gLSBhW2ldO1xuICAgIHJbaSsrXSA9IGMgJiB0aGlzLkRNO1xuICAgIGMgPj49IHRoaXMuREI7XG4gIH1cbiAgaWYgKGEudCA8IHRoaXMudCkge1xuICAgIGMgLT0gYS5zO1xuICAgIHdoaWxlIChpIDwgdGhpcy50KSB7XG4gICAgICBjICs9IHRoaXNbaV07XG4gICAgICByW2krK10gPSBjICYgdGhpcy5ETTtcbiAgICAgIGMgPj49IHRoaXMuREI7XG4gICAgfVxuICAgIGMgKz0gdGhpcy5zO1xuICB9IGVsc2Uge1xuICAgIGMgKz0gdGhpcy5zO1xuICAgIHdoaWxlIChpIDwgYS50KSB7XG4gICAgICBjIC09IGFbaV07XG4gICAgICByW2krK10gPSBjICYgdGhpcy5ETTtcbiAgICAgIGMgPj49IHRoaXMuREI7XG4gICAgfVxuICAgIGMgLT0gYS5zO1xuICB9XG4gIHIucyA9IChjIDwgMCkgPyAtMSA6IDA7XG4gIGlmIChjIDwgLTEpIHJbaSsrXSA9IHRoaXMuRFYgKyBjO1xuICBlbHNlIGlmIChjID4gMCkgcltpKytdID0gYztcbiAgci50ID0gaTtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpcyAqIGEsIHIgIT0gdGhpcyxhIChIQUMgMTQuMTIpXG4vLyBcInRoaXNcIiBzaG91bGQgYmUgdGhlIGxhcmdlciBvbmUgaWYgYXBwcm9wcmlhdGUuXG5cbmZ1bmN0aW9uIGJucE11bHRpcGx5VG8oYSwgcikge1xuICB2YXIgeCA9IHRoaXMuYWJzKCksXG4gICAgeSA9IGEuYWJzKCk7XG4gIHZhciBpID0geC50O1xuICByLnQgPSBpICsgeS50O1xuICB3aGlsZSAoLS1pID49IDApIHJbaV0gPSAwO1xuICBmb3IgKGkgPSAwOyBpIDwgeS50OyArK2kpIHJbaSArIHgudF0gPSB4LmFtKDAsIHlbaV0sIHIsIGksIDAsIHgudCk7XG4gIHIucyA9IDA7XG4gIHIuY2xhbXAoKTtcbiAgaWYgKHRoaXMucyAhPSBhLnMpIEJpZ0ludGVnZXIuWkVSTy5zdWJUbyhyLCByKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXNeMiwgciAhPSB0aGlzIChIQUMgMTQuMTYpXG5cbmZ1bmN0aW9uIGJucFNxdWFyZVRvKHIpIHtcbiAgdmFyIHggPSB0aGlzLmFicygpO1xuICB2YXIgaSA9IHIudCA9IDIgKiB4LnQ7XG4gIHdoaWxlICgtLWkgPj0gMCkgcltpXSA9IDA7XG4gIGZvciAoaSA9IDA7IGkgPCB4LnQgLSAxOyArK2kpIHtcbiAgICB2YXIgYyA9IHguYW0oaSwgeFtpXSwgciwgMiAqIGksIDAsIDEpO1xuICAgIGlmICgocltpICsgeC50XSArPSB4LmFtKGkgKyAxLCAyICogeFtpXSwgciwgMiAqIGkgKyAxLCBjLCB4LnQgLSBpIC0gMSkpID49IHguRFYpIHtcbiAgICAgIHJbaSArIHgudF0gLT0geC5EVjtcbiAgICAgIHJbaSArIHgudCArIDFdID0gMTtcbiAgICB9XG4gIH1cbiAgaWYgKHIudCA+IDApIHJbci50IC0gMV0gKz0geC5hbShpLCB4W2ldLCByLCAyICogaSwgMCwgMSk7XG4gIHIucyA9IDA7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgZGl2aWRlIHRoaXMgYnkgbSwgcXVvdGllbnQgYW5kIHJlbWFpbmRlciB0byBxLCByIChIQUMgMTQuMjApXG4vLyByICE9IHEsIHRoaXMgIT0gbS4gIHEgb3IgciBtYXkgYmUgbnVsbC5cblxuZnVuY3Rpb24gYm5wRGl2UmVtVG8obSwgcSwgcikge1xuICB2YXIgcG0gPSBtLmFicygpO1xuICBpZiAocG0udCA8PSAwKSByZXR1cm47XG4gIHZhciBwdCA9IHRoaXMuYWJzKCk7XG4gIGlmIChwdC50IDwgcG0udCkge1xuICAgIGlmIChxICE9IG51bGwpIHEuZnJvbUludCgwKTtcbiAgICBpZiAociAhPSBudWxsKSB0aGlzLmNvcHlUbyhyKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKHIgPT0gbnVsbCkgciA9IG5iaSgpO1xuICB2YXIgeSA9IG5iaSgpLFxuICAgIHRzID0gdGhpcy5zLFxuICAgIG1zID0gbS5zO1xuICB2YXIgbnNoID0gdGhpcy5EQiAtIG5iaXRzKHBtW3BtLnQgLSAxXSk7IC8vIG5vcm1hbGl6ZSBtb2R1bHVzXG4gIGlmIChuc2ggPiAwKSB7XG4gICAgcG0ubFNoaWZ0VG8obnNoLCB5KTtcbiAgICBwdC5sU2hpZnRUbyhuc2gsIHIpO1xuICB9IGVsc2Uge1xuICAgIHBtLmNvcHlUbyh5KTtcbiAgICBwdC5jb3B5VG8ocik7XG4gIH1cbiAgdmFyIHlzID0geS50O1xuICB2YXIgeTAgPSB5W3lzIC0gMV07XG4gIGlmICh5MCA9PSAwKSByZXR1cm47XG4gIHZhciB5dCA9IHkwICogKDEgPDwgdGhpcy5GMSkgKyAoKHlzID4gMSkgPyB5W3lzIC0gMl0gPj4gdGhpcy5GMiA6IDApO1xuICB2YXIgZDEgPSB0aGlzLkZWIC8geXQsXG4gICAgZDIgPSAoMSA8PCB0aGlzLkYxKSAvIHl0LFxuICAgIGUgPSAxIDw8IHRoaXMuRjI7XG4gIHZhciBpID0gci50LFxuICAgIGogPSBpIC0geXMsXG4gICAgdCA9IChxID09IG51bGwpID8gbmJpKCkgOiBxO1xuICB5LmRsU2hpZnRUbyhqLCB0KTtcbiAgaWYgKHIuY29tcGFyZVRvKHQpID49IDApIHtcbiAgICByW3IudCsrXSA9IDE7XG4gICAgci5zdWJUbyh0LCByKTtcbiAgfVxuICBCaWdJbnRlZ2VyLk9ORS5kbFNoaWZ0VG8oeXMsIHQpO1xuICB0LnN1YlRvKHksIHkpOyAvLyBcIm5lZ2F0aXZlXCIgeSBzbyB3ZSBjYW4gcmVwbGFjZSBzdWIgd2l0aCBhbSBsYXRlclxuICB3aGlsZSAoeS50IDwgeXMpIHlbeS50KytdID0gMDtcbiAgd2hpbGUgKC0taiA+PSAwKSB7XG4gICAgLy8gRXN0aW1hdGUgcXVvdGllbnQgZGlnaXRcbiAgICB2YXIgcWQgPSAoclstLWldID09IHkwKSA/IHRoaXMuRE0gOiBNYXRoLmZsb29yKHJbaV0gKiBkMSArIChyW2kgLSAxXSArIGUpICogZDIpO1xuICAgIGlmICgocltpXSArPSB5LmFtKDAsIHFkLCByLCBqLCAwLCB5cykpIDwgcWQpIHsgLy8gVHJ5IGl0IG91dFxuICAgICAgeS5kbFNoaWZ0VG8oaiwgdCk7XG4gICAgICByLnN1YlRvKHQsIHIpO1xuICAgICAgd2hpbGUgKHJbaV0gPCAtLXFkKSByLnN1YlRvKHQsIHIpO1xuICAgIH1cbiAgfVxuICBpZiAocSAhPSBudWxsKSB7XG4gICAgci5kclNoaWZ0VG8oeXMsIHEpO1xuICAgIGlmICh0cyAhPSBtcykgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHEsIHEpO1xuICB9XG4gIHIudCA9IHlzO1xuICByLmNsYW1wKCk7XG4gIGlmIChuc2ggPiAwKSByLnJTaGlmdFRvKG5zaCwgcik7IC8vIERlbm9ybWFsaXplIHJlbWFpbmRlclxuICBpZiAodHMgPCAwKSBCaWdJbnRlZ2VyLlpFUk8uc3ViVG8ociwgcik7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgbW9kIGFcblxuZnVuY3Rpb24gYm5Nb2QoYSkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLmFicygpLmRpdlJlbVRvKGEsIG51bGwsIHIpO1xuICBpZiAodGhpcy5zIDwgMCAmJiByLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLlpFUk8pID4gMCkgYS5zdWJUbyhyLCByKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIE1vZHVsYXIgcmVkdWN0aW9uIHVzaW5nIFwiY2xhc3NpY1wiIGFsZ29yaXRobVxuXG5mdW5jdGlvbiBDbGFzc2ljKG0pIHtcbiAgdGhpcy5tID0gbTtcbn1cblxuZnVuY3Rpb24gY0NvbnZlcnQoeCkge1xuICBpZiAoeC5zIDwgMCB8fCB4LmNvbXBhcmVUbyh0aGlzLm0pID49IDApIHJldHVybiB4Lm1vZCh0aGlzLm0pO1xuICBlbHNlIHJldHVybiB4O1xufVxuXG5mdW5jdGlvbiBjUmV2ZXJ0KHgpIHtcbiAgcmV0dXJuIHg7XG59XG5cbmZ1bmN0aW9uIGNSZWR1Y2UoeCkge1xuICB4LmRpdlJlbVRvKHRoaXMubSwgbnVsbCwgeCk7XG59XG5cbmZ1bmN0aW9uIGNNdWxUbyh4LCB5LCByKSB7XG4gIHgubXVsdGlwbHlUbyh5LCByKTtcbiAgdGhpcy5yZWR1Y2Uocik7XG59XG5cbmZ1bmN0aW9uIGNTcXJUbyh4LCByKSB7XG4gIHguc3F1YXJlVG8ocik7XG4gIHRoaXMucmVkdWNlKHIpO1xufVxuXG5DbGFzc2ljLnByb3RvdHlwZS5jb252ZXJ0ID0gY0NvbnZlcnQ7XG5DbGFzc2ljLnByb3RvdHlwZS5yZXZlcnQgPSBjUmV2ZXJ0O1xuQ2xhc3NpYy5wcm90b3R5cGUucmVkdWNlID0gY1JlZHVjZTtcbkNsYXNzaWMucHJvdG90eXBlLm11bFRvID0gY011bFRvO1xuQ2xhc3NpYy5wcm90b3R5cGUuc3FyVG8gPSBjU3FyVG87XG5cbi8vIChwcm90ZWN0ZWQpIHJldHVybiBcIi0xL3RoaXMgJSAyXkRCXCI7IHVzZWZ1bCBmb3IgTW9udC4gcmVkdWN0aW9uXG4vLyBqdXN0aWZpY2F0aW9uOlxuLy8gICAgICAgICB4eSA9PSAxIChtb2QgbSlcbi8vICAgICAgICAgeHkgPSAgMStrbVxuLy8gICB4eSgyLXh5KSA9ICgxK2ttKSgxLWttKVxuLy8geFt5KDIteHkpXSA9IDEta14ybV4yXG4vLyB4W3koMi14eSldID09IDEgKG1vZCBtXjIpXG4vLyBpZiB5IGlzIDEveCBtb2QgbSwgdGhlbiB5KDIteHkpIGlzIDEveCBtb2QgbV4yXG4vLyBzaG91bGQgcmVkdWNlIHggYW5kIHkoMi14eSkgYnkgbV4yIGF0IGVhY2ggc3RlcCB0byBrZWVwIHNpemUgYm91bmRlZC5cbi8vIEpTIG11bHRpcGx5IFwib3ZlcmZsb3dzXCIgZGlmZmVyZW50bHkgZnJvbSBDL0MrKywgc28gY2FyZSBpcyBuZWVkZWQgaGVyZS5cblxuZnVuY3Rpb24gYm5wSW52RGlnaXQoKSB7XG4gIGlmICh0aGlzLnQgPCAxKSByZXR1cm4gMDtcbiAgdmFyIHggPSB0aGlzWzBdO1xuICBpZiAoKHggJiAxKSA9PSAwKSByZXR1cm4gMDtcbiAgdmFyIHkgPSB4ICYgMzsgLy8geSA9PSAxL3ggbW9kIDJeMlxuICB5ID0gKHkgKiAoMiAtICh4ICYgMHhmKSAqIHkpKSAmIDB4ZjsgLy8geSA9PSAxL3ggbW9kIDJeNFxuICB5ID0gKHkgKiAoMiAtICh4ICYgMHhmZikgKiB5KSkgJiAweGZmOyAvLyB5ID09IDEveCBtb2QgMl44XG4gIHkgPSAoeSAqICgyIC0gKCgoeCAmIDB4ZmZmZikgKiB5KSAmIDB4ZmZmZikpKSAmIDB4ZmZmZjsgLy8geSA9PSAxL3ggbW9kIDJeMTZcbiAgLy8gbGFzdCBzdGVwIC0gY2FsY3VsYXRlIGludmVyc2UgbW9kIERWIGRpcmVjdGx5O1xuICAvLyBhc3N1bWVzIDE2IDwgREIgPD0gMzIgYW5kIGFzc3VtZXMgYWJpbGl0eSB0byBoYW5kbGUgNDgtYml0IGludHNcbiAgeSA9ICh5ICogKDIgLSB4ICogeSAlIHRoaXMuRFYpKSAlIHRoaXMuRFY7IC8vIHkgPT0gMS94IG1vZCAyXmRiaXRzXG4gIC8vIHdlIHJlYWxseSB3YW50IHRoZSBuZWdhdGl2ZSBpbnZlcnNlLCBhbmQgLURWIDwgeSA8IERWXG4gIHJldHVybiAoeSA+IDApID8gdGhpcy5EViAtIHkgOiAteTtcbn1cblxuLy8gTW9udGdvbWVyeSByZWR1Y3Rpb25cblxuZnVuY3Rpb24gTW9udGdvbWVyeShtKSB7XG4gIHRoaXMubSA9IG07XG4gIHRoaXMubXAgPSBtLmludkRpZ2l0KCk7XG4gIHRoaXMubXBsID0gdGhpcy5tcCAmIDB4N2ZmZjtcbiAgdGhpcy5tcGggPSB0aGlzLm1wID4+IDE1O1xuICB0aGlzLnVtID0gKDEgPDwgKG0uREIgLSAxNSkpIC0gMTtcbiAgdGhpcy5tdDIgPSAyICogbS50O1xufVxuXG4vLyB4UiBtb2QgbVxuXG5mdW5jdGlvbiBtb250Q29udmVydCh4KSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHguYWJzKCkuZGxTaGlmdFRvKHRoaXMubS50LCByKTtcbiAgci5kaXZSZW1Ubyh0aGlzLm0sIG51bGwsIHIpO1xuICBpZiAoeC5zIDwgMCAmJiByLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLlpFUk8pID4gMCkgdGhpcy5tLnN1YlRvKHIsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8geC9SIG1vZCBtXG5cbmZ1bmN0aW9uIG1vbnRSZXZlcnQoeCkge1xuICB2YXIgciA9IG5iaSgpO1xuICB4LmNvcHlUbyhyKTtcbiAgdGhpcy5yZWR1Y2Uocik7XG4gIHJldHVybiByO1xufVxuXG4vLyB4ID0geC9SIG1vZCBtIChIQUMgMTQuMzIpXG5cbmZ1bmN0aW9uIG1vbnRSZWR1Y2UoeCkge1xuICB3aGlsZSAoeC50IDw9IHRoaXMubXQyKSAvLyBwYWQgeCBzbyBhbSBoYXMgZW5vdWdoIHJvb20gbGF0ZXJcbiAgICB4W3gudCsrXSA9IDA7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5tLnQ7ICsraSkge1xuICAgIC8vIGZhc3RlciB3YXkgb2YgY2FsY3VsYXRpbmcgdTAgPSB4W2ldKm1wIG1vZCBEVlxuICAgIHZhciBqID0geFtpXSAmIDB4N2ZmZjtcbiAgICB2YXIgdTAgPSAoaiAqIHRoaXMubXBsICsgKCgoaiAqIHRoaXMubXBoICsgKHhbaV0gPj4gMTUpICogdGhpcy5tcGwpICYgdGhpcy51bSkgPDwgMTUpKSAmIHguRE07XG4gICAgLy8gdXNlIGFtIHRvIGNvbWJpbmUgdGhlIG11bHRpcGx5LXNoaWZ0LWFkZCBpbnRvIG9uZSBjYWxsXG4gICAgaiA9IGkgKyB0aGlzLm0udDtcbiAgICB4W2pdICs9IHRoaXMubS5hbSgwLCB1MCwgeCwgaSwgMCwgdGhpcy5tLnQpO1xuICAgIC8vIHByb3BhZ2F0ZSBjYXJyeVxuICAgIHdoaWxlICh4W2pdID49IHguRFYpIHtcbiAgICAgIHhbal0gLT0geC5EVjtcbiAgICAgIHhbKytqXSsrO1xuICAgIH1cbiAgfVxuICB4LmNsYW1wKCk7XG4gIHguZHJTaGlmdFRvKHRoaXMubS50LCB4KTtcbiAgaWYgKHguY29tcGFyZVRvKHRoaXMubSkgPj0gMCkgeC5zdWJUbyh0aGlzLm0sIHgpO1xufVxuXG4vLyByID0gXCJ4XjIvUiBtb2QgbVwiOyB4ICE9IHJcblxuZnVuY3Rpb24gbW9udFNxclRvKHgsIHIpIHtcbiAgeC5zcXVhcmVUbyhyKTtcbiAgdGhpcy5yZWR1Y2Uocik7XG59XG5cbi8vIHIgPSBcInh5L1IgbW9kIG1cIjsgeCx5ICE9IHJcblxuZnVuY3Rpb24gbW9udE11bFRvKHgsIHksIHIpIHtcbiAgeC5tdWx0aXBseVRvKHksIHIpO1xuICB0aGlzLnJlZHVjZShyKTtcbn1cblxuTW9udGdvbWVyeS5wcm90b3R5cGUuY29udmVydCA9IG1vbnRDb252ZXJ0O1xuTW9udGdvbWVyeS5wcm90b3R5cGUucmV2ZXJ0ID0gbW9udFJldmVydDtcbk1vbnRnb21lcnkucHJvdG90eXBlLnJlZHVjZSA9IG1vbnRSZWR1Y2U7XG5Nb250Z29tZXJ5LnByb3RvdHlwZS5tdWxUbyA9IG1vbnRNdWxUbztcbk1vbnRnb21lcnkucHJvdG90eXBlLnNxclRvID0gbW9udFNxclRvO1xuXG4vLyAocHJvdGVjdGVkKSB0cnVlIGlmZiB0aGlzIGlzIGV2ZW5cblxuZnVuY3Rpb24gYm5wSXNFdmVuKCkge1xuICByZXR1cm4gKCh0aGlzLnQgPiAwKSA/ICh0aGlzWzBdICYgMSkgOiB0aGlzLnMpID09IDA7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHRoaXNeZSwgZSA8IDJeMzIsIGRvaW5nIHNxciBhbmQgbXVsIHdpdGggXCJyXCIgKEhBQyAxNC43OSlcblxuZnVuY3Rpb24gYm5wRXhwKGUsIHopIHtcbiAgaWYgKGUgPiAweGZmZmZmZmZmIHx8IGUgPCAxKSByZXR1cm4gQmlnSW50ZWdlci5PTkU7XG4gIHZhciByID0gbmJpKCksXG4gICAgcjIgPSBuYmkoKSxcbiAgICBnID0gei5jb252ZXJ0KHRoaXMpLFxuICAgIGkgPSBuYml0cyhlKSAtIDE7XG4gIGcuY29weVRvKHIpO1xuICB3aGlsZSAoLS1pID49IDApIHtcbiAgICB6LnNxclRvKHIsIHIyKTtcbiAgICBpZiAoKGUgJiAoMSA8PCBpKSkgPiAwKSB6Lm11bFRvKHIyLCBnLCByKTtcbiAgICBlbHNlIHtcbiAgICAgIHZhciB0ID0gcjtcbiAgICAgIHIgPSByMjtcbiAgICAgIHIyID0gdDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHoucmV2ZXJ0KHIpO1xufVxuXG4vLyAocHVibGljKSB0aGlzXmUgJSBtLCAwIDw9IGUgPCAyXjMyXG5cbmZ1bmN0aW9uIGJuTW9kUG93SW50KGUsIG0pIHtcbiAgdmFyIHo7XG4gIGlmIChlIDwgMjU2IHx8IG0uaXNFdmVuKCkpIHogPSBuZXcgQ2xhc3NpYyhtKTtcbiAgZWxzZSB6ID0gbmV3IE1vbnRnb21lcnkobSk7XG4gIHJldHVybiB0aGlzLmV4cChlLCB6KTtcbn1cblxuLy8gcHJvdGVjdGVkXG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5jb3B5VG8gPSBibnBDb3B5VG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5mcm9tSW50ID0gYm5wRnJvbUludDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmZyb21TdHJpbmcgPSBibnBGcm9tU3RyaW5nO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuY2xhbXAgPSBibnBDbGFtcDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRsU2hpZnRUbyA9IGJucERMU2hpZnRUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRyU2hpZnRUbyA9IGJucERSU2hpZnRUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmxTaGlmdFRvID0gYm5wTFNoaWZ0VG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5yU2hpZnRUbyA9IGJucFJTaGlmdFRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc3ViVG8gPSBibnBTdWJUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLm11bHRpcGx5VG8gPSBibnBNdWx0aXBseVRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc3F1YXJlVG8gPSBibnBTcXVhcmVUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRpdlJlbVRvID0gYm5wRGl2UmVtVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5pbnZEaWdpdCA9IGJucEludkRpZ2l0O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuaXNFdmVuID0gYm5wSXNFdmVuO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZXhwID0gYm5wRXhwO1xuXG4vLyBwdWJsaWNcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRvU3RyaW5nID0gYm5Ub1N0cmluZztcbkJpZ0ludGVnZXIucHJvdG90eXBlLm5lZ2F0ZSA9IGJuTmVnYXRlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYWJzID0gYm5BYnM7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5jb21wYXJlVG8gPSBibkNvbXBhcmVUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmJpdExlbmd0aCA9IGJuQml0TGVuZ3RoO1xuQmlnSW50ZWdlci5wcm90b3R5cGUubW9kID0gYm5Nb2Q7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tb2RQb3dJbnQgPSBibk1vZFBvd0ludDtcblxuLy8gXCJjb25zdGFudHNcIlxuQmlnSW50ZWdlci5aRVJPID0gbmJ2KDApO1xuQmlnSW50ZWdlci5PTkUgPSBuYnYoMSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQmlnSW50ZWdlcjtcblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuLypcbiAqIENvcHlyaWdodCAoYykgMjAwMy0yMDA1ICBUb20gV3UgKHRqd0Bjcy5TdGFuZm9yZC5FRFUpIFxuICogQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcbiAqXG4gKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmdcbiAqIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZVxuICogXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nXG4gKiB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsXG4gKiBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG9cbiAqIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0b1xuICogdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlXG4gKiBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUy1JU1wiIEFORCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBcbiAqIEVYUFJFU1MsIElNUExJRUQgT1IgT1RIRVJXSVNFLCBJTkNMVURJTkcgV0lUSE9VVCBMSU1JVEFUSU9OLCBBTlkgXG4gKiBXQVJSQU5UWSBPRiBNRVJDSEFOVEFCSUxJVFkgT1IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBcbiAqXG4gKiBJTiBOTyBFVkVOVCBTSEFMTCBUT00gV1UgQkUgTElBQkxFIEZPUiBBTlkgU1BFQ0lBTCwgSU5DSURFTlRBTCxcbiAqIElORElSRUNUIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPRiBBTlkgS0lORCwgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUlxuICogUkVTVUxUSU5HIEZST00gTE9TUyBPRiBVU0UsIERBVEEgT1IgUFJPRklUUywgV0hFVEhFUiBPUiBOT1QgQURWSVNFRCBPRlxuICogVEhFIFBPU1NJQklMSVRZIE9GIERBTUFHRSwgQU5EIE9OIEFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBBUklTSU5HIE9VVFxuICogT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1IgUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS5cbiAqXG4gKiBJbiBhZGRpdGlvbiwgdGhlIGZvbGxvd2luZyBjb25kaXRpb24gYXBwbGllczpcbiAqXG4gKiBBbGwgcmVkaXN0cmlidXRpb25zIG11c3QgcmV0YWluIGFuIGludGFjdCBjb3B5IG9mIHRoaXMgY29weXJpZ2h0IG5vdGljZVxuICogYW5kIGRpc2NsYWltZXIuXG4gKi9cblxuXG4vLyBFeHRlbmRlZCBKYXZhU2NyaXB0IEJOIGZ1bmN0aW9ucywgcmVxdWlyZWQgZm9yIFJTQSBwcml2YXRlIG9wcy5cblxuLy8gVmVyc2lvbiAxLjE6IG5ldyBCaWdJbnRlZ2VyKFwiMFwiLCAxMCkgcmV0dXJucyBcInByb3BlclwiIHplcm9cbi8vIFZlcnNpb24gMS4yOiBzcXVhcmUoKSBBUEksIGlzUHJvYmFibGVQcmltZSBmaXhcblxuLy8gKHB1YmxpYylcbmZ1bmN0aW9uIGJuQ2xvbmUoKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuY29weVRvKHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuIHZhbHVlIGFzIGludGVnZXJcblxuZnVuY3Rpb24gYm5JbnRWYWx1ZSgpIHtcbiAgaWYgKHRoaXMucyA8IDApIHtcbiAgICBpZiAodGhpcy50ID09IDEpIHJldHVybiB0aGlzWzBdIC0gdGhpcy5EVjtcbiAgICBlbHNlIGlmICh0aGlzLnQgPT0gMCkgcmV0dXJuIC0xO1xuICB9IGVsc2UgaWYgKHRoaXMudCA9PSAxKSByZXR1cm4gdGhpc1swXTtcbiAgZWxzZSBpZiAodGhpcy50ID09IDApIHJldHVybiAwO1xuICAvLyBhc3N1bWVzIDE2IDwgREIgPCAzMlxuICByZXR1cm4gKCh0aGlzWzFdICYgKCgxIDw8ICgzMiAtIHRoaXMuREIpKSAtIDEpKSA8PCB0aGlzLkRCKSB8IHRoaXNbMF07XG59XG5cbi8vIChwdWJsaWMpIHJldHVybiB2YWx1ZSBhcyBieXRlXG5cbmZ1bmN0aW9uIGJuQnl0ZVZhbHVlKCkge1xuICByZXR1cm4gKHRoaXMudCA9PSAwKSA/IHRoaXMucyA6ICh0aGlzWzBdIDw8IDI0KSA+PiAyNDtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuIHZhbHVlIGFzIHNob3J0IChhc3N1bWVzIERCPj0xNilcblxuZnVuY3Rpb24gYm5TaG9ydFZhbHVlKCkge1xuICByZXR1cm4gKHRoaXMudCA9PSAwKSA/IHRoaXMucyA6ICh0aGlzWzBdIDw8IDE2KSA+PiAxNjtcbn1cblxuLy8gKHByb3RlY3RlZCkgcmV0dXJuIHggcy50LiByXnggPCBEVlxuXG5mdW5jdGlvbiBibnBDaHVua1NpemUocikge1xuICByZXR1cm4gTWF0aC5mbG9vcihNYXRoLkxOMiAqIHRoaXMuREIgLyBNYXRoLmxvZyhyKSk7XG59XG5cbi8vIChwdWJsaWMpIDAgaWYgdGhpcyA9PSAwLCAxIGlmIHRoaXMgPiAwXG5cbmZ1bmN0aW9uIGJuU2lnTnVtKCkge1xuICBpZiAodGhpcy5zIDwgMCkgcmV0dXJuIC0xO1xuICBlbHNlIGlmICh0aGlzLnQgPD0gMCB8fCAodGhpcy50ID09IDEgJiYgdGhpc1swXSA8PSAwKSkgcmV0dXJuIDA7XG4gIGVsc2UgcmV0dXJuIDE7XG59XG5cbi8vIChwcm90ZWN0ZWQpIGNvbnZlcnQgdG8gcmFkaXggc3RyaW5nXG5cbmZ1bmN0aW9uIGJucFRvUmFkaXgoYikge1xuICBpZiAoYiA9PSBudWxsKSBiID0gMTA7XG4gIGlmICh0aGlzLnNpZ251bSgpID09IDAgfHwgYiA8IDIgfHwgYiA+IDM2KSByZXR1cm4gXCIwXCI7XG4gIHZhciBjcyA9IHRoaXMuY2h1bmtTaXplKGIpO1xuICB2YXIgYSA9IE1hdGgucG93KGIsIGNzKTtcbiAgdmFyIGQgPSBuYnYoYSksXG4gICAgeSA9IG5iaSgpLFxuICAgIHogPSBuYmkoKSxcbiAgICByID0gXCJcIjtcbiAgdGhpcy5kaXZSZW1UbyhkLCB5LCB6KTtcbiAgd2hpbGUgKHkuc2lnbnVtKCkgPiAwKSB7XG4gICAgciA9IChhICsgei5pbnRWYWx1ZSgpKS50b1N0cmluZyhiKS5zdWJzdHIoMSkgKyByO1xuICAgIHkuZGl2UmVtVG8oZCwgeSwgeik7XG4gIH1cbiAgcmV0dXJuIHouaW50VmFsdWUoKS50b1N0cmluZyhiKSArIHI7XG59XG5cbi8vIChwcm90ZWN0ZWQpIGNvbnZlcnQgZnJvbSByYWRpeCBzdHJpbmdcblxuZnVuY3Rpb24gYm5wRnJvbVJhZGl4KHMsIGIpIHtcbiAgdGhpcy5mcm9tSW50KDApO1xuICBpZiAoYiA9PSBudWxsKSBiID0gMTA7XG4gIHZhciBjcyA9IHRoaXMuY2h1bmtTaXplKGIpO1xuICB2YXIgZCA9IE1hdGgucG93KGIsIGNzKSxcbiAgICBtaSA9IGZhbHNlLFxuICAgIGogPSAwLFxuICAgIHcgPSAwO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHMubGVuZ3RoOyArK2kpIHtcbiAgICB2YXIgeCA9IGludEF0KHMsIGkpO1xuICAgIGlmICh4IDwgMCkge1xuICAgICAgaWYgKHMuY2hhckF0KGkpID09IFwiLVwiICYmIHRoaXMuc2lnbnVtKCkgPT0gMCkgbWkgPSB0cnVlO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHcgPSBiICogdyArIHg7XG4gICAgaWYgKCsraiA+PSBjcykge1xuICAgICAgdGhpcy5kTXVsdGlwbHkoZCk7XG4gICAgICB0aGlzLmRBZGRPZmZzZXQodywgMCk7XG4gICAgICBqID0gMDtcbiAgICAgIHcgPSAwO1xuICAgIH1cbiAgfVxuICBpZiAoaiA+IDApIHtcbiAgICB0aGlzLmRNdWx0aXBseShNYXRoLnBvdyhiLCBqKSk7XG4gICAgdGhpcy5kQWRkT2Zmc2V0KHcsIDApO1xuICB9XG4gIGlmIChtaSkgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHRoaXMsIHRoaXMpO1xufVxuXG4vLyAocHJvdGVjdGVkKSBhbHRlcm5hdGUgY29uc3RydWN0b3JcblxuZnVuY3Rpb24gYm5wRnJvbU51bWJlcihhLCBiLCBjKSB7XG4gIGlmIChcIm51bWJlclwiID09IHR5cGVvZiBiKSB7XG4gICAgLy8gbmV3IEJpZ0ludGVnZXIoaW50LGludCxSTkcpXG4gICAgaWYgKGEgPCAyKSB0aGlzLmZyb21JbnQoMSk7XG4gICAgZWxzZSB7XG4gICAgICB0aGlzLmZyb21OdW1iZXIoYSwgYyk7XG4gICAgICBpZiAoIXRoaXMudGVzdEJpdChhIC0gMSkpIC8vIGZvcmNlIE1TQiBzZXRcbiAgICAgICAgdGhpcy5iaXR3aXNlVG8oQmlnSW50ZWdlci5PTkUuc2hpZnRMZWZ0KGEgLSAxKSwgb3Bfb3IsIHRoaXMpO1xuICAgICAgaWYgKHRoaXMuaXNFdmVuKCkpIHRoaXMuZEFkZE9mZnNldCgxLCAwKTsgLy8gZm9yY2Ugb2RkXG4gICAgICB3aGlsZSAoIXRoaXMuaXNQcm9iYWJsZVByaW1lKGIpKSB7XG4gICAgICAgIHRoaXMuZEFkZE9mZnNldCgyLCAwKTtcbiAgICAgICAgaWYgKHRoaXMuYml0TGVuZ3RoKCkgPiBhKSB0aGlzLnN1YlRvKEJpZ0ludGVnZXIuT05FLnNoaWZ0TGVmdChhIC0gMSksIHRoaXMpO1xuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBuZXcgQmlnSW50ZWdlcihpbnQsUk5HKVxuICAgIHZhciB4ID0gbmV3IEFycmF5KCksXG4gICAgICB0ID0gYSAmIDc7XG4gICAgeC5sZW5ndGggPSAoYSA+PiAzKSArIDE7XG4gICAgYi5uZXh0Qnl0ZXMoeCk7XG4gICAgaWYgKHQgPiAwKSB4WzBdICY9ICgoMSA8PCB0KSAtIDEpO1xuICAgIGVsc2UgeFswXSA9IDA7XG4gICAgdGhpcy5mcm9tU3RyaW5nKHgsIDI1Nik7XG4gIH1cbn1cblxuLy8gKHB1YmxpYykgY29udmVydCB0byBiaWdlbmRpYW4gYnl0ZSBhcnJheVxuXG5mdW5jdGlvbiBiblRvQnl0ZUFycmF5KCkge1xuICB2YXIgaSA9IHRoaXMudCxcbiAgICByID0gbmV3IEFycmF5KCk7XG4gIHJbMF0gPSB0aGlzLnM7XG4gIHZhciBwID0gdGhpcy5EQiAtIChpICogdGhpcy5EQikgJSA4LFxuICAgIGQsIGsgPSAwO1xuICBpZiAoaS0tID4gMCkge1xuICAgIGlmIChwIDwgdGhpcy5EQiAmJiAoZCA9IHRoaXNbaV0gPj4gcCkgIT0gKHRoaXMucyAmIHRoaXMuRE0pID4+IHApXG4gICAgICByW2srK10gPSBkIHwgKHRoaXMucyA8PCAodGhpcy5EQiAtIHApKTtcbiAgICB3aGlsZSAoaSA+PSAwKSB7XG4gICAgICBpZiAocCA8IDgpIHtcbiAgICAgICAgZCA9ICh0aGlzW2ldICYgKCgxIDw8IHApIC0gMSkpIDw8ICg4IC0gcCk7XG4gICAgICAgIGQgfD0gdGhpc1stLWldID4+IChwICs9IHRoaXMuREIgLSA4KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGQgPSAodGhpc1tpXSA+PiAocCAtPSA4KSkgJiAweGZmO1xuICAgICAgICBpZiAocCA8PSAwKSB7XG4gICAgICAgICAgcCArPSB0aGlzLkRCO1xuICAgICAgICAgIC0taTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy9pZigoZCYweDgwKSAhPSAwKSBkIHw9IC0yNTY7XG4gICAgICAvL2lmKGsgPT0gMCAmJiAodGhpcy5zJjB4ODApICE9IChkJjB4ODApKSArK2s7XG4gICAgICBpZiAoayA+IDAgfHwgZCAhPSB0aGlzLnMpIHJbaysrXSA9IGQ7XG4gICAgfVxuICB9XG4gIHJldHVybiByO1xufVxuXG5mdW5jdGlvbiBibkVxdWFscyhhKSB7XG4gIHJldHVybiAodGhpcy5jb21wYXJlVG8oYSkgPT0gMCk7XG59XG5cbmZ1bmN0aW9uIGJuTWluKGEpIHtcbiAgcmV0dXJuICh0aGlzLmNvbXBhcmVUbyhhKSA8IDApID8gdGhpcyA6IGE7XG59XG5cbmZ1bmN0aW9uIGJuTWF4KGEpIHtcbiAgcmV0dXJuICh0aGlzLmNvbXBhcmVUbyhhKSA+IDApID8gdGhpcyA6IGE7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzIG9wIGEgKGJpdHdpc2UpXG5cbmZ1bmN0aW9uIGJucEJpdHdpc2VUbyhhLCBvcCwgcikge1xuICB2YXIgaSwgZiwgbSA9IE1hdGgubWluKGEudCwgdGhpcy50KTtcbiAgZm9yIChpID0gMDsgaSA8IG07ICsraSkgcltpXSA9IG9wKHRoaXNbaV0sIGFbaV0pO1xuICBpZiAoYS50IDwgdGhpcy50KSB7XG4gICAgZiA9IGEucyAmIHRoaXMuRE07XG4gICAgZm9yIChpID0gbTsgaSA8IHRoaXMudDsgKytpKSByW2ldID0gb3AodGhpc1tpXSwgZik7XG4gICAgci50ID0gdGhpcy50O1xuICB9IGVsc2Uge1xuICAgIGYgPSB0aGlzLnMgJiB0aGlzLkRNO1xuICAgIGZvciAoaSA9IG07IGkgPCBhLnQ7ICsraSkgcltpXSA9IG9wKGYsIGFbaV0pO1xuICAgIHIudCA9IGEudDtcbiAgfVxuICByLnMgPSBvcCh0aGlzLnMsIGEucyk7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyAmIGFcblxuZnVuY3Rpb24gb3BfYW5kKHgsIHkpIHtcbiAgcmV0dXJuIHggJiB5O1xufVxuXG5mdW5jdGlvbiBibkFuZChhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuYml0d2lzZVRvKGEsIG9wX2FuZCwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzIHwgYVxuXG5mdW5jdGlvbiBvcF9vcih4LCB5KSB7XG4gIHJldHVybiB4IHwgeTtcbn1cblxuZnVuY3Rpb24gYm5PcihhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuYml0d2lzZVRvKGEsIG9wX29yLCByKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgXiBhXG5cbmZ1bmN0aW9uIG9wX3hvcih4LCB5KSB7XG4gIHJldHVybiB4IF4geTtcbn1cblxuZnVuY3Rpb24gYm5Yb3IoYSkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLmJpdHdpc2VUbyhhLCBvcF94b3IsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyAmIH5hXG5cbmZ1bmN0aW9uIG9wX2FuZG5vdCh4LCB5KSB7XG4gIHJldHVybiB4ICYgfnk7XG59XG5cbmZ1bmN0aW9uIGJuQW5kTm90KGEpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgdGhpcy5iaXR3aXNlVG8oYSwgb3BfYW5kbm90LCByKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIH50aGlzXG5cbmZ1bmN0aW9uIGJuTm90KCkge1xuICB2YXIgciA9IG5iaSgpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudDsgKytpKSByW2ldID0gdGhpcy5ETSAmIH50aGlzW2ldO1xuICByLnQgPSB0aGlzLnQ7XG4gIHIucyA9IH50aGlzLnM7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzIDw8IG5cblxuZnVuY3Rpb24gYm5TaGlmdExlZnQobikge1xuICB2YXIgciA9IG5iaSgpO1xuICBpZiAobiA8IDApIHRoaXMuclNoaWZ0VG8oLW4sIHIpO1xuICBlbHNlIHRoaXMubFNoaWZ0VG8obiwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzID4+IG5cblxuZnVuY3Rpb24gYm5TaGlmdFJpZ2h0KG4pIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgaWYgKG4gPCAwKSB0aGlzLmxTaGlmdFRvKC1uLCByKTtcbiAgZWxzZSB0aGlzLnJTaGlmdFRvKG4sIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gcmV0dXJuIGluZGV4IG9mIGxvd2VzdCAxLWJpdCBpbiB4LCB4IDwgMl4zMVxuXG5mdW5jdGlvbiBsYml0KHgpIHtcbiAgaWYgKHggPT0gMCkgcmV0dXJuIC0xO1xuICB2YXIgciA9IDA7XG4gIGlmICgoeCAmIDB4ZmZmZikgPT0gMCkge1xuICAgIHggPj49IDE2O1xuICAgIHIgKz0gMTY7XG4gIH1cbiAgaWYgKCh4ICYgMHhmZikgPT0gMCkge1xuICAgIHggPj49IDg7XG4gICAgciArPSA4O1xuICB9XG4gIGlmICgoeCAmIDB4ZikgPT0gMCkge1xuICAgIHggPj49IDQ7XG4gICAgciArPSA0O1xuICB9XG4gIGlmICgoeCAmIDMpID09IDApIHtcbiAgICB4ID4+PSAyO1xuICAgIHIgKz0gMjtcbiAgfVxuICBpZiAoKHggJiAxKSA9PSAwKSsrcjtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHJldHVybnMgaW5kZXggb2YgbG93ZXN0IDEtYml0IChvciAtMSBpZiBub25lKVxuXG5mdW5jdGlvbiBibkdldExvd2VzdFNldEJpdCgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnQ7ICsraSlcbiAgICBpZiAodGhpc1tpXSAhPSAwKSByZXR1cm4gaSAqIHRoaXMuREIgKyBsYml0KHRoaXNbaV0pO1xuICBpZiAodGhpcy5zIDwgMCkgcmV0dXJuIHRoaXMudCAqIHRoaXMuREI7XG4gIHJldHVybiAtMTtcbn1cblxuLy8gcmV0dXJuIG51bWJlciBvZiAxIGJpdHMgaW4geFxuXG5mdW5jdGlvbiBjYml0KHgpIHtcbiAgdmFyIHIgPSAwO1xuICB3aGlsZSAoeCAhPSAwKSB7XG4gICAgeCAmPSB4IC0gMTtcbiAgICArK3I7XG4gIH1cbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHJldHVybiBudW1iZXIgb2Ygc2V0IGJpdHNcblxuZnVuY3Rpb24gYm5CaXRDb3VudCgpIHtcbiAgdmFyIHIgPSAwLFxuICAgIHggPSB0aGlzLnMgJiB0aGlzLkRNO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudDsgKytpKSByICs9IGNiaXQodGhpc1tpXSBeIHgpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdHJ1ZSBpZmYgbnRoIGJpdCBpcyBzZXRcblxuZnVuY3Rpb24gYm5UZXN0Qml0KG4pIHtcbiAgdmFyIGogPSBNYXRoLmZsb29yKG4gLyB0aGlzLkRCKTtcbiAgaWYgKGogPj0gdGhpcy50KSByZXR1cm4gKHRoaXMucyAhPSAwKTtcbiAgcmV0dXJuICgodGhpc1tqXSAmICgxIDw8IChuICUgdGhpcy5EQikpKSAhPSAwKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgdGhpcyBvcCAoMTw8bilcblxuZnVuY3Rpb24gYm5wQ2hhbmdlQml0KG4sIG9wKSB7XG4gIHZhciByID0gQmlnSW50ZWdlci5PTkUuc2hpZnRMZWZ0KG4pO1xuICB0aGlzLmJpdHdpc2VUbyhyLCBvcCwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzIHwgKDE8PG4pXG5cbmZ1bmN0aW9uIGJuU2V0Qml0KG4pIHtcbiAgcmV0dXJuIHRoaXMuY2hhbmdlQml0KG4sIG9wX29yKTtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyAmIH4oMTw8bilcblxuZnVuY3Rpb24gYm5DbGVhckJpdChuKSB7XG4gIHJldHVybiB0aGlzLmNoYW5nZUJpdChuLCBvcF9hbmRub3QpO1xufVxuXG4vLyAocHVibGljKSB0aGlzIF4gKDE8PG4pXG5cbmZ1bmN0aW9uIGJuRmxpcEJpdChuKSB7XG4gIHJldHVybiB0aGlzLmNoYW5nZUJpdChuLCBvcF94b3IpO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpcyArIGFcblxuZnVuY3Rpb24gYm5wQWRkVG8oYSwgcikge1xuICB2YXIgaSA9IDAsXG4gICAgYyA9IDAsXG4gICAgbSA9IE1hdGgubWluKGEudCwgdGhpcy50KTtcbiAgd2hpbGUgKGkgPCBtKSB7XG4gICAgYyArPSB0aGlzW2ldICsgYVtpXTtcbiAgICByW2krK10gPSBjICYgdGhpcy5ETTtcbiAgICBjID4+PSB0aGlzLkRCO1xuICB9XG4gIGlmIChhLnQgPCB0aGlzLnQpIHtcbiAgICBjICs9IGEucztcbiAgICB3aGlsZSAoaSA8IHRoaXMudCkge1xuICAgICAgYyArPSB0aGlzW2ldO1xuICAgICAgcltpKytdID0gYyAmIHRoaXMuRE07XG4gICAgICBjID4+PSB0aGlzLkRCO1xuICAgIH1cbiAgICBjICs9IHRoaXMucztcbiAgfSBlbHNlIHtcbiAgICBjICs9IHRoaXMucztcbiAgICB3aGlsZSAoaSA8IGEudCkge1xuICAgICAgYyArPSBhW2ldO1xuICAgICAgcltpKytdID0gYyAmIHRoaXMuRE07XG4gICAgICBjID4+PSB0aGlzLkRCO1xuICAgIH1cbiAgICBjICs9IGEucztcbiAgfVxuICByLnMgPSAoYyA8IDApID8gLTEgOiAwO1xuICBpZiAoYyA+IDApIHJbaSsrXSA9IGM7XG4gIGVsc2UgaWYgKGMgPCAtMSkgcltpKytdID0gdGhpcy5EViArIGM7XG4gIHIudCA9IGk7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyArIGFcblxuZnVuY3Rpb24gYm5BZGQoYSkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLmFkZFRvKGEsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyAtIGFcblxuZnVuY3Rpb24gYm5TdWJ0cmFjdChhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuc3ViVG8oYSwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzICogYVxuXG5mdW5jdGlvbiBibk11bHRpcGx5KGEpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgdGhpcy5tdWx0aXBseVRvKGEsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdGhpc14yXG5cbmZ1bmN0aW9uIGJuU3F1YXJlKCkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLnNxdWFyZVRvKHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyAvIGFcblxuZnVuY3Rpb24gYm5EaXZpZGUoYSkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLmRpdlJlbVRvKGEsIHIsIG51bGwpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyAlIGFcblxuZnVuY3Rpb24gYm5SZW1haW5kZXIoYSkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLmRpdlJlbVRvKGEsIG51bGwsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgW3RoaXMvYSx0aGlzJWFdXG5cbmZ1bmN0aW9uIGJuRGl2aWRlQW5kUmVtYWluZGVyKGEpIHtcbiAgdmFyIHEgPSBuYmkoKSxcbiAgICByID0gbmJpKCk7XG4gIHRoaXMuZGl2UmVtVG8oYSwgcSwgcik7XG4gIHJldHVybiBuZXcgQXJyYXkocSwgcik7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHRoaXMgKj0gbiwgdGhpcyA+PSAwLCAxIDwgbiA8IERWXG5cbmZ1bmN0aW9uIGJucERNdWx0aXBseShuKSB7XG4gIHRoaXNbdGhpcy50XSA9IHRoaXMuYW0oMCwgbiAtIDEsIHRoaXMsIDAsIDAsIHRoaXMudCk7XG4gICsrdGhpcy50O1xuICB0aGlzLmNsYW1wKCk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHRoaXMgKz0gbiA8PCB3IHdvcmRzLCB0aGlzID49IDBcblxuZnVuY3Rpb24gYm5wREFkZE9mZnNldChuLCB3KSB7XG4gIGlmIChuID09IDApIHJldHVybjtcbiAgd2hpbGUgKHRoaXMudCA8PSB3KSB0aGlzW3RoaXMudCsrXSA9IDA7XG4gIHRoaXNbd10gKz0gbjtcbiAgd2hpbGUgKHRoaXNbd10gPj0gdGhpcy5EVikge1xuICAgIHRoaXNbd10gLT0gdGhpcy5EVjtcbiAgICBpZiAoKyt3ID49IHRoaXMudCkgdGhpc1t0aGlzLnQrK10gPSAwO1xuICAgICsrdGhpc1t3XTtcbiAgfVxufVxuXG4vLyBBIFwibnVsbFwiIHJlZHVjZXJcblxuZnVuY3Rpb24gTnVsbEV4cCgpIHt9XG5cbmZ1bmN0aW9uIG5Ob3AoeCkge1xuICByZXR1cm4geDtcbn1cblxuZnVuY3Rpb24gbk11bFRvKHgsIHksIHIpIHtcbiAgeC5tdWx0aXBseVRvKHksIHIpO1xufVxuXG5mdW5jdGlvbiBuU3FyVG8oeCwgcikge1xuICB4LnNxdWFyZVRvKHIpO1xufVxuXG5OdWxsRXhwLnByb3RvdHlwZS5jb252ZXJ0ID0gbk5vcDtcbk51bGxFeHAucHJvdG90eXBlLnJldmVydCA9IG5Ob3A7XG5OdWxsRXhwLnByb3RvdHlwZS5tdWxUbyA9IG5NdWxUbztcbk51bGxFeHAucHJvdG90eXBlLnNxclRvID0gblNxclRvO1xuXG4vLyAocHVibGljKSB0aGlzXmVcblxuZnVuY3Rpb24gYm5Qb3coZSkge1xuICByZXR1cm4gdGhpcy5leHAoZSwgbmV3IE51bGxFeHAoKSk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSBsb3dlciBuIHdvcmRzIG9mIFwidGhpcyAqIGFcIiwgYS50IDw9IG5cbi8vIFwidGhpc1wiIHNob3VsZCBiZSB0aGUgbGFyZ2VyIG9uZSBpZiBhcHByb3ByaWF0ZS5cblxuZnVuY3Rpb24gYm5wTXVsdGlwbHlMb3dlclRvKGEsIG4sIHIpIHtcbiAgdmFyIGkgPSBNYXRoLm1pbih0aGlzLnQgKyBhLnQsIG4pO1xuICByLnMgPSAwOyAvLyBhc3N1bWVzIGEsdGhpcyA+PSAwXG4gIHIudCA9IGk7XG4gIHdoaWxlIChpID4gMCkgclstLWldID0gMDtcbiAgdmFyIGo7XG4gIGZvciAoaiA9IHIudCAtIHRoaXMudDsgaSA8IGo7ICsraSkgcltpICsgdGhpcy50XSA9IHRoaXMuYW0oMCwgYVtpXSwgciwgaSwgMCwgdGhpcy50KTtcbiAgZm9yIChqID0gTWF0aC5taW4oYS50LCBuKTsgaSA8IGo7ICsraSkgdGhpcy5hbSgwLCBhW2ldLCByLCBpLCAwLCBuIC0gaSk7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IFwidGhpcyAqIGFcIiB3aXRob3V0IGxvd2VyIG4gd29yZHMsIG4gPiAwXG4vLyBcInRoaXNcIiBzaG91bGQgYmUgdGhlIGxhcmdlciBvbmUgaWYgYXBwcm9wcmlhdGUuXG5cbmZ1bmN0aW9uIGJucE11bHRpcGx5VXBwZXJUbyhhLCBuLCByKSB7XG4gIC0tbjtcbiAgdmFyIGkgPSByLnQgPSB0aGlzLnQgKyBhLnQgLSBuO1xuICByLnMgPSAwOyAvLyBhc3N1bWVzIGEsdGhpcyA+PSAwXG4gIHdoaWxlICgtLWkgPj0gMCkgcltpXSA9IDA7XG4gIGZvciAoaSA9IE1hdGgubWF4KG4gLSB0aGlzLnQsIDApOyBpIDwgYS50OyArK2kpXG4gICAgclt0aGlzLnQgKyBpIC0gbl0gPSB0aGlzLmFtKG4gLSBpLCBhW2ldLCByLCAwLCAwLCB0aGlzLnQgKyBpIC0gbik7XG4gIHIuY2xhbXAoKTtcbiAgci5kclNoaWZ0VG8oMSwgcik7XG59XG5cbi8vIEJhcnJldHQgbW9kdWxhciByZWR1Y3Rpb25cblxuZnVuY3Rpb24gQmFycmV0dChtKSB7XG4gIC8vIHNldHVwIEJhcnJldHRcbiAgdGhpcy5yMiA9IG5iaSgpO1xuICB0aGlzLnEzID0gbmJpKCk7XG4gIEJpZ0ludGVnZXIuT05FLmRsU2hpZnRUbygyICogbS50LCB0aGlzLnIyKTtcbiAgdGhpcy5tdSA9IHRoaXMucjIuZGl2aWRlKG0pO1xuICB0aGlzLm0gPSBtO1xufVxuXG5mdW5jdGlvbiBiYXJyZXR0Q29udmVydCh4KSB7XG4gIGlmICh4LnMgPCAwIHx8IHgudCA+IDIgKiB0aGlzLm0udCkgcmV0dXJuIHgubW9kKHRoaXMubSk7XG4gIGVsc2UgaWYgKHguY29tcGFyZVRvKHRoaXMubSkgPCAwKSByZXR1cm4geDtcbiAgZWxzZSB7XG4gICAgdmFyIHIgPSBuYmkoKTtcbiAgICB4LmNvcHlUbyhyKTtcbiAgICB0aGlzLnJlZHVjZShyKTtcbiAgICByZXR1cm4gcjtcbiAgfVxufVxuXG5mdW5jdGlvbiBiYXJyZXR0UmV2ZXJ0KHgpIHtcbiAgcmV0dXJuIHg7XG59XG5cbi8vIHggPSB4IG1vZCBtIChIQUMgMTQuNDIpXG5cbmZ1bmN0aW9uIGJhcnJldHRSZWR1Y2UoeCkge1xuICB4LmRyU2hpZnRUbyh0aGlzLm0udCAtIDEsIHRoaXMucjIpO1xuICBpZiAoeC50ID4gdGhpcy5tLnQgKyAxKSB7XG4gICAgeC50ID0gdGhpcy5tLnQgKyAxO1xuICAgIHguY2xhbXAoKTtcbiAgfVxuICB0aGlzLm11Lm11bHRpcGx5VXBwZXJUbyh0aGlzLnIyLCB0aGlzLm0udCArIDEsIHRoaXMucTMpO1xuICB0aGlzLm0ubXVsdGlwbHlMb3dlclRvKHRoaXMucTMsIHRoaXMubS50ICsgMSwgdGhpcy5yMik7XG4gIHdoaWxlICh4LmNvbXBhcmVUbyh0aGlzLnIyKSA8IDApIHguZEFkZE9mZnNldCgxLCB0aGlzLm0udCArIDEpO1xuICB4LnN1YlRvKHRoaXMucjIsIHgpO1xuICB3aGlsZSAoeC5jb21wYXJlVG8odGhpcy5tKSA+PSAwKSB4LnN1YlRvKHRoaXMubSwgeCk7XG59XG5cbi8vIHIgPSB4XjIgbW9kIG07IHggIT0gclxuXG5mdW5jdGlvbiBiYXJyZXR0U3FyVG8oeCwgcikge1xuICB4LnNxdWFyZVRvKHIpO1xuICB0aGlzLnJlZHVjZShyKTtcbn1cblxuLy8gciA9IHgqeSBtb2QgbTsgeCx5ICE9IHJcblxuZnVuY3Rpb24gYmFycmV0dE11bFRvKHgsIHksIHIpIHtcbiAgeC5tdWx0aXBseVRvKHksIHIpO1xuICB0aGlzLnJlZHVjZShyKTtcbn1cblxuQmFycmV0dC5wcm90b3R5cGUuY29udmVydCA9IGJhcnJldHRDb252ZXJ0O1xuQmFycmV0dC5wcm90b3R5cGUucmV2ZXJ0ID0gYmFycmV0dFJldmVydDtcbkJhcnJldHQucHJvdG90eXBlLnJlZHVjZSA9IGJhcnJldHRSZWR1Y2U7XG5CYXJyZXR0LnByb3RvdHlwZS5tdWxUbyA9IGJhcnJldHRNdWxUbztcbkJhcnJldHQucHJvdG90eXBlLnNxclRvID0gYmFycmV0dFNxclRvO1xuXG4vLyAocHVibGljKSB0aGlzXmUgJSBtIChIQUMgMTQuODUpXG5cbmZ1bmN0aW9uIGJuTW9kUG93KGUsIG0pIHtcbiAgdmFyIGkgPSBlLmJpdExlbmd0aCgpLFxuICAgIGssIHIgPSBuYnYoMSksXG4gICAgejtcbiAgaWYgKGkgPD0gMCkgcmV0dXJuIHI7XG4gIGVsc2UgaWYgKGkgPCAxOCkgayA9IDE7XG4gIGVsc2UgaWYgKGkgPCA0OCkgayA9IDM7XG4gIGVsc2UgaWYgKGkgPCAxNDQpIGsgPSA0O1xuICBlbHNlIGlmIChpIDwgNzY4KSBrID0gNTtcbiAgZWxzZSBrID0gNjtcbiAgaWYgKGkgPCA4KVxuICAgIHogPSBuZXcgQ2xhc3NpYyhtKTtcbiAgZWxzZSBpZiAobS5pc0V2ZW4oKSlcbiAgICB6ID0gbmV3IEJhcnJldHQobSk7XG4gIGVsc2VcbiAgICB6ID0gbmV3IE1vbnRnb21lcnkobSk7XG5cbiAgLy8gcHJlY29tcHV0YXRpb25cbiAgdmFyIGcgPSBuZXcgQXJyYXkoKSxcbiAgICBuID0gMyxcbiAgICBrMSA9IGsgLSAxLFxuICAgIGttID0gKDEgPDwgaykgLSAxO1xuICBnWzFdID0gei5jb252ZXJ0KHRoaXMpO1xuICBpZiAoayA+IDEpIHtcbiAgICB2YXIgZzIgPSBuYmkoKTtcbiAgICB6LnNxclRvKGdbMV0sIGcyKTtcbiAgICB3aGlsZSAobiA8PSBrbSkge1xuICAgICAgZ1tuXSA9IG5iaSgpO1xuICAgICAgei5tdWxUbyhnMiwgZ1tuIC0gMl0sIGdbbl0pO1xuICAgICAgbiArPSAyO1xuICAgIH1cbiAgfVxuXG4gIHZhciBqID0gZS50IC0gMSxcbiAgICB3LCBpczEgPSB0cnVlLFxuICAgIHIyID0gbmJpKCksXG4gICAgdDtcbiAgaSA9IG5iaXRzKGVbal0pIC0gMTtcbiAgd2hpbGUgKGogPj0gMCkge1xuICAgIGlmIChpID49IGsxKSB3ID0gKGVbal0gPj4gKGkgLSBrMSkpICYga207XG4gICAgZWxzZSB7XG4gICAgICB3ID0gKGVbal0gJiAoKDEgPDwgKGkgKyAxKSkgLSAxKSkgPDwgKGsxIC0gaSk7XG4gICAgICBpZiAoaiA+IDApIHcgfD0gZVtqIC0gMV0gPj4gKHRoaXMuREIgKyBpIC0gazEpO1xuICAgIH1cblxuICAgIG4gPSBrO1xuICAgIHdoaWxlICgodyAmIDEpID09IDApIHtcbiAgICAgIHcgPj49IDE7XG4gICAgICAtLW47XG4gICAgfVxuICAgIGlmICgoaSAtPSBuKSA8IDApIHtcbiAgICAgIGkgKz0gdGhpcy5EQjtcbiAgICAgIC0tajtcbiAgICB9XG4gICAgaWYgKGlzMSkgeyAvLyByZXQgPT0gMSwgZG9uJ3QgYm90aGVyIHNxdWFyaW5nIG9yIG11bHRpcGx5aW5nIGl0XG4gICAgICBnW3ddLmNvcHlUbyhyKTtcbiAgICAgIGlzMSA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICB3aGlsZSAobiA+IDEpIHtcbiAgICAgICAgei5zcXJUbyhyLCByMik7XG4gICAgICAgIHouc3FyVG8ocjIsIHIpO1xuICAgICAgICBuIC09IDI7XG4gICAgICB9XG4gICAgICBpZiAobiA+IDApIHouc3FyVG8ociwgcjIpO1xuICAgICAgZWxzZSB7XG4gICAgICAgIHQgPSByO1xuICAgICAgICByID0gcjI7XG4gICAgICAgIHIyID0gdDtcbiAgICAgIH1cbiAgICAgIHoubXVsVG8ocjIsIGdbd10sIHIpO1xuICAgIH1cblxuICAgIHdoaWxlIChqID49IDAgJiYgKGVbal0gJiAoMSA8PCBpKSkgPT0gMCkge1xuICAgICAgei5zcXJUbyhyLCByMik7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSByMjtcbiAgICAgIHIyID0gdDtcbiAgICAgIGlmICgtLWkgPCAwKSB7XG4gICAgICAgIGkgPSB0aGlzLkRCIC0gMTtcbiAgICAgICAgLS1qO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gei5yZXZlcnQocik7XG59XG5cbi8vIChwdWJsaWMpIGdjZCh0aGlzLGEpIChIQUMgMTQuNTQpXG5cbmZ1bmN0aW9uIGJuR0NEKGEpIHtcbiAgdmFyIHggPSAodGhpcy5zIDwgMCkgPyB0aGlzLm5lZ2F0ZSgpIDogdGhpcy5jbG9uZSgpO1xuICB2YXIgeSA9IChhLnMgPCAwKSA/IGEubmVnYXRlKCkgOiBhLmNsb25lKCk7XG4gIGlmICh4LmNvbXBhcmVUbyh5KSA8IDApIHtcbiAgICB2YXIgdCA9IHg7XG4gICAgeCA9IHk7XG4gICAgeSA9IHQ7XG4gIH1cbiAgdmFyIGkgPSB4LmdldExvd2VzdFNldEJpdCgpLFxuICAgIGcgPSB5LmdldExvd2VzdFNldEJpdCgpO1xuICBpZiAoZyA8IDApIHJldHVybiB4O1xuICBpZiAoaSA8IGcpIGcgPSBpO1xuICBpZiAoZyA+IDApIHtcbiAgICB4LnJTaGlmdFRvKGcsIHgpO1xuICAgIHkuclNoaWZ0VG8oZywgeSk7XG4gIH1cbiAgd2hpbGUgKHguc2lnbnVtKCkgPiAwKSB7XG4gICAgaWYgKChpID0geC5nZXRMb3dlc3RTZXRCaXQoKSkgPiAwKSB4LnJTaGlmdFRvKGksIHgpO1xuICAgIGlmICgoaSA9IHkuZ2V0TG93ZXN0U2V0Qml0KCkpID4gMCkgeS5yU2hpZnRUbyhpLCB5KTtcbiAgICBpZiAoeC5jb21wYXJlVG8oeSkgPj0gMCkge1xuICAgICAgeC5zdWJUbyh5LCB4KTtcbiAgICAgIHguclNoaWZ0VG8oMSwgeCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHkuc3ViVG8oeCwgeSk7XG4gICAgICB5LnJTaGlmdFRvKDEsIHkpO1xuICAgIH1cbiAgfVxuICBpZiAoZyA+IDApIHkubFNoaWZ0VG8oZywgeSk7XG4gIHJldHVybiB5O1xufVxuXG4vLyAocHJvdGVjdGVkKSB0aGlzICUgbiwgbiA8IDJeMjZcblxuZnVuY3Rpb24gYm5wTW9kSW50KG4pIHtcbiAgaWYgKG4gPD0gMCkgcmV0dXJuIDA7XG4gIHZhciBkID0gdGhpcy5EViAlIG4sXG4gICAgciA9ICh0aGlzLnMgPCAwKSA/IG4gLSAxIDogMDtcbiAgaWYgKHRoaXMudCA+IDApXG4gICAgaWYgKGQgPT0gMCkgciA9IHRoaXNbMF0gJSBuO1xuICAgIGVsc2UgZm9yICh2YXIgaSA9IHRoaXMudCAtIDE7IGkgPj0gMDsgLS1pKSByID0gKGQgKiByICsgdGhpc1tpXSkgJSBuO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgMS90aGlzICUgbSAoSEFDIDE0LjYxKVxuXG5mdW5jdGlvbiBibk1vZEludmVyc2UobSkge1xuICB2YXIgYWMgPSBtLmlzRXZlbigpO1xuICBpZiAoKHRoaXMuaXNFdmVuKCkgJiYgYWMpIHx8IG0uc2lnbnVtKCkgPT0gMCkgcmV0dXJuIEJpZ0ludGVnZXIuWkVSTztcbiAgdmFyIHUgPSBtLmNsb25lKCksXG4gICAgdiA9IHRoaXMuY2xvbmUoKTtcbiAgdmFyIGEgPSBuYnYoMSksXG4gICAgYiA9IG5idigwKSxcbiAgICBjID0gbmJ2KDApLFxuICAgIGQgPSBuYnYoMSk7XG4gIHdoaWxlICh1LnNpZ251bSgpICE9IDApIHtcbiAgICB3aGlsZSAodS5pc0V2ZW4oKSkge1xuICAgICAgdS5yU2hpZnRUbygxLCB1KTtcbiAgICAgIGlmIChhYykge1xuICAgICAgICBpZiAoIWEuaXNFdmVuKCkgfHwgIWIuaXNFdmVuKCkpIHtcbiAgICAgICAgICBhLmFkZFRvKHRoaXMsIGEpO1xuICAgICAgICAgIGIuc3ViVG8obSwgYik7XG4gICAgICAgIH1cbiAgICAgICAgYS5yU2hpZnRUbygxLCBhKTtcbiAgICAgIH0gZWxzZSBpZiAoIWIuaXNFdmVuKCkpIGIuc3ViVG8obSwgYik7XG4gICAgICBiLnJTaGlmdFRvKDEsIGIpO1xuICAgIH1cbiAgICB3aGlsZSAodi5pc0V2ZW4oKSkge1xuICAgICAgdi5yU2hpZnRUbygxLCB2KTtcbiAgICAgIGlmIChhYykge1xuICAgICAgICBpZiAoIWMuaXNFdmVuKCkgfHwgIWQuaXNFdmVuKCkpIHtcbiAgICAgICAgICBjLmFkZFRvKHRoaXMsIGMpO1xuICAgICAgICAgIGQuc3ViVG8obSwgZCk7XG4gICAgICAgIH1cbiAgICAgICAgYy5yU2hpZnRUbygxLCBjKTtcbiAgICAgIH0gZWxzZSBpZiAoIWQuaXNFdmVuKCkpIGQuc3ViVG8obSwgZCk7XG4gICAgICBkLnJTaGlmdFRvKDEsIGQpO1xuICAgIH1cbiAgICBpZiAodS5jb21wYXJlVG8odikgPj0gMCkge1xuICAgICAgdS5zdWJUbyh2LCB1KTtcbiAgICAgIGlmIChhYykgYS5zdWJUbyhjLCBhKTtcbiAgICAgIGIuc3ViVG8oZCwgYik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHYuc3ViVG8odSwgdik7XG4gICAgICBpZiAoYWMpIGMuc3ViVG8oYSwgYyk7XG4gICAgICBkLnN1YlRvKGIsIGQpO1xuICAgIH1cbiAgfVxuICBpZiAodi5jb21wYXJlVG8oQmlnSW50ZWdlci5PTkUpICE9IDApIHJldHVybiBCaWdJbnRlZ2VyLlpFUk87XG4gIGlmIChkLmNvbXBhcmVUbyhtKSA+PSAwKSByZXR1cm4gZC5zdWJ0cmFjdChtKTtcbiAgaWYgKGQuc2lnbnVtKCkgPCAwKSBkLmFkZFRvKG0sIGQpO1xuICBlbHNlIHJldHVybiBkO1xuICBpZiAoZC5zaWdudW0oKSA8IDApIHJldHVybiBkLmFkZChtKTtcbiAgZWxzZSByZXR1cm4gZDtcbn1cblxudmFyIGxvd3ByaW1lcyA9IFsyLCAzLCA1LCA3LCAxMSwgMTMsIDE3LCAxOSwgMjMsIDI5LCAzMSwgMzcsIDQxLCA0MywgNDcsIDUzLCA1OSwgNjEsIDY3LCA3MSwgNzMsIDc5LCA4MywgODksIDk3LCAxMDEsXG4gICAgMTAzLCAxMDcsIDEwOSwgMTEzLCAxMjcsIDEzMSwgMTM3LCAxMzksIDE0OSwgMTUxLCAxNTcsIDE2MywgMTY3LCAxNzMsIDE3OSwgMTgxLCAxOTEsIDE5MywgMTk3LCAxOTksIDIxMSwgMjIzLCAyMjcsXG4gICAgMjI5LCAyMzMsIDIzOSwgMjQxLCAyNTEsIDI1NywgMjYzLCAyNjksIDI3MSwgMjc3LCAyODEsIDI4MywgMjkzLCAzMDcsIDMxMSwgMzEzLCAzMTcsIDMzMSwgMzM3LCAzNDcsIDM0OSwgMzUzLCAzNTksXG4gICAgMzY3LCAzNzMsIDM3OSwgMzgzLCAzODksIDM5NywgNDAxLCA0MDksIDQxOSwgNDIxLCA0MzEsIDQzMywgNDM5LCA0NDMsIDQ0OSwgNDU3LCA0NjEsIDQ2MywgNDY3LCA0NzksIDQ4NywgNDkxLCA0OTksXG4gICAgNTAzLCA1MDksIDUyMSwgNTIzLCA1NDEsIDU0NywgNTU3LCA1NjMsIDU2OSwgNTcxLCA1NzcsIDU4NywgNTkzLCA1OTksIDYwMSwgNjA3LCA2MTMsIDYxNywgNjE5LCA2MzEsIDY0MSwgNjQzLCA2NDcsXG4gICAgNjUzLCA2NTksIDY2MSwgNjczLCA2NzcsIDY4MywgNjkxLCA3MDEsIDcwOSwgNzE5LCA3MjcsIDczMywgNzM5LCA3NDMsIDc1MSwgNzU3LCA3NjEsIDc2OSwgNzczLCA3ODcsIDc5NywgODA5LCA4MTEsXG4gICAgODIxLCA4MjMsIDgyNywgODI5LCA4MzksIDg1MywgODU3LCA4NTksIDg2MywgODc3LCA4ODEsIDg4MywgODg3LCA5MDcsIDkxMSwgOTE5LCA5MjksIDkzNywgOTQxLCA5NDcsIDk1MywgOTY3LCA5NzEsXG4gICAgOTc3LCA5ODMsIDk5MSwgOTk3XG5dO1xudmFyIGxwbGltID0gKDEgPDwgMjYpIC8gbG93cHJpbWVzW2xvd3ByaW1lcy5sZW5ndGggLSAxXTtcblxuLy8gKHB1YmxpYykgdGVzdCBwcmltYWxpdHkgd2l0aCBjZXJ0YWludHkgPj0gMS0uNV50XG5cbmZ1bmN0aW9uIGJuSXNQcm9iYWJsZVByaW1lKHQpIHtcbiAgdmFyIGksIHggPSB0aGlzLmFicygpO1xuICBpZiAoeC50ID09IDEgJiYgeFswXSA8PSBsb3dwcmltZXNbbG93cHJpbWVzLmxlbmd0aCAtIDFdKSB7XG4gICAgZm9yIChpID0gMDsgaSA8IGxvd3ByaW1lcy5sZW5ndGg7ICsraSlcbiAgICAgIGlmICh4WzBdID09IGxvd3ByaW1lc1tpXSkgcmV0dXJuIHRydWU7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGlmICh4LmlzRXZlbigpKSByZXR1cm4gZmFsc2U7XG4gIGkgPSAxO1xuICB3aGlsZSAoaSA8IGxvd3ByaW1lcy5sZW5ndGgpIHtcbiAgICB2YXIgbSA9IGxvd3ByaW1lc1tpXSxcbiAgICAgIGogPSBpICsgMTtcbiAgICB3aGlsZSAoaiA8IGxvd3ByaW1lcy5sZW5ndGggJiYgbSA8IGxwbGltKSBtICo9IGxvd3ByaW1lc1tqKytdO1xuICAgIG0gPSB4Lm1vZEludChtKTtcbiAgICB3aGlsZSAoaSA8IGopIGlmIChtICUgbG93cHJpbWVzW2krK10gPT0gMCkgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiB4Lm1pbGxlclJhYmluKHQpO1xufVxuXG4vKiBhZGRlZCBieSBSZWN1cml0eSBMYWJzICovXG5cbmZ1bmN0aW9uIG5iaXRzKHgpIHtcbiAgdmFyIG4gPSAxLFxuICAgIHQ7XG4gIGlmICgodCA9IHggPj4+IDE2KSAhPSAwKSB7XG4gICAgeCA9IHQ7XG4gICAgbiArPSAxNjtcbiAgfVxuICBpZiAoKHQgPSB4ID4+IDgpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICBuICs9IDg7XG4gIH1cbiAgaWYgKCh0ID0geCA+PiA0KSAhPSAwKSB7XG4gICAgeCA9IHQ7XG4gICAgbiArPSA0O1xuICB9XG4gIGlmICgodCA9IHggPj4gMikgIT0gMCkge1xuICAgIHggPSB0O1xuICAgIG4gKz0gMjtcbiAgfVxuICBpZiAoKHQgPSB4ID4+IDEpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICBuICs9IDE7XG4gIH1cbiAgcmV0dXJuIG47XG59XG5cbmZ1bmN0aW9uIGJuVG9NUEkoKSB7XG4gIHZhciBiYSA9IHRoaXMudG9CeXRlQXJyYXkoKTtcbiAgdmFyIHNpemUgPSAoYmEubGVuZ3RoIC0gMSkgKiA4ICsgbmJpdHMoYmFbMF0pO1xuICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKHNpemUgJiAweEZGMDApID4+IDgpO1xuICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShzaXplICYgMHhGRik7XG4gIHJlc3VsdCArPSB1dGlsLmJpbjJzdHIoYmEpO1xuICByZXR1cm4gcmVzdWx0O1xufVxuLyogRU5EIG9mIGFkZGl0aW9uICovXG5cbi8vIChwcm90ZWN0ZWQpIHRydWUgaWYgcHJvYmFibHkgcHJpbWUgKEhBQyA0LjI0LCBNaWxsZXItUmFiaW4pXG5mdW5jdGlvbiBibnBNaWxsZXJSYWJpbih0KSB7XG4gIHZhciBuMSA9IHRoaXMuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpO1xuICB2YXIgayA9IG4xLmdldExvd2VzdFNldEJpdCgpO1xuICBpZiAoayA8PSAwKSByZXR1cm4gZmFsc2U7XG4gIHZhciByID0gbjEuc2hpZnRSaWdodChrKTtcbiAgdCA9ICh0ICsgMSkgPj4gMTtcbiAgaWYgKHQgPiBsb3dwcmltZXMubGVuZ3RoKSB0ID0gbG93cHJpbWVzLmxlbmd0aDtcbiAgdmFyIGEgPSBuYmkoKTtcbiAgdmFyIGosIGJhc2VzID0gW107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdDsgKytpKSB7XG4gICAgLy9QaWNrIGJhc2VzIGF0IHJhbmRvbSwgaW5zdGVhZCBvZiBzdGFydGluZyBhdCAyXG4gICAgZm9yICg7Oykge1xuICAgICAgaiA9IGxvd3ByaW1lc1tNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBsb3dwcmltZXMubGVuZ3RoKV07XG4gICAgICBpZiAoYmFzZXMuaW5kZXhPZihqKSA9PSAtMSkgYnJlYWs7XG4gICAgfVxuICAgIGJhc2VzLnB1c2goaik7XG4gICAgYS5mcm9tSW50KGopO1xuICAgIHZhciB5ID0gYS5tb2RQb3cociwgdGhpcyk7XG4gICAgaWYgKHkuY29tcGFyZVRvKEJpZ0ludGVnZXIuT05FKSAhPSAwICYmIHkuY29tcGFyZVRvKG4xKSAhPSAwKSB7XG4gICAgICB2YXIgaiA9IDE7XG4gICAgICB3aGlsZSAoaisrIDwgayAmJiB5LmNvbXBhcmVUbyhuMSkgIT0gMCkge1xuICAgICAgICB5ID0geS5tb2RQb3dJbnQoMiwgdGhpcyk7XG4gICAgICAgIGlmICh5LmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgPT0gMCkgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgaWYgKHkuY29tcGFyZVRvKG4xKSAhPSAwKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIHJldHVybiB0cnVlO1xufVxuXG52YXIgQmlnSW50ZWdlciA9IHJlcXVpcmUoJy4vanNibi5qcycpO1xuXG4vLyBwcm90ZWN0ZWRcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNodW5rU2l6ZSA9IGJucENodW5rU2l6ZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRvUmFkaXggPSBibnBUb1JhZGl4O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZnJvbVJhZGl4ID0gYm5wRnJvbVJhZGl4O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZnJvbU51bWJlciA9IGJucEZyb21OdW1iZXI7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5iaXR3aXNlVG8gPSBibnBCaXR3aXNlVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5jaGFuZ2VCaXQgPSBibnBDaGFuZ2VCaXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5hZGRUbyA9IGJucEFkZFRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZE11bHRpcGx5ID0gYm5wRE11bHRpcGx5O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZEFkZE9mZnNldCA9IGJucERBZGRPZmZzZXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tdWx0aXBseUxvd2VyVG8gPSBibnBNdWx0aXBseUxvd2VyVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tdWx0aXBseVVwcGVyVG8gPSBibnBNdWx0aXBseVVwcGVyVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tb2RJbnQgPSBibnBNb2RJbnQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5taWxsZXJSYWJpbiA9IGJucE1pbGxlclJhYmluO1xuXG4vLyBwdWJsaWNcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNsb25lID0gYm5DbG9uZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmludFZhbHVlID0gYm5JbnRWYWx1ZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmJ5dGVWYWx1ZSA9IGJuQnl0ZVZhbHVlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc2hvcnRWYWx1ZSA9IGJuU2hvcnRWYWx1ZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnNpZ251bSA9IGJuU2lnTnVtO1xuQmlnSW50ZWdlci5wcm90b3R5cGUudG9CeXRlQXJyYXkgPSBiblRvQnl0ZUFycmF5O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZXF1YWxzID0gYm5FcXVhbHM7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5taW4gPSBibk1pbjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1heCA9IGJuTWF4O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYW5kID0gYm5BbmQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5vciA9IGJuT3I7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS54b3IgPSBiblhvcjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmFuZE5vdCA9IGJuQW5kTm90O1xuQmlnSW50ZWdlci5wcm90b3R5cGUubm90ID0gYm5Ob3Q7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5zaGlmdExlZnQgPSBiblNoaWZ0TGVmdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnNoaWZ0UmlnaHQgPSBiblNoaWZ0UmlnaHQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5nZXRMb3dlc3RTZXRCaXQgPSBibkdldExvd2VzdFNldEJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmJpdENvdW50ID0gYm5CaXRDb3VudDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRlc3RCaXQgPSBiblRlc3RCaXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5zZXRCaXQgPSBiblNldEJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNsZWFyQml0ID0gYm5DbGVhckJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmZsaXBCaXQgPSBibkZsaXBCaXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5hZGQgPSBibkFkZDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnN1YnRyYWN0ID0gYm5TdWJ0cmFjdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm11bHRpcGx5ID0gYm5NdWx0aXBseTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRpdmlkZSA9IGJuRGl2aWRlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUucmVtYWluZGVyID0gYm5SZW1haW5kZXI7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5kaXZpZGVBbmRSZW1haW5kZXIgPSBibkRpdmlkZUFuZFJlbWFpbmRlcjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1vZFBvdyA9IGJuTW9kUG93O1xuQmlnSW50ZWdlci5wcm90b3R5cGUubW9kSW52ZXJzZSA9IGJuTW9kSW52ZXJzZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnBvdyA9IGJuUG93O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZ2NkID0gYm5HQ0Q7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5pc1Byb2JhYmxlUHJpbWUgPSBibklzUHJvYmFibGVQcmltZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRvTVBJID0gYm5Ub01QSTtcblxuLy8gSlNCTi1zcGVjaWZpYyBleHRlbnNpb25cbkJpZ0ludGVnZXIucHJvdG90eXBlLnNxdWFyZSA9IGJuU3F1YXJlO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0Fcbi8vXG4vLyBSU0EgaW1wbGVtZW50YXRpb25cblxuLyoqXG4gKiBAcmVxdWlyZXMgY3J5cHRvL3B1YmxpY19rZXkvanNiblxuICogQHJlcXVpcmVzIGNyeXB0by9yYW5kb21cbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIGNyeXB0by9wdWJsaWNfa2V5L3JzYVxuICovXG5cbnZhciBCaWdJbnRlZ2VyID0gcmVxdWlyZSgnLi9qc2JuLmpzJyksXG4gIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyksXG4gIHJhbmRvbSA9IHJlcXVpcmUoJy4uL3JhbmRvbS5qcycpO1xuXG5mdW5jdGlvbiBTZWN1cmVSYW5kb20oKSB7XG4gIGZ1bmN0aW9uIG5leHRCeXRlcyhieXRlQXJyYXkpIHtcbiAgICBmb3IgKHZhciBuID0gMDsgbiA8IGJ5dGVBcnJheS5sZW5ndGg7IG4rKykge1xuICAgICAgYnl0ZUFycmF5W25dID0gcmFuZG9tLmdldFNlY3VyZVJhbmRvbU9jdGV0KCk7XG4gICAgfVxuICB9XG4gIHRoaXMubmV4dEJ5dGVzID0gbmV4dEJ5dGVzO1xufVxuXG5mdW5jdGlvbiBSU0EoKSB7XG4gIC8qKlxuICAgKiBUaGlzIGZ1bmN0aW9uIHVzZXMganNibiBCaWcgTnVtIGxpYnJhcnkgdG8gZGVjcnlwdCBSU0FcbiAgICogQHBhcmFtIG1cbiAgICogICAgICAgICAgICBtZXNzYWdlXG4gICAqIEBwYXJhbSBkXG4gICAqICAgICAgICAgICAgUlNBIGQgYXMgQmlnSW50ZWdlclxuICAgKiBAcGFyYW0gcFxuICAgKiAgICAgICAgICAgIFJTQSBwIGFzIEJpZ0ludGVnZXJcbiAgICogQHBhcmFtIHFcbiAgICogICAgICAgICAgICBSU0EgcSBhcyBCaWdJbnRlZ2VyXG4gICAqIEBwYXJhbSB1XG4gICAqICAgICAgICAgICAgUlNBIHUgYXMgQmlnSW50ZWdlclxuICAgKiBAcmV0dXJuIHtCaWdJbnRlZ2VyfSBUaGUgZGVjcnlwdGVkIHZhbHVlIG9mIHRoZSBtZXNzYWdlXG4gICAqL1xuICBmdW5jdGlvbiBkZWNyeXB0KG0sIGQsIHAsIHEsIHUpIHtcbiAgICB2YXIgeHAgPSBtLm1vZChwKS5tb2RQb3coZC5tb2QocC5zdWJ0cmFjdChCaWdJbnRlZ2VyLk9ORSkpLCBwKTtcbiAgICB2YXIgeHEgPSBtLm1vZChxKS5tb2RQb3coZC5tb2QocS5zdWJ0cmFjdChCaWdJbnRlZ2VyLk9ORSkpLCBxKTtcbiAgICB1dGlsLnByaW50X2RlYnVnKFwicnNhLmpzIGRlY3J5cHRcXG54cG46XCIgKyB1dGlsLmhleHN0cmR1bXAoeHAudG9NUEkoKSkgKyBcIlxcbnhxbjpcIiArIHV0aWwuaGV4c3RyZHVtcCh4cS50b01QSSgpKSk7XG5cbiAgICB2YXIgdCA9IHhxLnN1YnRyYWN0KHhwKTtcbiAgICBpZiAodFswXSA9PSAwKSB7XG4gICAgICB0ID0geHAuc3VidHJhY3QoeHEpO1xuICAgICAgdCA9IHQubXVsdGlwbHkodSkubW9kKHEpO1xuICAgICAgdCA9IHEuc3VidHJhY3QodCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHQgPSB0Lm11bHRpcGx5KHUpLm1vZChxKTtcbiAgICB9XG4gICAgcmV0dXJuIHQubXVsdGlwbHkocCkuYWRkKHhwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBlbmNyeXB0IG1lc3NhZ2VcbiAgICogQHBhcmFtIG0gbWVzc2FnZSBhcyBCaWdJbnRlZ2VyXG4gICAqIEBwYXJhbSBlIHB1YmxpYyBNUEkgcGFydCBhcyBCaWdJbnRlZ2VyXG4gICAqIEBwYXJhbSBuIHB1YmxpYyBNUEkgcGFydCBhcyBCaWdJbnRlZ2VyXG4gICAqIEByZXR1cm4gQmlnSW50ZWdlclxuICAgKi9cbiAgZnVuY3Rpb24gZW5jcnlwdChtLCBlLCBuKSB7XG4gICAgcmV0dXJuIG0ubW9kUG93SW50KGUsIG4pO1xuICB9XG5cbiAgLyogU2lnbiBhbmQgVmVyaWZ5ICovXG4gIGZ1bmN0aW9uIHNpZ24obSwgZCwgbikge1xuICAgIHJldHVybiBtLm1vZFBvdyhkLCBuKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHZlcmlmeSh4LCBlLCBuKSB7XG4gICAgcmV0dXJuIHgubW9kUG93SW50KGUsIG4pO1xuICB9XG5cbiAgLy8gXCJlbXB0eVwiIFJTQSBrZXkgY29uc3RydWN0b3JcblxuICBmdW5jdGlvbiBrZXlPYmplY3QoKSB7XG4gICAgdGhpcy5uID0gbnVsbDtcbiAgICB0aGlzLmUgPSAwO1xuICAgIHRoaXMuZWUgPSBudWxsO1xuICAgIHRoaXMuZCA9IG51bGw7XG4gICAgdGhpcy5wID0gbnVsbDtcbiAgICB0aGlzLnEgPSBudWxsO1xuICAgIHRoaXMuZG1wMSA9IG51bGw7XG4gICAgdGhpcy5kbXExID0gbnVsbDtcbiAgICB0aGlzLnUgPSBudWxsO1xuICB9XG5cbiAgLy8gR2VuZXJhdGUgYSBuZXcgcmFuZG9tIHByaXZhdGUga2V5IEIgYml0cyBsb25nLCB1c2luZyBwdWJsaWMgZXhwdCBFXG5cbiAgZnVuY3Rpb24gZ2VuZXJhdGUoQiwgRSkge1xuICAgIHZhciBrZXkgPSBuZXcga2V5T2JqZWN0KCk7XG4gICAgdmFyIHJuZyA9IG5ldyBTZWN1cmVSYW5kb20oKTtcbiAgICB2YXIgcXMgPSBCID4+IDE7XG4gICAga2V5LmUgPSBwYXJzZUludChFLCAxNik7XG4gICAga2V5LmVlID0gbmV3IEJpZ0ludGVnZXIoRSwgMTYpO1xuICAgIGZvciAoOzspIHtcbiAgICAgIGZvciAoOzspIHtcbiAgICAgICAga2V5LnAgPSBuZXcgQmlnSW50ZWdlcihCIC0gcXMsIDEsIHJuZyk7XG4gICAgICAgIGlmIChrZXkucC5zdWJ0cmFjdChCaWdJbnRlZ2VyLk9ORSkuZ2NkKGtleS5lZSkuY29tcGFyZVRvKEJpZ0ludGVnZXIuT05FKSA9PSAwICYmIGtleS5wLmlzUHJvYmFibGVQcmltZSgxMCkpXG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBmb3IgKDs7KSB7XG4gICAgICAgIGtleS5xID0gbmV3IEJpZ0ludGVnZXIocXMsIDEsIHJuZyk7XG4gICAgICAgIGlmIChrZXkucS5zdWJ0cmFjdChCaWdJbnRlZ2VyLk9ORSkuZ2NkKGtleS5lZSkuY29tcGFyZVRvKEJpZ0ludGVnZXIuT05FKSA9PSAwICYmIGtleS5xLmlzUHJvYmFibGVQcmltZSgxMCkpXG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoa2V5LnAuY29tcGFyZVRvKGtleS5xKSA8PSAwKSB7XG4gICAgICAgIHZhciB0ID0ga2V5LnA7XG4gICAgICAgIGtleS5wID0ga2V5LnE7XG4gICAgICAgIGtleS5xID0gdDtcbiAgICAgIH1cbiAgICAgIHZhciBwMSA9IGtleS5wLnN1YnRyYWN0KEJpZ0ludGVnZXIuT05FKTtcbiAgICAgIHZhciBxMSA9IGtleS5xLnN1YnRyYWN0KEJpZ0ludGVnZXIuT05FKTtcbiAgICAgIHZhciBwaGkgPSBwMS5tdWx0aXBseShxMSk7XG4gICAgICBpZiAocGhpLmdjZChrZXkuZWUpLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgPT0gMCkge1xuICAgICAgICBrZXkubiA9IGtleS5wLm11bHRpcGx5KGtleS5xKTtcbiAgICAgICAga2V5LmQgPSBrZXkuZWUubW9kSW52ZXJzZShwaGkpO1xuICAgICAgICBrZXkuZG1wMSA9IGtleS5kLm1vZChwMSk7XG4gICAgICAgIGtleS5kbXExID0ga2V5LmQubW9kKHExKTtcbiAgICAgICAga2V5LnUgPSBrZXkucC5tb2RJbnZlcnNlKGtleS5xKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBrZXk7XG4gIH1cblxuICB0aGlzLmVuY3J5cHQgPSBlbmNyeXB0O1xuICB0aGlzLmRlY3J5cHQgPSBkZWNyeXB0O1xuICB0aGlzLnZlcmlmeSA9IHZlcmlmeTtcbiAgdGhpcy5zaWduID0gc2lnbjtcbiAgdGhpcy5nZW5lcmF0ZSA9IGdlbmVyYXRlO1xuICB0aGlzLmtleU9iamVjdCA9IGtleU9iamVjdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSU0E7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQSBcblxuLy8gVGhlIEdQRzRCcm93c2VycyBjcnlwdG8gaW50ZXJmYWNlXG5cbi8qKlxuICogQHJlcXVpcmVzIHR5cGUvbXBpXG4gKiBAbW9kdWxlIGNyeXB0by9yYW5kb21cbiAqL1xuXG52YXIgdHlwZV9tcGkgPSByZXF1aXJlKCcuLi90eXBlL21waS5qcycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgLyoqXG4gICAqIFJldHJpZXZlIHNlY3VyZSByYW5kb20gYnl0ZSBzdHJpbmcgb2YgdGhlIHNwZWNpZmllZCBsZW5ndGhcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5ndGggTGVuZ3RoIGluIGJ5dGVzIHRvIGdlbmVyYXRlXG4gICAqIEByZXR1cm4ge1N0cmluZ30gUmFuZG9tIGJ5dGUgc3RyaW5nXG4gICAqL1xuICBnZXRSYW5kb21CeXRlczogZnVuY3Rpb24obGVuZ3RoKSB7XG4gICAgdmFyIHJlc3VsdCA9ICcnO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuZ2V0U2VjdXJlUmFuZG9tT2N0ZXQoKSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybiBhIHBzZXVkby1yYW5kb20gbnVtYmVyIGluIHRoZSBzcGVjaWZpZWQgcmFuZ2VcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBmcm9tIE1pbiBvZiB0aGUgcmFuZG9tIG51bWJlclxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHRvIE1heCBvZiB0aGUgcmFuZG9tIG51bWJlciAobWF4IDMyYml0KVxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBIHBzZXVkbyByYW5kb20gbnVtYmVyXG4gICAqL1xuICBnZXRQc2V1ZG9SYW5kb206IGZ1bmN0aW9uKGZyb20sIHRvKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqICh0byAtIGZyb20pKSArIGZyb207XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybiBhIHNlY3VyZSByYW5kb20gbnVtYmVyIGluIHRoZSBzcGVjaWZpZWQgcmFuZ2VcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBmcm9tIE1pbiBvZiB0aGUgcmFuZG9tIG51bWJlclxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHRvIE1heCBvZiB0aGUgcmFuZG9tIG51bWJlciAobWF4IDMyYml0KVxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBIHNlY3VyZSByYW5kb20gbnVtYmVyXG4gICAqL1xuICBnZXRTZWN1cmVSYW5kb206IGZ1bmN0aW9uKGZyb20sIHRvKSB7XG4gICAgdmFyIGJ1ZiA9IG5ldyBVaW50MzJBcnJheSgxKTtcbiAgICB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhidWYpO1xuICAgIHZhciBiaXRzID0gKCh0byAtIGZyb20pKS50b1N0cmluZygyKS5sZW5ndGg7XG4gICAgd2hpbGUgKChidWZbMF0gJiAoTWF0aC5wb3coMiwgYml0cykgLSAxKSkgPiAodG8gLSBmcm9tKSlcbiAgICAgIHdpbmRvdy5jcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKGJ1Zik7XG4gICAgcmV0dXJuIGZyb20gKyAoTWF0aC5hYnMoYnVmWzBdICYgKE1hdGgucG93KDIsIGJpdHMpIC0gMSkpKTtcbiAgfSxcblxuICBnZXRTZWN1cmVSYW5kb21PY3RldDogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGJ1ZiA9IG5ldyBVaW50MzJBcnJheSgxKTtcbiAgICB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhidWYpO1xuICAgIHJldHVybiBidWZbMF0gJiAweEZGO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBzZWN1cmUgcmFuZG9tIGJpZyBpbnRlZ2VyIG9mIGJpdHMgbGVuZ3RoXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYml0cyBCaXQgbGVuZ3RoIG9mIHRoZSBNUEkgdG8gY3JlYXRlXG4gICAqIEByZXR1cm4ge0JpZ0ludGVnZXJ9IFJlc3VsdGluZyBiaWcgaW50ZWdlclxuICAgKi9cbiAgZ2V0UmFuZG9tQmlnSW50ZWdlcjogZnVuY3Rpb24oYml0cykge1xuICAgIGlmIChiaXRzIDwgMCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHZhciBudW1CeXRlcyA9IE1hdGguZmxvb3IoKGJpdHMgKyA3KSAvIDgpO1xuXG4gICAgdmFyIHJhbmRvbUJpdHMgPSB0aGlzLmdldFJhbmRvbUJ5dGVzKG51bUJ5dGVzKTtcbiAgICBpZiAoYml0cyAlIDggPiAwKSB7XG5cbiAgICAgIHJhbmRvbUJpdHMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuICAgICAgKE1hdGgucG93KDIsIGJpdHMgJSA4KSAtIDEpICZcbiAgICAgICAgcmFuZG9tQml0cy5jaGFyQ29kZUF0KDApKSArXG4gICAgICAgIHJhbmRvbUJpdHMuc3Vic3RyaW5nKDEpO1xuICAgIH1cbiAgICB2YXIgbXBpID0gbmV3IHR5cGVfbXBpKCk7XG4gICAgbXBpLmZyb21CeXRlcyhyYW5kb21CaXRzKTtcbiAgICByZXR1cm4gbXBpLnRvQmlnSW50ZWdlcigpO1xuICB9LFxuXG4gIGdldFJhbmRvbUJpZ0ludGVnZXJJblJhbmdlOiBmdW5jdGlvbihtaW4sIG1heCkge1xuICAgIGlmIChtYXguY29tcGFyZVRvKG1pbikgPD0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciByYW5nZSA9IG1heC5zdWJ0cmFjdChtaW4pO1xuICAgIHZhciByID0gdGhpcy5nZXRSYW5kb21CaWdJbnRlZ2VyKHJhbmdlLmJpdExlbmd0aCgpKTtcbiAgICB3aGlsZSAociA+IHJhbmdlKSB7XG4gICAgICByID0gdGhpcy5nZXRSYW5kb21CaWdJbnRlZ2VyKHJhbmdlLmJpdExlbmd0aCgpKTtcbiAgICB9XG4gICAgcmV0dXJuIG1pbi5hZGQocik7XG4gIH1cblxufTtcbiIsIi8qKlxuICogQHJlcXVpcmVzIGNyeXB0by9oYXNoXG4gKiBAcmVxdWlyZXMgY3J5cHRvL3BrY3MxXG4gKiBAcmVxdWlyZXMgY3J5cHRvL3B1YmxpY19rZXlcbiAqIEBtb2R1bGUgY3J5cHRvL3NpZ25hdHVyZSAqL1xuXG52YXIgcHVibGljS2V5ID0gcmVxdWlyZSgnLi9wdWJsaWNfa2V5JyksXG4gIHBrY3MxID0gcmVxdWlyZSgnLi9wa2NzMS5qcycpLFxuICBoYXNoTW9kdWxlID0gcmVxdWlyZSgnLi9oYXNoJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAvKipcbiAgICogXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBwdWJsaWMgS2V5IGFsZ29yaXRobVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGhhc2hfYWxnbyBIYXNoIGFsZ29yaXRobVxuICAgKiBAcGFyYW0ge0FycmF5PG1vZHVsZTp0eXBlL21waT59IG1zZ19NUElzIFNpZ25hdHVyZSBtdWx0aXByZWNpc2lvbiBpbnRlZ2Vyc1xuICAgKiBAcGFyYW0ge0FycmF5PG1vZHVsZTp0eXBlL21waT59IHB1YmxpY2tleV9NUElzIFB1YmxpYyBrZXkgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgb24gd2hlcmUgdGhlIHNpZ25hdHVyZSB3YXMgY29tcHV0ZWQgb24uXG4gICAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUgaWYgc2lnbmF0dXJlIChzaWdfZGF0YSB3YXMgZXF1YWwgdG8gZGF0YSBvdmVyIGhhc2gpXG4gICAqL1xuICB2ZXJpZnk6IGZ1bmN0aW9uKGFsZ28sIGhhc2hfYWxnbywgbXNnX01QSXMsIHB1YmxpY2tleV9NUElzLCBkYXRhKSB7XG4gICAgdmFyIGNhbGNfaGFzaCA9IGhhc2hNb2R1bGUuZGlnZXN0KGhhc2hfYWxnbywgZGF0YSk7XG5cbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgLy8gUlNBIChFbmNyeXB0IG9yIFNpZ24pIFtIQUNdICBcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgLy8gUlNBIEVuY3J5cHQtT25seSBbSEFDXVxuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyBSU0EgU2lnbi1Pbmx5IFtIQUNdXG4gICAgICAgIHZhciByc2EgPSBuZXcgcHVibGljS2V5LnJzYSgpO1xuICAgICAgICB2YXIgbiA9IHB1YmxpY2tleV9NUElzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgZSA9IHB1YmxpY2tleV9NUElzWzFdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgeCA9IG1zZ19NUElzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgZG9wdWJsaWMgPSByc2EudmVyaWZ5KHgsIGUsIG4pO1xuICAgICAgICB2YXIgaGFzaCA9IHBrY3MxLmVtc2EuZGVjb2RlKGhhc2hfYWxnbywgZG9wdWJsaWMudG9NUEkoKS5zdWJzdHJpbmcoMikpO1xuICAgICAgICBpZiAoaGFzaCA9PSAtMSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUEtDUzEgcGFkZGluZyBpbiBtZXNzYWdlIG9yIGtleSBpbmNvcnJlY3QuIEFib3J0aW5nLi4uJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGhhc2ggPT0gY2FsY19oYXNoO1xuXG4gICAgICBjYXNlIDE2OlxuICAgICAgICAvLyBFbGdhbWFsIChFbmNyeXB0LU9ubHkpIFtFTEdBTUFMXSBbSEFDXVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJzaWduaW5nIHdpdGggRWxnYW1hbCBpcyBub3QgZGVmaW5lZCBpbiB0aGUgT3BlblBHUCBzdGFuZGFyZC5cIik7XG4gICAgICBjYXNlIDE3OlxuICAgICAgICAvLyBEU0EgKERpZ2l0YWwgU2lnbmF0dXJlIEFsZ29yaXRobSkgW0ZJUFMxODZdIFtIQUNdXG4gICAgICAgIHZhciBkc2EgPSBuZXcgcHVibGljS2V5LmRzYSgpO1xuICAgICAgICB2YXIgczEgPSBtc2dfTVBJc1swXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgdmFyIHMyID0gbXNnX01QSXNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBwID0gcHVibGlja2V5X01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBxID0gcHVibGlja2V5X01QSXNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBnID0gcHVibGlja2V5X01QSXNbMl0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciB5ID0gcHVibGlja2V5X01QSXNbM10udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBtID0gZGF0YTtcbiAgICAgICAgdmFyIGRvcHVibGljID0gZHNhLnZlcmlmeShoYXNoX2FsZ28sIHMxLCBzMiwgbSwgcCwgcSwgZywgeSk7XG4gICAgICAgIHJldHVybiBkb3B1YmxpYy5jb21wYXJlVG8oczEpID09IDA7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc2lnbmF0dXJlIGFsZ29yaXRobS4nKTtcbiAgICB9XG5cbiAgfSxcblxuICAvKipcbiAgICogQ3JlYXRlIGEgc2lnbmF0dXJlIG9uIGRhdGEgdXNpbmcgdGhlIHNwZWNpZmllZCBhbGdvcml0aG1cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBoYXNoX2FsZ28gaGFzaCBBbGdvcml0aG0gdG8gdXNlIChTZWUgUkZDNDg4MCA5LjQpXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBBc3ltbWV0cmljIGNpcGhlciBhbGdvcml0aG0gdG8gdXNlIChTZWUgUkZDNDg4MCA5LjEpXG4gICAqIEBwYXJhbSB7QXJyYXk8bW9kdWxlOnR5cGUvbXBpPn0gcHVibGljTVBJcyBQdWJsaWMga2V5IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIFxuICAgKiBvZiB0aGUgcHJpdmF0ZSBrZXkgXG4gICAqIEBwYXJhbSB7QXJyYXk8bW9kdWxlOnR5cGUvbXBpPn0gc2VjcmV0TVBJcyBQcml2YXRlIGtleSBtdWx0aXByZWNpc2lvbiBcbiAgICogaW50ZWdlcnMgd2hpY2ggaXMgdXNlZCB0byBzaWduIHRoZSBkYXRhXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgdG8gYmUgc2lnbmVkXG4gICAqIEByZXR1cm4ge0FycmF5PG1vZHVsZTp0eXBlL21waT59XG4gICAqL1xuICBzaWduOiBmdW5jdGlvbihoYXNoX2FsZ28sIGFsZ28sIGtleUludGVnZXJzLCBkYXRhKSB7XG5cbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgLy8gUlNBIChFbmNyeXB0IG9yIFNpZ24pIFtIQUNdICBcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgLy8gUlNBIEVuY3J5cHQtT25seSBbSEFDXVxuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyBSU0EgU2lnbi1Pbmx5IFtIQUNdXG4gICAgICAgIHZhciByc2EgPSBuZXcgcHVibGljS2V5LnJzYSgpO1xuICAgICAgICB2YXIgZCA9IGtleUludGVnZXJzWzJdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgbiA9IGtleUludGVnZXJzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgbSA9IHBrY3MxLmVtc2EuZW5jb2RlKGhhc2hfYWxnbyxcbiAgICAgICAgICBkYXRhLCBrZXlJbnRlZ2Vyc1swXS5ieXRlTGVuZ3RoKCkpO1xuXG4gICAgICAgIHJldHVybiByc2Euc2lnbihtLCBkLCBuKS50b01QSSgpO1xuXG4gICAgICBjYXNlIDE3OlxuICAgICAgICAvLyBEU0EgKERpZ2l0YWwgU2lnbmF0dXJlIEFsZ29yaXRobSkgW0ZJUFMxODZdIFtIQUNdXG4gICAgICAgIHZhciBkc2EgPSBuZXcgcHVibGljS2V5LmRzYSgpO1xuXG4gICAgICAgIHZhciBwID0ga2V5SW50ZWdlcnNbMF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBxID0ga2V5SW50ZWdlcnNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBnID0ga2V5SW50ZWdlcnNbMl0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciB5ID0ga2V5SW50ZWdlcnNbM10udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciB4ID0ga2V5SW50ZWdlcnNbNF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBtID0gZGF0YTtcbiAgICAgICAgdmFyIHJlc3VsdCA9IGRzYS5zaWduKGhhc2hfYWxnbywgbSwgZywgcCwgcSwgeCk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdFswXS50b1N0cmluZygpICsgcmVzdWx0WzFdLnRvU3RyaW5nKCk7XG4gICAgICBjYXNlIDE2OlxuICAgICAgICAvLyBFbGdhbWFsIChFbmNyeXB0LU9ubHkpIFtFTEdBTUFMXSBbSEFDXVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NpZ25pbmcgd2l0aCBFbGdhbWFsIGlzIG5vdCBkZWZpbmVkIGluIHRoZSBPcGVuUEdQIHN0YW5kYXJkLicpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZSBhbGdvcml0aG0uJyk7XG4gICAgfVxuICB9XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy9cbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy9cbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEByZXF1aXJlcyBlbmNvZGluZy9iYXNlNjRcbiAqIEByZXF1aXJlcyBlbnVtc1xuICogQHJlcXVpcmVzIGNvbmZpZ1xuICogQG1vZHVsZSBlbmNvZGluZy9hcm1vclxuICovXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCcuL2Jhc2U2NC5qcycpLFxuICBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG4gIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpO1xuXG4vKipcbiAqIEZpbmRzIG91dCB3aGljaCBBc2NpaSBBcm1vcmluZyB0eXBlIGlzIHVzZWQuIFRoaXMgaXMgYW4gaW50ZXJuYWwgZnVuY3Rpb25cbiAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IFtTdHJpbmddIGFzY2lpIGFybW9yZWQgdGV4dFxuICogQHJldHVybnMge0ludGVnZXJ9IDAgPSBNRVNTQUdFIFBBUlQgbiBvZiBtXG4gKiAgICAgICAgIDEgPSBNRVNTQUdFIFBBUlQgblxuICogICAgICAgICAyID0gU0lHTkVEIE1FU1NBR0VcbiAqICAgICAgICAgMyA9IFBHUCBNRVNTQUdFXG4gKiAgICAgICAgIDQgPSBQVUJMSUMgS0VZIEJMT0NLXG4gKiAgICAgICAgIDUgPSBQUklWQVRFIEtFWSBCTE9DS1xuICogICAgICAgICBudWxsID0gdW5rbm93blxuICovXG5mdW5jdGlvbiBnZXRUeXBlKHRleHQpIHtcbiAgdmFyIHJlSGVhZGVyID0gL14tLS0tLShbXi1dKyktLS0tLSRcXG4vbTtcblxuICB2YXIgaGVhZGVyID0gdGV4dC5tYXRjaChyZUhlYWRlcik7XG5cbiAgLy8gQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgWC9ZXG4gIC8vIFVzZWQgZm9yIG11bHRpLXBhcnQgbWVzc2FnZXMsIHdoZXJlIHRoZSBhcm1vciBpcyBzcGxpdCBhbW9uZ3N0IFlcbiAgLy8gcGFydHMsIGFuZCB0aGlzIGlzIHRoZSBYdGggcGFydCBvdXQgb2YgWS5cbiAgaWYgKGhlYWRlclsxXS5tYXRjaCgvQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgXFxkK1xcL1xcZCsvKSkge1xuICAgIHJldHVybiBlbnVtcy5hcm1vci5tdWx0aXBhcnRfc2VjdGlvbjtcbiAgfSBlbHNlXG4gIC8vIEJFR0lOIFBHUCBNRVNTQUdFLCBQQVJUIFhcbiAgLy8gVXNlZCBmb3IgbXVsdGktcGFydCBtZXNzYWdlcywgd2hlcmUgdGhpcyBpcyB0aGUgWHRoIHBhcnQgb2YgYW5cbiAgLy8gdW5zcGVjaWZpZWQgbnVtYmVyIG9mIHBhcnRzLiBSZXF1aXJlcyB0aGUgTUVTU0FHRS1JRCBBcm1vclxuICAvLyBIZWFkZXIgdG8gYmUgdXNlZC5cbiAgaWYgKGhlYWRlclsxXS5tYXRjaCgvQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgXFxkKy8pKSB7XG4gICAgcmV0dXJuIGVudW1zLmFybW9yLm11bHRpcGFydF9sYXN0O1xuXG4gIH0gZWxzZVxuICAvLyBCRUdJTiBQR1AgU0lHTkFUVVJFXG4gIC8vIFVzZWQgZm9yIGRldGFjaGVkIHNpZ25hdHVyZXMsIE9wZW5QR1AvTUlNRSBzaWduYXR1cmVzLCBhbmRcbiAgLy8gY2xlYXJ0ZXh0IHNpZ25hdHVyZXMuIE5vdGUgdGhhdCBQR1AgMi54IHVzZXMgQkVHSU4gUEdQIE1FU1NBR0VcbiAgLy8gZm9yIGRldGFjaGVkIHNpZ25hdHVyZXMuXG4gIGlmIChoZWFkZXJbMV0ubWF0Y2goL0JFR0lOIFBHUCBTSUdORUQgTUVTU0FHRS8pKSB7XG4gICAgcmV0dXJuIGVudW1zLmFybW9yLnNpZ25lZDtcblxuICB9IGVsc2VcbiAgLy8gQkVHSU4gUEdQIE1FU1NBR0VcbiAgLy8gVXNlZCBmb3Igc2lnbmVkLCBlbmNyeXB0ZWQsIG9yIGNvbXByZXNzZWQgZmlsZXMuXG4gIGlmIChoZWFkZXJbMV0ubWF0Y2goL0JFR0lOIFBHUCBNRVNTQUdFLykpIHtcbiAgICByZXR1cm4gZW51bXMuYXJtb3IubWVzc2FnZTtcblxuICB9IGVsc2VcbiAgLy8gQkVHSU4gUEdQIFBVQkxJQyBLRVkgQkxPQ0tcbiAgLy8gVXNlZCBmb3IgYXJtb3JpbmcgcHVibGljIGtleXMuXG4gIGlmIChoZWFkZXJbMV0ubWF0Y2goL0JFR0lOIFBHUCBQVUJMSUMgS0VZIEJMT0NLLykpIHtcbiAgICByZXR1cm4gZW51bXMuYXJtb3IucHVibGljX2tleTtcblxuICB9IGVsc2VcbiAgLy8gQkVHSU4gUEdQIFBSSVZBVEUgS0VZIEJMT0NLXG4gIC8vIFVzZWQgZm9yIGFybW9yaW5nIHByaXZhdGUga2V5cy5cbiAgaWYgKGhlYWRlclsxXS5tYXRjaCgvQkVHSU4gUEdQIFBSSVZBVEUgS0VZIEJMT0NLLykpIHtcbiAgICByZXR1cm4gZW51bXMuYXJtb3IucHJpdmF0ZV9rZXk7XG4gIH1cbn1cblxuLyoqXG4gKiBBZGQgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiB0byB0aGUgYXJtb3IgdmVyc2lvbiBvZiBhbiBPcGVuUEdQIGJpbmFyeVxuICogcGFja2V0IGJsb2NrLlxuICogQGF1dGhvciAgQWxleFxuICogQHZlcnNpb24gMjAxMS0xMi0xNlxuICogQHJldHVybnMge1N0cmluZ30gVGhlIGhlYWRlciBpbmZvcm1hdGlvblxuICovXG5mdW5jdGlvbiBhZGRoZWFkZXIoKSB7XG4gIHZhciByZXN1bHQgPSBcIlwiO1xuICBpZiAoY29uZmlnLnNob3dfdmVyc2lvbikge1xuICAgIHJlc3VsdCArPSBcIlZlcnNpb246IFwiICsgY29uZmlnLnZlcnNpb25zdHJpbmcgKyAnXFxyXFxuJztcbiAgfVxuICBpZiAoY29uZmlnLnNob3dfY29tbWVudCkge1xuICAgIHJlc3VsdCArPSBcIkNvbW1lbnQ6IFwiICsgY29uZmlnLmNvbW1lbnRzdHJpbmcgKyAnXFxyXFxuJztcbiAgfVxuICByZXN1bHQgKz0gJ1xcclxcbic7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cblxuXG4vKipcbiAqIENhbGN1bGF0ZXMgYSBjaGVja3N1bSBvdmVyIHRoZSBnaXZlbiBkYXRhIGFuZCByZXR1cm5zIGl0IGJhc2U2NCBlbmNvZGVkXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEByZXR1cm4ge1N0cmluZ30gQmFzZTY0IGVuY29kZWQgY2hlY2tzdW1cbiAqL1xuZnVuY3Rpb24gZ2V0Q2hlY2tTdW0oZGF0YSkge1xuICB2YXIgYyA9IGNyZWF0ZWNyYzI0KGRhdGEpO1xuICB2YXIgc3RyID0gXCJcIiArIFN0cmluZy5mcm9tQ2hhckNvZGUoYyA+PiAxNikgK1xuICAgIFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgPj4gOCkgJiAweEZGKSArXG4gICAgU3RyaW5nLmZyb21DaGFyQ29kZShjICYgMHhGRik7XG4gIHJldHVybiBiYXNlNjQuZW5jb2RlKHN0cik7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgY2hlY2tzdW0gb3ZlciB0aGUgZ2l2ZW4gZGF0YSBhbmQgY29tcGFyZXMgaXQgd2l0aCB0aGVcbiAqIGdpdmVuIGJhc2U2NCBlbmNvZGVkIGNoZWNrc3VtXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEBwYXJhbSB7U3RyaW5nfSBjaGVja3N1bSBCYXNlNjQgZW5jb2RlZCBjaGVja3N1bVxuICogQHJldHVybiB7Qm9vbGVhbn0gVHJ1ZSBpZiB0aGUgZ2l2ZW4gY2hlY2tzdW0gaXMgY29ycmVjdDsgb3RoZXJ3aXNlIGZhbHNlXG4gKi9cbmZ1bmN0aW9uIHZlcmlmeUNoZWNrU3VtKGRhdGEsIGNoZWNrc3VtKSB7XG4gIHZhciBjID0gZ2V0Q2hlY2tTdW0oZGF0YSk7XG4gIHZhciBkID0gY2hlY2tzdW07XG4gIHJldHVybiBjWzBdID09IGRbMF0gJiYgY1sxXSA9PSBkWzFdICYmIGNbMl0gPT0gZFsyXTtcbn1cbi8qKlxuICogSW50ZXJuYWwgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGEgQ1JDLTI0IGNoZWNrc3VtIG92ZXIgYSBnaXZlbiBzdHJpbmcgKGRhdGEpXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEByZXR1cm4ge0ludGVnZXJ9IFRoZSBDUkMtMjQgY2hlY2tzdW0gYXMgbnVtYmVyXG4gKi9cbnZhciBjcmNfdGFibGUgPSBbXG4gICAgMHgwMDAwMDAwMCwgMHgwMDg2NGNmYiwgMHgwMThhZDUwZCwgMHgwMTBjOTlmNiwgMHgwMzkzZTZlMSwgMHgwMzE1YWExYSwgMHgwMjE5MzNlYywgMHgwMjlmN2YxNywgMHgwN2ExODEzOSxcbiAgICAweDA3MjdjZGMyLCAweDA2MmI1NDM0LCAweDA2YWQxOGNmLCAweDA0MzI2N2Q4LCAweDA0YjQyYjIzLCAweDA1YjhiMmQ1LCAweDA1M2VmZTJlLCAweDBmYzU0ZTg5LCAweDBmNDMwMjcyLFxuICAgIDB4MGU0ZjliODQsIDB4MGVjOWQ3N2YsIDB4MGM1NmE4NjgsIDB4MGNkMGU0OTMsIDB4MGRkYzdkNjUsIDB4MGQ1YTMxOWUsIDB4MDg2NGNmYjAsIDB4MDhlMjgzNGIsIDB4MDllZTFhYmQsXG4gICAgMHgwOTY4NTY0NiwgMHgwYmY3Mjk1MSwgMHgwYjcxNjVhYSwgMHgwYTdkZmM1YywgMHgwYWZiYjBhNywgMHgxZjBjZDFlOSwgMHgxZjhhOWQxMiwgMHgxZTg2MDRlNCwgMHgxZTAwNDgxZixcbiAgICAweDFjOWYzNzA4LCAweDFjMTk3YmYzLCAweDFkMTVlMjA1LCAweDFkOTNhZWZlLCAweDE4YWQ1MGQwLCAweDE4MmIxYzJiLCAweDE5Mjc4NWRkLCAweDE5YTFjOTI2LCAweDFiM2ViNjMxLFxuICAgIDB4MWJiOGZhY2EsIDB4MWFiNDYzM2MsIDB4MWEzMjJmYzcsIDB4MTBjOTlmNjAsIDB4MTA0ZmQzOWIsIDB4MTE0MzRhNmQsIDB4MTFjNTA2OTYsIDB4MTM1YTc5ODEsIDB4MTNkYzM1N2EsXG4gICAgMHgxMmQwYWM4YywgMHgxMjU2ZTA3NywgMHgxNzY4MWU1OSwgMHgxN2VlNTJhMiwgMHgxNmUyY2I1NCwgMHgxNjY0ODdhZiwgMHgxNGZiZjhiOCwgMHgxNDdkYjQ0MywgMHgxNTcxMmRiNSxcbiAgICAweDE1Zjc2MTRlLCAweDNlMTlhM2QyLCAweDNlOWZlZjI5LCAweDNmOTM3NmRmLCAweDNmMTUzYTI0LCAweDNkOGE0NTMzLCAweDNkMGMwOWM4LCAweDNjMDA5MDNlLCAweDNjODZkY2M1LFxuICAgIDB4MzliODIyZWIsIDB4MzkzZTZlMTAsIDB4MzgzMmY3ZTYsIDB4MzhiNGJiMWQsIDB4M2EyYmM0MGEsIDB4M2FhZDg4ZjEsIDB4M2JhMTExMDcsIDB4M2IyNzVkZmMsIDB4MzFkY2VkNWIsXG4gICAgMHgzMTVhYTFhMCxcbiAgICAweDMwNTYzODU2LCAweDMwZDA3NGFkLCAweDMyNGYwYmJhLCAweDMyYzk0NzQxLCAweDMzYzVkZWI3LCAweDMzNDM5MjRjLCAweDM2N2Q2YzYyLCAweDM2ZmIyMDk5LCAweDM3ZjdiOTZmLFxuICAgIDB4Mzc3MWY1OTQsIDB4MzVlZThhODMsIDB4MzU2OGM2NzgsIDB4MzQ2NDVmOGUsIDB4MzRlMjEzNzUsIDB4MjExNTcyM2IsIDB4MjE5MzNlYzAsIDB4MjA5ZmE3MzYsIDB4MjAxOWViY2QsXG4gICAgMHgyMjg2OTRkYSwgMHgyMjAwZDgyMSwgMHgyMzBjNDFkNywgMHgyMzhhMGQyYywgMHgyNmI0ZjMwMiwgMHgyNjMyYmZmOSwgMHgyNzNlMjYwZiwgMHgyN2I4NmFmNCwgMHgyNTI3MTVlMyxcbiAgICAweDI1YTE1OTE4LCAweDI0YWRjMGVlLCAweDI0MmI4YzE1LCAweDJlZDAzY2IyLCAweDJlNTY3MDQ5LCAweDJmNWFlOWJmLCAweDJmZGNhNTQ0LCAweDJkNDNkYTUzLCAweDJkYzU5NmE4LFxuICAgIDB4MmNjOTBmNWUsIDB4MmM0ZjQzYTUsIDB4Mjk3MWJkOGIsIDB4MjlmN2YxNzAsIDB4MjhmYjY4ODYsIDB4Mjg3ZDI0N2QsIDB4MmFlMjViNmEsIDB4MmE2NDE3OTEsIDB4MmI2ODhlNjcsXG4gICAgMHgyYmVlYzI5YywgMHg3YzMzNDdhNCwgMHg3Y2I1MGI1ZiwgMHg3ZGI5OTJhOSwgMHg3ZDNmZGU1MiwgMHg3ZmEwYTE0NSwgMHg3ZjI2ZWRiZSwgMHg3ZTJhNzQ0OCwgMHg3ZWFjMzhiMyxcbiAgICAweDdiOTJjNjlkLCAweDdiMTQ4YTY2LCAweDdhMTgxMzkwLCAweDdhOWU1ZjZiLCAweDc4MDEyMDdjLCAweDc4ODc2Yzg3LCAweDc5OGJmNTcxLCAweDc5MGRiOThhLCAweDczZjYwOTJkLFxuICAgIDB4NzM3MDQ1ZDYsIDB4NzI3Y2RjMjAsIDB4NzJmYTkwZGIsIDB4NzA2NWVmY2MsIDB4NzBlM2EzMzcsIDB4NzFlZjNhYzEsIDB4NzE2OTc2M2EsIDB4NzQ1Nzg4MTQsIDB4NzRkMWM0ZWYsXG4gICAgMHg3NWRkNWQxOSwgMHg3NTViMTFlMiwgMHg3N2M0NmVmNSwgMHg3NzQyMjIwZSwgMHg3NjRlYmJmOCwgMHg3NmM4ZjcwMywgMHg2MzNmOTY0ZCwgMHg2M2I5ZGFiNiwgMHg2MmI1NDM0MCxcbiAgICAweDYyMzMwZmJiLFxuICAgIDB4NjBhYzcwYWMsIDB4NjAyYTNjNTcsIDB4NjEyNmE1YTEsIDB4NjFhMGU5NWEsIDB4NjQ5ZTE3NzQsIDB4NjQxODViOGYsIDB4NjUxNGMyNzksIDB4NjU5MjhlODIsIDB4NjcwZGYxOTUsXG4gICAgMHg2NzhiYmQ2ZSwgMHg2Njg3MjQ5OCwgMHg2NjAxNjg2MywgMHg2Y2ZhZDhjNCwgMHg2YzdjOTQzZiwgMHg2ZDcwMGRjOSwgMHg2ZGY2NDEzMiwgMHg2ZjY5M2UyNSwgMHg2ZmVmNzJkZSxcbiAgICAweDZlZTNlYjI4LCAweDZlNjVhN2QzLCAweDZiNWI1OWZkLCAweDZiZGQxNTA2LCAweDZhZDE4Y2YwLCAweDZhNTdjMDBiLCAweDY4YzhiZjFjLCAweDY4NGVmM2U3LCAweDY5NDI2YTExLFxuICAgIDB4NjljNDI2ZWEsIDB4NDIyYWU0NzYsIDB4NDJhY2E4OGQsIDB4NDNhMDMxN2IsIDB4NDMyNjdkODAsIDB4NDFiOTAyOTcsIDB4NDEzZjRlNmMsIDB4NDAzM2Q3OWEsIDB4NDBiNTliNjEsXG4gICAgMHg0NThiNjU0ZiwgMHg0NTBkMjliNCwgMHg0NDAxYjA0MiwgMHg0NDg3ZmNiOSwgMHg0NjE4ODNhZSwgMHg0NjllY2Y1NSwgMHg0NzkyNTZhMywgMHg0NzE0MWE1OCwgMHg0ZGVmYWFmZixcbiAgICAweDRkNjllNjA0LCAweDRjNjU3ZmYyLCAweDRjZTMzMzA5LCAweDRlN2M0YzFlLCAweDRlZmEwMGU1LCAweDRmZjY5OTEzLCAweDRmNzBkNWU4LCAweDRhNGUyYmM2LCAweDRhYzg2NzNkLFxuICAgIDB4NGJjNGZlY2IsIDB4NGI0MmIyMzAsIDB4NDlkZGNkMjcsIDB4NDk1YjgxZGMsIDB4NDg1NzE4MmEsIDB4NDhkMTU0ZDEsIDB4NWQyNjM1OWYsIDB4NWRhMDc5NjQsIDB4NWNhY2UwOTIsXG4gICAgMHg1YzJhYWM2OSwgMHg1ZWI1ZDM3ZSwgMHg1ZTMzOWY4NSwgMHg1ZjNmMDY3MywgMHg1ZmI5NGE4OCwgMHg1YTg3YjRhNiwgMHg1YTAxZjg1ZCwgMHg1YjBkNjFhYiwgMHg1YjhiMmQ1MCxcbiAgICAweDU5MTQ1MjQ3LCAweDU5OTIxZWJjLCAweDU4OWU4NzRhLCAweDU4MThjYmIxLCAweDUyZTM3YjE2LCAweDUyNjUzN2VkLCAweDUzNjlhZTFiLCAweDUzZWZlMmUwLCAweDUxNzA5ZGY3LFxuICAgIDB4NTFmNmQxMGMsXG4gICAgMHg1MGZhNDhmYSwgMHg1MDdjMDQwMSwgMHg1NTQyZmEyZiwgMHg1NWM0YjZkNCwgMHg1NGM4MmYyMiwgMHg1NDRlNjNkOSwgMHg1NmQxMWNjZSwgMHg1NjU3NTAzNSwgMHg1NzViYzljMyxcbiAgICAweDU3ZGQ4NTM4XG5dO1xuXG5mdW5jdGlvbiBjcmVhdGVjcmMyNChpbnB1dCkge1xuICB2YXIgY3JjID0gMHhCNzA0Q0U7XG4gIHZhciBpbmRleCA9IDA7XG5cbiAgd2hpbGUgKChpbnB1dC5sZW5ndGggLSBpbmRleCkgPiAxNikge1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMSkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMikpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMykpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNCkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNSkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNikpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNykpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgOCkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgOSkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMTApKSAmIDB4ZmZdO1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCArIDExKSkgJiAweGZmXTtcbiAgICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXggKyAxMikpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMTMpKSAmIDB4ZmZdO1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCArIDE0KSkgJiAweGZmXTtcbiAgICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXggKyAxNSkpICYgMHhmZl07XG4gICAgaW5kZXggKz0gMTY7XG4gIH1cblxuICBmb3IgKHZhciBqID0gaW5kZXg7IGogPCBpbnB1dC5sZW5ndGg7IGorKykge1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCsrKSkgJiAweGZmXTtcbiAgfVxuICByZXR1cm4gY3JjICYgMHhmZmZmZmY7XG59XG5cbi8qKlxuICogU3BsaXRzIGEgbWVzc2FnZSBpbnRvIHR3byBwYXJ0cywgdGhlIGhlYWRlcnMgYW5kIHRoZSBib2R5LiBUaGlzIGlzIGFuIGludGVybmFsIGZ1bmN0aW9uXG4gKiBAcGFyYW0ge1N0cmluZ30gdGV4dCBPcGVuUEdQIGFybW9yZWQgbWVzc2FnZSBwYXJ0XG4gKiBAcmV0dXJucyB7KEJvb2xlYW58T2JqZWN0KX0gRWl0aGVyIGZhbHNlIGluIGNhc2Ugb2YgYW4gZXJyb3JcbiAqIG9yIGFuIG9iamVjdCB3aXRoIGF0dHJpYnV0ZSBcImhlYWRlcnNcIiBjb250YWluaW5nIHRoZSBoZWFkZXJzIGFuZFxuICogYW5kIGFuIGF0dHJpYnV0ZSBcImJvZHlcIiBjb250YWluaW5nIHRoZSBib2R5LlxuICovXG5mdW5jdGlvbiBzcGxpdEhlYWRlcnModGV4dCkge1xuICB2YXIgcmVFbXB0eUxpbmUgPSAvXltcXHQgXSpcXG4vbTtcbiAgdmFyIGhlYWRlcnMgPSBcIlwiO1xuICB2YXIgYm9keSA9IHRleHQ7XG5cbiAgdmFyIG1hdGNoUmVzdWx0ID0gcmVFbXB0eUxpbmUuZXhlYyh0ZXh0KTtcblxuICBpZiAobWF0Y2hSZXN1bHQgIT0gbnVsbCkge1xuICAgIGhlYWRlcnMgPSB0ZXh0LnNsaWNlKDAsIG1hdGNoUmVzdWx0LmluZGV4KTtcbiAgICBib2R5ID0gdGV4dC5zbGljZShtYXRjaFJlc3VsdC5pbmRleCArIG1hdGNoUmVzdWx0WzBdLmxlbmd0aCk7XG4gIH1cblxuICByZXR1cm4geyBoZWFkZXJzOiBoZWFkZXJzLCBib2R5OiBib2R5IH07XG59XG5cbi8qKlxuICogU3BsaXRzIGEgbWVzc2FnZSBpbnRvIHR3byBwYXJ0cywgdGhlIGJvZHkgYW5kIHRoZSBjaGVja3N1bS4gVGhpcyBpcyBhbiBpbnRlcm5hbCBmdW5jdGlvblxuICogQHBhcmFtIHtTdHJpbmd9IHRleHQgT3BlblBHUCBhcm1vcmVkIG1lc3NhZ2UgcGFydFxuICogQHJldHVybnMgeyhCb29sZWFufE9iamVjdCl9IEVpdGhlciBmYWxzZSBpbiBjYXNlIG9mIGFuIGVycm9yXG4gKiBvciBhbiBvYmplY3Qgd2l0aCBhdHRyaWJ1dGUgXCJib2R5XCIgY29udGFpbmluZyB0aGUgYm9keVxuICogYW5kIGFuIGF0dHJpYnV0ZSBcImNoZWNrc3VtXCIgY29udGFpbmluZyB0aGUgY2hlY2tzdW0uXG4gKi9cbmZ1bmN0aW9uIHNwbGl0Q2hlY2tzdW0odGV4dCkge1xuICB2YXIgcmVDaGVja3N1bVN0YXJ0ID0gL149L207XG4gIHZhciBib2R5ID0gdGV4dDtcbiAgdmFyIGNoZWNrc3VtID0gXCJcIjtcblxuICB2YXIgbWF0Y2hSZXN1bHQgPSByZUNoZWNrc3VtU3RhcnQuZXhlYyh0ZXh0KTtcblxuICBpZiAobWF0Y2hSZXN1bHQgIT0gbnVsbCkge1xuICAgIGJvZHkgPSB0ZXh0LnNsaWNlKDAsIG1hdGNoUmVzdWx0LmluZGV4KTtcbiAgICBjaGVja3N1bSA9IHRleHQuc2xpY2UobWF0Y2hSZXN1bHQuaW5kZXggKyAxKTtcbiAgfVxuXG4gIHJldHVybiB7IGJvZHk6IGJvZHksIGNoZWNrc3VtOiBjaGVja3N1bSB9O1xufVxuXG4vKipcbiAqIERlQXJtb3IgYW4gT3BlblBHUCBhcm1vcmVkIG1lc3NhZ2U7IHZlcmlmeSB0aGUgY2hlY2tzdW0gYW5kIHJldHVyblxuICogdGhlIGVuY29kZWQgYnl0ZXNcbiAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IE9wZW5QR1AgYXJtb3JlZCBtZXNzYWdlXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3Qgd2l0aCBhdHRyaWJ1dGUgXCJ0ZXh0XCIgY29udGFpbmluZyB0aGUgbWVzc2FnZSB0ZXh0LFxuICogYW4gYXR0cmlidXRlIFwiZGF0YVwiIGNvbnRhaW5pbmcgdGhlIGJ5dGVzIGFuZCBcInR5cGVcIiBmb3IgdGhlIEFTQ0lJIGFybW9yIHR5cGVcbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gZGVhcm1vcih0ZXh0KSB7XG4gIHZhciByZVNwbGl0ID0gL14tLS0tLVteLV0rLS0tLS0kXFxuL207XG5cbiAgdGV4dCA9IHRleHQucmVwbGFjZSgvXFxyL2csICcnKTtcblxuICB2YXIgdHlwZSA9IGdldFR5cGUodGV4dCk7XG4gIGlmICghdHlwZSkge1xuICAgIHRocm93IG5ldyBFcnJvcignVW5rbm93IEFTQ0lJIGFybW9yIHR5cGUnKTtcbiAgfSBcblxuICB2YXIgc3BsaXR0ZXh0ID0gdGV4dC5zcGxpdChyZVNwbGl0KTtcblxuICAvLyBJRSBoYXMgYSBidWcgaW4gc3BsaXQgd2l0aCBhIHJlLiBJZiB0aGUgcGF0dGVybiBtYXRjaGVzIHRoZSBiZWdpbm5pbmcgb2YgdGhlXG4gIC8vIHN0cmluZyBpdCBkb2Vzbid0IGNyZWF0ZSBhbiBlbXB0eSBhcnJheSBlbGVtZW50IDAuIFNvIHdlIG5lZWQgdG8gZGV0ZWN0IHRoaXNcbiAgLy8gc28gd2Uga25vdyB0aGUgaW5kZXggb2YgdGhlIGRhdGEgd2UgYXJlIGludGVyZXN0ZWQgaW4uXG4gIHZhciBpbmRleEJhc2UgPSAxO1xuXG4gIHZhciByZXN1bHQsIGNoZWNrc3VtO1xuXG4gIGlmICh0ZXh0LnNlYXJjaChyZVNwbGl0KSAhPSBzcGxpdHRleHRbMF0ubGVuZ3RoKSB7XG4gICAgaW5kZXhCYXNlID0gMDtcbiAgfVxuXG4gIGlmICh0eXBlICE9IDIpIHtcbiAgICB2YXIgbXNnID0gc3BsaXRIZWFkZXJzKHNwbGl0dGV4dFtpbmRleEJhc2VdKTtcbiAgICB2YXIgbXNnX3N1bSA9IHNwbGl0Q2hlY2tzdW0obXNnLmJvZHkpO1xuXG4gICAgcmVzdWx0ID0ge1xuICAgICAgZGF0YTogYmFzZTY0LmRlY29kZShtc2dfc3VtLmJvZHkpLFxuICAgICAgdHlwZTogdHlwZVxuICAgIH07XG5cbiAgICBjaGVja3N1bSA9IG1zZ19zdW0uY2hlY2tzdW07XG4gIH0gZWxzZSB7XG4gICAgLy8gUmV2ZXJzZSBkYXNoLWVzY2FwaW5nIGZvciBtc2cgYW5kIHJlbW92ZSB0cmFpbGluZyB3aGl0ZXNwYWNlIGF0IGVuZCBvZiBsaW5lXG4gICAgdmFyIG1zZyA9IHNwbGl0SGVhZGVycyhzcGxpdHRleHRbaW5kZXhCYXNlXS5yZXBsYWNlKC9eLSAvbWcsICcnKS5yZXBsYWNlKC9bXFx0IF0rXFxuL2csIFwiXFxuXCIpKTtcbiAgICB2YXIgc2lnID0gc3BsaXRIZWFkZXJzKHNwbGl0dGV4dFtpbmRleEJhc2UgKyAxXS5yZXBsYWNlKC9eLSAvbWcsICcnKSk7XG4gICAgdmFyIHNpZ19zdW0gPSBzcGxpdENoZWNrc3VtKHNpZy5ib2R5KTtcblxuICAgIHJlc3VsdCA9IHtcbiAgICAgIHRleHQ6ICBtc2cuYm9keS5yZXBsYWNlKC9cXG4kLywgJycpLnJlcGxhY2UoL1xcbi9nLCBcIlxcclxcblwiKSxcbiAgICAgIGRhdGE6IGJhc2U2NC5kZWNvZGUoc2lnX3N1bS5ib2R5KSxcbiAgICAgIHR5cGU6IHR5cGVcbiAgICB9O1xuXG4gICAgY2hlY2tzdW0gPSBzaWdfc3VtLmNoZWNrc3VtO1xuICB9XG5cbiAgaWYgKCF2ZXJpZnlDaGVja1N1bShyZXN1bHQuZGF0YSwgY2hlY2tzdW0pKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiQXNjaWkgYXJtb3IgaW50ZWdyaXR5IGNoZWNrIG9uIG1lc3NhZ2UgZmFpbGVkOiAnXCJcbiAgICAgICsgY2hlY2tzdW1cbiAgICAgICsgXCInIHNob3VsZCBiZSAnXCJcbiAgICAgICsgZ2V0Q2hlY2tTdW0ocmVzdWx0KSArIFwiJ1wiKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG59XG5cblxuLyoqXG4gKiBBcm1vciBhbiBPcGVuUEdQIGJpbmFyeSBwYWNrZXQgYmxvY2tcbiAqIEBwYXJhbSB7SW50ZWdlcn0gbWVzc2FnZXR5cGUgdHlwZSBvZiB0aGUgbWVzc2FnZVxuICogQHBhcmFtIGJvZHlcbiAqIEBwYXJhbSB7SW50ZWdlcn0gcGFydGluZGV4XG4gKiBAcGFyYW0ge0ludGVnZXJ9IHBhcnR0b3RhbFxuICogQHJldHVybnMge1N0cmluZ30gQXJtb3JlZCB0ZXh0XG4gKiBAc3RhdGljXG4gKi9cbmZ1bmN0aW9uIGFybW9yKG1lc3NhZ2V0eXBlLCBib2R5LCBwYXJ0aW5kZXgsIHBhcnR0b3RhbCkge1xuICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgc3dpdGNoIChtZXNzYWdldHlwZSkge1xuICAgIGNhc2UgZW51bXMuYXJtb3IubXVsdGlwYXJ0X3NlY3Rpb246XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUJFR0lOIFBHUCBNRVNTQUdFLCBQQVJUIFwiICsgcGFydGluZGV4ICsgXCIvXCIgKyBwYXJ0dG90YWwgKyBcIi0tLS0tXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gYWRkaGVhZGVyKCk7XG4gICAgICByZXN1bHQgKz0gYmFzZTY0LmVuY29kZShib2R5KTtcbiAgICAgIHJlc3VsdCArPSBcIlxcclxcbj1cIiArIGdldENoZWNrU3VtKGJvZHkpICsgXCJcXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBcIi0tLS0tRU5EIFBHUCBNRVNTQUdFLCBQQVJUIFwiICsgcGFydGluZGV4ICsgXCIvXCIgKyBwYXJ0dG90YWwgKyBcIi0tLS0tXFxyXFxuXCI7XG4gICAgICBicmVhaztcbiAgICBjYXNlIGVudW1zLmFybW9yLm11dGxpcGFydF9sYXN0OlxuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1CRUdJTiBQR1AgTUVTU0FHRSwgUEFSVCBcIiArIHBhcnRpbmRleCArIFwiLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBhZGRoZWFkZXIoKTtcbiAgICAgIHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGJvZHkpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keSkgKyBcIlxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1FTkQgUEdQIE1FU1NBR0UsIFBBUlQgXCIgKyBwYXJ0aW5kZXggKyBcIi0tLS0tXFxyXFxuXCI7XG4gICAgICBicmVhaztcbiAgICBjYXNlIGVudW1zLmFybW9yLnNpZ25lZDpcbiAgICAgIHJlc3VsdCArPSBcIlxcclxcbi0tLS0tQkVHSU4gUEdQIFNJR05FRCBNRVNTQUdFLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBcIkhhc2g6IFwiICsgYm9keS5oYXNoICsgXCJcXHJcXG5cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBib2R5LnRleHQucmVwbGFjZSgvXFxuLS9nLCBcIlxcbi0gLVwiKTtcbiAgICAgIHJlc3VsdCArPSBcIlxcclxcbi0tLS0tQkVHSU4gUEdQIFNJR05BVFVSRS0tLS0tXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gYWRkaGVhZGVyKCk7XG4gICAgICByZXN1bHQgKz0gYmFzZTY0LmVuY29kZShib2R5LmRhdGEpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keS5kYXRhKSArIFwiXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgU0lHTkFUVVJFLS0tLS1cXHJcXG5cIjtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgZW51bXMuYXJtb3IubWVzc2FnZTpcbiAgICAgIHJlc3VsdCArPSBcIi0tLS0tQkVHSU4gUEdQIE1FU1NBR0UtLS0tLVxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IGFkZGhlYWRlcigpO1xuICAgICAgcmVzdWx0ICs9IGJhc2U2NC5lbmNvZGUoYm9keSk7XG4gICAgICByZXN1bHQgKz0gXCJcXHJcXG49XCIgKyBnZXRDaGVja1N1bShib2R5KSArIFwiXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgTUVTU0FHRS0tLS0tXFxyXFxuXCI7XG4gICAgICBicmVhaztcbiAgICBjYXNlIGVudW1zLmFybW9yLnB1YmxpY19rZXk6XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUJFR0lOIFBHUCBQVUJMSUMgS0VZIEJMT0NLLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBhZGRoZWFkZXIoKTtcbiAgICAgIHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGJvZHkpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keSkgKyBcIlxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLVxcclxcblxcclxcblwiO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBlbnVtcy5hcm1vci5wcml2YXRlX2tleTpcbiAgICAgIHJlc3VsdCArPSBcIi0tLS0tQkVHSU4gUEdQIFBSSVZBVEUgS0VZIEJMT0NLLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBhZGRoZWFkZXIoKTtcbiAgICAgIHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGJvZHkpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keSkgKyBcIlxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1FTkQgUEdQIFBSSVZBVEUgS0VZIEJMT0NLLS0tLS1cXHJcXG5cIjtcbiAgICAgIGJyZWFrO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGVuY29kZTogYXJtb3IsXG4gIGRlY29kZTogZGVhcm1vclxufTtcbiIsIi8qIE9wZW5QR1AgcmFkaXgtNjQvYmFzZTY0IHN0cmluZyBlbmNvZGluZy9kZWNvZGluZ1xuICogQ29weXJpZ2h0IDIwMDUgSGVyYmVydCBIYW5ld2lua2VsLCB3d3cuaGFuZVdJTi5kZVxuICogdmVyc2lvbiAxLjAsIGNoZWNrIHd3dy5oYW5lV0lOLmRlIGZvciB0aGUgbGF0ZXN0IHZlcnNpb25cbiAqXG4gKiBUaGlzIHNvZnR3YXJlIGlzIHByb3ZpZGVkIGFzLWlzLCB3aXRob3V0IGV4cHJlc3Mgb3IgaW1wbGllZCB3YXJyYW50eS4gIFxuICogUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgZGlzdHJpYnV0ZSBvciBzZWxsIHRoaXMgc29mdHdhcmUsIHdpdGggb3JcbiAqIHdpdGhvdXQgZmVlLCBmb3IgYW55IHB1cnBvc2UgYW5kIGJ5IGFueSBpbmRpdmlkdWFsIG9yIG9yZ2FuaXphdGlvbiwgaXMgaGVyZWJ5XG4gKiBncmFudGVkLCBwcm92aWRlZCB0aGF0IHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBhcmFncmFwaCBhcHBlYXIgXG4gKiBpbiBhbGwgY29waWVzLiBEaXN0cmlidXRpb24gYXMgYSBwYXJ0IG9mIGFuIGFwcGxpY2F0aW9uIG9yIGJpbmFyeSBtdXN0XG4gKiBpbmNsdWRlIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGluIHRoZSBkb2N1bWVudGF0aW9uIGFuZC9vciBvdGhlciBtYXRlcmlhbHNcbiAqIHByb3ZpZGVkIHdpdGggdGhlIGFwcGxpY2F0aW9uIG9yIGRpc3RyaWJ1dGlvbi5cbiAqL1xuXG4vKipcbiAqIEBtb2R1bGUgZW5jb2RpbmcvYmFzZTY0XG4gKi9cblxudmFyIGI2NHMgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLyc7XG5cbi8qKlxuICogQ29udmVydCBiaW5hcnkgc3RyaW5nIHRvIHJhZGl4LTY0XG4gKiBAcGFyYW0ge1N0cmluZ30gdCBiaW5hcnkgc3RyaW5nIHRvIGNvbnZlcnRcbiAqIEByZXR1cm5zIHtzdHJpbmd9IHJhZGl4LTY0IHZlcnNpb24gb2YgaW5wdXQgc3RyaW5nXG4gKiBAc3RhdGljXG4gKi9cbmZ1bmN0aW9uIHMycih0KSB7XG4gIHZhciBhLCBjLCBuO1xuICB2YXIgciA9ICcnLFxuICAgIGwgPSAwLFxuICAgIHMgPSAwO1xuICB2YXIgdGwgPSB0Lmxlbmd0aDtcblxuICBmb3IgKG4gPSAwOyBuIDwgdGw7IG4rKykge1xuICAgIGMgPSB0LmNoYXJDb2RlQXQobik7XG4gICAgaWYgKHMgPT0gMCkge1xuICAgICAgciArPSBiNjRzLmNoYXJBdCgoYyA+PiAyKSAmIDYzKTtcbiAgICAgIGEgPSAoYyAmIDMpIDw8IDQ7XG4gICAgfSBlbHNlIGlmIChzID09IDEpIHtcbiAgICAgIHIgKz0gYjY0cy5jaGFyQXQoKGEgfCAoYyA+PiA0KSAmIDE1KSk7XG4gICAgICBhID0gKGMgJiAxNSkgPDwgMjtcbiAgICB9IGVsc2UgaWYgKHMgPT0gMikge1xuICAgICAgciArPSBiNjRzLmNoYXJBdChhIHwgKChjID4+IDYpICYgMykpO1xuICAgICAgbCArPSAxO1xuICAgICAgaWYgKChsICUgNjApID09IDApXG4gICAgICAgIHIgKz0gXCJcXG5cIjtcbiAgICAgIHIgKz0gYjY0cy5jaGFyQXQoYyAmIDYzKTtcbiAgICB9XG4gICAgbCArPSAxO1xuICAgIGlmICgobCAlIDYwKSA9PSAwKVxuICAgICAgciArPSBcIlxcblwiO1xuXG4gICAgcyArPSAxO1xuICAgIGlmIChzID09IDMpXG4gICAgICBzID0gMDtcbiAgfVxuICBpZiAocyA+IDApIHtcbiAgICByICs9IGI2NHMuY2hhckF0KGEpO1xuICAgIGwgKz0gMTtcbiAgICBpZiAoKGwgJSA2MCkgPT0gMClcbiAgICAgIHIgKz0gXCJcXG5cIjtcbiAgICByICs9ICc9JztcbiAgICBsICs9IDE7XG4gIH1cbiAgaWYgKHMgPT0gMSkge1xuICAgIGlmICgobCAlIDYwKSA9PSAwKVxuICAgICAgciArPSBcIlxcblwiO1xuICAgIHIgKz0gJz0nO1xuICB9XG5cbiAgcmV0dXJuIHI7XG59XG5cbi8qKlxuICogQ29udmVydCByYWRpeC02NCB0byBiaW5hcnkgc3RyaW5nXG4gKiBAcGFyYW0ge1N0cmluZ30gdCByYWRpeC02NCBzdHJpbmcgdG8gY29udmVydFxuICogQHJldHVybnMge3N0cmluZ30gYmluYXJ5IHZlcnNpb24gb2YgaW5wdXQgc3RyaW5nXG4gKiBAc3RhdGljXG4gKi9cbmZ1bmN0aW9uIHIycyh0KSB7XG4gIHZhciBjLCBuO1xuICB2YXIgciA9ICcnLFxuICAgIHMgPSAwLFxuICAgIGEgPSAwO1xuICB2YXIgdGwgPSB0Lmxlbmd0aDtcblxuICBmb3IgKG4gPSAwOyBuIDwgdGw7IG4rKykge1xuICAgIGMgPSBiNjRzLmluZGV4T2YodC5jaGFyQXQobikpO1xuICAgIGlmIChjID49IDApIHtcbiAgICAgIGlmIChzKVxuICAgICAgICByICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYSB8IChjID4+ICg2IC0gcykpICYgMjU1KTtcbiAgICAgIHMgPSAocyArIDIpICYgNztcbiAgICAgIGEgPSAoYyA8PCBzKSAmIDI1NTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHI7XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBlbmNvZGU6IHMycixcbiAgZGVjb2RlOiByMnNcbn1cbiIsIi8qKlxuICogQG1vZHVsZSBlbnVtc1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuXG4gIC8qKiBBIHN0cmluZyB0byBrZXkgc3BlY2lmaWVyIHR5cGVcbiAgICogQGVudW0ge0ludGVnZXJ9XG4gICAqIEByZWFkb25seVxuICAgKi9cbiAgczJrOiB7XG4gICAgc2ltcGxlOiAwLFxuICAgIHNhbHRlZDogMSxcbiAgICBpdGVyYXRlZDogMyxcbiAgICBnbnU6IDEwMVxuICB9LFxuXG4gIC8qKiBSRkM0ODgwLCBzZWN0aW9uIDkuMVxuICAgKiBAZW51bSB7SW50ZWdlcn1cbiAgICogQHJlYWRvbmx5XG4gICAqL1xuICBwdWJsaWNLZXk6IHtcbiAgICByc2FfZW5jcnlwdF9zaWduOiAxLFxuICAgIHJzYV9lbmNyeXB0OiAyLFxuICAgIHJzYV9zaWduOiAzLFxuICAgIGVsZ2FtYWw6IDE2LFxuICAgIGRzYTogMTdcbiAgfSxcblxuICAvKiogUkZDNDg4MCwgc2VjdGlvbiA5LjJcbiAgICogQGVudW0ge0ludGVnZXJ9XG4gICAqIEByZWFkb25seVxuICAgKi9cbiAgc3ltbWV0cmljOiB7XG4gICAgcGxhaW50ZXh0OiAwLFxuICAgIC8qKiBOb3QgaW1wbGVtZW50ZWQhICovXG4gICAgaWRlYTogMSxcbiAgICB0cmlwbGVkZXM6IDIsXG4gICAgY2FzdDU6IDMsXG4gICAgYmxvd2Zpc2g6IDQsXG4gICAgYWVzMTI4OiA3LFxuICAgIGFlczE5MjogOCxcbiAgICBhZXMyNTY6IDksXG4gICAgdHdvZmlzaDogMTBcbiAgfSxcblxuICAvKiogUkZDNDg4MCwgc2VjdGlvbiA5LjNcbiAgICogQGVudW0ge0ludGVnZXJ9XG4gICAqIEByZWFkb25seVxuICAgKi9cbiAgY29tcHJlc3Npb246IHtcbiAgICB1bmNvbXByZXNzZWQ6IDAsXG4gICAgLyoqIFJGQzE5NTEgKi9cbiAgICB6aXA6IDEsXG4gICAgLyoqIFJGQzE5NTAgKi9cbiAgICB6bGliOiAyLFxuICAgIGJ6aXAyOiAzXG4gIH0sXG5cbiAgLyoqIFJGQzQ4ODAsIHNlY3Rpb24gOS40XG4gICAqIEBlbnVtIHtJbnRlZ2VyfVxuICAgKiBAcmVhZG9ubHlcbiAgICovXG4gIGhhc2g6IHtcbiAgICBtZDU6IDEsXG4gICAgc2hhMTogMixcbiAgICByaXBlbWQ6IDMsXG4gICAgc2hhMjU2OiA4LFxuICAgIHNoYTM4NDogOSxcbiAgICBzaGE1MTI6IDEwLFxuICAgIHNoYTIyNDogMTFcbiAgfSxcblxuICAvKiogQSBsaXN0IG9mIHBhY2tldCB0eXBlcyBhbmQgbnVtZXJpYyB0YWdzIGFzc29jaWF0ZWQgd2l0aCB0aGVtLlxuICAgKiBAZW51bSB7SW50ZWdlcn1cbiAgICogQHJlYWRvbmx5XG4gICAqL1xuICBwYWNrZXQ6IHtcbiAgICBwdWJsaWNfa2V5X2VuY3J5cHRlZF9zZXNzaW9uX2tleTogMSxcbiAgICBzaWduYXR1cmU6IDIsXG4gICAgc3ltX2VuY3J5cHRlZF9zZXNzaW9uX2tleTogMyxcbiAgICBvbmVfcGFzc19zaWduYXR1cmU6IDQsXG4gICAgc2VjcmV0X2tleTogNSxcbiAgICBwdWJsaWNfa2V5OiA2LFxuICAgIHNlY3JldF9zdWJrZXk6IDcsXG4gICAgY29tcHJlc3NlZDogOCxcbiAgICBzeW1tZXRyaWNhbGx5X2VuY3J5cHRlZDogOSxcbiAgICBtYXJrZXI6IDEwLFxuICAgIGxpdGVyYWw6IDExLFxuICAgIHRydXN0OiAxMixcbiAgICB1c2VyaWQ6IDEzLFxuICAgIHB1YmxpY19zdWJrZXk6IDE0LFxuICAgIHVzZXJfYXR0cmlidXRlOiAxNyxcbiAgICBzeW1fZW5jcnlwdGVkX2ludGVncml0eV9wcm90ZWN0ZWQ6IDE4LFxuICAgIG1vZGlmaWNhdGlvbl9kZXRlY3Rpb25fY29kZTogMTlcbiAgfSxcblxuICAvKiogRGF0YSB0eXBlcyBpbiB0aGUgbGl0ZXJhbCBwYWNrZXRcbiAgICogQGVudW0ge0ludGVnZXJ9XG4gICAqIEByZWFkb25seVxuICAgKi9cbiAgbGl0ZXJhbDoge1xuICAgIC8qKiBCaW5hcnkgZGF0YSAnYicgKi9cbiAgICBiaW5hcnk6ICdiJy5jaGFyQ29kZUF0KCksXG4gICAgLyoqIFRleHQgZGF0YSAndCcgKi9cbiAgICB0ZXh0OiAndCcuY2hhckNvZGVBdCgpLFxuICAgIC8qKiBVdGY4IGRhdGEgJ3UnICovXG4gICAgdXRmODogJ3UnLmNoYXJDb2RlQXQoKVxuICB9LFxuXG5cbiAgLyoqIE9uZSBwYXNzIHNpZ25hdHVyZSBwYWNrZXQgdHlwZVxuICAgKiBAZW51bSB7SW50ZWdlcn1cbiAgICogQHJlYWRvbmx5XG4gICAqL1xuICBzaWduYXR1cmU6IHtcbiAgICAvKiogMHgwMDogU2lnbmF0dXJlIG9mIGEgYmluYXJ5IGRvY3VtZW50LiAqL1xuICAgIGJpbmFyeTogMCxcbiAgICAvKiogMHgwMTogU2lnbmF0dXJlIG9mIGEgY2Fub25pY2FsIHRleHQgZG9jdW1lbnQuPGJyLz5cbiAgICAgKiBDYW5vbmljYWx5emluZyB0aGUgZG9jdW1lbnQgYnkgY29udmVydGluZyBsaW5lIGVuZGluZ3MuICovXG4gICAgdGV4dDogMSxcbiAgICAvKiogMHgwMjogU3RhbmRhbG9uZSBzaWduYXR1cmUuPGJyLz5cbiAgICAgKiBUaGlzIHNpZ25hdHVyZSBpcyBhIHNpZ25hdHVyZSBvZiBvbmx5IGl0cyBvd24gc3VicGFja2V0IGNvbnRlbnRzLlxuICAgICAqIEl0IGlzIGNhbGN1bGF0ZWQgaWRlbnRpY2FsbHkgdG8gYSBzaWduYXR1cmUgb3ZlciBhIHplcm8tbGVuZ2hcbiAgICAgKiBiaW5hcnkgZG9jdW1lbnQuICBOb3RlIHRoYXQgaXQgZG9lc24ndCBtYWtlIHNlbnNlIHRvIGhhdmUgYSBWM1xuICAgICAqIHN0YW5kYWxvbmUgc2lnbmF0dXJlLiAqL1xuICAgIHN0YW5kYWxvbmU6IDIsXG4gICAgLyoqIDB4MTA6IEdlbmVyaWMgY2VydGlmaWNhdGlvbiBvZiBhIFVzZXIgSUQgYW5kIFB1YmxpYy1LZXkgcGFja2V0Ljxici8+XG4gICAgICogVGhlIGlzc3VlciBvZiB0aGlzIGNlcnRpZmljYXRpb24gZG9lcyBub3QgbWFrZSBhbnkgcGFydGljdWxhclxuICAgICAqIGFzc2VydGlvbiBhcyB0byBob3cgd2VsbCB0aGUgY2VydGlmaWVyIGhhcyBjaGVja2VkIHRoYXQgdGhlIG93bmVyXG4gICAgICogb2YgdGhlIGtleSBpcyBpbiBmYWN0IHRoZSBwZXJzb24gZGVzY3JpYmVkIGJ5IHRoZSBVc2VyIElELiAqL1xuICAgIGNlcnRfZ2VuZXJpYzogMTYsXG4gICAgLyoqIDB4MTE6IFBlcnNvbmEgY2VydGlmaWNhdGlvbiBvZiBhIFVzZXIgSUQgYW5kIFB1YmxpYy1LZXkgcGFja2V0Ljxici8+XG4gICAgICogVGhlIGlzc3VlciBvZiB0aGlzIGNlcnRpZmljYXRpb24gaGFzIG5vdCBkb25lIGFueSB2ZXJpZmljYXRpb24gb2ZcbiAgICAgKiB0aGUgY2xhaW0gdGhhdCB0aGUgb3duZXIgb2YgdGhpcyBrZXkgaXMgdGhlIFVzZXIgSUQgc3BlY2lmaWVkLiAqL1xuICAgIGNlcnRfcGVyc29uYTogMTcsXG4gICAgLyoqIDB4MTI6IENhc3VhbCBjZXJ0aWZpY2F0aW9uIG9mIGEgVXNlciBJRCBhbmQgUHVibGljLUtleSBwYWNrZXQuPGJyLz5cbiAgICAgKiBUaGUgaXNzdWVyIG9mIHRoaXMgY2VydGlmaWNhdGlvbiBoYXMgZG9uZSBzb21lIGNhc3VhbFxuICAgICAqIHZlcmlmaWNhdGlvbiBvZiB0aGUgY2xhaW0gb2YgaWRlbnRpdHkuICovXG4gICAgY2VydF9jYXN1YWw6IDE4LFxuICAgIC8qKiAweDEzOiBQb3NpdGl2ZSBjZXJ0aWZpY2F0aW9uIG9mIGEgVXNlciBJRCBhbmQgUHVibGljLUtleSBwYWNrZXQuPGJyLz5cbiAgICAgKiBUaGUgaXNzdWVyIG9mIHRoaXMgY2VydGlmaWNhdGlvbiBoYXMgZG9uZSBzdWJzdGFudGlhbFxuICAgICAqIHZlcmlmaWNhdGlvbiBvZiB0aGUgY2xhaW0gb2YgaWRlbnRpdHkuPGJyLz5cbiAgICAgKiA8YnIvPlxuICAgICAqIE1vc3QgT3BlblBHUCBpbXBsZW1lbnRhdGlvbnMgbWFrZSB0aGVpciBcImtleSBzaWduYXR1cmVzXCIgYXMgMHgxMFxuICAgICAqIGNlcnRpZmljYXRpb25zLiAgU29tZSBpbXBsZW1lbnRhdGlvbnMgY2FuIGlzc3VlIDB4MTEtMHgxM1xuICAgICAqIGNlcnRpZmljYXRpb25zLCBidXQgZmV3IGRpZmZlcmVudGlhdGUgYmV0d2VlbiB0aGUgdHlwZXMuICovXG4gICAgY2VydF9wb3NpdGl2ZTogMTksXG4gICAgLyoqIDB4MzA6IENlcnRpZmljYXRpb24gcmV2b2NhdGlvbiBzaWduYXR1cmU8YnIvPlxuICAgICAqIFRoaXMgc2lnbmF0dXJlIHJldm9rZXMgYW4gZWFybGllciBVc2VyIElEIGNlcnRpZmljYXRpb24gc2lnbmF0dXJlXG4gICAgICogKHNpZ25hdHVyZSBjbGFzcyAweDEwIHRocm91Z2ggMHgxMykgb3IgZGlyZWN0LWtleSBzaWduYXR1cmVcbiAgICAgKiAoMHgxRikuICBJdCBzaG91bGQgYmUgaXNzdWVkIGJ5IHRoZSBzYW1lIGtleSB0aGF0IGlzc3VlZCB0aGVcbiAgICAgKiByZXZva2VkIHNpZ25hdHVyZSBvciBhbiBhdXRob3JpemVkIHJldm9jYXRpb24ga2V5LiAgVGhlIHNpZ25hdHVyZVxuICAgICAqIGlzIGNvbXB1dGVkIG92ZXIgdGhlIHNhbWUgZGF0YSBhcyB0aGUgY2VydGlmaWNhdGUgdGhhdCBpdFxuICAgICAqIHJldm9rZXMsIGFuZCBzaG91bGQgaGF2ZSBhIGxhdGVyIGNyZWF0aW9uIGRhdGUgdGhhbiB0aGF0XG4gICAgICogY2VydGlmaWNhdGUuICovXG4gICAgY2VydF9yZXZvY2F0aW9uOiA0OCxcbiAgICAvKiogMHgxODogU3Via2V5IEJpbmRpbmcgU2lnbmF0dXJlPGJyLz5cbiAgICAgKiBUaGlzIHNpZ25hdHVyZSBpcyBhIHN0YXRlbWVudCBieSB0aGUgdG9wLWxldmVsIHNpZ25pbmcga2V5IHRoYXRcbiAgICAgKiBpbmRpY2F0ZXMgdGhhdCBpdCBvd25zIHRoZSBzdWJrZXkuICBUaGlzIHNpZ25hdHVyZSBpcyBjYWxjdWxhdGVkXG4gICAgICogZGlyZWN0bHkgb24gdGhlIHByaW1hcnkga2V5IGFuZCBzdWJrZXksIGFuZCBub3Qgb24gYW55IFVzZXIgSUQgb3JcbiAgICAgKiBvdGhlciBwYWNrZXRzLiAgQSBzaWduYXR1cmUgdGhhdCBiaW5kcyBhIHNpZ25pbmcgc3Via2V5IE1VU1QgaGF2ZVxuICAgICAqIGFuIEVtYmVkZGVkIFNpZ25hdHVyZSBzdWJwYWNrZXQgaW4gdGhpcyBiaW5kaW5nIHNpZ25hdHVyZSB0aGF0XG4gICAgICogY29udGFpbnMgYSAweDE5IHNpZ25hdHVyZSBtYWRlIGJ5IHRoZSBzaWduaW5nIHN1YmtleSBvbiB0aGVcbiAgICAgKiBwcmltYXJ5IGtleSBhbmQgc3Via2V5LiAqL1xuICAgIHN1YmtleV9iaW5kaW5nOiAyNCxcbiAgICAvKiogMHgxOTogUHJpbWFyeSBLZXkgQmluZGluZyBTaWduYXR1cmU8YnIvPlxuICAgICAqIFRoaXMgc2lnbmF0dXJlIGlzIGEgc3RhdGVtZW50IGJ5IGEgc2lnbmluZyBzdWJrZXksIGluZGljYXRpbmdcbiAgICAgKiB0aGF0IGl0IGlzIG93bmVkIGJ5IHRoZSBwcmltYXJ5IGtleSBhbmQgc3Via2V5LiAgVGhpcyBzaWduYXR1cmVcbiAgICAgKiBpcyBjYWxjdWxhdGVkIHRoZSBzYW1lIHdheSBhcyBhIDB4MTggc2lnbmF0dXJlOiBkaXJlY3RseSBvbiB0aGVcbiAgICAgKiBwcmltYXJ5IGtleSBhbmQgc3Via2V5LCBhbmQgbm90IG9uIGFueSBVc2VyIElEIG9yIG90aGVyIHBhY2tldHMuPGJyLz5cbiAgICAgKiA8YnIvPlxuICAgICAqIFdoZW4gYSBzaWduYXR1cmUgaXMgbWFkZSBvdmVyIGEga2V5LCB0aGUgaGFzaCBkYXRhIHN0YXJ0cyB3aXRoIHRoZVxuICAgICAqIG9jdGV0IDB4OTksIGZvbGxvd2VkIGJ5IGEgdHdvLW9jdGV0IGxlbmd0aCBvZiB0aGUga2V5LCBhbmQgdGhlbiBib2R5XG4gICAgICogb2YgdGhlIGtleSBwYWNrZXQuICAoTm90ZSB0aGF0IHRoaXMgaXMgYW4gb2xkLXN0eWxlIHBhY2tldCBoZWFkZXIgZm9yXG4gICAgICogYSBrZXkgcGFja2V0IHdpdGggdHdvLW9jdGV0IGxlbmd0aC4pICBBIHN1YmtleSBiaW5kaW5nIHNpZ25hdHVyZVxuICAgICAqICh0eXBlIDB4MTgpIG9yIHByaW1hcnkga2V5IGJpbmRpbmcgc2lnbmF0dXJlICh0eXBlIDB4MTkpIHRoZW4gaGFzaGVzXG4gICAgICogdGhlIHN1YmtleSB1c2luZyB0aGUgc2FtZSBmb3JtYXQgYXMgdGhlIG1haW4ga2V5IChhbHNvIHVzaW5nIDB4OTkgYXNcbiAgICAgKiB0aGUgZmlyc3Qgb2N0ZXQpLiAqL1xuICAgIGtleV9iaW5kaW5nOiAyNSxcbiAgICAvKiogMHgxRjogU2lnbmF0dXJlIGRpcmVjdGx5IG9uIGEga2V5PGJyLz5cbiAgICAgKiBUaGlzIHNpZ25hdHVyZSBpcyBjYWxjdWxhdGVkIGRpcmVjdGx5IG9uIGEga2V5LiAgSXQgYmluZHMgdGhlXG4gICAgICogaW5mb3JtYXRpb24gaW4gdGhlIFNpZ25hdHVyZSBzdWJwYWNrZXRzIHRvIHRoZSBrZXksIGFuZCBpc1xuICAgICAqIGFwcHJvcHJpYXRlIHRvIGJlIHVzZWQgZm9yIHN1YnBhY2tldHMgdGhhdCBwcm92aWRlIGluZm9ybWF0aW9uXG4gICAgICogYWJvdXQgdGhlIGtleSwgc3VjaCBhcyB0aGUgUmV2b2NhdGlvbiBLZXkgc3VicGFja2V0LiAgSXQgaXMgYWxzb1xuICAgICAqIGFwcHJvcHJpYXRlIGZvciBzdGF0ZW1lbnRzIHRoYXQgbm9uLXNlbGYgY2VydGlmaWVycyB3YW50IHRvIG1ha2VcbiAgICAgKiBhYm91dCB0aGUga2V5IGl0c2VsZiwgcmF0aGVyIHRoYW4gdGhlIGJpbmRpbmcgYmV0d2VlbiBhIGtleSBhbmQgYVxuICAgICAqIG5hbWUuICovXG4gICAga2V5OiAzMSxcbiAgICAvKiogMHgyMDogS2V5IHJldm9jYXRpb24gc2lnbmF0dXJlPGJyLz5cbiAgICAgKiBUaGUgc2lnbmF0dXJlIGlzIGNhbGN1bGF0ZWQgZGlyZWN0bHkgb24gdGhlIGtleSBiZWluZyByZXZva2VkLiAgQVxuICAgICAqIHJldm9rZWQga2V5IGlzIG5vdCB0byBiZSB1c2VkLiAgT25seSByZXZvY2F0aW9uIHNpZ25hdHVyZXMgYnkgdGhlXG4gICAgICoga2V5IGJlaW5nIHJldm9rZWQsIG9yIGJ5IGFuIGF1dGhvcml6ZWQgcmV2b2NhdGlvbiBrZXksIHNob3VsZCBiZVxuICAgICAqIGNvbnNpZGVyZWQgdmFsaWQgcmV2b2NhdGlvbiBzaWduYXR1cmVzLmEgKi9cbiAgICBrZXlfcmV2b2NhdGlvbjogMzIsXG4gICAgLyoqIDB4Mjg6IFN1YmtleSByZXZvY2F0aW9uIHNpZ25hdHVyZTxici8+XG4gICAgICogVGhlIHNpZ25hdHVyZSBpcyBjYWxjdWxhdGVkIGRpcmVjdGx5IG9uIHRoZSBzdWJrZXkgYmVpbmcgcmV2b2tlZC5cbiAgICAgKiBBIHJldm9rZWQgc3Via2V5IGlzIG5vdCB0byBiZSB1c2VkLiAgT25seSByZXZvY2F0aW9uIHNpZ25hdHVyZXNcbiAgICAgKiBieSB0aGUgdG9wLWxldmVsIHNpZ25hdHVyZSBrZXkgdGhhdCBpcyBib3VuZCB0byB0aGlzIHN1YmtleSwgb3JcbiAgICAgKiBieSBhbiBhdXRob3JpemVkIHJldm9jYXRpb24ga2V5LCBzaG91bGQgYmUgY29uc2lkZXJlZCB2YWxpZFxuICAgICAqIHJldm9jYXRpb24gc2lnbmF0dXJlcy48YnIvPlxuICAgICAqIDxici8+XG4gICAgICogS2V5IHJldm9jYXRpb24gc2lnbmF0dXJlcyAodHlwZXMgMHgyMCBhbmQgMHgyOClcbiAgICAgKiBoYXNoIG9ubHkgdGhlIGtleSBiZWluZyByZXZva2VkLiAqL1xuICAgIHN1YmtleV9yZXZvY2F0aW9uOiA0MCxcbiAgICAvKiogMHg0MDogVGltZXN0YW1wIHNpZ25hdHVyZS48YnIvPlxuICAgICAqIFRoaXMgc2lnbmF0dXJlIGlzIG9ubHkgbWVhbmluZ2Z1bCBmb3IgdGhlIHRpbWVzdGFtcCBjb250YWluZWQgaW5cbiAgICAgKiBpdC4gKi9cbiAgICB0aW1lc3RhbXA6IDY0LFxuICAgIC8qKiAweDUwOiBUaGlyZC1QYXJ0eSBDb25maXJtYXRpb24gc2lnbmF0dXJlLjxici8+XG4gICAgICogVGhpcyBzaWduYXR1cmUgaXMgYSBzaWduYXR1cmUgb3ZlciBzb21lIG90aGVyIE9wZW5QR1AgU2lnbmF0dXJlXG4gICAgICogcGFja2V0KHMpLiAgSXQgaXMgYW5hbG9nb3VzIHRvIGEgbm90YXJ5IHNlYWwgb24gdGhlIHNpZ25lZCBkYXRhLlxuICAgICAqIEEgdGhpcmQtcGFydHkgc2lnbmF0dXJlIFNIT1VMRCBpbmNsdWRlIFNpZ25hdHVyZSBUYXJnZXRcbiAgICAgKiBzdWJwYWNrZXQocykgdG8gZ2l2ZSBlYXN5IGlkZW50aWZpY2F0aW9uLiAgTm90ZSB0aGF0IHdlIHJlYWxseSBkb1xuICAgICAqIG1lYW4gU0hPVUxELiAgVGhlcmUgYXJlIHBsYXVzaWJsZSB1c2VzIGZvciB0aGlzIChzdWNoIGFzIGEgYmxpbmRcbiAgICAgKiBwYXJ0eSB0aGF0IG9ubHkgc2VlcyB0aGUgc2lnbmF0dXJlLCBub3QgdGhlIGtleSBvciBzb3VyY2VcbiAgICAgKiBkb2N1bWVudCkgdGhhdCBjYW5ub3QgaW5jbHVkZSBhIHRhcmdldCBzdWJwYWNrZXQuICovXG4gICAgdGhpcmRfcGFydHk6IDgwXG4gIH0sXG5cbiAgLyoqIFNpZ25hdHVyZSBzdWJwYWNrZXQgdHlwZVxuICAgKiBAZW51bSB7SW50ZWdlcn1cbiAgICogQHJlYWRvbmx5XG4gICAqL1xuICBzaWduYXR1cmVTdWJwYWNrZXQ6IHtcbiAgICBzaWduYXR1cmVfY3JlYXRpb25fdGltZTogMixcbiAgICBzaWduYXR1cmVfZXhwaXJhdGlvbl90aW1lOiAzLFxuICAgIGV4cG9ydGFibGVfY2VydGlmaWNhdGlvbjogNCxcbiAgICB0cnVzdF9zaWduYXR1cmU6IDUsXG4gICAgcmVndWxhcl9leHByZXNzaW9uOiA2LFxuICAgIHJldm9jYWJsZTogNyxcbiAgICBrZXlfZXhwaXJhdGlvbl90aW1lOiA5LFxuICAgIHBsYWNlaG9sZGVyX2JhY2t3YXJkc19jb21wYXRpYmlsaXR5OiAxMCxcbiAgICBwcmVmZXJyZWRfc3ltbWV0cmljX2FsZ29yaXRobXM6IDExLFxuICAgIHJldm9jYXRpb25fa2V5OiAxMixcbiAgICBpc3N1ZXI6IDE2LFxuICAgIG5vdGF0aW9uX2RhdGE6IDIwLFxuICAgIHByZWZlcnJlZF9oYXNoX2FsZ29yaXRobXM6IDIxLFxuICAgIHByZWZlcnJlZF9jb21wcmVzc2lvbl9hbGdvcml0aG1zOiAyMixcbiAgICBrZXlfc2VydmVyX3ByZWZlcmVuY2VzOiAyMyxcbiAgICBwcmVmZXJyZWRfa2V5X3NlcnZlcjogMjQsXG4gICAgcHJpbWFyeV91c2VyX2lkOiAyNSxcbiAgICBwb2xpY3lfdXJpOiAyNixcbiAgICBrZXlfZmxhZ3M6IDI3LFxuICAgIHNpZ25lcnNfdXNlcl9pZDogMjgsXG4gICAgcmVhc29uX2Zvcl9yZXZvY2F0aW9uOiAyOSxcbiAgICBmZWF0dXJlczogMzAsXG4gICAgc2lnbmF0dXJlX3RhcmdldDogMzEsXG4gICAgZW1iZWRkZWRfc2lnbmF0dXJlOiAzMlxuICB9LFxuXG4gIC8qKiBLZXkgZmxhZ3NcbiAgICogQGVudW0ge0ludGVnZXJ9XG4gICAqIEByZWFkb25seVxuICAgKi9cbiAga2V5RmxhZ3M6IHtcbiAgICAvKiogMHgwMSAtIFRoaXMga2V5IG1heSBiZSB1c2VkIHRvIGNlcnRpZnkgb3RoZXIga2V5cy4gKi9cbiAgICBjZXJ0aWZ5X2tleXM6IDEsXG4gICAgLyoqIDB4MDIgLSBUaGlzIGtleSBtYXkgYmUgdXNlZCB0byBzaWduIGRhdGEuICovXG4gICAgc2lnbl9kYXRhOiAyLFxuICAgIC8qKiAweDA0IC0gVGhpcyBrZXkgbWF5IGJlIHVzZWQgdG8gZW5jcnlwdCBjb21tdW5pY2F0aW9ucy4gKi9cbiAgICBlbmNyeXB0X2NvbW11bmljYXRpb246IDQsXG4gICAgLyoqIDB4MDggLSBUaGlzIGtleSBtYXkgYmUgdXNlZCB0byBlbmNyeXB0IHN0b3JhZ2UuICovXG4gICAgZW5jcnlwdF9zdG9yYWdlOiA4LFxuICAgIC8qKiAweDEwIC0gVGhlIHByaXZhdGUgY29tcG9uZW50IG9mIHRoaXMga2V5IG1heSBoYXZlIGJlZW4gc3BsaXRcbiAgICAgKiAgICAgICAgYnkgYSBzZWNyZXQtc2hhcmluZyBtZWNoYW5pc20uICovXG4gICAgc3BsaXRfcHJpdmF0ZV9rZXk6IDE2LFxuICAgIC8qKiAweDIwIC0gVGhpcyBrZXkgbWF5IGJlIHVzZWQgZm9yIGF1dGhlbnRpY2F0aW9uLiAqL1xuICAgIGF1dGhlbnRpY2F0aW9uOiAzMixcbiAgICAvKiogMHg4MCAtIFRoZSBwcml2YXRlIGNvbXBvbmVudCBvZiB0aGlzIGtleSBtYXkgYmUgaW4gdGhlXG4gICAgICogICAgICAgIHBvc3Nlc3Npb24gb2YgbW9yZSB0aGFuIG9uZSBwZXJzb24uICovXG4gICAgc2hhcmVkX3ByaXZhdGVfa2V5OiAxMjhcbiAgfSxcblxuICAvKiogS2V5IHN0YXR1c1xuICAgKiBAZW51bSB7SW50ZWdlcn1cbiAgICogQHJlYWRvbmx5XG4gICAqL1xuICBrZXlTdGF0dXM6IHtcbiAgICBpbnZhbGlkOiAgICAgIDAsXG4gICAgZXhwaXJlZDogICAgICAxLFxuICAgIHJldm9rZWQ6ICAgICAgMixcbiAgICB2YWxpZDogICAgICAgIDMsXG4gICAgbm9fc2VsZl9jZXJ0OiA0XG4gIH0sXG5cbiAgLyoqIEFybW9yIHR5cGVcbiAgICogQGVudW0ge0ludGVnZXJ9XG4gICAqIEByZWFkb25seVxuICAgKi9cbiAgYXJtb3I6IHtcbiAgICBtdWx0aXBhcnRfc2VjdGlvbjogMCxcbiAgICBtdWx0aXBhcnRfbGFzdDogMSxcbiAgICBzaWduZWQ6IDIsXG4gICAgbWVzc2FnZTogMyxcbiAgICBwdWJsaWNfa2V5OiA0LFxuICAgIHByaXZhdGVfa2V5OiA1XG4gIH0sXG5cbiAgLyoqIEFzc2VydHMgdmFsaWRpdHkgYW5kIGNvbnZlcnRzIGZyb20gc3RyaW5nL2ludGVnZXIgdG8gaW50ZWdlci4gKi9cbiAgd3JpdGU6IGZ1bmN0aW9uKHR5cGUsIGUpIHtcbiAgICBpZiAodHlwZW9mIGUgPT0gJ251bWJlcicpIHtcbiAgICAgIGUgPSB0aGlzLnJlYWQodHlwZSwgZSk7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVbZV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHR5cGVbZV07XG4gICAgfSBlbHNlIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBlbnVtIHZhbHVlLicpO1xuICB9LFxuICAvKiogQ29udmVydHMgZnJvbSBhbiBpbnRlZ2VyIHRvIHN0cmluZy4gKi9cbiAgcmVhZDogZnVuY3Rpb24odHlwZSwgZSkge1xuICAgIGZvciAodmFyIGkgaW4gdHlwZSlcbiAgICAgIGlmICh0eXBlW2ldID09IGUpIHJldHVybiBpO1xuXG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGVudW0gdmFsdWUuJyk7XG4gIH1cbn1cbiIsIlxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL29wZW5wZ3AuanMnKTtcblxubW9kdWxlLmV4cG9ydHMua2V5ID0gcmVxdWlyZSgnLi9rZXkuanMnKTtcbm1vZHVsZS5leHBvcnRzLm1lc3NhZ2UgPSByZXF1aXJlKCcuL21lc3NhZ2UuanMnKTtcbm1vZHVsZS5leHBvcnRzLmNsZWFydGV4dCA9IHJlcXVpcmUoJy4vY2xlYXJ0ZXh0LmpzJyk7XG4vKipcbiAqIEBzZWUgbW9kdWxlOnV0aWwvdXRpbFxuICogQG1vZHVsZSB1dGlsXG4gKi9cbm1vZHVsZS5leHBvcnRzLnV0aWwgPSByZXF1aXJlKCcuL3V0aWwvdXRpbC5qcycpO1xubW9kdWxlLmV4cG9ydHMucGFja2V0ID0gcmVxdWlyZSgnLi9wYWNrZXQnKTtcbi8qKlxuICogQHNlZSBtb2R1bGU6dHlwZS9tcGlcbiAqIEBtb2R1bGUgbXBpXG4gKi9cbm1vZHVsZS5leHBvcnRzLm1waSA9IHJlcXVpcmUoJy4vdHlwZS9tcGkuanMnKTtcbi8qKlxuICogQHNlZSBtb2R1bGU6dHlwZS9zMmtcbiAqIEBtb2R1bGUgczJrXG4gKi9cbm1vZHVsZS5leHBvcnRzLnMyayA9IHJlcXVpcmUoJy4vdHlwZS9zMmsuanMnKTtcbi8qKlxuICogQHNlZSBtb2R1bGU6dHlwZS9rZXlpZFxuICogQG1vZHVsZSBrZXlpZFxuICovXG5tb2R1bGUuZXhwb3J0cy5rZXlpZCA9IHJlcXVpcmUoJy4vdHlwZS9rZXlpZC5qcycpO1xuLyoqXG4gKiBAc2VlIG1vZHVsZTplbmNvZGluZy9hcm1vclxuICogQG1vZHVsZSBhcm1vclxuICovXG5tb2R1bGUuZXhwb3J0cy5hcm1vciA9IHJlcXVpcmUoJy4vZW5jb2RpbmcvYXJtb3IuanMnKTtcbm1vZHVsZS5leHBvcnRzLmVudW1zID0gcmVxdWlyZSgnLi9lbnVtcy5qcycpO1xuLyoqXG4gKiBAc2VlIG1vZHVsZTpjb25maWcvY29uZmlnXG4gKiBAbW9kdWxlIGNvbmZpZ1xuICovXG5tb2R1bGUuZXhwb3J0cy5jb25maWcgPSByZXF1aXJlKCcuL2NvbmZpZy9jb25maWcuanMnKTtcbm1vZHVsZS5leHBvcnRzLmNyeXB0byA9IHJlcXVpcmUoJy4vY3J5cHRvJyk7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEByZXF1aXJlcyBjb25maWdcbiAqIEByZXF1aXJlcyBlbmNvZGluZy9hcm1vclxuICogQHJlcXVpcmVzIGVudW1zXG4gKiBAcmVxdWlyZXMgcGFja2V0XG4gKiBAbW9kdWxlIGtleVxuICovXG5cbnZhciBwYWNrZXQgPSByZXF1aXJlKCcuL3BhY2tldCcpLFxuICBlbnVtcyA9IHJlcXVpcmUoJy4vZW51bXMuanMnKSxcbiAgYXJtb3IgPSByZXF1aXJlKCcuL2VuY29kaW5nL2FybW9yLmpzJyksXG4gIGNvbmZpZyA9IHJlcXVpcmUoJy4vY29uZmlnJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIENsYXNzIHRoYXQgcmVwcmVzZW50cyBhbiBPcGVuUEdQIGtleS4gTXVzdCBjb250YWluIGEgcHJpbWFyeSBrZXkuXG4gKiBDYW4gY29udGFpbiBhZGRpdGlvbmFsIHN1YmtleXMsIHNpZ25hdHVyZXMsIHVzZXIgaWRzLCB1c2VyIGF0dHJpYnV0ZXMuXG4gKiBAcGFyYW0gIHttb2R1bGU6cGFja2V0L3BhY2tldGxpc3R9IHBhY2tldGxpc3QgVGhlIHBhY2tldHMgdGhhdCBmb3JtIHRoaXMga2V5XG4gKi9cblxuZnVuY3Rpb24gS2V5KHBhY2tldGxpc3QpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEtleSkpIHtcbiAgICByZXR1cm4gbmV3IEtleShwYWNrZXRsaXN0KTtcbiAgfVxuICAvLyBzYW1lIGRhdGEgYXMgaW4gcGFja2V0bGlzdCBidXQgaW4gc3RydWN0dXJlZCBmb3JtXG4gIHRoaXMucHJpbWFyeUtleSA9IG51bGw7XG4gIHRoaXMucmV2b2NhdGlvblNpZ25hdHVyZSA9IG51bGw7XG4gIHRoaXMuZGlyZWN0U2lnbmF0dXJlcyA9IG51bGw7XG4gIHRoaXMudXNlcnMgPSBudWxsO1xuICB0aGlzLnN1YktleXMgPSBudWxsO1xuICB0aGlzLnBhY2tldGxpc3Qyc3RydWN0dXJlKHBhY2tldGxpc3QpO1xuICBpZiAoIXRoaXMucHJpbWFyeUtleSB8fCAhdGhpcy51c2Vycykge1xuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBrZXk6IG5lZWQgYXQgbGVhc3Qga2V5IGFuZCB1c2VyIElEIHBhY2tldCcpO1xuICB9XG59XG5cbi8qKlxuICogVHJhbnNmb3JtcyBwYWNrZXRsaXN0IHRvIHN0cnVjdHVyZWQga2V5IGRhdGFcbiAqIEBwYXJhbSAge21vZHVsZTpwYWNrZXQvcGFja2V0bGlzdH0gcGFja2V0bGlzdCBUaGUgcGFja2V0cyB0aGF0IGZvcm0gYSBrZXlcbiAqL1xuS2V5LnByb3RvdHlwZS5wYWNrZXRsaXN0MnN0cnVjdHVyZSA9IGZ1bmN0aW9uKHBhY2tldGxpc3QpIHtcbiAgdmFyIHVzZXIsIHByaW1hcnlLZXlJZCwgc3ViS2V5O1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHBhY2tldGxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICBzd2l0Y2ggKHBhY2tldGxpc3RbaV0udGFnKSB7XG4gICAgICBjYXNlIGVudW1zLnBhY2tldC5wdWJsaWNfa2V5OlxuICAgICAgY2FzZSBlbnVtcy5wYWNrZXQuc2VjcmV0X2tleTpcbiAgICAgICAgdGhpcy5wcmltYXJ5S2V5ID0gcGFja2V0bGlzdFtpXTtcbiAgICAgICAgcHJpbWFyeUtleUlkID0gdGhpcy5wcmltYXJ5S2V5LmdldEtleUlkKCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBlbnVtcy5wYWNrZXQudXNlcmlkOlxuICAgICAgY2FzZSBlbnVtcy5wYWNrZXQudXNlcl9hdHRyaWJ1dGU6XG4gICAgICAgIHVzZXIgPSBuZXcgVXNlcihwYWNrZXRsaXN0W2ldKTtcbiAgICAgICAgaWYgKCF0aGlzLnVzZXJzKSB0aGlzLnVzZXJzID0gW107XG4gICAgICAgIHRoaXMudXNlcnMucHVzaCh1c2VyKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIGVudW1zLnBhY2tldC5wdWJsaWNfc3Via2V5OlxuICAgICAgY2FzZSBlbnVtcy5wYWNrZXQuc2VjcmV0X3N1YmtleTpcbiAgICAgICAgdXNlciA9IG51bGw7XG4gICAgICAgIGlmICghdGhpcy5zdWJLZXlzKSB0aGlzLnN1YktleXMgPSBbXTtcbiAgICAgICAgc3ViS2V5ID0gbmV3IFN1YktleShwYWNrZXRsaXN0W2ldKTtcbiAgICAgICAgdGhpcy5zdWJLZXlzLnB1c2goc3ViS2V5KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIGVudW1zLnBhY2tldC5zaWduYXR1cmU6XG4gICAgICAgIHN3aXRjaCAocGFja2V0bGlzdFtpXS5zaWduYXR1cmVUeXBlKSB7XG4gICAgICAgICAgY2FzZSBlbnVtcy5zaWduYXR1cmUuY2VydF9nZW5lcmljOlxuICAgICAgICAgIGNhc2UgZW51bXMuc2lnbmF0dXJlLmNlcnRfcGVyc29uYTpcbiAgICAgICAgICBjYXNlIGVudW1zLnNpZ25hdHVyZS5jZXJ0X2Nhc3VhbDpcbiAgICAgICAgICBjYXNlIGVudW1zLnNpZ25hdHVyZS5jZXJ0X3Bvc2l0aXZlOlxuICAgICAgICAgICAgaWYgKHBhY2tldGxpc3RbaV0uaXNzdWVyS2V5SWQuZXF1YWxzKHByaW1hcnlLZXlJZCkpIHtcbiAgICAgICAgICAgICAgaWYgKCF1c2VyLnNlbGZDZXJ0aWZpY2F0aW9ucykgdXNlci5zZWxmQ2VydGlmaWNhdGlvbnMgPSBbXTtcbiAgICAgICAgICAgICAgdXNlci5zZWxmQ2VydGlmaWNhdGlvbnMucHVzaChwYWNrZXRsaXN0W2ldKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGlmICghdXNlci5vdGhlckNlcnRpZmljYXRpb25zKSB1c2VyLm90aGVyQ2VydGlmaWNhdGlvbnMgPSBbXTtcbiAgICAgICAgICAgICAgdXNlci5vdGhlckNlcnRpZmljYXRpb25zLnB1c2gocGFja2V0bGlzdFtpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIGVudW1zLnNpZ25hdHVyZS5jZXJ0X3Jldm9jYXRpb246XG4gICAgICAgICAgICBpZiAodXNlcikge1xuICAgICAgICAgICAgICBpZiAoIXVzZXIucmV2b2NhdGlvbkNlcnRpZmljYXRpb25zKSB1c2VyLnJldm9jYXRpb25DZXJ0aWZpY2F0aW9ucyA9IFtdO1xuICAgICAgICAgICAgICB1c2VyLnJldm9jYXRpb25DZXJ0aWZpY2F0aW9ucy5wdXNoKHBhY2tldGxpc3RbaV0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLmRpcmVjdFNpZ25hdHVyZXMpIHRoaXMuZGlyZWN0U2lnbmF0dXJlcyA9IFtdO1xuICAgICAgICAgICAgICB0aGlzLmRpcmVjdFNpZ25hdHVyZXMucHVzaChwYWNrZXRsaXN0W2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIGNhc2UgZW51bXMuc2lnbmF0dXJlLmtleTpcbiAgICAgICAgICAgIGlmICghdGhpcy5kaXJlY3RTaWduYXR1cmVzKSB0aGlzLmRpcmVjdFNpZ25hdHVyZXMgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuZGlyZWN0U2lnbmF0dXJlcy5wdXNoKHBhY2tldGxpc3RbaV0pO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgY2FzZSBlbnVtcy5zaWduYXR1cmUuc3Via2V5X2JpbmRpbmc6XG4gICAgICAgICAgICBzdWJLZXkuYmluZGluZ1NpZ25hdHVyZSA9IHBhY2tldGxpc3RbaV07XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIGVudW1zLnNpZ25hdHVyZS5rZXlfcmV2b2NhdGlvbjpcbiAgICAgICAgICAgIHRoaXMucmV2b2NhdGlvblNpZ25hdHVyZSA9IHBhY2tldGxpc3RbaV07XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIGVudW1zLnNpZ25hdHVyZS5zdWJrZXlfcmV2b2NhdGlvbjpcbiAgICAgICAgICAgIHN1YktleS5yZXZvY2F0aW9uU2lnbmF0dXJlID0gcGFja2V0bGlzdFtpXTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiBUcmFuc2Zvcm1zIHN0cnVjdHVyZWQga2V5IGRhdGEgdG8gcGFja2V0bGlzdFxuICogQHJldHVybiB7bW9kdWxlOnBhY2tldC9wYWNrZXRsaXN0fSBUaGUgcGFja2V0cyB0aGF0IGZvcm0gYSBrZXlcbiAqL1xuS2V5LnByb3RvdHlwZS50b1BhY2tldGxpc3QgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgcGFja2V0bGlzdC5wdXNoKHRoaXMucHJpbWFyeUtleSk7XG4gIHBhY2tldGxpc3QucHVzaCh0aGlzLnJldm9jYXRpb25TaWduYXR1cmUpO1xuICBwYWNrZXRsaXN0LmNvbmNhdCh0aGlzLmRpcmVjdFNpZ25hdHVyZXMpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudXNlcnMubGVuZ3RoOyBpKyspIHtcbiAgICBwYWNrZXRsaXN0LmNvbmNhdCh0aGlzLnVzZXJzW2ldLnRvUGFja2V0bGlzdCgpKTtcbiAgfVxuICBpZiAodGhpcy5zdWJLZXlzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnN1YktleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHBhY2tldGxpc3QuY29uY2F0KHRoaXMuc3ViS2V5c1tpXS50b1BhY2tldGxpc3QoKSk7XG4gICAgfSBcbiAgfVxuICByZXR1cm4gcGFja2V0bGlzdDtcbn07XG5cbi8qKiBcbiAqIFJldHVybnMgdGhlIHByaW1hcnkga2V5IHBhY2tldCAoc2VjcmV0IG9yIHB1YmxpYylcbiAqIEByZXR1cm5zIHsobW9kdWxlOnBhY2tldC9zZWNyZXRfa2V5fG1vZHVsZTpwYWNrZXQvcHVibGljX2tleXxudWxsKX0gXG4gKi9cbktleS5wcm90b3R5cGUuZ2V0S2V5UGFja2V0ID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnByaW1hcnlLZXk7XG59O1xuXG4vKiogXG4gKiBSZXR1cm5zIGFsbCB0aGUgcHJpdmF0ZSBhbmQgcHVibGljIHN1YmtleSBwYWNrZXRzXG4gKiBAcmV0dXJucyB7QXJyYXk8KG1vZHVsZTpwYWNrZXQvcHVibGljX3N1YmtleXxtb2R1bGU6cGFja2V0L3NlY3JldF9zdWJrZXkpPn0gXG4gKi9cbktleS5wcm90b3R5cGUuZ2V0U3Via2V5UGFja2V0cyA9IGZ1bmN0aW9uKCkge1xuICB2YXIgc3ViS2V5cyA9IFtdO1xuICBpZiAodGhpcy5zdWJLZXlzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnN1YktleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHN1YktleXMucHVzaCh0aGlzLnN1YktleXNbaV0uc3ViS2V5KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHN1YktleXM7XG59O1xuXG4vKiogXG4gKiBSZXR1cm5zIGFsbCB0aGUgcHJpdmF0ZSBhbmQgcHVibGljIGtleSBhbmQgc3Via2V5IHBhY2tldHNcbiAqIEByZXR1cm5zIHtBcnJheTwobW9kdWxlOnBhY2tldC9wdWJsaWNfc3Via2V5fG1vZHVsZTpwYWNrZXQvc2VjcmV0X3N1YmtleXxtb2R1bGU6cGFja2V0L3NlY3JldF9rZXl8bW9kdWxlOnBhY2tldC9wdWJsaWNfa2V5KT59IFxuICovXG5LZXkucHJvdG90eXBlLmdldEFsbEtleVBhY2tldHMgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIFt0aGlzLmdldEtleVBhY2tldCgpXS5jb25jYXQodGhpcy5nZXRTdWJrZXlQYWNrZXRzKCkpO1xufTtcblxuLyoqIFxuICogUmV0dXJucyBrZXkgSURzIG9mIGFsbCBrZXkgcGFja2V0c1xuICogQHJldHVybnMge0FycmF5PG1vZHVsZTp0eXBlL2tleWlkPn0gXG4gKi9cbktleS5wcm90b3R5cGUuZ2V0S2V5SWRzID0gZnVuY3Rpb24oKSB7XG4gIHZhciBrZXlJZHMgPSBbXTtcbiAgdmFyIGtleXMgPSB0aGlzLmdldEFsbEtleVBhY2tldHMoKTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAga2V5SWRzLnB1c2goa2V5c1tpXS5nZXRLZXlJZCgpKTtcbiAgfVxuICByZXR1cm4ga2V5SWRzO1xufTtcblxuZnVuY3Rpb24gZmluZEtleShrZXlzLCBrZXlJZHMpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGtleUlkID0ga2V5c1tpXS5nZXRLZXlJZCgpOyBcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IGtleUlkcy5sZW5ndGg7IGorKykge1xuICAgICAgaWYgKGtleUlkLmVxdWFscyhrZXlJZHNbal0pKSB7XG4gICAgICAgIHJldHVybiBrZXlzW2ldO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGZpcnN0IHB1YmxpYyBrZXkgcGFja2V0IGZvciBnaXZlbiBhcnJheSBvZiBrZXkgSURzXG4gKiBAcGFyYW0gIHtBcnJheTxtb2R1bGU6dHlwZS9rZXlpZD59IGtleUlkcyBcbiAqIEByZXR1cm4geyhtb2R1bGU6cGFja2V0L3B1YmxpY19zdWJrZXl8bW9kdWxlOnBhY2tldC9wdWJsaWNfa2V5fG51bGwpfVxuICovXG5LZXkucHJvdG90eXBlLmdldFB1YmxpY0tleVBhY2tldCA9IGZ1bmN0aW9uKGtleUlkcykge1xuICBpZiAodGhpcy5wcmltYXJ5S2V5LnRhZyA9PSBlbnVtcy5wYWNrZXQucHVibGljX2tleSkge1xuICAgIHJldHVybiBmaW5kS2V5KHRoaXMuZ2V0QWxsS2V5UGFja2V0cygpLCBrZXlJZHMpOyAgXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH0gIFxufTtcblxuLyoqXG4gKiBSZXR1cm5zIGZpcnN0IHByaXZhdGUga2V5IHBhY2tldCBmb3IgZ2l2ZW4gYXJyYXkgb2Yga2V5IElEc1xuICogQHBhcmFtICB7QXJyYXk8bW9kdWxlOnR5cGUva2V5aWQ+fSBrZXlJZHNcbiAqIEByZXR1cm4geyhtb2R1bGU6cGFja2V0L3NlY3JldF9zdWJrZXl8bW9kdWxlOnBhY2tldC9zZWNyZXRfa2V5fG51bGwpfVxuICovXG5LZXkucHJvdG90eXBlLmdldFByaXZhdGVLZXlQYWNrZXQgPSBmdW5jdGlvbihrZXlJZHMpIHtcbiAgaWYgKHRoaXMucHJpbWFyeUtleS50YWcgPT0gZW51bXMucGFja2V0LnNlY3JldF9rZXkpIHtcbiAgICByZXR1cm4gZmluZEtleSh0aGlzLmdldEFsbEtleVBhY2tldHMoKSwga2V5SWRzKTsgIFxuICB9IGVsc2Uge1xuICAgIHJldHVybiBudWxsO1xuICB9XG59O1xuXG4vKipcbiAqIFJldHVybnMgdXNlcmlkc1xuICogQHJldHVybiB7QXJyYXk8c3RyaW5nPn0gYXJyYXkgb2YgdXNlcmlkc1xuICovXG5LZXkucHJvdG90eXBlLmdldFVzZXJJZHMgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHVzZXJpZHMgPSBbXTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnVzZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKHRoaXMudXNlcnNbaV0udXNlcklkKSB7XG4gICAgICB1c2VyaWRzLnB1c2godGhpcy51c2Vyc1tpXS51c2VySWQud3JpdGUoKSk7XG4gICAgfVxuICB9XG4gIHJldHVybiB1c2VyaWRzO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBpcyBhIHB1YmxpYyBrZXlcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbktleS5wcm90b3R5cGUuaXNQdWJsaWMgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHRoaXMucHJpbWFyeUtleS50YWcgPT0gZW51bXMucGFja2V0LnB1YmxpY19rZXk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIGlzIGEgcHJpdmF0ZSBrZXlcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbktleS5wcm90b3R5cGUuaXNQcml2YXRlID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnByaW1hcnlLZXkudGFnID09IGVudW1zLnBhY2tldC5zZWNyZXRfa2V5O1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIGtleSBhcyBwdWJsaWMga2V5IChzaGFsbG93IGNvcHkpXG4gKiBAcmV0dXJuIHttb2R1bGU6a2V5fktleX0gbmV3IHB1YmxpYyBLZXlcbiAqL1xuS2V5LnByb3RvdHlwZS50b1B1YmxpYyA9IGZ1bmN0aW9uKCkge1xuICB2YXIgcGFja2V0bGlzdCA9IG5ldyBwYWNrZXQubGlzdCgpO1xuICB2YXIga2V5UGFja2V0cyA9IHRoaXMudG9QYWNrZXRsaXN0KCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwga2V5UGFja2V0cy5sZW5ndGg7IGkrKykge1xuICAgIHN3aXRjaCAoa2V5UGFja2V0c1tpXS50YWcpIHtcbiAgICAgIGNhc2UgZW51bXMucGFja2V0LnNlY3JldF9rZXk6XG4gICAgICAgIHZhciBieXRlcyA9IGtleVBhY2tldHNbaV0ud3JpdGVQdWJsaWNLZXkoKTtcbiAgICAgICAgdmFyIHB1YktleVBhY2tldCA9IG5ldyBwYWNrZXQucHVibGljX2tleSgpO1xuICAgICAgICBwdWJLZXlQYWNrZXQucmVhZChieXRlcyk7XG4gICAgICAgIHBhY2tldGxpc3QucHVzaChwdWJLZXlQYWNrZXQpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgZW51bXMucGFja2V0LnNlY3JldF9zdWJrZXk6XG4gICAgICAgIHZhciBieXRlcyA9IGtleVBhY2tldHNbaV0ud3JpdGVQdWJsaWNLZXkoKTtcbiAgICAgICAgdmFyIHB1YlN1YmtleVBhY2tldCA9IG5ldyBwYWNrZXQucHVibGljX3N1YmtleSgpO1xuICAgICAgICBwdWJTdWJrZXlQYWNrZXQucmVhZChieXRlcyk7XG4gICAgICAgIHBhY2tldGxpc3QucHVzaChwdWJTdWJrZXlQYWNrZXQpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHBhY2tldGxpc3QucHVzaChrZXlQYWNrZXRzW2ldKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG5ldyBLZXkocGFja2V0bGlzdCk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgQVNDSUkgYXJtb3JlZCB0ZXh0IG9mIGtleVxuICogQHJldHVybiB7U3RyaW5nfSBBU0NJSSBhcm1vclxuICovXG5LZXkucHJvdG90eXBlLmFybW9yID0gZnVuY3Rpb24oKSB7XG4gIHZhciB0eXBlID0gdGhpcy5pc1B1YmxpYygpID8gZW51bXMuYXJtb3IucHVibGljX2tleSA6IGVudW1zLmFybW9yLnByaXZhdGVfa2V5O1xuICByZXR1cm4gYXJtb3IuZW5jb2RlKHR5cGUsIHRoaXMudG9QYWNrZXRsaXN0KCkud3JpdGUoKSk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgZmlyc3Qga2V5IHBhY2tldCB0aGF0IGlzIGF2YWlsYWJsZSBmb3Igc2lnbmluZ1xuICogQHJldHVybiB7KG1vZHVsZTpwYWNrZXQvc2VjcmV0X3N1YmtleXxtb2R1bGU6cGFja2V0L3NlY3JldF9rZXl8bnVsbCl9IGtleSBwYWNrZXQgb3IgbnVsbCBpZiBubyBzaWduaW5nIGtleSBoYXMgYmVlbiBmb3VuZFxuICovXG5LZXkucHJvdG90eXBlLmdldFNpZ25pbmdLZXlQYWNrZXQgPSBmdW5jdGlvbigpIHtcbiAgaWYgKHRoaXMuaXNQdWJsaWMoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignTmVlZCBwcml2YXRlIGtleSBmb3Igc2lnbmluZycpO1xuICB9XG4gIHZhciBwcmltYXJ5VXNlciA9IHRoaXMuZ2V0UHJpbWFyeVVzZXIoKTtcbiAgaWYgKHByaW1hcnlVc2VyICYmIFxuICAgICAgaXNWYWxpZFNpZ25pbmdLZXlQYWNrZXQodGhpcy5wcmltYXJ5S2V5LCBwcmltYXJ5VXNlci5zZWxmQ2VydGlmaWNhdGUpKSB7XG4gICAgcmV0dXJuIHRoaXMucHJpbWFyeUtleTtcbiAgfVxuICBpZiAodGhpcy5zdWJLZXlzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnN1YktleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh0aGlzLnN1YktleXNbaV0uaXNWYWxpZFNpZ25pbmdLZXkodGhpcy5wcmltYXJ5S2V5KSkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdWJLZXlzW2ldLnN1YktleTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59O1xuXG4vKipcbiAqIFJldHVybnMgcHJlZmVycmVkIHNpZ25hdHVyZSBoYXNoIGFsZ29yaXRobSBvZiB0aGlzIGtleVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5LZXkucHJvdG90eXBlLmdldFByZWZlcnJlZEhhc2hBbGdvcml0aG0gPSBmdW5jdGlvbigpIHtcbiAgdmFyIHByaW1hcnlVc2VyID0gdGhpcy5nZXRQcmltYXJ5VXNlcigpO1xuICBpZiAocHJpbWFyeVVzZXIgJiYgcHJpbWFyeVVzZXIuc2VsZkNlcnRpZmljYXRlLnByZWZlcnJlZEhhc2hBbGdvcml0aG1zKSB7XG4gICAgcmV0dXJuIHByaW1hcnlVc2VyLnNlbGZDZXJ0aWZpY2F0ZS5wcmVmZXJyZWRIYXNoQWxnb3JpdGhtc1swXTtcbiAgfVxuICByZXR1cm4gY29uZmlnLnByZWZlcl9oYXNoX2FsZ29yaXRobTtcbn07XG5cbmZ1bmN0aW9uIGlzVmFsaWRFbmNyeXB0aW9uS2V5UGFja2V0KGtleVBhY2tldCwgc2lnbmF0dXJlKSB7XG4gIHJldHVybiBrZXlQYWNrZXQuYWxnb3JpdGhtICE9PSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgZW51bXMucHVibGljS2V5LmRzYSkgJiZcbiAgICAgICAgIGtleVBhY2tldC5hbGdvcml0aG0gIT09IGVudW1zLnJlYWQoZW51bXMucHVibGljS2V5LCBlbnVtcy5wdWJsaWNLZXkucnNhX3NpZ24pICYmXG4gICAgICAgICAoKHNpZ25hdHVyZS5rZXlGbGFncyAmIGVudW1zLmtleUZsYWdzLmVuY3J5cHRfY29tbXVuaWNhdGlvbikgIT09IDAgfHxcbiAgICAgICAgICAoc2lnbmF0dXJlLmtleUZsYWdzICYgZW51bXMua2V5RmxhZ3MuZW5jcnlwdF9zdG9yYWdlKSAhPT0gMCB8fFxuICAgICAgICAgICFzaWduYXR1cmUua2V5RmxhZ3MpO1xufTtcblxuZnVuY3Rpb24gaXNWYWxpZFNpZ25pbmdLZXlQYWNrZXQoa2V5UGFja2V0LCBzaWduYXR1cmUpIHtcbiAgcmV0dXJuIChrZXlQYWNrZXQuYWxnb3JpdGhtID09IGVudW1zLnJlYWQoZW51bXMucHVibGljS2V5LCBlbnVtcy5wdWJsaWNLZXkuZHNhKSB8fFxuICAgICAgICAgIGtleVBhY2tldC5hbGdvcml0aG0gPT0gZW51bXMucmVhZChlbnVtcy5wdWJsaWNLZXksIGVudW1zLnB1YmxpY0tleS5yc2Ffc2lnbikgfHxcbiAgICAgICAgICBrZXlQYWNrZXQuYWxnb3JpdGhtID09IGVudW1zLnJlYWQoZW51bXMucHVibGljS2V5LCBlbnVtcy5wdWJsaWNLZXkucnNhX2VuY3J5cHRfc2lnbikpICYmXG4gICAgICAgICAoKHNpZ25hdHVyZS5rZXlGbGFncyAmIGVudW1zLmtleUZsYWdzLnNpZ25fZGF0YSkgIT09IDAgfHxcbiAgICAgICAgICAhc2lnbmF0dXJlLmtleUZsYWdzKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyB0aGUgZmlyc3QgdmFsaWQgZW5jcnlwdGlvbiBrZXkgcGFja2V0IGZvciB0aGlzIGtleVxuICogQHJldHVybnMgeyhtb2R1bGU6cGFja2V0L3B1YmxpY19zdWJrZXl8bW9kdWxlOnBhY2tldC9zZWNyZXRfc3Via2V5fG1vZHVsZTpwYWNrZXQvc2VjcmV0X2tleXxtb2R1bGU6cGFja2V0L3B1YmxpY19rZXl8bnVsbCl9IGtleSBwYWNrZXQgb3IgbnVsbCBpZiBubyBlbmNyeXB0aW9uIGtleSBoYXMgYmVlbiBmb3VuZFxuICovXG5LZXkucHJvdG90eXBlLmdldEVuY3J5cHRpb25LZXlQYWNrZXQgPSBmdW5jdGlvbigpIHtcbiAgLy8gVjQ6IGJ5IGNvbnZlbnRpb24gc3Via2V5cyBhcmUgcHJlZmVyZWQgZm9yIGVuY3J5cHRpb24gc2VydmljZVxuICAvLyBWMzoga2V5cyBNVVNUIE5PVCBoYXZlIHN1YmtleXNcbiAgaWYgKHRoaXMuc3ViS2V5cykge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5zdWJLZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAodGhpcy5zdWJLZXlzW2ldLmlzVmFsaWRFbmNyeXB0aW9uS2V5KHRoaXMucHJpbWFyeUtleSkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3ViS2V5c1tpXS5zdWJLZXk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIC8vIGlmIG5vIHZhbGlkIHN1YmtleSBmb3IgZW5jcnlwdGlvbiwgZXZhbHVhdGUgcHJpbWFyeSBrZXlcbiAgdmFyIHByaW1hcnlVc2VyID0gdGhpcy5nZXRQcmltYXJ5VXNlcigpO1xuICBpZiAocHJpbWFyeVVzZXIgJiYgXG4gICAgICBpc1ZhbGlkRW5jcnlwdGlvbktleVBhY2tldCh0aGlzLnByaW1hcnlLZXksIHByaW1hcnlVc2VyLnNlbGZDZXJ0aWZpY2F0ZSkpIHtcbiAgICByZXR1cm4gdGhpcy5wcmltYXJ5S2V5O1xuICB9XG4gIHJldHVybiBudWxsO1xufTtcblxuLyoqXG4gKiBEZWNyeXB0cyBhbGwgc2VjcmV0IGtleSBhbmQgc3Via2V5IHBhY2tldHNcbiAqIEBwYXJhbSAge1N0cmluZ30gcGFzc3BocmFzZSBcbiAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUgaWYgYWxsIGtleSBhbmQgc3Via2V5IHBhY2tldHMgZGVjcnlwdGVkIHN1Y2Nlc3NmdWxseVxuICovXG5LZXkucHJvdG90eXBlLmRlY3J5cHQgPSBmdW5jdGlvbihwYXNzcGhyYXNlKSB7XG4gIGlmICh0aGlzLmlzUHJpdmF0ZSgpKSB7XG4gICAgdmFyIGtleXMgPSB0aGlzLmdldEFsbEtleVBhY2tldHMoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBzdWNjZXNzID0ga2V5c1tpXS5kZWNyeXB0KHBhc3NwaHJhc2UpO1xuICAgICAgaWYgKCFzdWNjZXNzKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBFcnJvcihcIk5vdGhpbmcgdG8gZGVjcnlwdCBpbiBhIHB1YmxpYyBrZXlcIik7XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59O1xuXG4vKipcbiAqIERlY3J5cHRzIHNwZWNpZmljIGtleSBwYWNrZXRzIGJ5IGtleSBJRFxuICogQHBhcmFtICB7QXJyYXk8bW9kdWxlOnR5cGUva2V5aWQ+fSBrZXlJZHNcbiAqIEBwYXJhbSAge1N0cmluZ30gcGFzc3BocmFzZSBcbiAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUgaWYgYWxsIGtleSBwYWNrZXRzIGRlY3J5cHRlZCBzdWNjZXNzZnVsbHlcbiAqL1xuS2V5LnByb3RvdHlwZS5kZWNyeXB0S2V5UGFja2V0ID0gZnVuY3Rpb24oa2V5SWRzLCBwYXNzcGhyYXNlKSB7XG4gIGlmICh0aGlzLmlzUHJpdmF0ZSgpKSB7XG4gICAgdmFyIGtleXMgPSB0aGlzLmdldEFsbEtleVBhY2tldHMoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBrZXlJZCA9IGtleXNbaV0uZ2V0S2V5SWQoKTsgXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGtleUlkcy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoa2V5SWQuZXF1YWxzKGtleUlkc1tqXSkpIHtcbiAgICAgICAgICB2YXIgc3VjY2VzcyA9IGtleXNbaV0uZGVjcnlwdChwYXNzcGhyYXNlKTtcbiAgICAgICAgICBpZiAoIXN1Y2Nlc3MpIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJOb3RoaW5nIHRvIGRlY3J5cHQgaW4gYSBwdWJsaWMga2V5XCIpO1xuICB9XG4gIHJldHVybiB0cnVlO1xufTtcblxuLyoqXG4gKiBWZXJpZnkgcHJpbWFyeSBrZXkuIENoZWNrcyBmb3IgcmV2b2NhdGlvbiBzaWduYXR1cmVzLCBleHBpcmF0aW9uIHRpbWVcbiAqIGFuZCB2YWxpZCBzZWxmIHNpZ25hdHVyZVxuICogQHJldHVybiB7bW9kdWxlOmVudW1zLmtleVN0YXR1c30gVGhlIHN0YXR1cyBvZiB0aGUgcHJpbWFyeSBrZXlcbiAqL1xuS2V5LnByb3RvdHlwZS52ZXJpZnlQcmltYXJ5S2V5ID0gZnVuY3Rpb24oKSB7XG4gIC8vIGNoZWNrIHJldm9jYXRpb24gc2lnbmF0dXJlXG4gIGlmICh0aGlzLnJldm9jYXRpb25TaWduYXR1cmUgJiYgIXRoaXMucmV2b2NhdGlvblNpZ25hdHVyZS5pc0V4cGlyZWQoKSAmJiBcbiAgICAgKHRoaXMucmV2b2NhdGlvblNpZ25hdHVyZS52ZXJpZmllZCB8fCBcbiAgICAgIHRoaXMucmV2b2NhdGlvblNpZ25hdHVyZS52ZXJpZnkodGhpcy5wcmltYXJ5S2V5LCB7a2V5OiB0aGlzLnByaW1hcnlLZXl9KSkpIHtcbiAgICByZXR1cm4gZW51bXMua2V5U3RhdHVzLnJldm9rZWQ7XG4gIH1cbiAgLy8gY2hlY2sgVjMgZXhwaXJhdGlvbiB0aW1lXG4gIGlmICh0aGlzLnByaW1hcnlLZXkudmVyc2lvbiA9PSAzICYmIHRoaXMucHJpbWFyeUtleS5leHBpcmF0aW9uVGltZVYzICE9PSAwICYmXG4gICAgRGF0ZS5ub3coKSA+ICh0aGlzLnByaW1hcnlLZXkuY3JlYXRlZC5nZXRUaW1lKCkgKyB0aGlzLnByaW1hcnlLZXkuZXhwaXJhdGlvblRpbWVWMyoyNCozNjAwKjEwMDApKSB7XG4gICAgcmV0dXJuIGVudW1zLmtleVN0YXR1cy5leHBpcmVkO1xuICB9XG4gIC8vIGNoZWNrIGZvciBhdCBsZWFzdCBvbmUgc2VsZiBzaWduYXR1cmUuIFNlbGYgc2lnbmF0dXJlIG9mIHVzZXIgSUQgbm90IG1hbmRhdG9yeVxuICAvLyBTZWUgaHR0cDovL3Rvb2xzLmlldGYub3JnL2h0bWwvcmZjNDg4MCNzZWN0aW9uLTExLjFcbiAgdmFyIHNlbGZTaWduZWQgPSBmYWxzZTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnVzZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKHRoaXMudXNlcnNbaV0udXNlcklkICYmIHRoaXMudXNlcnNbaV0uc2VsZkNlcnRpZmljYXRpb25zKSB7XG4gICAgICBzZWxmU2lnbmVkID0gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgaWYgKCFzZWxmU2lnbmVkKSB7XG4gICAgcmV0dXJuIGVudW1zLmtleVN0YXR1cy5ub19zZWxmX2NlcnQ7XG4gIH1cbiAgLy8gY2hlY2sgZm9yIHZhbGlkIHNlbGYgc2lnbmF0dXJlXG4gIHZhciBwcmltYXJ5VXNlciA9IHRoaXMuZ2V0UHJpbWFyeVVzZXIoKTtcbiAgaWYgKCFwcmltYXJ5VXNlcikge1xuICAgIHJldHVybiBlbnVtcy5rZXlTdGF0dXMuaW52YWxpZDtcbiAgfVxuICAvLyBjaGVjayBWNCBleHBpcmF0aW9uIHRpbWVcbiAgaWYgKHRoaXMucHJpbWFyeUtleS52ZXJzaW9uID09IDQgJiYgcHJpbWFyeVVzZXIuc2VsZkNlcnRpZmljYXRlLmtleU5ldmVyRXhwaXJlcyA9PT0gZmFsc2UgJiZcbiAgICBEYXRlLm5vdygpID4gKHByaW1hcnlVc2VyLnNlbGZDZXJ0aWZpY2F0ZS5jcmVhdGVkLmdldFRpbWUoKSArIHByaW1hcnlVc2VyLnNlbGZDZXJ0aWZpY2F0ZS5rZXlFeHBpcmF0aW9uVGltZSoxMDAwKSkge1xuICAgIHJldHVybiBlbnVtcy5rZXlTdGF0dXMuZXhwaXJlZDtcbiAgfVxuICByZXR1cm4gZW51bXMua2V5U3RhdHVzLnZhbGlkO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHByaW1hcnkgdXNlciBhbmQgbW9zdCBzaWduaWZpY2FudCAobGF0ZXN0IHZhbGlkKSBzZWxmIHNpZ25hdHVyZVxuICogLSBpZiBtdWx0aXBsZSB1c2VycyBhcmUgbWFya2VkIGFzIHByaW1hcnkgdXNlcnMgcmV0dXJucyB0aGUgb25lIHdpdGggdGhlIGxhdGVzdCBzZWxmIHNpZ25hdHVyZVxuICogLSBpZiBubyBwcmltYXJ5IHVzZXIgaXMgZm91bmQgcmV0dXJucyB0aGUgdXNlciB3aXRoIHRoZSBsYXRlc3Qgc2VsZiBzaWduYXR1cmVcbiAqIEByZXR1cm4ge3t1c2VyOiBBcnJheTxtb2R1bGU6cGFja2V0L1VzZXI+LCBzZWxmQ2VydGlmaWNhdGU6IEFycmF5PG1vZHVsZTpwYWNrZXQvc2lnbmF0dXJlPn19IFRoZSBwcmltYXJ5IHVzZXIgYW5kIHRoZSBzZWxmIHNpZ25hdHVyZVxuICovXG5LZXkucHJvdG90eXBlLmdldFByaW1hcnlVc2VyID0gZnVuY3Rpb24oKSB7XG4gIHZhciB1c2VyID0gbnVsbDtcbiAgdmFyIHVzZXJTZWxmQ2VydDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnVzZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKCF0aGlzLnVzZXJzW2ldLnVzZXJJZCkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHZhciBzZWxmQ2VydCA9IHRoaXMudXNlcnNbaV0uZ2V0VmFsaWRTZWxmQ2VydGlmaWNhdGUodGhpcy5wcmltYXJ5S2V5KTtcbiAgICBpZiAoIXNlbGZDZXJ0KSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKCF1c2VyIHx8IFxuICAgICAgICAhdXNlclNlbGZDZXJ0LmlzUHJpbWFyeVVzZXJJRCAmJiBzZWxmQ2VydC5pc1ByaW1hcnlVc2VySUQgfHxcbiAgICAgICAgIHVzZXJTZWxmQ2VydC5jcmVhdGVkIDwgc2VsZkNlcnQuY3JlYXRlZCkge1xuICAgICAgdXNlciA9IHRoaXMudXNlcnNbaV07XG4gICAgICB1c2VyU2VsZkNlcnQgPSBzZWxmQ2VydDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHVzZXIgPyB7dXNlcjogdXNlciwgc2VsZkNlcnRpZmljYXRlOiB1c2VyU2VsZkNlcnR9IDogbnVsbDtcbn1cblxuLy8gVE9ET1xuS2V5LnByb3RvdHlwZS5yZXZva2UgPSBmdW5jdGlvbigpIHtcblxufTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgQ2xhc3MgdGhhdCByZXByZXNlbnRzIGFuIHVzZXIgSUQgb3IgYXR0cmlidXRlIHBhY2tldCBhbmQgdGhlIHJlbGV2YW50IHNpZ25hdHVyZXMuXG4gKi9cbmZ1bmN0aW9uIFVzZXIodXNlclBhY2tldCkge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgVXNlcikpIHtcbiAgICByZXR1cm4gbmV3IFVzZXIodXNlclBhY2tldCk7XG4gIH1cbiAgdGhpcy51c2VySWQgPSB1c2VyUGFja2V0LnRhZyA9PSBlbnVtcy5wYWNrZXQudXNlcmlkID8gdXNlclBhY2tldCA6IG51bGw7XG4gIHRoaXMudXNlckF0dHJpYnV0ZSA9IHVzZXJQYWNrZXQudGFnID09IGVudW1zLnBhY2tldC51c2VyX2F0dHJpYnV0ZSA/IHVzZXJQYWNrZXQgOiBudWxsXG4gIHRoaXMuc2VsZkNlcnRpZmljYXRpb25zID0gbnVsbDtcbiAgdGhpcy5vdGhlckNlcnRpZmljYXRpb25zID0gbnVsbDtcbiAgdGhpcy5yZXZvY2F0aW9uQ2VydGlmaWNhdGlvbnMgPSBudWxsO1xufVxuXG4vKipcbiAqIFRyYW5zZm9ybXMgc3RydWN0dXJlZCB1c2VyIGRhdGEgdG8gcGFja2V0bGlzdFxuICogQHJldHVybiB7bW9kdWxlOnBhY2tldC9wYWNrZXRsaXN0fVxuICovXG5Vc2VyLnByb3RvdHlwZS50b1BhY2tldGxpc3QgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgcGFja2V0bGlzdC5wdXNoKHRoaXMudXNlcklkIHx8IHRoaXMudXNlckF0dHJpYnV0ZSk7XG4gIHBhY2tldGxpc3QuY29uY2F0KHRoaXMucmV2b2NhdGlvbkNlcnRpZmljYXRpb25zKTtcbiAgcGFja2V0bGlzdC5jb25jYXQodGhpcy5zZWxmQ2VydGlmaWNhdGlvbnMpO1xuICBwYWNrZXRsaXN0LmNvbmNhdCh0aGlzLm90aGVyQ2VydGlmaWNhdGlvbnMpO1xuICByZXR1cm4gcGFja2V0bGlzdDtcbn07XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgc2VsZiBzaWduYXR1cmUgb2YgdGhlIHVzZXIgaXMgcmV2b2tlZFxuICogQHBhcmFtICB7bW9kdWxlOnBhY2tldC9zaWduYXR1cmV9ICAgICAgICAgICAgICAgICAgICBjZXJ0aWZpY2F0ZVxuICogQHBhcmFtICB7bW9kdWxlOnBhY2tldC9zZWNyZXRfa2V5fG1vZHVsZTpwYWNrZXQvcHVibGljX2tleX0gcHJpbWFyeUtleSAgVGhlIHByaW1hcnkga2V5IHBhY2tldFxuICogQHJldHVybiB7Qm9vbGVhbn0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRydWUgaWYgdGhlIGNlcnRpZmljYXRlIGlzIHJldm9rZWRcbiAqL1xuVXNlci5wcm90b3R5cGUuaXNSZXZva2VkID0gZnVuY3Rpb24oY2VydGlmaWNhdGUsIHByaW1hcnlLZXkpIHtcbiAgaWYgKHRoaXMucmV2b2NhdGlvbkNlcnRpZmljYXRpb25zKSB7XG4gICAgdmFyIHRoYXQgPSB0aGlzO1xuICAgIHJldHVybiB0aGlzLnJldm9jYXRpb25DZXJ0aWZpY2F0aW9ucy5zb21lKGZ1bmN0aW9uKHJldkNlcnQpIHtcbiAgICAgICAgICAgICByZXR1cm4gcmV2Q2VydC5pc3N1ZXJLZXlJZC5lcXVhbHMoY2VydGlmaWNhdGUuaXNzdWVyS2V5SWQpICYmXG4gICAgICAgICAgICAgICAgICAgICFyZXZDZXJ0LmlzRXhwaXJlZCgpICYmIFxuICAgICAgICAgICAgICAgICAgICAocmV2Q2VydC52ZXJpZmllZCB8fCBcbiAgICAgICAgICAgICAgICAgICAgIHJldkNlcnQudmVyaWZ5KHByaW1hcnlLZXksIHt1c2VyaWQ6IHRoYXQudXNlcklkIHx8IHRoYXQudXNlckF0dHJpYnV0ZSwga2V5OiBwcmltYXJ5S2V5fSkpO1xuICAgICAgICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBtb3N0IHNpZ25pZmljYW50IChsYXRlc3QgdmFsaWQpIHNlbGYgc2lnbmF0dXJlIG9mIHRoZSB1c2VyXG4gKiBAcGFyYW0gIHttb2R1bGU6cGFja2V0L3NlY3JldF9rZXl8bW9kdWxlOnBhY2tldC9wdWJsaWNfa2V5fSBwcmltYXJ5S2V5IFRoZSBwcmltYXJ5IGtleSBwYWNrZXRcbiAqIEByZXR1cm4ge21vZHVsZTpwYWNrZXQvc2lnbmF0dXJlfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGUgc2VsZiBzaWduYXR1cmVcbiAqL1xuVXNlci5wcm90b3R5cGUuZ2V0VmFsaWRTZWxmQ2VydGlmaWNhdGUgPSBmdW5jdGlvbihwcmltYXJ5S2V5KSB7XG4gIGlmICghdGhpcy5zZWxmQ2VydGlmaWNhdGlvbnMpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICB2YXIgdmFsaWRDZXJ0ID0gW107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5zZWxmQ2VydGlmaWNhdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAodGhpcy5pc1Jldm9rZWQodGhpcy5zZWxmQ2VydGlmaWNhdGlvbnNbaV0sIHByaW1hcnlLZXkpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnNlbGZDZXJ0aWZpY2F0aW9uc1tpXS5pc0V4cGlyZWQoKSAmJlxuICAgICAgICh0aGlzLnNlbGZDZXJ0aWZpY2F0aW9uc1tpXS52ZXJpZmllZCB8fCBcbiAgICAgICAgdGhpcy5zZWxmQ2VydGlmaWNhdGlvbnNbaV0udmVyaWZ5KHByaW1hcnlLZXksIHt1c2VyaWQ6IHRoaXMudXNlcklkIHx8IHRoaXMudXNlckF0dHJpYnV0ZSwga2V5OiBwcmltYXJ5S2V5fSkpKSB7XG4gICAgICB2YWxpZENlcnQucHVzaCh0aGlzLnNlbGZDZXJ0aWZpY2F0aW9uc1tpXSk7XG4gICAgfVxuICB9XG4gIC8vIG1vc3QgcmVjZW50IGZpcnN0XG4gIHZhbGlkQ2VydCA9IHZhbGlkQ2VydC5zb3J0KGZ1bmN0aW9uKGEsIGIpIHtcbiAgICBhID0gYS5jcmVhdGVkO1xuICAgIGIgPSBiLmNyZWF0ZWQ7XG4gICAgcmV0dXJuIGE+YiA/IC0xIDogYTxiID8gMSA6IDA7XG4gIH0pO1xuICByZXR1cm4gdmFsaWRDZXJ0WzBdO1xufTtcblxuLyoqXG4gKiBWZXJpZnkgVXNlci4gQ2hlY2tzIGZvciBleGlzdGVuY2Ugb2Ygc2VsZiBzaWduYXR1cmVzLCByZXZvY2F0aW9uIHNpZ25hdHVyZXNcbiAqIGFuZCB2YWxpZGl0eSBvZiBzZWxmIHNpZ25hdHVyZVxuICogQHBhcmFtICB7bW9kdWxlOnBhY2tldC9zZWNyZXRfa2V5fG1vZHVsZTpwYWNrZXQvcHVibGljX2tleX0gcHJpbWFyeUtleSBUaGUgcHJpbWFyeSBrZXkgcGFja2V0XG4gKiBAcmV0dXJuIHttb2R1bGU6ZW51bXMua2V5U3RhdHVzfSBzdGF0dXMgb2YgdXNlciAgICBcbiAqL1xuVXNlci5wcm90b3R5cGUudmVyaWZ5ID0gZnVuY3Rpb24ocHJpbWFyeUtleSkge1xuICBpZiAoIXRoaXMuc2VsZkNlcnRpZmljYXRpb25zKSB7XG4gICAgcmV0dXJuIGVudW1zLmtleVN0YXR1cy5ub19zZWxmX2NlcnQ7XG4gIH1cbiAgdmFyIHN0YXR1cztcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnNlbGZDZXJ0aWZpY2F0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgIGlmICh0aGlzLmlzUmV2b2tlZCh0aGlzLnNlbGZDZXJ0aWZpY2F0aW9uc1tpXSwgcHJpbWFyeUtleSkpIHtcbiAgICAgIHN0YXR1cyA9IGVudW1zLmtleVN0YXR1cy5yZXZva2VkO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGlmICghKHRoaXMuc2VsZkNlcnRpZmljYXRpb25zW2ldLnZlcmlmaWVkIHx8IFxuICAgICAgICB0aGlzLnNlbGZDZXJ0aWZpY2F0aW9uc1tpXS52ZXJpZnkocHJpbWFyeUtleSwge3VzZXJpZDogdGhpcy51c2VySWQgfHwgdGhpcy51c2VyQXR0cmlidXRlLCBrZXk6IHByaW1hcnlLZXl9KSkpIHtcbiAgICAgIHN0YXR1cyA9IGVudW1zLmtleVN0YXR1cy5pbnZhbGlkO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGlmICh0aGlzLnNlbGZDZXJ0aWZpY2F0aW9uc1tpXS5pc0V4cGlyZWQoKSkge1xuICAgICAgc3RhdHVzID0gZW51bXMua2V5U3RhdHVzLmV4cGlyZWQ7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgc3RhdHVzID0gZW51bXMua2V5U3RhdHVzLnZhbGlkO1xuICAgIGJyZWFrO1xuICB9XG4gIHJldHVybiBzdGF0dXM7XG59O1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBDbGFzcyB0aGF0IHJlcHJlc2VudHMgYSBzdWJrZXkgcGFja2V0IGFuZCB0aGUgcmVsZXZhbnQgc2lnbmF0dXJlcy5cbiAqL1xuZnVuY3Rpb24gU3ViS2V5KHN1YktleVBhY2tldCkge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgU3ViS2V5KSkge1xuICAgIHJldHVybiBuZXcgU3ViS2V5KHN1YktleVBhY2tldCk7XG4gIH1cbiAgdGhpcy5zdWJLZXkgPSBzdWJLZXlQYWNrZXQ7XG4gIHRoaXMuYmluZGluZ1NpZ25hdHVyZSA9IG51bGw7XG4gIHRoaXMucmV2b2NhdGlvblNpZ25hdHVyZSA9IG51bGw7XG59XG5cbi8qKlxuICogVHJhbnNmb3JtcyBzdHJ1Y3R1cmVkIHN1YmtleSBkYXRhIHRvIHBhY2tldGxpc3RcbiAqIEByZXR1cm4ge21vZHVsZTpwYWNrZXQvcGFja2V0bGlzdH1cbiAqL1xuU3ViS2V5LnByb3RvdHlwZS50b1BhY2tldGxpc3QgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgcGFja2V0bGlzdC5wdXNoKHRoaXMuc3ViS2V5KTtcbiAgcGFja2V0bGlzdC5wdXNoKHRoaXMucmV2b2NhdGlvblNpZ25hdHVyZSk7XG4gIHBhY2tldGxpc3QucHVzaCh0aGlzLmJpbmRpbmdTaWduYXR1cmUpO1xuICByZXR1cm4gcGFja2V0bGlzdDtcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIHRoZSBzdWJrZXkgY2FuIGJlIHVzZWQgZm9yIGVuY3J5cHRpb25cbiAqIEBwYXJhbSAge21vZHVsZTpwYWNrZXQvc2VjcmV0X2tleXxtb2R1bGU6cGFja2V0L3B1YmxpY19rZXl9ICBwcmltYXJ5S2V5IFRoZSBwcmltYXJ5IGtleSBwYWNrZXRcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cblN1YktleS5wcm90b3R5cGUuaXNWYWxpZEVuY3J5cHRpb25LZXkgPSBmdW5jdGlvbihwcmltYXJ5S2V5KSB7XG4gIHJldHVybiB0aGlzLnZlcmlmeShwcmltYXJ5S2V5KSA9PSBlbnVtcy5rZXlTdGF0dXMudmFsaWQgJiZcbiAgICAgICAgIGlzVmFsaWRFbmNyeXB0aW9uS2V5UGFja2V0KHRoaXMuc3ViS2V5LCB0aGlzLmJpbmRpbmdTaWduYXR1cmUpO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgdGhlIHN1YmtleSBjYW4gYmUgdXNlZCBmb3Igc2lnbmluZyBvZiBkYXRhXG4gKiBAcGFyYW0gIHttb2R1bGU6cGFja2V0L3NlY3JldF9rZXl8bW9kdWxlOnBhY2tldC9wdWJsaWNfa2V5fSAgcHJpbWFyeUtleSBUaGUgcHJpbWFyeSBrZXkgcGFja2V0XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5TdWJLZXkucHJvdG90eXBlLmlzVmFsaWRTaWduaW5nS2V5ID0gZnVuY3Rpb24ocHJpbWFyeUtleSkge1xuICByZXR1cm4gdGhpcy52ZXJpZnkocHJpbWFyeUtleSkgPT0gZW51bXMua2V5U3RhdHVzLnZhbGlkICYmXG4gICAgICAgICBpc1ZhbGlkU2lnbmluZ0tleVBhY2tldCh0aGlzLnN1YktleSwgdGhpcy5iaW5kaW5nU2lnbmF0dXJlKTtcbn07XG5cbi8qKlxuICogVmVyaWZ5IHN1YmtleS4gQ2hlY2tzIGZvciByZXZvY2F0aW9uIHNpZ25hdHVyZXMsIGV4cGlyYXRpb24gdGltZVxuICogYW5kIHZhbGlkIGJpbmRpbmcgc2lnbmF0dXJlXG4gKiBAcmV0dXJuIHttb2R1bGU6ZW51bXMua2V5U3RhdHVzfSBUaGUgc3RhdHVzIG9mIHRoZSBzdWJrZXlcbiAqL1xuU3ViS2V5LnByb3RvdHlwZS52ZXJpZnkgPSBmdW5jdGlvbihwcmltYXJ5S2V5KSB7XG4gIC8vIGNoZWNrIHN1YmtleSByZXZvY2F0aW9uIHNpZ25hdHVyZVxuICBpZiAodGhpcy5yZXZvY2F0aW9uU2lnbmF0dXJlICYmICF0aGlzLnJldm9jYXRpb25TaWduYXR1cmUuaXNFeHBpcmVkKCkgJiYgXG4gICAgICh0aGlzLnJldm9jYXRpb25TaWduYXR1cmUudmVyaWZpZWQgfHwgXG4gICAgICB0aGlzLnJldm9jYXRpb25TaWduYXR1cmUudmVyaWZ5KHByaW1hcnlLZXksIHtrZXk6IHRoaXMuc3ViS2V5fSkpKSB7XG4gICAgcmV0dXJuIGVudW1zLmtleVN0YXR1cy5yZXZva2VkO1xuICB9XG4gIC8vIGNoZWNrIFYzIGV4cGlyYXRpb24gdGltZVxuICBpZiAodGhpcy5zdWJLZXkudmVyc2lvbiA9PSAzICYmIHRoaXMuc3ViS2V5LmV4cGlyYXRpb25UaW1lVjMgIT09IDAgJiZcbiAgICAgIERhdGUubm93KCkgPiAodGhpcy5zdWJLZXkuY3JlYXRlZC5nZXRUaW1lKCkgKyB0aGlzLnN1YktleS5leHBpcmF0aW9uVGltZVYzKjI0KjM2MDAqMTAwMCkpIHtcbiAgICByZXR1cm4gZW51bXMua2V5U3RhdHVzLmV4cGlyZWQ7XG4gIH1cbiAgLy8gY2hlY2sgc3Via2V5IGJpbmRpbmcgc2lnbmF0dXJlXG4gIGlmICghdGhpcy5iaW5kaW5nU2lnbmF0dXJlKSB7XG4gICAgcmV0dXJuIGVudW1zLmtleVN0YXR1cy5pbnZhbGlkO1xuICB9XG4gIGlmICh0aGlzLmJpbmRpbmdTaWduYXR1cmUuaXNFeHBpcmVkKCkpIHtcbiAgICByZXR1cm4gZW51bXMua2V5U3RhdHVzLmV4cGlyZWQ7XG4gIH1cbiAgaWYgKCEodGhpcy5iaW5kaW5nU2lnbmF0dXJlLnZlcmlmaWVkIHx8XG4gICAgICAgIHRoaXMuYmluZGluZ1NpZ25hdHVyZS52ZXJpZnkocHJpbWFyeUtleSwge2tleTogcHJpbWFyeUtleSwgYmluZDogdGhpcy5zdWJLZXl9KSkpIHtcbiAgICByZXR1cm4gZW51bXMua2V5U3RhdHVzLmludmFsaWQ7XG4gIH1cbiAgLy8gY2hlY2sgVjQgZXhwaXJhdGlvbiB0aW1lXG4gIGlmICh0aGlzLnN1YktleS52ZXJzaW9uID09IDQgJiZcbiAgICAgIHRoaXMuYmluZGluZ1NpZ25hdHVyZS5rZXlOZXZlckV4cGlyZXMgPT09IGZhbHNlICYmXG4gICAgICBEYXRlLm5vdygpID4gKHRoaXMuc3ViS2V5LmNyZWF0ZWQuZ2V0VGltZSgpICsgdGhpcy5iaW5kaW5nU2lnbmF0dXJlLmtleUV4cGlyYXRpb25UaW1lKjEwMDApKSB7XG4gICAgcmV0dXJuIGVudW1zLmtleVN0YXR1cy5leHBpcmVkO1xuICB9XG4gIHJldHVybiBlbnVtcy5rZXlTdGF0dXMudmFsaWQ7XG59O1xuXG4vKipcbiAqIFJlYWRzIGFuIE9wZW5QR1AgYXJtb3JlZCB0ZXh0IGFuZCByZXR1cm5zIG9uZSBvciBtdWx0aXBsZSBrZXkgb2JqZWN0c1xuICogQHBhcmFtIHtTdHJpbmd9IGFybW9yZWRUZXh0IHRleHQgdG8gYmUgcGFyc2VkXG4gKiBAcmV0dXJuIHt7a2V5czogQXJyYXk8bW9kdWxlOmtleX5LZXk+LCBlcnI6IChBcnJheTxFcnJvcj58bnVsbCl9fSByZXN1bHQgb2JqZWN0IHdpdGgga2V5IGFuZCBlcnJvciBhcnJheXNcbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gcmVhZEFybW9yZWQoYXJtb3JlZFRleHQpIHtcbiAgdmFyIHJlc3VsdCA9IHt9O1xuICByZXN1bHQua2V5cyA9IFtdO1xuICB0cnkge1xuICAgIHZhciBpbnB1dCA9IGFybW9yLmRlY29kZShhcm1vcmVkVGV4dCk7XG4gICAgaWYgKCEoaW5wdXQudHlwZSA9PSBlbnVtcy5hcm1vci5wdWJsaWNfa2V5IHx8IGlucHV0LnR5cGUgPT0gZW51bXMuYXJtb3IucHJpdmF0ZV9rZXkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FybW9yZWQgdGV4dCBub3Qgb2YgdHlwZSBrZXknKTtcbiAgICB9XG4gICAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgICBwYWNrZXRsaXN0LnJlYWQoaW5wdXQuZGF0YSk7XG4gICAgdmFyIGtleUluZGV4ID0gcGFja2V0bGlzdC5pbmRleE9mVGFnKGVudW1zLnBhY2tldC5wdWJsaWNfa2V5LCBlbnVtcy5wYWNrZXQuc2VjcmV0X2tleSk7XG4gICAgaWYgKGtleUluZGV4Lmxlbmd0aCA9PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGtleSBwYWNrZXQgZm91bmQgaW4gYXJtb3JlZCB0ZXh0JylcbiAgICB9XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBrZXlJbmRleC5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIG9uZUtleUxpc3QgPSBwYWNrZXRsaXN0LnNsaWNlKGtleUluZGV4W2ldLCBrZXlJbmRleFtpICsgMV0pO1xuICAgICAgdHJ5IHtcbiAgICAgICAgdmFyIG5ld0tleSA9IG5ldyBLZXkob25lS2V5TGlzdCk7XG4gICAgICAgIHJlc3VsdC5rZXlzLnB1c2gobmV3S2V5KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVzdWx0LmVyciA9IHJlc3VsdC5lcnIgfHwgW107XG4gICAgICAgIHJlc3VsdC5lcnIucHVzaChlKTsgXG4gICAgICB9XG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgcmVzdWx0LmVyciA9IHJlc3VsdC5lcnIgfHwgW107XG4gICAgcmVzdWx0LmVyci5wdXNoKGUpOyBcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIG5ldyBPcGVuUEdQIGtleS4gQ3VycmVudGx5IG9ubHkgc3VwcG9ydHMgUlNBIGtleXMuXG4gKiBQcmltYXJ5IGFuZCBzdWJrZXkgd2lsbCBiZSBvZiBzYW1lIHR5cGUuXG4gKiBAcGFyYW0ge0ludGVnZXJ9IGtleVR5cGUgICAgdG8gaW5kaWNhdGUgd2hhdCB0eXBlIG9mIGtleSB0byBtYWtlLiBcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSU0EgaXMgMS4gU2VlIGh0dHA6Ly90b29scy5pZXRmLm9yZy9odG1sL3JmYzQ4ODAjc2VjdGlvbi05LjFcbiAqIEBwYXJhbSB7SW50ZWdlcn0gbnVtQml0cyAgICBudW1iZXIgb2YgYml0cyBmb3IgdGhlIGtleSBjcmVhdGlvbi5cbiAqIEBwYXJhbSB7U3RyaW5nfSAgdXNlcklkICAgICBhc3N1bWVzIGFscmVhZHkgaW4gZm9ybSBvZiBcIlVzZXIgTmFtZSA8dXNlcm5hbWVAZW1haWwuY29tPlwiXG4gKiBAcGFyYW0ge1N0cmluZ30gIHBhc3NwaHJhc2UgVGhlIHBhc3NwaHJhc2UgdXNlZCB0byBlbmNyeXB0IHRoZSByZXN1bHRpbmcgcHJpdmF0ZSBrZXlcbiAqIEByZXR1cm4ge21vZHVsZTprZXl+S2V5fVxuICogQHN0YXRpY1xuICovXG5mdW5jdGlvbiBnZW5lcmF0ZShrZXlUeXBlLCBudW1CaXRzLCB1c2VySWQsIHBhc3NwaHJhc2UpIHtcbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcblxuICB2YXIgc2VjcmV0S2V5UGFja2V0ID0gbmV3IHBhY2tldC5zZWNyZXRfa2V5KCk7XG4gIHNlY3JldEtleVBhY2tldC5hbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwga2V5VHlwZSk7XG4gIHNlY3JldEtleVBhY2tldC5nZW5lcmF0ZShudW1CaXRzKTtcbiAgc2VjcmV0S2V5UGFja2V0LmVuY3J5cHQocGFzc3BocmFzZSk7XG5cbiAgdmFyIHVzZXJJZFBhY2tldCA9IG5ldyBwYWNrZXQudXNlcmlkKCk7XG4gIHVzZXJJZFBhY2tldC5yZWFkKHVzZXJJZCk7XG5cbiAgdmFyIGRhdGFUb1NpZ24gPSB7fTtcbiAgZGF0YVRvU2lnbi51c2VyaWQgPSB1c2VySWRQYWNrZXQ7XG4gIGRhdGFUb1NpZ24ua2V5ID0gc2VjcmV0S2V5UGFja2V0O1xuICB2YXIgc2lnbmF0dXJlUGFja2V0ID0gbmV3IHBhY2tldC5zaWduYXR1cmUoKTtcbiAgc2lnbmF0dXJlUGFja2V0LnNpZ25hdHVyZVR5cGUgPSBlbnVtcy5zaWduYXR1cmUuY2VydF9nZW5lcmljO1xuICBzaWduYXR1cmVQYWNrZXQucHVibGljS2V5QWxnb3JpdGhtID0ga2V5VHlwZTtcbiAgLy9UT0RPIHdlIHNob3VsZCBsb2FkIHByZWZlcnJlZCBoYXNoIGZyb20gY29uZmlnLCBvciBhcyBpbnB1dCB0byB0aGlzIGZ1bmN0aW9uXG4gIHNpZ25hdHVyZVBhY2tldC5oYXNoQWxnb3JpdGhtID0gZW51bXMuaGFzaC5zaGEyNTY7XG4gIHNpZ25hdHVyZVBhY2tldC5rZXlGbGFncyA9IFtlbnVtcy5rZXlGbGFncy5jZXJ0aWZ5X2tleXMgfCBlbnVtcy5rZXlGbGFncy5zaWduX2RhdGFdO1xuICBzaWduYXR1cmVQYWNrZXQuc2lnbihzZWNyZXRLZXlQYWNrZXQsIGRhdGFUb1NpZ24pO1xuXG4gIHZhciBzZWNyZXRTdWJrZXlQYWNrZXQgPSBuZXcgcGFja2V0LnNlY3JldF9zdWJrZXkoKTtcbiAgc2VjcmV0U3Via2V5UGFja2V0LmFsZ29yaXRobSA9IGVudW1zLnJlYWQoZW51bXMucHVibGljS2V5LCBrZXlUeXBlKTtcbiAgc2VjcmV0U3Via2V5UGFja2V0LmdlbmVyYXRlKG51bUJpdHMpO1xuICBzZWNyZXRTdWJrZXlQYWNrZXQuZW5jcnlwdChwYXNzcGhyYXNlKTtcblxuICBkYXRhVG9TaWduID0ge307XG4gIGRhdGFUb1NpZ24ua2V5ID0gc2VjcmV0S2V5UGFja2V0O1xuICBkYXRhVG9TaWduLmJpbmQgPSBzZWNyZXRTdWJrZXlQYWNrZXQ7XG4gIHZhciBzdWJrZXlTaWduYXR1cmVQYWNrZXQgPSBuZXcgcGFja2V0LnNpZ25hdHVyZSgpO1xuICBzdWJrZXlTaWduYXR1cmVQYWNrZXQuc2lnbmF0dXJlVHlwZSA9IGVudW1zLnNpZ25hdHVyZS5zdWJrZXlfYmluZGluZztcbiAgc3Via2V5U2lnbmF0dXJlUGFja2V0LnB1YmxpY0tleUFsZ29yaXRobSA9IGtleVR5cGU7XG4gIC8vVE9ETyB3ZSBzaG91bGQgbG9hZCBwcmVmZXJyZWQgaGFzaCBmcm9tIGNvbmZpZywgb3IgYXMgaW5wdXQgdG8gdGhpcyBmdW5jdGlvblxuICBzdWJrZXlTaWduYXR1cmVQYWNrZXQuaGFzaEFsZ29yaXRobSA9IGVudW1zLmhhc2guc2hhMjU2O1xuICBzdWJrZXlTaWduYXR1cmVQYWNrZXQua2V5RmxhZ3MgPSBbZW51bXMua2V5RmxhZ3MuZW5jcnlwdF9jb21tdW5pY2F0aW9uIHwgZW51bXMua2V5RmxhZ3MuZW5jcnlwdF9zdG9yYWdlXTtcbiAgc3Via2V5U2lnbmF0dXJlUGFja2V0LnNpZ24oc2VjcmV0S2V5UGFja2V0LCBkYXRhVG9TaWduKTtcblxuICBwYWNrZXRsaXN0LnB1c2goc2VjcmV0S2V5UGFja2V0KTtcbiAgcGFja2V0bGlzdC5wdXNoKHVzZXJJZFBhY2tldCk7XG4gIHBhY2tldGxpc3QucHVzaChzaWduYXR1cmVQYWNrZXQpO1xuICBwYWNrZXRsaXN0LnB1c2goc2VjcmV0U3Via2V5UGFja2V0KTtcbiAgcGFja2V0bGlzdC5wdXNoKHN1YmtleVNpZ25hdHVyZVBhY2tldCk7XG5cbiAgcmV0dXJuIG5ldyBLZXkocGFja2V0bGlzdCk7XG59XG5cbmV4cG9ydHMuS2V5ID0gS2V5O1xuZXhwb3J0cy5yZWFkQXJtb3JlZCA9IHJlYWRBcm1vcmVkO1xuZXhwb3J0cy5nZW5lcmF0ZSA9IGdlbmVyYXRlO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBAcmVxdWlyZXMgY29uZmlnXG4gKiBAcmVxdWlyZXMgY3J5cHRvXG4gKiBAcmVxdWlyZXMgZW5jb2RpbmcvYXJtb3JcbiAqIEByZXF1aXJlcyBlbnVtc1xuICogQHJlcXVpcmVzIHBhY2tldFxuICogQG1vZHVsZSBtZXNzYWdlXG4gKi9cblxudmFyIHBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0JyksXG4gIGVudW1zID0gcmVxdWlyZSgnLi9lbnVtcy5qcycpLFxuICBhcm1vciA9IHJlcXVpcmUoJy4vZW5jb2RpbmcvYXJtb3IuanMnKSxcbiAgY29uZmlnID0gcmVxdWlyZSgnLi9jb25maWcnKSxcbiAgY3J5cHRvID0gcmVxdWlyZSgnLi9jcnlwdG8nKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgQ2xhc3MgdGhhdCByZXByZXNlbnRzIGFuIE9wZW5QR1AgbWVzc2FnZS5cbiAqIENhbiBiZSBhbiBlbmNyeXB0ZWQgbWVzc2FnZSwgc2lnbmVkIG1lc3NhZ2UsIGNvbXByZXNzZWQgbWVzc2FnZSBvciBsaXRlcmFsIG1lc3NhZ2VcbiAqIEBwYXJhbSAge21vZHVsZTpwYWNrZXQvcGFja2V0bGlzdH0gcGFja2V0bGlzdCBUaGUgcGFja2V0cyB0aGF0IGZvcm0gdGhpcyBtZXNzYWdlXG4gKiBTZWUgaHR0cDovL3Rvb2xzLmlldGYub3JnL2h0bWwvcmZjNDg4MCNzZWN0aW9uLTExLjNcbiAqL1xuXG5mdW5jdGlvbiBNZXNzYWdlKHBhY2tldGxpc3QpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIE1lc3NhZ2UpKSB7XG4gICAgcmV0dXJuIG5ldyBNZXNzYWdlKHBhY2tldGxpc3QpO1xuICB9XG4gIHRoaXMucGFja2V0cyA9IHBhY2tldGxpc3QgfHwgbmV3IHBhY2tldC5saXN0KCk7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUga2V5IElEcyBvZiB0aGUga2V5cyB0byB3aGljaCB0aGUgc2Vzc2lvbiBrZXkgaXMgZW5jcnlwdGVkXG4gKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6dHlwZS9rZXlpZD59IGFycmF5IG9mIGtleWlkIG9iamVjdHNcbiAqL1xuTWVzc2FnZS5wcm90b3R5cGUuZ2V0RW5jcnlwdGlvbktleUlkcyA9IGZ1bmN0aW9uKCkge1xuICB2YXIga2V5SWRzID0gW107XG4gIHZhciBwa0VTS2V5UGFja2V0bGlzdCA9IHRoaXMucGFja2V0cy5maWx0ZXJCeVRhZyhlbnVtcy5wYWNrZXQucHVibGljX2tleV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXkpO1xuICBwa0VTS2V5UGFja2V0bGlzdC5mb3JFYWNoKGZ1bmN0aW9uKHBhY2tldCkge1xuICAgIGtleUlkcy5wdXNoKHBhY2tldC5wdWJsaWNLZXlJZCk7XG4gIH0pO1xuICByZXR1cm4ga2V5SWRzO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBrZXkgSURzIG9mIHRoZSBrZXlzIHRoYXQgc2lnbmVkIHRoZSBtZXNzYWdlXG4gKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6dHlwZS9rZXlpZD59IGFycmF5IG9mIGtleWlkIG9iamVjdHNcbiAqL1xuTWVzc2FnZS5wcm90b3R5cGUuZ2V0U2lnbmluZ0tleUlkcyA9IGZ1bmN0aW9uKCkge1xuICB2YXIga2V5SWRzID0gW107XG4gIHZhciBtc2cgPSB0aGlzLnVud3JhcENvbXByZXNzZWQoKTtcbiAgLy8gc2VhcmNoIGZvciBvbmUgcGFzcyBzaWduYXR1cmVzXG4gIHZhciBvbmVQYXNzU2lnTGlzdCA9IG1zZy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC5vbmVfcGFzc19zaWduYXR1cmUpO1xuICBvbmVQYXNzU2lnTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKHBhY2tldCkge1xuICAgIGtleUlkcy5wdXNoKHBhY2tldC5zaWduaW5nS2V5SWQpO1xuICB9KTtcbiAgLy8gaWYgbm90aGluZyBmb3VuZCBsb29rIGZvciBzaWduYXR1cmUgcGFja2V0c1xuICBpZiAoIWtleUlkcy5sZW5ndGgpIHtcbiAgICB2YXIgc2lnbmF0dXJlTGlzdCA9IG1zZy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC5zaWduYXR1cmUpO1xuICAgIHNpZ25hdHVyZUxpc3QuZm9yRWFjaChmdW5jdGlvbihwYWNrZXQpIHtcbiAgICAgIGtleUlkcy5wdXNoKHBhY2tldC5pc3N1ZXJLZXlJZCk7XG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGtleUlkcztcbn07XG5cbi8qKlxuICogRGVjcnlwdCB0aGUgbWVzc2FnZVxuICogQHBhcmFtIHttb2R1bGU6a2V5fktleX0gcHJpdmF0ZUtleSBwcml2YXRlIGtleSB3aXRoIGRlY3J5cHRlZCBzZWNyZXQgZGF0YSAgICAgICAgICAgXG4gKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6bWVzc2FnZX5NZXNzYWdlPn0gbmV3IG1lc3NhZ2Ugd2l0aCBkZWNyeXB0ZWQgY29udGVudFxuICovXG5NZXNzYWdlLnByb3RvdHlwZS5kZWNyeXB0ID0gZnVuY3Rpb24ocHJpdmF0ZUtleSkge1xuICB2YXIgZW5jcnlwdGlvbktleUlkcyA9IHRoaXMuZ2V0RW5jcnlwdGlvbktleUlkcygpO1xuICBpZiAoIWVuY3J5cHRpb25LZXlJZHMubGVuZ3RoKSB7XG4gICAgLy8gbm90aGluZyB0byBkZWNyeXB0IHJldHVybiB1bm1vZGlmaWVkIG1lc3NhZ2VcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICB2YXIgcHJpdmF0ZUtleVBhY2tldCA9IHByaXZhdGVLZXkuZ2V0UHJpdmF0ZUtleVBhY2tldChlbmNyeXB0aW9uS2V5SWRzKTtcbiAgaWYgKCFwcml2YXRlS2V5UGFja2V0LmlzRGVjcnlwdGVkKSB0aHJvdyBuZXcgRXJyb3IoJ1ByaXZhdGUga2V5IGlzIG5vdCBkZWNyeXB0ZWQuJyk7XG4gIHZhciBwa0VTS2V5UGFja2V0bGlzdCA9IHRoaXMucGFja2V0cy5maWx0ZXJCeVRhZyhlbnVtcy5wYWNrZXQucHVibGljX2tleV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXkpO1xuICB2YXIgcGtFU0tleVBhY2tldDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBwa0VTS2V5UGFja2V0bGlzdC5sZW5ndGg7IGkrKykge1xuICAgIGlmIChwa0VTS2V5UGFja2V0bGlzdFtpXS5wdWJsaWNLZXlJZC5lcXVhbHMocHJpdmF0ZUtleVBhY2tldC5nZXRLZXlJZCgpKSkge1xuICAgICAgcGtFU0tleVBhY2tldCA9IHBrRVNLZXlQYWNrZXRsaXN0W2ldO1xuICAgICAgcGtFU0tleVBhY2tldC5kZWNyeXB0KHByaXZhdGVLZXlQYWNrZXQpO1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIGlmIChwa0VTS2V5UGFja2V0KSB7XG4gICAgdmFyIHN5bUVuY3J5cHRlZFBhY2tldGxpc3QgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnN5bW1ldHJpY2FsbHlfZW5jcnlwdGVkLCBlbnVtcy5wYWNrZXQuc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkKTtcbiAgICBpZiAoc3ltRW5jcnlwdGVkUGFja2V0bGlzdC5sZW5ndGggIT09IDApIHtcbiAgICAgIHZhciBzeW1FbmNyeXB0ZWRQYWNrZXQgPSBzeW1FbmNyeXB0ZWRQYWNrZXRsaXN0WzBdO1xuICAgICAgc3ltRW5jcnlwdGVkUGFja2V0LmRlY3J5cHQocGtFU0tleVBhY2tldC5zZXNzaW9uS2V5QWxnb3JpdGhtLCBwa0VTS2V5UGFja2V0LnNlc3Npb25LZXkpO1xuICAgICAgcmV0dXJuIG5ldyBNZXNzYWdlKHN5bUVuY3J5cHRlZFBhY2tldC5wYWNrZXRzKTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogR2V0IGxpdGVyYWwgZGF0YSB0aGF0IGlzIHRoZSBib2R5IG9mIHRoZSBtZXNzYWdlXG4gKiBAcmV0dXJuIHsoU3RyaW5nfG51bGwpfSBsaXRlcmFsIGJvZHkgb2YgdGhlIG1lc3NhZ2UgYXMgc3RyaW5nXG4gKi9cbk1lc3NhZ2UucHJvdG90eXBlLmdldExpdGVyYWxEYXRhID0gZnVuY3Rpb24oKSB7XG4gIHZhciBsaXRlcmFsID0gdGhpcy5wYWNrZXRzLmZpbmRQYWNrZXQoZW51bXMucGFja2V0LmxpdGVyYWwpO1xuICByZXR1cm4gbGl0ZXJhbCAmJiBsaXRlcmFsLmRhdGEgfHwgbnVsbDtcbn07XG5cbi8qKlxuICogR2V0IGxpdGVyYWwgZGF0YSBhcyB0ZXh0XG4gKiBAcmV0dXJuIHsoU3RyaW5nfG51bGwpfSBsaXRlcmFsIGJvZHkgb2YgdGhlIG1lc3NhZ2UgaW50ZXJwcmV0ZWQgYXMgdGV4dFxuICovXG5NZXNzYWdlLnByb3RvdHlwZS5nZXRUZXh0ID0gZnVuY3Rpb24oKSB7XG4gIHZhciBsaXRlcmFsID0gdGhpcy5wYWNrZXRzLmZpbmRQYWNrZXQoZW51bXMucGFja2V0LmxpdGVyYWwpO1xuICBpZiAobGl0ZXJhbCkge1xuICAgIHJldHVybiBsaXRlcmFsLmdldFRleHQoKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufTtcblxuLyoqXG4gKiBFbmNyeXB0IHRoZSBtZXNzYWdlXG4gKiBAcGFyYW0gIHtBcnJheTxtb2R1bGU6a2V5fktleT59IGtleXMgYXJyYXkgb2Yga2V5cywgdXNlZCB0byBlbmNyeXB0IHRoZSBtZXNzYWdlXG4gKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6bWVzc2FnZX5NZXNzYWdlPn0gbmV3IG1lc3NhZ2Ugd2l0aCBlbmNyeXB0ZWQgY29udGVudFxuICovXG5NZXNzYWdlLnByb3RvdHlwZS5lbmNyeXB0ID0gZnVuY3Rpb24oa2V5cykge1xuICB2YXIgcGFja2V0bGlzdCA9IG5ldyBwYWNrZXQubGlzdCgpO1xuICAvL1RPRE8gZ2V0IHByZWZlcnJlZCBhbGdvIGZyb20gc2lnbmF0dXJlXG4gIHZhciBzZXNzaW9uS2V5ID0gY3J5cHRvLmdlbmVyYXRlU2Vzc2lvbktleShlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgY29uZmlnLmVuY3J5cHRpb25fY2lwaGVyKSk7XG4gIGtleXMuZm9yRWFjaChmdW5jdGlvbihrZXkpIHtcbiAgICB2YXIgZW5jcnlwdGlvbktleVBhY2tldCA9IGtleS5nZXRFbmNyeXB0aW9uS2V5UGFja2V0KCk7XG4gICAgaWYgKGVuY3J5cHRpb25LZXlQYWNrZXQpIHtcbiAgICAgIHZhciBwa0VTS2V5UGFja2V0ID0gbmV3IHBhY2tldC5wdWJsaWNfa2V5X2VuY3J5cHRlZF9zZXNzaW9uX2tleSgpO1xuICAgICAgcGtFU0tleVBhY2tldC5wdWJsaWNLZXlJZCA9IGVuY3J5cHRpb25LZXlQYWNrZXQuZ2V0S2V5SWQoKTtcbiAgICAgIHBrRVNLZXlQYWNrZXQucHVibGljS2V5QWxnb3JpdGhtID0gZW5jcnlwdGlvbktleVBhY2tldC5hbGdvcml0aG07XG4gICAgICBwa0VTS2V5UGFja2V0LnNlc3Npb25LZXkgPSBzZXNzaW9uS2V5O1xuICAgICAgLy9UT0RPIGdldCBwcmVmZXJyZWQgYWxnbyBmcm9tIHNpZ25hdHVyZVxuICAgICAgcGtFU0tleVBhY2tldC5zZXNzaW9uS2V5QWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5zeW1tZXRyaWMsIGNvbmZpZy5lbmNyeXB0aW9uX2NpcGhlcik7XG4gICAgICBwa0VTS2V5UGFja2V0LmVuY3J5cHQoZW5jcnlwdGlvbktleVBhY2tldCk7XG4gICAgICBwYWNrZXRsaXN0LnB1c2gocGtFU0tleVBhY2tldCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGZpbmQgdmFsaWQga2V5IHBhY2tldCBmb3IgZW5jcnlwdGlvbiBpbiBrZXkgJyArIGtleS5wcmltYXJ5S2V5LmdldEtleUlkKCkudG9IZXgoKSk7XG4gICAgfVxuICB9KTtcbiAgdmFyIHN5bUVuY3J5cHRlZFBhY2tldDtcbiAgaWYgKGNvbmZpZy5pbnRlZ3JpdHlfcHJvdGVjdCkge1xuICAgIHN5bUVuY3J5cHRlZFBhY2tldCA9IG5ldyBwYWNrZXQuc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkKCk7XG4gIH0gZWxzZSB7XG4gICAgc3ltRW5jcnlwdGVkUGFja2V0ID0gbmV3IHBhY2tldC5zeW1tZXRyaWNhbGx5X2VuY3J5cHRlZCgpO1xuICB9XG4gIHN5bUVuY3J5cHRlZFBhY2tldC5wYWNrZXRzID0gdGhpcy5wYWNrZXRzO1xuICAvL1RPRE8gZ2V0IHByZWZlcnJlZCBhbGdvIGZyb20gc2lnbmF0dXJlXG4gIHN5bUVuY3J5cHRlZFBhY2tldC5lbmNyeXB0KGVudW1zLnJlYWQoZW51bXMuc3ltbWV0cmljLCBjb25maWcuZW5jcnlwdGlvbl9jaXBoZXIpLCBzZXNzaW9uS2V5KTtcbiAgcGFja2V0bGlzdC5wdXNoKHN5bUVuY3J5cHRlZFBhY2tldCk7XG4gIHJldHVybiBuZXcgTWVzc2FnZShwYWNrZXRsaXN0KTtcbn07XG5cbi8qKlxuICogU2lnbiB0aGUgbWVzc2FnZSAodGhlIGxpdGVyYWwgZGF0YSBwYWNrZXQgb2YgdGhlIG1lc3NhZ2UpXG4gKiBAcGFyYW0gIHtBcnJheTxtb2R1bGU6a2V5fktleT59IHByaXZhdGVLZXkgcHJpdmF0ZSBrZXlzIHdpdGggZGVjcnlwdGVkIHNlY3JldCBrZXkgZGF0YSBmb3Igc2lnbmluZ1xuICogQHJldHVybiB7bW9kdWxlOm1lc3NhZ2V+TWVzc2FnZX0gICAgICBuZXcgbWVzc2FnZSB3aXRoIHNpZ25lZCBjb250ZW50XG4gKi9cbk1lc3NhZ2UucHJvdG90eXBlLnNpZ24gPSBmdW5jdGlvbihwcml2YXRlS2V5cykge1xuXG4gIHZhciBwYWNrZXRsaXN0ID0gbmV3IHBhY2tldC5saXN0KCk7XG5cbiAgdmFyIGxpdGVyYWxEYXRhUGFja2V0ID0gdGhpcy5wYWNrZXRzLmZpbmRQYWNrZXQoZW51bXMucGFja2V0LmxpdGVyYWwpO1xuICBpZiAoIWxpdGVyYWxEYXRhUGFja2V0KSB0aHJvdyBuZXcgRXJyb3IoJ05vIGxpdGVyYWwgZGF0YSBwYWNrZXQgdG8gc2lnbi4nKTtcbiAgXG4gIHZhciBsaXRlcmFsRm9ybWF0ID0gZW51bXMud3JpdGUoZW51bXMubGl0ZXJhbCwgbGl0ZXJhbERhdGFQYWNrZXQuZm9ybWF0KTtcbiAgdmFyIHNpZ25hdHVyZVR5cGUgPSBsaXRlcmFsRm9ybWF0ID09IGVudW1zLmxpdGVyYWwuYmluYXJ5IFxuICAgICAgICAgICAgICAgICAgICAgID8gZW51bXMuc2lnbmF0dXJlLmJpbmFyeSA6IGVudW1zLnNpZ25hdHVyZS50ZXh0OyBcbiAgXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgcHJpdmF0ZUtleXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgb25lUGFzc1NpZyA9IG5ldyBwYWNrZXQub25lX3Bhc3Nfc2lnbmF0dXJlKCk7XG4gICAgb25lUGFzc1NpZy50eXBlID0gc2lnbmF0dXJlVHlwZTtcbiAgICAvL1RPRE8gZ2V0IHByZWZlcnJlZCBoYXNoZyBhbGdvIGZyb20ga2V5IHNpZ25hdHVyZVxuICAgIG9uZVBhc3NTaWcuaGFzaEFsZ29yaXRobSA9IGNvbmZpZy5wcmVmZXJfaGFzaF9hbGdvcml0aG07XG4gICAgdmFyIHNpZ25pbmdLZXlQYWNrZXQgPSBwcml2YXRlS2V5c1tpXS5nZXRTaWduaW5nS2V5UGFja2V0KCk7XG4gICAgaWYgKCFzaWduaW5nS2V5UGFja2V0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBmaW5kIHZhbGlkIGtleSBwYWNrZXQgZm9yIHNpZ25pbmcgaW4ga2V5ICcgKyBwcml2YXRlS2V5c1tpXS5wcmltYXJ5S2V5LmdldEtleUlkKCkudG9IZXgoKSk7XG4gICAgfVxuICAgIG9uZVBhc3NTaWcucHVibGljS2V5QWxnb3JpdGhtID0gc2lnbmluZ0tleVBhY2tldC5hbGdvcml0aG07XG4gICAgb25lUGFzc1NpZy5zaWduaW5nS2V5SWQgPSBzaWduaW5nS2V5UGFja2V0LmdldEtleUlkKCk7XG4gICAgcGFja2V0bGlzdC5wdXNoKG9uZVBhc3NTaWcpO1xuICB9XG5cbiAgcGFja2V0bGlzdC5wdXNoKGxpdGVyYWxEYXRhUGFja2V0KTtcbiAgXG4gIGZvciAodmFyIGkgPSBwcml2YXRlS2V5cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgIHZhciBzaWduYXR1cmVQYWNrZXQgPSBuZXcgcGFja2V0LnNpZ25hdHVyZSgpO1xuICAgIHNpZ25hdHVyZVBhY2tldC5zaWduYXR1cmVUeXBlID0gc2lnbmF0dXJlVHlwZTtcbiAgICBzaWduYXR1cmVQYWNrZXQuaGFzaEFsZ29yaXRobSA9IGNvbmZpZy5wcmVmZXJfaGFzaF9hbGdvcml0aG07XG4gICAgc2lnbmF0dXJlUGFja2V0LnB1YmxpY0tleUFsZ29yaXRobSA9IHNpZ25pbmdLZXlQYWNrZXQuYWxnb3JpdGhtO1xuICAgIGlmICghc2lnbmluZ0tleVBhY2tldC5pc0RlY3J5cHRlZCkgdGhyb3cgbmV3IEVycm9yKCdQcml2YXRlIGtleSBpcyBub3QgZGVjcnlwdGVkLicpO1xuICAgIHNpZ25hdHVyZVBhY2tldC5zaWduKHNpZ25pbmdLZXlQYWNrZXQsIGxpdGVyYWxEYXRhUGFja2V0KTtcbiAgICBwYWNrZXRsaXN0LnB1c2goc2lnbmF0dXJlUGFja2V0KTtcbiAgfVxuXG4gIHJldHVybiBuZXcgTWVzc2FnZShwYWNrZXRsaXN0KTtcbn07XG5cbi8qKlxuICogVmVyaWZ5IG1lc3NhZ2Ugc2lnbmF0dXJlc1xuICogQHBhcmFtIHtBcnJheTxtb2R1bGU6a2V5fktleT59IHB1YmxpY0tleXMgcHVibGljIGtleXMgdG8gdmVyaWZ5IHNpZ25hdHVyZXNcbiAqIEByZXR1cm4ge0FycmF5PCh7a2V5aWQ6IG1vZHVsZTp0eXBlL2tleWlkLCB2YWxpZDogQm9vbGVhbn0pPn0gbGlzdCBvZiBzaWduZXIncyBrZXlpZCBhbmQgdmFsaWRpdHkgb2Ygc2lnbmF0dXJlXG4gKi9cbk1lc3NhZ2UucHJvdG90eXBlLnZlcmlmeSA9IGZ1bmN0aW9uKHB1YmxpY0tleXMpIHtcbiAgdmFyIHJlc3VsdCA9IFtdO1xuICB2YXIgbXNnID0gdGhpcy51bndyYXBDb21wcmVzc2VkKCk7XG4gIHZhciBsaXRlcmFsRGF0YUxpc3QgPSBtc2cucGFja2V0cy5maWx0ZXJCeVRhZyhlbnVtcy5wYWNrZXQubGl0ZXJhbCk7XG4gIGlmIChsaXRlcmFsRGF0YUxpc3QubGVuZ3RoICE9PSAxKSB0aHJvdyBuZXcgRXJyb3IoJ0NhbiBvbmx5IHZlcmlmeSBtZXNzYWdlIHdpdGggb25lIGxpdGVyYWwgZGF0YSBwYWNrZXQuJyk7XG4gIHZhciBzaWduYXR1cmVMaXN0ID0gbXNnLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnNpZ25hdHVyZSk7XG4gIHB1YmxpY0tleXMuZm9yRWFjaChmdW5jdGlvbihwdWJLZXkpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpZ25hdHVyZUxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBwdWJsaWNLZXlQYWNrZXQgPSBwdWJLZXkuZ2V0UHVibGljS2V5UGFja2V0KFtzaWduYXR1cmVMaXN0W2ldLmlzc3VlcktleUlkXSk7XG4gICAgICBpZiAocHVibGljS2V5UGFja2V0KSB7XG4gICAgICAgIHZhciB2ZXJpZmllZFNpZyA9IHt9O1xuICAgICAgICB2ZXJpZmllZFNpZy5rZXlpZCA9IHNpZ25hdHVyZUxpc3RbaV0uaXNzdWVyS2V5SWQ7XG4gICAgICAgIHZlcmlmaWVkU2lnLnZhbGlkID0gc2lnbmF0dXJlTGlzdFtpXS52ZXJpZnkocHVibGljS2V5UGFja2V0LCBsaXRlcmFsRGF0YUxpc3RbMF0pO1xuICAgICAgICByZXN1bHQucHVzaCh2ZXJpZmllZFNpZyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFVud3JhcCBjb21wcmVzc2VkIG1lc3NhZ2VcbiAqIEByZXR1cm4ge21vZHVsZTptZXNzYWdlfk1lc3NhZ2V9IG1lc3NhZ2UgQ29udGVudCBvZiBjb21wcmVzc2VkIG1lc3NhZ2VcbiAqL1xuTWVzc2FnZS5wcm90b3R5cGUudW53cmFwQ29tcHJlc3NlZCA9IGZ1bmN0aW9uKCkge1xuICB2YXIgY29tcHJlc3NlZCA9IHRoaXMucGFja2V0cy5maWx0ZXJCeVRhZyhlbnVtcy5wYWNrZXQuY29tcHJlc3NlZCk7XG4gIGlmIChjb21wcmVzc2VkLmxlbmd0aCkge1xuICAgIHJldHVybiBuZXcgTWVzc2FnZShjb21wcmVzc2VkWzBdLnBhY2tldHMpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59O1xuXG4vKipcbiAqIFJldHVybnMgQVNDSUkgYXJtb3JlZCB0ZXh0IG9mIG1lc3NhZ2VcbiAqIEByZXR1cm4ge1N0cmluZ30gQVNDSUkgYXJtb3JcbiAqL1xuTWVzc2FnZS5wcm90b3R5cGUuYXJtb3IgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIGFybW9yLmVuY29kZShlbnVtcy5hcm1vci5tZXNzYWdlLCB0aGlzLnBhY2tldHMud3JpdGUoKSk7XG59O1xuXG4vKipcbiAqIHJlYWRzIGFuIE9wZW5QR1AgYXJtb3JlZCBtZXNzYWdlIGFuZCByZXR1cm5zIGEgbWVzc2FnZSBvYmplY3RcbiAqIEBwYXJhbSB7U3RyaW5nfSBhcm1vcmVkVGV4dCB0ZXh0IHRvIGJlIHBhcnNlZFxuICogQHJldHVybiB7bW9kdWxlOm1lc3NhZ2V+TWVzc2FnZX0gbmV3IG1lc3NhZ2Ugb2JqZWN0XG4gKiBAc3RhdGljXG4gKi9cbmZ1bmN0aW9uIHJlYWRBcm1vcmVkKGFybW9yZWRUZXh0KSB7XG4gIC8vVE9ETyBob3cgZG8gd2Ugd2FudCB0byBoYW5kbGUgYmFkIHRleHQ/IEV4Y2VwdGlvbiB0aHJvd2luZ1xuICAvL1RPRE8gZG9uJ3QgYWNjZXB0IG5vbi1tZXNzYWdlIGFybW9yZWQgdGV4dHNcbiAgdmFyIGlucHV0ID0gYXJtb3IuZGVjb2RlKGFybW9yZWRUZXh0KS5kYXRhO1xuICB2YXIgcGFja2V0bGlzdCA9IG5ldyBwYWNrZXQubGlzdCgpO1xuICBwYWNrZXRsaXN0LnJlYWQoaW5wdXQpO1xuICB2YXIgbmV3TWVzc2FnZSA9IG5ldyBNZXNzYWdlKHBhY2tldGxpc3QpO1xuICByZXR1cm4gbmV3TWVzc2FnZTtcbn1cblxuLyoqXG4gKiBjcmVhdGVzIG5ldyBtZXNzYWdlIG9iamVjdCBmcm9tIHRleHRcbiAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0XG4gKiBAcmV0dXJuIHttb2R1bGU6bWVzc2FnZX5NZXNzYWdlfSBuZXcgbWVzc2FnZSBvYmplY3RcbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gZnJvbVRleHQodGV4dCkge1xuICB2YXIgbGl0ZXJhbERhdGFQYWNrZXQgPSBuZXcgcGFja2V0LmxpdGVyYWwoKTtcbiAgLy8gdGV4dCB3aWxsIGJlIGNvbnZlcnRlZCB0byBVVEY4XG4gIGxpdGVyYWxEYXRhUGFja2V0LnNldFRleHQodGV4dCk7XG4gIHZhciBsaXRlcmFsRGF0YVBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgbGl0ZXJhbERhdGFQYWNrZXRsaXN0LnB1c2gobGl0ZXJhbERhdGFQYWNrZXQpO1xuICB2YXIgbmV3TWVzc2FnZSA9IG5ldyBNZXNzYWdlKGxpdGVyYWxEYXRhUGFja2V0bGlzdCk7XG4gIHJldHVybiBuZXdNZXNzYWdlO1xufVxuXG4vKipcbiAqIGNyZWF0ZXMgbmV3IG1lc3NhZ2Ugb2JqZWN0IGZyb20gYmluYXJ5IGRhdGFcbiAqIEBwYXJhbSB7U3RyaW5nfSBieXRlc1xuICogQHJldHVybiB7bW9kdWxlOm1lc3NhZ2V+TWVzc2FnZX0gbmV3IG1lc3NhZ2Ugb2JqZWN0XG4gKiBAc3RhdGljXG4gKi9cbmZ1bmN0aW9uIGZyb21CaW5hcnkoYnl0ZXMpIHtcbiAgdmFyIGxpdGVyYWxEYXRhUGFja2V0ID0gbmV3IHBhY2tldC5saXRlcmFsKCk7XG4gIGxpdGVyYWxEYXRhUGFja2V0LnNldEJ5dGVzKGJ5dGVzLCBlbnVtcy5yZWFkKGVudW1zLmxpdGVyYWwsIGVudW1zLmxpdGVyYWwuYmluYXJ5KSk7XG4gIHZhciBsaXRlcmFsRGF0YVBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgbGl0ZXJhbERhdGFQYWNrZXRsaXN0LnB1c2gobGl0ZXJhbERhdGFQYWNrZXQpO1xuICB2YXIgbmV3TWVzc2FnZSA9IG5ldyBNZXNzYWdlKGxpdGVyYWxEYXRhUGFja2V0bGlzdCk7XG4gIHJldHVybiBuZXdNZXNzYWdlO1xufVxuXG5leHBvcnRzLk1lc3NhZ2UgPSBNZXNzYWdlO1xuZXhwb3J0cy5yZWFkQXJtb3JlZCA9IHJlYWRBcm1vcmVkO1xuZXhwb3J0cy5mcm9tVGV4dCA9IGZyb21UZXh0O1xuZXhwb3J0cy5mcm9tQmluYXJ5ID0gZnJvbUJpbmFyeTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQGZpbGVvdmVydmlldyBUaGUgb3BlbnBncCBiYXNlIG1vZHVsZSBzaG91bGQgcHJvdmlkZSBhbGwgb2YgdGhlIGZ1bmN0aW9uYWxpdHkgXG4gKiB0byBjb25zdW1lIHRoZSBvcGVucGdwLmpzIGxpYnJhcnkuIEFsbCBhZGRpdGlvbmFsIGNsYXNzZXMgYXJlIGRvY3VtZW50ZWQgXG4gKiBmb3IgZXh0ZW5kaW5nIGFuZCBkZXZlbG9waW5nIG9uIHRvcCBvZiB0aGUgYmFzZSBsaWJyYXJ5LlxuICovXG5cbi8qKlxuICogQHJlcXVpcmVzIGNsZWFydGV4dFxuICogQHJlcXVpcmVzIGNvbmZpZ1xuICogQHJlcXVpcmVzIGVuY29kaW5nL2FybW9yXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEByZXF1aXJlcyBtZXNzYWdlXG4gKiBAcmVxdWlyZXMgcGFja2V0XG4gKiBAbW9kdWxlIG9wZW5wZ3BcbiAqL1xuXG52YXIgYXJtb3IgPSByZXF1aXJlKCcuL2VuY29kaW5nL2FybW9yLmpzJyksXG4gIHBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0JyksXG4gIGVudW1zID0gcmVxdWlyZSgnLi9lbnVtcy5qcycpLFxuICBjb25maWcgPSByZXF1aXJlKCcuL2NvbmZpZycpLFxuICBtZXNzYWdlID0gcmVxdWlyZSgnLi9tZXNzYWdlLmpzJyksXG4gIGNsZWFydGV4dCA9IHJlcXVpcmUoJy4vY2xlYXJ0ZXh0LmpzJyksXG4gIGtleSA9IHJlcXVpcmUoJy4va2V5LmpzJyk7XG5cblxuLyoqXG4gKiBFbmNyeXB0cyBtZXNzYWdlIHRleHQgd2l0aCBrZXlzXG4gKiBAcGFyYW0gIHtBcnJheTxtb2R1bGU6a2V5fktleT59ICBrZXlzIGFycmF5IG9mIGtleXMsIHVzZWQgdG8gZW5jcnlwdCB0aGUgbWVzc2FnZVxuICogQHBhcmFtICB7U3RyaW5nfSB0ZXh0IG1lc3NhZ2UgYXMgbmF0aXZlIEphdmFTY3JpcHQgc3RyaW5nXG4gKiBAcmV0dXJuIHtTdHJpbmd9ICAgICAgZW5jcnlwdGVkIEFTQ0lJIGFybW9yZWQgbWVzc2FnZVxuICogQHN0YXRpY1xuICovXG5mdW5jdGlvbiBlbmNyeXB0TWVzc2FnZShrZXlzLCB0ZXh0KSB7XG4gIHZhciBtc2cgPSBtZXNzYWdlLmZyb21UZXh0KHRleHQpO1xuICBtc2cgPSBtc2cuZW5jcnlwdChrZXlzKTtcbiAgdmFyIGFybW9yZWQgPSBhcm1vci5lbmNvZGUoZW51bXMuYXJtb3IubWVzc2FnZSwgbXNnLnBhY2tldHMud3JpdGUoKSk7XG4gIHJldHVybiBhcm1vcmVkO1xufVxuXG4vKipcbiAqIFNpZ25zIG1lc3NhZ2UgdGV4dCBhbmQgZW5jcnlwdHMgaXRcbiAqIEBwYXJhbSAge0FycmF5PG1vZHVsZTprZXl+S2V5Pn0gIHB1YmxpY0tleXMgYXJyYXkgb2Yga2V5cywgdXNlZCB0byBlbmNyeXB0IHRoZSBtZXNzYWdlXG4gKiBAcGFyYW0gIHttb2R1bGU6a2V5fktleX0gICAgcHJpdmF0ZUtleSBwcml2YXRlIGtleSB3aXRoIGRlY3J5cHRlZCBzZWNyZXQga2V5IGRhdGEgZm9yIHNpZ25pbmdcbiAqIEBwYXJhbSAge1N0cmluZ30gdGV4dCAgICAgICBtZXNzYWdlIGFzIG5hdGl2ZSBKYXZhU2NyaXB0IHN0cmluZ1xuICogQHJldHVybiB7U3RyaW5nfSAgICAgICAgICAgIGVuY3J5cHRlZCBBU0NJSSBhcm1vcmVkIG1lc3NhZ2VcbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gc2lnbkFuZEVuY3J5cHRNZXNzYWdlKHB1YmxpY0tleXMsIHByaXZhdGVLZXksIHRleHQpIHtcbiAgdmFyIG1zZyA9IG1lc3NhZ2UuZnJvbVRleHQodGV4dCk7XG4gIG1zZyA9IG1zZy5zaWduKFtwcml2YXRlS2V5XSk7XG4gIG1zZyA9IG1zZy5lbmNyeXB0KHB1YmxpY0tleXMpO1xuICB2YXIgYXJtb3JlZCA9IGFybW9yLmVuY29kZShlbnVtcy5hcm1vci5tZXNzYWdlLCBtc2cucGFja2V0cy53cml0ZSgpKTtcbiAgcmV0dXJuIGFybW9yZWQ7XG59XG5cbi8qKlxuICogRGVjcnlwdHMgbWVzc2FnZVxuICogQHBhcmFtICB7bW9kdWxlOmtleX5LZXl9ICAgICBwcml2YXRlS2V5IHByaXZhdGUga2V5IHdpdGggZGVjcnlwdGVkIHNlY3JldCBrZXkgZGF0YVxuICogQHBhcmFtICB7bW9kdWxlOm1lc3NhZ2V+TWVzc2FnZX0gbWVzc2FnZSAgICB0aGUgbWVzc2FnZSBvYmplY3Qgd2l0aCB0aGUgZW5jcnlwdGVkIGRhdGFcbiAqIEByZXR1cm4geyhTdHJpbmd8bnVsbCl9ICAgICAgICBkZWNyeXB0ZWQgbWVzc2FnZSBhcyBhcyBuYXRpdmUgSmF2YVNjcmlwdCBzdHJpbmdcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3IgbnVsbCBpZiBubyBsaXRlcmFsIGRhdGEgZm91bmRcbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gZGVjcnlwdE1lc3NhZ2UocHJpdmF0ZUtleSwgbWVzc2FnZSkge1xuICBtZXNzYWdlID0gbWVzc2FnZS5kZWNyeXB0KHByaXZhdGVLZXkpO1xuICByZXR1cm4gbWVzc2FnZS5nZXRUZXh0KCk7XG59XG5cbi8qKlxuICogRGVjcnlwdHMgbWVzc2FnZSBhbmQgdmVyaWZpZXMgc2lnbmF0dXJlc1xuICogQHBhcmFtICB7bW9kdWxlOmtleX5LZXl9ICAgICBwcml2YXRlS2V5IHByaXZhdGUga2V5IHdpdGggZGVjcnlwdGVkIHNlY3JldCBrZXkgZGF0YVxuICogQHBhcmFtICB7QXJyYXk8bW9kdWxlOmtleX5LZXk+fSAgIHB1YmxpY0tleXMgcHVibGljIGtleXMgdG8gdmVyaWZ5IHNpZ25hdHVyZXNcbiAqIEBwYXJhbSAge21vZHVsZTptZXNzYWdlfk1lc3NhZ2V9IG1lc3NhZ2UgICAgdGhlIG1lc3NhZ2Ugb2JqZWN0IHdpdGggc2lnbmVkIGFuZCBlbmNyeXB0ZWQgZGF0YVxuICogQHJldHVybiB7e3RleHQ6IFN0cmluZywgc2lnbmF0dXJlczogQXJyYXk8e2tleWlkOiBtb2R1bGU6dHlwZS9rZXlpZCwgdmFsaWQ6IEJvb2xlYW59Pn19XG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3J5cHRlZCBtZXNzYWdlIGFzIGFzIG5hdGl2ZSBKYXZhU2NyaXB0IHN0cmluZ1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoIHZlcmlmaWVkIHNpZ25hdHVyZXMgb3IgbnVsbCBpZiBubyBsaXRlcmFsIGRhdGEgZm91bmRcbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gZGVjcnlwdEFuZFZlcmlmeU1lc3NhZ2UocHJpdmF0ZUtleSwgcHVibGljS2V5cywgbWVzc2FnZSkge1xuICB2YXIgcmVzdWx0ID0ge307XG4gIG1lc3NhZ2UgPSBtZXNzYWdlLmRlY3J5cHQocHJpdmF0ZUtleSk7XG4gIHJlc3VsdC50ZXh0ID0gbWVzc2FnZS5nZXRUZXh0KCk7XG4gIGlmIChyZXN1bHQudGV4dCkge1xuICAgIHJlc3VsdC5zaWduYXR1cmVzID0gbWVzc2FnZS52ZXJpZnkocHVibGljS2V5cyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBTaWducyBhIGNsZWFydGV4dCBtZXNzYWdlXG4gKiBAcGFyYW0gIHtBcnJheTxtb2R1bGU6a2V5fktleT59ICBwcml2YXRlS2V5cyBwcml2YXRlIGtleSB3aXRoIGRlY3J5cHRlZCBzZWNyZXQga2V5IGRhdGEgdG8gc2lnbiBjbGVhcnRleHRcbiAqIEBwYXJhbSAge1N0cmluZ30gdGV4dCAgICAgICAgY2xlYXJ0ZXh0XG4gKiBAcmV0dXJuIHtTdHJpbmd9ICAgICAgICAgICAgIEFTQ0lJIGFybW9yZWQgbWVzc2FnZVxuICogQHN0YXRpY1xuICovXG5mdW5jdGlvbiBzaWduQ2xlYXJNZXNzYWdlKHByaXZhdGVLZXlzLCB0ZXh0KSB7XG4gIHZhciBjbGVhcnRleHRNZXNzYWdlID0gbmV3IGNsZWFydGV4dC5DbGVhcnRleHRNZXNzYWdlKHRleHQpO1xuICBjbGVhcnRleHRNZXNzYWdlLnNpZ24ocHJpdmF0ZUtleXMpO1xuICByZXR1cm4gY2xlYXJ0ZXh0TWVzc2FnZS5hcm1vcigpO1xufVxuXG4vKipcbiAqIFZlcmlmaWVzIHNpZ25hdHVyZXMgb2YgY2xlYXJ0ZXh0IHNpZ25lZCBtZXNzYWdlXG4gKiBAcGFyYW0gIHtBcnJheTxtb2R1bGU6a2V5fktleT59ICAgICAgICAgICAgcHVibGljS2V5cyBwdWJsaWMga2V5cyB0byB2ZXJpZnkgc2lnbmF0dXJlc1xuICogQHBhcmFtICB7bW9kdWxlOmNsZWFydGV4dH5DbGVhcnRleHRNZXNzYWdlfSBtZXNzYWdlICAgIGNsZWFydGV4dCBtZXNzYWdlIG9iamVjdCB3aXRoIHNpZ25hdHVyZXNcbiAqIEByZXR1cm4ge3t0ZXh0OiBTdHJpbmcsIHNpZ25hdHVyZXM6IEFycmF5PHtrZXlpZDogbW9kdWxlOnR5cGUva2V5aWQsIHZhbGlkOiBCb29sZWFufT59fVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhcnRleHQgd2l0aCBzdGF0dXMgb2YgdmVyaWZpZWQgc2lnbmF0dXJlc1xuICogQHN0YXRpY1xuICovXG5mdW5jdGlvbiB2ZXJpZnlDbGVhclNpZ25lZE1lc3NhZ2UocHVibGljS2V5cywgbWVzc2FnZSkge1xuICB2YXIgcmVzdWx0ID0ge307XG4gIGlmICghKG1lc3NhZ2UgaW5zdGFuY2VvZiBjbGVhcnRleHQuQ2xlYXJ0ZXh0TWVzc2FnZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1BhcmFtZXRlciBbbWVzc2FnZV0gbmVlZHMgdG8gYmUgb2YgdHlwZSBDbGVhcnRleHRNZXNzYWdlLicpO1xuICB9XG4gIHJlc3VsdC50ZXh0ID0gbWVzc2FnZS5nZXRUZXh0KCk7XG4gIHJlc3VsdC5zaWduYXR1cmVzID0gbWVzc2FnZS52ZXJpZnkocHVibGljS2V5cyk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIGEgbmV3IE9wZW5QR1Aga2V5IHBhaXIuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIFJTQSBrZXlzLlxuICogUHJpbWFyeSBhbmQgc3Via2V5IHdpbGwgYmUgb2Ygc2FtZSB0eXBlLlxuICogQHBhcmFtIHtJbnRlZ2VyfSBrZXlUeXBlICAgIHRvIGluZGljYXRlIHdoYXQgdHlwZSBvZiBrZXkgdG8gbWFrZS4gXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUlNBIGlzIDEuIFNlZSBodHRwOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM0ODgwI3NlY3Rpb24tOS4xXG4gKiBAcGFyYW0ge0ludGVnZXJ9IG51bUJpdHMgICAgbnVtYmVyIG9mIGJpdHMgZm9yIHRoZSBrZXkgY3JlYXRpb24uIChzaG91bGQgYmUgMTAyNCssIGdlbmVyYWxseSlcbiAqIEBwYXJhbSB7U3RyaW5nfSAgdXNlcklkICAgICBhc3N1bWVzIGFscmVhZHkgaW4gZm9ybSBvZiBcIlVzZXIgTmFtZSA8dXNlcm5hbWVAZW1haWwuY29tPlwiXG4gKiBAcGFyYW0ge1N0cmluZ30gIHBhc3NwaHJhc2UgVGhlIHBhc3NwaHJhc2UgdXNlZCB0byBlbmNyeXB0IHRoZSByZXN1bHRpbmcgcHJpdmF0ZSBrZXlcbiAqIEByZXR1cm4ge09iamVjdH0ge2tleTogQXJyYXk8bW9kdWxlOmtleX5LZXk+LCBwcml2YXRlS2V5QXJtb3JlZDogQXJyYXk8U3RyaW5nPiwgcHVibGljS2V5QXJtb3JlZDogQXJyYXk8U3RyaW5nPn1cbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gZ2VuZXJhdGVLZXlQYWlyKGtleVR5cGUsIG51bUJpdHMsIHVzZXJJZCwgcGFzc3BocmFzZSkge1xuICB2YXIgcmVzdWx0ID0ge307XG4gIHZhciBuZXdLZXkgPSBrZXkuZ2VuZXJhdGUoa2V5VHlwZSwgbnVtQml0cywgdXNlcklkLCBwYXNzcGhyYXNlKTtcbiAgcmVzdWx0LmtleSA9IG5ld0tleTtcbiAgcmVzdWx0LnByaXZhdGVLZXlBcm1vcmVkID0gbmV3S2V5LmFybW9yKCk7XG4gIHJlc3VsdC5wdWJsaWNLZXlBcm1vcmVkID0gbmV3S2V5LnRvUHVibGljKCkuYXJtb3IoKTtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZXhwb3J0cy5lbmNyeXB0TWVzc2FnZSA9IGVuY3J5cHRNZXNzYWdlO1xuZXhwb3J0cy5zaWduQW5kRW5jcnlwdE1lc3NhZ2UgPSBzaWduQW5kRW5jcnlwdE1lc3NhZ2U7XG5leHBvcnRzLmRlY3J5cHRNZXNzYWdlID0gZGVjcnlwdE1lc3NhZ2U7XG5leHBvcnRzLmRlY3J5cHRBbmRWZXJpZnlNZXNzYWdlID0gZGVjcnlwdEFuZFZlcmlmeU1lc3NhZ2VcbmV4cG9ydHMuc2lnbkNsZWFyTWVzc2FnZSA9IHNpZ25DbGVhck1lc3NhZ2U7XG5leHBvcnRzLnZlcmlmeUNsZWFyU2lnbmVkTWVzc2FnZSA9IHZlcmlmeUNsZWFyU2lnbmVkTWVzc2FnZTtcbmV4cG9ydHMuZ2VuZXJhdGVLZXlQYWlyID0gZ2VuZXJhdGVLZXlQYWlyO1xuIiwiLyoqXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEBtb2R1bGUgcGFja2V0XG4gKi9cbnZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbi8vIFRoaXMgaXMgcHJldHR5IHVnbHksIGJ1dCBicm93c2VyaWZ5IG5lZWRzIHRvIGhhdmUgdGhlIHJlcXVpcmVzIGV4cGxpY2l0bHkgd3JpdHRlbi5cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIC8qKiBAc2VlIG1vZHVsZTpwYWNrZXQvY29tcHJlc3NlZCAqL1xuICBjb21wcmVzc2VkOiByZXF1aXJlKCcuL2NvbXByZXNzZWQuanMnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOnBhY2tldC9zeW1fZW5jcnlwdGVkX2ludGVncml0eV9wcm90ZWN0ZWQgKi9cbiAgc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkOiByZXF1aXJlKCcuL3N5bV9lbmNyeXB0ZWRfaW50ZWdyaXR5X3Byb3RlY3RlZC5qcycpLFxuICAvKiogQHNlZSBtb2R1bGU6cGFja2V0L3B1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5ICovXG4gIHB1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5OiByZXF1aXJlKCcuL3B1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5LmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpwYWNrZXQvc3ltX2VuY3J5cHRlZF9zZXNzaW9uX2tleSAqL1xuICBzeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5OiByZXF1aXJlKCcuL3N5bV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXkuanMnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOnBhY2tldC9saXRlcmFsICovXG4gIGxpdGVyYWw6IHJlcXVpcmUoJy4vbGl0ZXJhbC5qcycpLFxuICAvKiogQHNlZSBtb2R1bGU6cGFja2V0L3B1YmxpY19rZXkgKi9cbiAgcHVibGljX2tleTogcmVxdWlyZSgnLi9wdWJsaWNfa2V5LmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpwYWNrZXQvc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQgKi9cbiAgc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQ6IHJlcXVpcmUoJy4vc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQuanMnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOnBhY2tldC9tYXJrZXIgKi9cbiAgbWFya2VyOiByZXF1aXJlKCcuL21hcmtlci5qcycpLFxuICAvKiogQHNlZSBtb2R1bGU6cGFja2V0L3B1YmxpY19zdWJrZXkgKi9cbiAgcHVibGljX3N1YmtleTogcmVxdWlyZSgnLi9wdWJsaWNfc3Via2V5LmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpwYWNrZXQvdXNlcl9hdHRyaWJ1dGUgKi9cbiAgdXNlcl9hdHRyaWJ1dGU6IHJlcXVpcmUoJy4vdXNlcl9hdHRyaWJ1dGUuanMnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOnBhY2tldC9vbmVfcGFzc19zaWduYXR1cmUgKi9cbiAgb25lX3Bhc3Nfc2lnbmF0dXJlOiByZXF1aXJlKCcuL29uZV9wYXNzX3NpZ25hdHVyZS5qcycpLFxuICAvKiogQHNlZSBtb2R1bGU6cGFja2V0L3NlY3JldF9rZXkgKi9cbiAgc2VjcmV0X2tleTogcmVxdWlyZSgnLi9zZWNyZXRfa2V5LmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpwYWNrZXQvdXNlcmlkICovXG4gIHVzZXJpZDogcmVxdWlyZSgnLi91c2VyaWQuanMnKSxcbiAgLyoqIEBzZWUgbW9kdWxlOnBhY2tldC9zZWNyZXRfc3Via2V5ICovXG4gIHNlY3JldF9zdWJrZXk6IHJlcXVpcmUoJy4vc2VjcmV0X3N1YmtleS5qcycpLFxuICAvKiogQHNlZSBtb2R1bGU6cGFja2V0L3NpZ25hdHVyZSAqL1xuICBzaWduYXR1cmU6IHJlcXVpcmUoJy4vc2lnbmF0dXJlLmpzJyksXG4gIC8qKiBAc2VlIG1vZHVsZTpwYWNrZXQvdHJ1c3QgKi9cbiAgdHJ1c3Q6IHJlcXVpcmUoJy4vdHJ1c3QuanMnKVxufVxuXG5mb3IgKHZhciBpIGluIGVudW1zLnBhY2tldCkge1xuICB2YXIgcGFja2V0Q2xhc3MgPSBtb2R1bGUuZXhwb3J0c1tpXTtcblxuICBpZiAocGFja2V0Q2xhc3MgIT0gdW5kZWZpbmVkKVxuICAgIHBhY2tldENsYXNzLnByb3RvdHlwZS50YWcgPSBlbnVtcy5wYWNrZXRbaV07XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEltcGxlbWVudGF0aW9uIG9mIHRoZSBDb21wcmVzc2VkIERhdGEgUGFja2V0IChUYWcgOCk8YnIvPlxuICogPGJyLz5cbiAqIFJGQzQ4ODAgNS42OiBUaGUgQ29tcHJlc3NlZCBEYXRhIHBhY2tldCBjb250YWlucyBjb21wcmVzc2VkIGRhdGEuICBUeXBpY2FsbHksXG4gKiB0aGlzIHBhY2tldCBpcyBmb3VuZCBhcyB0aGUgY29udGVudHMgb2YgYW4gZW5jcnlwdGVkIHBhY2tldCwgb3IgZm9sbG93aW5nXG4gKiBhIFNpZ25hdHVyZSBvciBPbmUtUGFzcyBTaWduYXR1cmUgcGFja2V0LCBhbmQgY29udGFpbnMgYSBsaXRlcmFsIGRhdGEgcGFja2V0LlxuICogQHJlcXVpcmVzIGNvbXByZXNzaW9uL2p4Z1xuICogQHJlcXVpcmVzIGVuY29kaW5nL2Jhc2U2NFxuICogQHJlcXVpcmVzIGVudW1zXG4gKiBAbW9kdWxlIHBhY2tldC9jb21wcmVzc2VkXG4gKi9cblxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcbiAgSlhHID0gcmVxdWlyZSgnLi4vY29tcHJlc3Npb24vanhnLmpzJyksXG4gIGJhc2U2NCA9IHJlcXVpcmUoJy4uL2VuY29kaW5nL2Jhc2U2NC5qcycpO1xuXG4vKipcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGNvbXByZXNzZWQoKSB7XG4gIC8qKlxuICAgKiBMaXN0IG9mIHBhY2tldHNcbiAgICogQHR5cGUge21vZHVsZTpwYWNrZXQvcGFja2V0bGlzdH1cbiAgICovXG4gIHRoaXMucGFja2V0cyA9IG51bGw7XG4gIC8qKlxuICAgKiBDb21wcmVzc2lvbiBhbGdvcml0aG1cbiAgICogQHR5cGUge2NvbXByZXNzaW9ufVxuICAgKi9cbiAgdGhpcy5hbGdvcml0aG0gPSAndW5jb21wcmVzc2VkJztcblxuICAvKipcbiAgICogQ29tcHJlc3NlZCBwYWNrZXQgZGF0YVxuICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgKi9cbiAgdGhpcy5jb21wcmVzc2VkID0gbnVsbDtcblxuXG4gIC8qKlxuICAgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciB0aGUgcGFja2V0LlxuICAgKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXMgUGF5bG9hZCBvZiBhIHRhZyA4IHBhY2tldFxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICAvLyBPbmUgb2N0ZXQgdGhhdCBnaXZlcyB0aGUgYWxnb3JpdGhtIHVzZWQgdG8gY29tcHJlc3MgdGhlIHBhY2tldC5cbiAgICB0aGlzLmFsZ29yaXRobSA9IGVudW1zLnJlYWQoZW51bXMuY29tcHJlc3Npb24sIGJ5dGVzLmNoYXJDb2RlQXQoMCkpO1xuXG4gICAgLy8gQ29tcHJlc3NlZCBkYXRhLCB3aGljaCBtYWtlcyB1cCB0aGUgcmVtYWluZGVyIG9mIHRoZSBwYWNrZXQuXG4gICAgdGhpcy5jb21wcmVzc2VkID0gYnl0ZXMuc3Vic3RyKDEpO1xuXG4gICAgdGhpcy5kZWNvbXByZXNzKCk7XG4gIH1cblxuXG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgY29tcHJlc3NlZCBwYWNrZXQuXG4gICAqIEByZXR1cm4ge1N0cmluZ30gYmluYXJ5IGNvbXByZXNzZWQgcGFja2V0XG4gICAqL1xuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuY29tcHJlc3NlZCA9PSBudWxsKVxuICAgICAgdGhpcy5jb21wcmVzcygpO1xuXG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuY29tcHJlc3Npb24sIHRoaXMuYWxnb3JpdGhtKSkgKyB0aGlzLmNvbXByZXNzZWQ7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBEZWNvbXByZXNzaW9uIG1ldGhvZCBmb3IgZGVjb21wcmVzc2luZyB0aGUgY29tcHJlc3NlZCBkYXRhXG4gICAqIHJlYWQgYnkgcmVhZF9wYWNrZXRcbiAgICovXG4gIHRoaXMuZGVjb21wcmVzcyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBkZWNvbXByZXNzZWQ7XG5cbiAgICBzd2l0Y2ggKHRoaXMuYWxnb3JpdGhtKSB7XG4gICAgICBjYXNlICd1bmNvbXByZXNzZWQnOlxuICAgICAgICBkZWNvbXByZXNzZWQgPSB0aGlzLmNvbXByZXNzZWQ7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICd6aXAnOlxuICAgICAgICB2YXIgY29tcERhdGEgPSB0aGlzLmNvbXByZXNzZWQ7XG5cbiAgICAgICAgdmFyIHJhZGl4ID0gYmFzZTY0LmVuY29kZShjb21wRGF0YSkucmVwbGFjZSgvXFxuL2csIFwiXCIpO1xuICAgICAgICAvLyBubyBoZWFkZXIgaW4gdGhpcyBjYXNlLCBkaXJlY3RseSBjYWxsIGRlZmxhdGVcbiAgICAgICAgdmFyIGp4Z19vYmogPSBuZXcgSlhHLlV0aWwuVW56aXAoSlhHLlV0aWwuQmFzZTY0LmRlY29kZUFzQXJyYXkocmFkaXgpKTtcblxuICAgICAgICBkZWNvbXByZXNzZWQgPSB1bmVzY2FwZShqeGdfb2JqLmRlZmxhdGUoKVswXVswXSk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICd6bGliJzpcbiAgICAgICAgLy9SRkMgMTk1MC4gQml0cyAwLTMgQ29tcHJlc3Npb24gTWV0aG9kXG4gICAgICAgIHZhciBjb21wcmVzc2lvbk1ldGhvZCA9IHRoaXMuY29tcHJlc3NlZC5jaGFyQ29kZUF0KDApICUgMHgxMDtcblxuICAgICAgICAvL0JpdHMgNC03IFJGQyAxOTUwIGFyZSBMWjc3IFdpbmRvdy4gR2VuZXJhbGx5IHRoaXMgdmFsdWUgaXMgNyA9PSAzMmsgd2luZG93IHNpemUuXG4gICAgICAgIC8vIDJuZCBCeXRlIGluIFJGQyAxOTUwIGlzIGZvciBcIkZMQUdzXCIgQWxsb3dzIGZvciBhIERpY3Rpb25hcnkgXG4gICAgICAgIC8vIChob3cgaXMgdGhpcyBkZWZpbmVkKS4gQmFzaWMgY2hlY2tzdW0sIGFuZCBjb21wcmVzc2lvbiBsZXZlbC5cblxuICAgICAgICBpZiAoY29tcHJlc3Npb25NZXRob2QgPT0gOCkgeyAvL0NNIDggaXMgZm9yIERFRkxBVEUsIFJGQyAxOTUxXG4gICAgICAgICAgLy8gcmVtb3ZlIDQgYnl0ZXMgQURMRVIzMiBjaGVja3N1bSBmcm9tIHRoZSBlbmRcbiAgICAgICAgICB2YXIgY29tcERhdGEgPSB0aGlzLmNvbXByZXNzZWQuc3Vic3RyaW5nKDAsIHRoaXMuY29tcHJlc3NlZC5sZW5ndGggLSA0KTtcbiAgICAgICAgICB2YXIgcmFkaXggPSBiYXNlNjQuZW5jb2RlKGNvbXBEYXRhKS5yZXBsYWNlKC9cXG4vZywgXCJcIik7XG4gICAgICAgICAgLy9UT0RPIGNoZWNrIEFETEVSMzIgY2hlY2tzdW1cbiAgICAgICAgICBkZWNvbXByZXNzZWQgPSBKWEcuZGVjb21wcmVzcyhyYWRpeCk7XG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb21wcmVzc2lvbiBhbGdvcml0aG0gWkxJQiBvbmx5IHN1cHBvcnRzIFwiICtcbiAgICAgICAgICAgIFwiREVGTEFURSBjb21wcmVzc2lvbiBtZXRob2QuXCIpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdiemlwMic6XG4gICAgICAgIC8vIFRPRE86IG5lZWQgdG8gaW1wbGVtZW50IHRoaXNcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb21wcmVzc2lvbiBhbGdvcml0aG0gQlppcDIgW0JaMl0gaXMgbm90IGltcGxlbWVudGVkLicpO1xuICAgICAgICBicmVhaztcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29tcHJlc3Npb24gYWxnb3JpdGhtIHVua25vd24gOlwiICsgdGhpcy5hbG9ncml0aG0pO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICB0aGlzLnBhY2tldHMucmVhZChkZWNvbXByZXNzZWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbXByZXNzIHRoZSBwYWNrZXQgZGF0YSAobWVtYmVyIGRlY29tcHJlc3NlZERhdGEpXG4gICAqL1xuICB0aGlzLmNvbXByZXNzID0gZnVuY3Rpb24oKSB7XG4gICAgc3dpdGNoICh0aGlzLmFsZ29yaXRobSkge1xuXG4gICAgICBjYXNlICd1bmNvbXByZXNzZWQnOlxuICAgICAgICAvLyAtIFVuY29tcHJlc3NlZFxuICAgICAgICB0aGlzLmNvbXByZXNzZWQgPSB0aGlzLnBhY2tldHMud3JpdGUoKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ3ppcCc6XG4gICAgICAgIC8vIC0gWklQIFtSRkMxOTUxXVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb21wcmVzc2lvbiBhbGdvcml0aG0gWklQIFtSRkMxOTUxXSBpcyBub3QgaW1wbGVtZW50ZWQuXCIpO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnemxpYic6XG4gICAgICAgIC8vIC0gWkxJQiBbUkZDMTk1MF1cbiAgICAgICAgLy8gVE9ETzogbmVlZCB0byBpbXBsZW1lbnQgdGhpc1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb21wcmVzc2lvbiBhbGdvcml0aG0gWkxJQiBbUkZDMTk1MF0gaXMgbm90IGltcGxlbWVudGVkLlwiKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ2J6aXAyJzpcbiAgICAgICAgLy8gIC0gQlppcDIgW0JaMl1cbiAgICAgICAgLy8gVE9ETzogbmVlZCB0byBpbXBsZW1lbnQgdGhpc1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb21wcmVzc2lvbiBhbGdvcml0aG0gQlppcDIgW0JaMl0gaXMgbm90IGltcGxlbWVudGVkLlwiKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvbXByZXNzaW9uIGFsZ29yaXRobSB1bmtub3duIDpcIiArIHRoaXMudHlwZSk7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufTtcbiIsInZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBsaXN0OiByZXF1aXJlKCcuL3BhY2tldGxpc3QuanMnKVxufTtcblxudmFyIHBhY2tldHMgPSByZXF1aXJlKCcuL2FsbF9wYWNrZXRzLmpzJyk7XG5cbmZvciAodmFyIGkgaW4gcGFja2V0cylcbiAgbW9kdWxlLmV4cG9ydHNbaV0gPSBwYWNrZXRzW2ldO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgTGl0ZXJhbCBEYXRhIFBhY2tldCAoVGFnIDExKTxici8+XG4gKiA8YnIvPlxuICogUkZDNDg4MCA1Ljk6IEEgTGl0ZXJhbCBEYXRhIHBhY2tldCBjb250YWlucyB0aGUgYm9keSBvZiBhIG1lc3NhZ2U7IGRhdGEgdGhhdFxuICogaXMgbm90IHRvIGJlIGZ1cnRoZXIgaW50ZXJwcmV0ZWQuXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIHBhY2tldC9saXRlcmFsXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKTtcblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBsaXRlcmFsKCkge1xuICB0aGlzLmZvcm1hdCA9ICd1dGY4JzsgLy8gZGVmYXVsdCBmb3JtYXQgZm9yIGxpdGVyYWwgZGF0YSBwYWNrZXRzXG4gIHRoaXMuZGF0YSA9ICcnOyAvLyBsaXRlcmFsIGRhdGEgcmVwcmVzZW50YXRpb24gYXMgbmF0aXZlIEphdmFTY3JpcHQgc3RyaW5nIG9yIGJ5dGVzXG4gIHRoaXMuZGF0ZSA9IG5ldyBEYXRlKCk7XG5cblxuICAvKipcbiAgICogU2V0IHRoZSBwYWNrZXQgZGF0YSB0byBhIGphdmFzY3JpcHQgbmF0aXZlIHN0cmluZywgZW5kIG9mIGxpbmUgXG4gICAqIHdpbGwgYmUgbm9ybWFsaXplZCB0byBcXHJcXG4gYW5kIGJ5IGRlZmF1bHQgdGV4dCBpcyBjb252ZXJ0ZWQgdG8gVVRGOFxuICAgKiBAcGFyYW0ge1N0cmluZ30gdGV4dCBBbnkgbmF0aXZlIGphdmFzY3JpcHQgc3RyaW5nXG4gICAqL1xuICB0aGlzLnNldFRleHQgPSBmdW5jdGlvbiAodGV4dCkge1xuICAgIC8vIG5vcm1hbGl6ZSBFT0wgdG8gXFxyXFxuXG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXFxyL2csICcnKS5yZXBsYWNlKC9cXG4vZywgJ1xcclxcbicpO1xuICAgIC8vIGVuY29kZSBVVEY4XG4gICAgdGhpcy5kYXRhID0gdGhpcy5mb3JtYXQgPT0gJ3V0ZjgnID8gdXRpbC5lbmNvZGVfdXRmOCh0ZXh0KSA6IHRleHQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBsaXRlcmFsIGRhdGEgcGFja2V0cyBhcyBuYXRpdmUgSmF2YVNjcmlwdCBzdHJpbmdcbiAgICogd2l0aCBub3JtYWxpemVkIGVuZCBvZiBsaW5lIHRvIFxcblxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IGxpdGVyYWwgZGF0YSBhcyB0ZXh0XG4gICAqL1xuICB0aGlzLmdldFRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgLy8gZGVjb2RlIFVURjhcbiAgICB2YXIgdGV4dCA9IHV0aWwuZGVjb2RlX3V0ZjgodGhpcy5kYXRhKTtcbiAgICAvLyBub3JtYWxpemUgRU9MIHRvIFxcblxuICAgIHJldHVybiB0ZXh0LnJlcGxhY2UoL1xcclxcbi9nLCAnXFxuJyk7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBwYWNrZXQgZGF0YSB0byB2YWx1ZSByZXByZXNlbnRlZCBieSB0aGUgcHJvdmlkZWQgc3RyaW5nIG9mIGJ5dGVzLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXMgVGhlIHN0cmluZyBvZiBieXRlc1xuICAgKiBAcGFyYW0ge3V0Zjh8YmluYXJ5fHRleHR9IGZvcm1hdCBUaGUgZm9ybWF0IG9mIHRoZSBzdHJpbmcgb2YgYnl0ZXNcbiAgICovXG4gIHRoaXMuc2V0Qnl0ZXMgPSBmdW5jdGlvbiAoYnl0ZXMsIGZvcm1hdCkge1xuICAgIHRoaXMuZm9ybWF0ID0gZm9ybWF0O1xuICAgIHRoaXMuZGF0YSA9IGJ5dGVzO1xuICB9XG5cblxuICAvKipcbiAgICogR2V0IHRoZSBieXRlIHNlcXVlbmNlIHJlcHJlc2VudGluZyB0aGUgbGl0ZXJhbCBwYWNrZXQgZGF0YVxuICAgKiBAcmV0dXJucyB7U3RyaW5nfSBBIHNlcXVlbmNlIG9mIGJ5dGVzXG4gICAqL1xuICB0aGlzLmdldEJ5dGVzID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmRhdGE7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIGxpdGVyYWwgZGF0YSBwYWNrZXQgKHRhZyAxMSkuXG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBhIHRhZyAxMSBwYWNrZXRcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBwb3NpdGlvblxuICAgKiAgICAgICAgICAgIFBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgaW5wdXQgc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuXG4gICAqICAgICAgICAgICAgTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2ZcbiAgICogICAgICAgICAgICBpbnB1dCBhdCBwb3NpdGlvblxuICAgKiBAcmV0dXJuIHttb2R1bGU6cGFja2V0L2xpdGVyYWx9IG9iamVjdCByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgLy8gLSBBIG9uZS1vY3RldCBmaWVsZCB0aGF0IGRlc2NyaWJlcyBob3cgdGhlIGRhdGEgaXMgZm9ybWF0dGVkLlxuXG4gICAgdmFyIGZvcm1hdCA9IGVudW1zLnJlYWQoZW51bXMubGl0ZXJhbCwgYnl0ZXMuY2hhckNvZGVBdCgwKSk7XG5cbiAgICB2YXIgZmlsZW5hbWVfbGVuID0gYnl0ZXMuY2hhckNvZGVBdCgxKTtcbiAgICB0aGlzLmZpbGVuYW1lID0gdXRpbC5kZWNvZGVfdXRmOChieXRlcy5zdWJzdHIoMiwgZmlsZW5hbWVfbGVuKSk7XG5cbiAgICB0aGlzLmRhdGUgPSB1dGlsLnJlYWREYXRlKGJ5dGVzLnN1YnN0cigyICsgZmlsZW5hbWVfbGVuLCA0KSk7XG5cbiAgICB2YXIgZGF0YSA9IGJ5dGVzLnN1YnN0cmluZyg2ICsgZmlsZW5hbWVfbGVuKTtcblxuICAgIHRoaXMuc2V0Qnl0ZXMoZGF0YSwgZm9ybWF0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwYWNrZXRcbiAgICogXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIFRoZSBkYXRhIHRvIGJlIGluc2VydGVkIGFzIGJvZHlcbiAgICogQHJldHVybiB7U3RyaW5nfSBzdHJpbmctcmVwcmVzZW50YXRpb24gb2YgdGhlIHBhY2tldFxuICAgKi9cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZmlsZW5hbWUgPSB1dGlsLmVuY29kZV91dGY4KFwibXNnLnR4dFwiKTtcblxuICAgIHZhciBkYXRhID0gdGhpcy5nZXRCeXRlcygpO1xuXG4gICAgdmFyIHJlc3VsdCA9ICcnO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGVudW1zLndyaXRlKGVudW1zLmxpdGVyYWwsIHRoaXMuZm9ybWF0KSk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZmlsZW5hbWUubGVuZ3RoKTtcbiAgICByZXN1bHQgKz0gZmlsZW5hbWU7XG4gICAgcmVzdWx0ICs9IHV0aWwud3JpdGVEYXRlKHRoaXMuZGF0ZSk7XG4gICAgcmVzdWx0ICs9IGRhdGE7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuXG4vKipcbiAqIEltcGxlbWVudGF0aW9uIG9mIHRoZSBzdHJhbmdlIFwiTWFya2VyIHBhY2tldFwiIChUYWcgMTApPGJyLz5cbiAqIDxici8+XG4gKiBSRkM0ODgwIDUuODogQW4gZXhwZXJpbWVudGFsIHZlcnNpb24gb2YgUEdQIHVzZWQgdGhpcyBwYWNrZXQgYXMgdGhlIExpdGVyYWxcbiAqIHBhY2tldCwgYnV0IG5vIHJlbGVhc2VkIHZlcnNpb24gb2YgUEdQIGdlbmVyYXRlZCBMaXRlcmFsIHBhY2tldHMgd2l0aCB0aGlzXG4gKiB0YWcuIFdpdGggUEdQIDUueCwgdGhpcyBwYWNrZXQgaGFzIGJlZW4gcmVhc3NpZ25lZCBhbmQgaXMgcmVzZXJ2ZWQgZm9yIHVzZSBhc1xuICogdGhlIE1hcmtlciBwYWNrZXQuPGJyLz5cbiAqIDxici8+XG4gKiBTdWNoIGEgcGFja2V0IE1VU1QgYmUgaWdub3JlZCB3aGVuIHJlY2VpdmVkLlxuICogQG1vZHVsZSBwYWNrZXQvbWFya2VyXG4gKi9cblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBtYXJrZXIoKSB7XG4gIC8qKlxuICAgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIGxpdGVyYWwgZGF0YSBwYWNrZXQgKHRhZyAxMCkuXG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBhIHRhZyAxMCBwYWNrZXRcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBwb3NpdGlvblxuICAgKiAgICAgICAgICAgIFBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgaW5wdXQgc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuXG4gICAqICAgICAgICAgICAgTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2ZcbiAgICogICAgICAgICAgICBpbnB1dCBhdCBwb3NpdGlvblxuICAgKiBAcmV0dXJuIHttb2R1bGU6cGFja2V0L21hcmtlcn0gT2JqZWN0IHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbiAoYnl0ZXMpIHtcbiAgICBpZiAoYnl0ZXMuY2hhckNvZGVBdCgwKSA9PSAweDUwICYmIC8vIFBcbiAgICBieXRlcy5jaGFyQ29kZUF0KDEpID09IDB4NDcgJiYgLy8gR1xuICAgIGJ5dGVzLmNoYXJDb2RlQXQoMikgPT0gMHg1MCkgLy8gUFxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgLy8gbWFya2VyIHBhY2tldCBkb2VzIG5vdCBjb250YWluIFwiUEdQXCJcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogSW1wbGVtZW50YXRpb24gb2YgdGhlIE9uZS1QYXNzIFNpZ25hdHVyZSBQYWNrZXRzIChUYWcgNCk8YnIvPlxuICogPGJyLz5cbiAqIFJGQzQ4ODAgNS40OlxuICogVGhlIE9uZS1QYXNzIFNpZ25hdHVyZSBwYWNrZXQgcHJlY2VkZXMgdGhlIHNpZ25lZCBkYXRhIGFuZCBjb250YWluc1xuICogZW5vdWdoIGluZm9ybWF0aW9uIHRvIGFsbG93IHRoZSByZWNlaXZlciB0byBiZWdpbiBjYWxjdWxhdGluZyBhbnlcbiAqIGhhc2hlcyBuZWVkZWQgdG8gdmVyaWZ5IHRoZSBzaWduYXR1cmUuICBJdCBhbGxvd3MgdGhlIFNpZ25hdHVyZVxuICogcGFja2V0IHRvIGJlIHBsYWNlZCBhdCB0aGUgZW5kIG9mIHRoZSBtZXNzYWdlLCBzbyB0aGF0IHRoZSBzaWduZXJcbiAqIGNhbiBjb21wdXRlIHRoZSBlbnRpcmUgc2lnbmVkIG1lc3NhZ2UgaW4gb25lIHBhc3MuXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEByZXF1aXJlcyB0eXBlL2tleWlkXG4gKiBAbW9kdWxlIHBhY2tldC9vbmVfcGFzc19zaWduYXR1cmVcbiovXG5cbnZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG4gIHR5cGVfa2V5aWQgPSByZXF1aXJlKCcuLi90eXBlL2tleWlkLmpzJyk7XG5cbi8qKlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gb25lX3Bhc3Nfc2lnbmF0dXJlKCkge1xuICB0aGlzLnZlcnNpb24gPSBudWxsOyAvLyBBIG9uZS1vY3RldCB2ZXJzaW9uIG51bWJlci4gIFRoZSBjdXJyZW50IHZlcnNpb24gaXMgMy5cbiAgdGhpcy50eXBlID0gbnVsbDsgLy8gQSBvbmUtb2N0ZXQgc2lnbmF0dXJlIHR5cGUuICBTaWduYXR1cmUgdHlwZXMgYXJlIGRlc2NyaWJlZCBpbiBSRkM0ODgwIFNlY3Rpb24gNS4yLjEuXG4gIHRoaXMuaGFzaEFsZ29yaXRobSA9IG51bGw7IC8vIEEgb25lLW9jdGV0IG51bWJlciBkZXNjcmliaW5nIHRoZSBoYXNoIGFsZ29yaXRobSB1c2VkLiAoU2VlIFJGQzQ4ODAgOS40KVxuICB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSA9IG51bGw7IC8vIEEgb25lLW9jdGV0IG51bWJlciBkZXNjcmliaW5nIHRoZSBwdWJsaWMta2V5IGFsZ29yaXRobSB1c2VkLiAoU2VlIFJGQzQ4ODAgOS4xKVxuICB0aGlzLnNpZ25pbmdLZXlJZCA9IG51bGw7IC8vIEFuIGVpZ2h0LW9jdGV0IG51bWJlciBob2xkaW5nIHRoZSBLZXkgSUQgb2YgdGhlIHNpZ25pbmcga2V5LlxuICB0aGlzLmZsYWdzID0gbnVsbDsgLy8gIEEgb25lLW9jdGV0IG51bWJlciBob2xkaW5nIGEgZmxhZyBzaG93aW5nIHdoZXRoZXIgdGhlIHNpZ25hdHVyZSBpcyBuZXN0ZWQuICBBIHplcm8gdmFsdWUgaW5kaWNhdGVzIHRoYXQgdGhlIG5leHQgcGFja2V0IGlzIGFub3RoZXIgT25lLVBhc3MgU2lnbmF0dXJlIHBhY2tldCB0aGF0IGRlc2NyaWJlcyBhbm90aGVyIHNpZ25hdHVyZSB0byBiZSBhcHBsaWVkIHRvIHRoZSBzYW1lIG1lc3NhZ2UgZGF0YS5cblxuICAvKipcbiAgICogcGFyc2luZyBmdW5jdGlvbiBmb3IgYSBvbmUtcGFzcyBzaWduYXR1cmUgcGFja2V0ICh0YWcgNCkuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBieXRlcyBwYXlsb2FkIG9mIGEgdGFnIDQgcGFja2V0XG4gICAqIEByZXR1cm4ge21vZHVsZTpwYWNrZXQvb25lX3Bhc3Nfc2lnbmF0dXJlfSBvYmplY3QgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uIChieXRlcykge1xuICAgIHZhciBteXBvcyA9IDA7XG4gICAgLy8gQSBvbmUtb2N0ZXQgdmVyc2lvbiBudW1iZXIuICBUaGUgY3VycmVudCB2ZXJzaW9uIGlzIDMuXG4gICAgdGhpcy52ZXJzaW9uID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKTtcblxuICAgIC8vIEEgb25lLW9jdGV0IHNpZ25hdHVyZSB0eXBlLiAgU2lnbmF0dXJlIHR5cGVzIGFyZSBkZXNjcmliZWQgaW5cbiAgICAvLyAgIFNlY3Rpb24gNS4yLjEuXG4gICAgdGhpcy50eXBlID0gZW51bXMucmVhZChlbnVtcy5zaWduYXR1cmUsIGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKykpO1xuXG4gICAgLy8gQSBvbmUtb2N0ZXQgbnVtYmVyIGRlc2NyaWJpbmcgdGhlIGhhc2ggYWxnb3JpdGhtIHVzZWQuXG4gICAgdGhpcy5oYXNoQWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5oYXNoLCBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspKTtcblxuICAgIC8vIEEgb25lLW9jdGV0IG51bWJlciBkZXNjcmliaW5nIHRoZSBwdWJsaWMta2V5IGFsZ29yaXRobSB1c2VkLlxuICAgIHRoaXMucHVibGljS2V5QWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5wdWJsaWNLZXksIGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKykpO1xuXG4gICAgLy8gQW4gZWlnaHQtb2N0ZXQgbnVtYmVyIGhvbGRpbmcgdGhlIEtleSBJRCBvZiB0aGUgc2lnbmluZyBrZXkuXG4gICAgdGhpcy5zaWduaW5nS2V5SWQgPSBuZXcgdHlwZV9rZXlpZCgpO1xuICAgIHRoaXMuc2lnbmluZ0tleUlkLnJlYWQoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG4gICAgbXlwb3MgKz0gODtcblxuICAgIC8vIEEgb25lLW9jdGV0IG51bWJlciBob2xkaW5nIGEgZmxhZyBzaG93aW5nIHdoZXRoZXIgdGhlIHNpZ25hdHVyZVxuICAgIC8vICAgaXMgbmVzdGVkLiAgQSB6ZXJvIHZhbHVlIGluZGljYXRlcyB0aGF0IHRoZSBuZXh0IHBhY2tldCBpc1xuICAgIC8vICAgYW5vdGhlciBPbmUtUGFzcyBTaWduYXR1cmUgcGFja2V0IHRoYXQgZGVzY3JpYmVzIGFub3RoZXJcbiAgICAvLyAgIHNpZ25hdHVyZSB0byBiZSBhcHBsaWVkIHRvIHRoZSBzYW1lIG1lc3NhZ2UgZGF0YS5cbiAgICB0aGlzLmZsYWdzID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBjcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgb25lLXBhc3Mgc2lnbmF0dXJlIHBhY2tldFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgb25lLXBhc3Mgc2lnbmF0dXJlIHBhY2tldFxuICAgKi9cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcmVzdWx0ID0gXCJcIjtcblxuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDMpO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGVudW1zLndyaXRlKGVudW1zLnNpZ25hdHVyZSwgdGhpcy50eXBlKSk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuaGFzaCwgdGhpcy5oYXNoQWxnb3JpdGhtKSk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSkpO1xuICAgIHJlc3VsdCArPSB0aGlzLnNpZ25pbmdLZXlJZC53cml0ZSgpO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuZmxhZ3MpO1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQHJlcXVpcmVzIGVudW1zXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSBwYWNrZXQvcGFja2V0XG4gKi9cblxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcbiAgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgcmVhZFNpbXBsZUxlbmd0aDogZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICB2YXIgbGVuID0gMCxcbiAgICAgIG9mZnNldCxcbiAgICAgIHR5cGUgPSBieXRlcy5jaGFyQ29kZUF0KDApO1xuXG5cbiAgICBpZiAodHlwZSA8IDE5Mikge1xuICAgICAgbGVuID0gYnl0ZXMuY2hhckNvZGVBdCgwKTtcbiAgICAgIG9mZnNldCA9IDE7XG4gICAgfSBlbHNlIGlmICh0eXBlIDwgMjU1KSB7XG4gICAgICBsZW4gPSAoKGJ5dGVzLmNoYXJDb2RlQXQoMCkgLSAxOTIpIDw8IDgpICsgKGJ5dGVzLmNoYXJDb2RlQXQoMSkpICsgMTkyO1xuICAgICAgb2Zmc2V0ID0gMjtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT0gMjU1KSB7XG4gICAgICBsZW4gPSB1dGlsLnJlYWROdW1iZXIoYnl0ZXMuc3Vic3RyKDEsIDQpKTtcbiAgICAgIG9mZnNldCA9IDU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGxlbjogbGVuLFxuICAgICAgb2Zmc2V0OiBvZmZzZXRcbiAgICB9O1xuICB9LFxuXG4gIC8qKlxuICAgKiBFbmNvZGVzIGEgZ2l2ZW4gaW50ZWdlciBvZiBsZW5ndGggdG8gdGhlIG9wZW5wZ3AgbGVuZ3RoIHNwZWNpZmllciB0byBhXG4gICAqIHN0cmluZ1xuICAgKiBcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5ndGggVGhlIGxlbmd0aCB0byBlbmNvZGVcbiAgICogQHJldHVybiB7U3RyaW5nfSBTdHJpbmcgd2l0aCBvcGVucGdwIGxlbmd0aCByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgd3JpdGVTaW1wbGVMZW5ndGg6IGZ1bmN0aW9uKGxlbmd0aCkge1xuICAgIHZhciByZXN1bHQgPSBcIlwiO1xuICAgIGlmIChsZW5ndGggPCAxOTIpIHtcbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGxlbmd0aCk7XG4gICAgfSBlbHNlIGlmIChsZW5ndGggPiAxOTEgJiYgbGVuZ3RoIDwgODM4NCkge1xuICAgICAgLypcbiAgICAgICAqIGxldCBhID0gKHRvdGFsIGRhdGEgcGFja2V0IGxlbmd0aCkgLSAxOTIgbGV0IGJjID0gdHdvIG9jdGV0XG4gICAgICAgKiByZXByZXNlbnRhdGlvbiBvZiBhIGxldCBkID0gYiArIDE5MlxuICAgICAgICovXG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoKGxlbmd0aCAtIDE5MikgPj4gOCkgKyAxOTIpO1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGxlbmd0aCAtIDE5MikgJiAweEZGKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMjU1KTtcbiAgICAgIHJlc3VsdCArPSB1dGlsLndyaXRlTnVtYmVyKGxlbmd0aCwgNCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFdyaXRlcyBhIHBhY2tldCBoZWFkZXIgdmVyc2lvbiA0IHdpdGggdGhlIGdpdmVuIHRhZ190eXBlIGFuZCBsZW5ndGggdG8gYVxuICAgKiBzdHJpbmdcbiAgICogXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gdGFnX3R5cGUgVGFnIHR5cGVcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5ndGggTGVuZ3RoIG9mIHRoZSBwYXlsb2FkXG4gICAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIG9mIHRoZSBoZWFkZXJcbiAgICovXG4gIHdyaXRlSGVhZGVyOiBmdW5jdGlvbih0YWdfdHlwZSwgbGVuZ3RoKSB7XG4gICAgLyogd2UncmUgb25seSBnZW5lcmF0aW5nIHY0IHBhY2tldCBoZWFkZXJzIGhlcmUgKi9cbiAgICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweEMwIHwgdGFnX3R5cGUpO1xuICAgIHJlc3VsdCArPSB0aGlzLndyaXRlU2ltcGxlTGVuZ3RoKGxlbmd0aCk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSxcblxuICAvKipcbiAgICogV3JpdGVzIGEgcGFja2V0IGhlYWRlciBWZXJzaW9uIDMgd2l0aCB0aGUgZ2l2ZW4gdGFnX3R5cGUgYW5kIGxlbmd0aCB0byBhXG4gICAqIHN0cmluZ1xuICAgKiBcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSB0YWdfdHlwZSBUYWcgdHlwZVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlbmd0aCBMZW5ndGggb2YgdGhlIHBheWxvYWRcbiAgICogQHJldHVybiB7U3RyaW5nfSBTdHJpbmcgb2YgdGhlIGhlYWRlclxuICAgKi9cbiAgd3JpdGVPbGRIZWFkZXI6IGZ1bmN0aW9uKHRhZ190eXBlLCBsZW5ndGgpIHtcbiAgICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgICBpZiAobGVuZ3RoIDwgMjU2KSB7XG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDgwIHwgKHRhZ190eXBlIDw8IDIpKTtcbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGxlbmd0aCk7XG4gICAgfSBlbHNlIGlmIChsZW5ndGggPCA2NTUzNikge1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHg4MCB8ICh0YWdfdHlwZSA8PCAyKSB8IDEpO1xuICAgICAgcmVzdWx0ICs9IHV0aWwud3JpdGVOdW1iZXIobGVuZ3RoLCAyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHg4MCB8ICh0YWdfdHlwZSA8PCAyKSB8IDIpO1xuICAgICAgcmVzdWx0ICs9IHV0aWwud3JpdGVOdW1iZXIobGVuZ3RoLCA0KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSxcblxuICAvKipcbiAgICogR2VuZXJpYyBzdGF0aWMgUGFja2V0IFBhcnNlciBmdW5jdGlvblxuICAgKiBcbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IElucHV0IHN0cmVhbSBhcyBzdHJpbmdcbiAgICogQHBhcmFtIHtpbnRlZ2VyfSBwb3NpdGlvbiBQb3NpdGlvbiB0byBzdGFydCBwYXJzaW5nXG4gICAqIEBwYXJhbSB7aW50ZWdlcn0gbGVuIExlbmd0aCBvZiB0aGUgaW5wdXQgZnJvbSBwb3NpdGlvbiBvblxuICAgKiBAcmV0dXJuIHtPYmplY3R9IFJldHVybnMgYSBwYXJzZWQgbW9kdWxlOnBhY2tldC9wYWNrZXRcbiAgICovXG4gIHJlYWQ6IGZ1bmN0aW9uKGlucHV0LCBwb3NpdGlvbiwgbGVuKSB7XG4gICAgLy8gc29tZSBzYW5pdHkgY2hlY2tzXG4gICAgaWYgKGlucHV0ID09IG51bGwgfHwgaW5wdXQubGVuZ3RoIDw9IHBvc2l0aW9uIHx8IGlucHV0LnN1YnN0cmluZyhwb3NpdGlvbikubGVuZ3RoIDwgMiB8fCAoaW5wdXQuY2hhckNvZGVBdChwb3NpdGlvbikgJlxuICAgICAgMHg4MCkgPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRXJyb3IgZHVyaW5nIHBhcnNpbmcuIFRoaXMgbWVzc2FnZSAvIGtleSBpcyBwcm9iYWJseSBub3QgY29udGFpbmluZyBhIHZhbGlkIE9wZW5QR1AgZm9ybWF0LlwiKTtcbiAgICB9XG4gICAgdmFyIG15cG9zID0gcG9zaXRpb247XG4gICAgdmFyIHRhZyA9IC0xO1xuICAgIHZhciBmb3JtYXQgPSAtMTtcbiAgICB2YXIgcGFja2V0X2xlbmd0aDtcblxuICAgIGZvcm1hdCA9IDA7IC8vIDAgPSBvbGQgZm9ybWF0OyAxID0gbmV3IGZvcm1hdFxuICAgIGlmICgoaW5wdXQuY2hhckNvZGVBdChteXBvcykgJiAweDQwKSAhPSAwKSB7XG4gICAgICBmb3JtYXQgPSAxO1xuICAgIH1cblxuICAgIHZhciBwYWNrZXRfbGVuZ3RoX3R5cGU7XG4gICAgaWYgKGZvcm1hdCkge1xuICAgICAgLy8gbmV3IGZvcm1hdCBoZWFkZXJcbiAgICAgIHRhZyA9IGlucHV0LmNoYXJDb2RlQXQobXlwb3MpICYgMHgzRjsgLy8gYml0IDUtMFxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBvbGQgZm9ybWF0IGhlYWRlclxuICAgICAgdGFnID0gKGlucHV0LmNoYXJDb2RlQXQobXlwb3MpICYgMHgzRikgPj4gMjsgLy8gYml0IDUtMlxuICAgICAgcGFja2V0X2xlbmd0aF90eXBlID0gaW5wdXQuY2hhckNvZGVBdChteXBvcykgJiAweDAzOyAvLyBiaXQgMS0wXG4gICAgfVxuXG4gICAgLy8gaGVhZGVyIG9jdGV0IHBhcnNpbmcgZG9uZVxuICAgIG15cG9zKys7XG5cbiAgICAvLyBwYXJzZWQgbGVuZ3RoIGZyb20gbGVuZ3RoIGZpZWxkXG4gICAgdmFyIGJvZHlkYXRhID0gbnVsbDtcblxuICAgIC8vIHVzZWQgZm9yIHBhcnRpYWwgYm9keSBsZW5ndGhzXG4gICAgdmFyIHJlYWxfcGFja2V0X2xlbmd0aCA9IC0xO1xuICAgIGlmICghZm9ybWF0KSB7XG4gICAgICAvLyA0LjIuMS4gT2xkIEZvcm1hdCBQYWNrZXQgTGVuZ3Roc1xuICAgICAgc3dpdGNoIChwYWNrZXRfbGVuZ3RoX3R5cGUpIHtcbiAgICAgICAgY2FzZSAwOlxuICAgICAgICAgIC8vIFRoZSBwYWNrZXQgaGFzIGEgb25lLW9jdGV0IGxlbmd0aC4gVGhlIGhlYWRlciBpcyAyIG9jdGV0c1xuICAgICAgICAgIC8vIGxvbmcuXG4gICAgICAgICAgcGFja2V0X2xlbmd0aCA9IGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAvLyBUaGUgcGFja2V0IGhhcyBhIHR3by1vY3RldCBsZW5ndGguIFRoZSBoZWFkZXIgaXMgMyBvY3RldHNcbiAgICAgICAgICAvLyBsb25nLlxuICAgICAgICAgIHBhY2tldF9sZW5ndGggPSAoaW5wdXQuY2hhckNvZGVBdChteXBvcysrKSA8PCA4KSB8IGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAvLyBUaGUgcGFja2V0IGhhcyBhIGZvdXItb2N0ZXQgbGVuZ3RoLiBUaGUgaGVhZGVyIGlzIDVcbiAgICAgICAgICAvLyBvY3RldHMgbG9uZy5cbiAgICAgICAgICBwYWNrZXRfbGVuZ3RoID0gKGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKykgPDwgMjQpIHwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKykgPDwgMTYpIHwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKykgPDxcbiAgICAgICAgICAgIDgpIHwgaW5wdXQuY2hhckNvZGVBdChteXBvcysrKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAvLyAzIC0gVGhlIHBhY2tldCBpcyBvZiBpbmRldGVybWluYXRlIGxlbmd0aC4gVGhlIGhlYWRlciBpcyAxXG4gICAgICAgICAgLy8gb2N0ZXQgbG9uZywgYW5kIHRoZSBpbXBsZW1lbnRhdGlvbiBtdXN0IGRldGVybWluZSBob3cgbG9uZ1xuICAgICAgICAgIC8vIHRoZSBwYWNrZXQgaXMuIElmIHRoZSBwYWNrZXQgaXMgaW4gYSBmaWxlLCB0aGlzIG1lYW5zIHRoYXRcbiAgICAgICAgICAvLyB0aGUgcGFja2V0IGV4dGVuZHMgdW50aWwgdGhlIGVuZCBvZiB0aGUgZmlsZS4gSW4gZ2VuZXJhbCwgXG4gICAgICAgICAgLy8gYW4gaW1wbGVtZW50YXRpb24gU0hPVUxEIE5PVCB1c2UgaW5kZXRlcm1pbmF0ZS1sZW5ndGggXG4gICAgICAgICAgLy8gcGFja2V0cyBleGNlcHQgd2hlcmUgdGhlIGVuZCBvZiB0aGUgZGF0YSB3aWxsIGJlIGNsZWFyIFxuICAgICAgICAgIC8vIGZyb20gdGhlIGNvbnRleHQsIGFuZCBldmVuIHRoZW4gaXQgaXMgYmV0dGVyIHRvIHVzZSBhIFxuICAgICAgICAgIC8vIGRlZmluaXRlIGxlbmd0aCwgb3IgYSBuZXcgZm9ybWF0IGhlYWRlci4gVGhlIG5ldyBmb3JtYXQgXG4gICAgICAgICAgLy8gaGVhZGVycyBkZXNjcmliZWQgYmVsb3cgaGF2ZSBhIG1lY2hhbmlzbSBmb3IgcHJlY2lzZWx5XG4gICAgICAgICAgLy8gZW5jb2RpbmcgZGF0YSBvZiBpbmRldGVybWluYXRlIGxlbmd0aC5cbiAgICAgICAgICBwYWNrZXRfbGVuZ3RoID0gbGVuO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgfSBlbHNlIC8vIDQuMi4yLiBOZXcgRm9ybWF0IFBhY2tldCBMZW5ndGhzXG4gICAge1xuXG4gICAgICAvLyA0LjIuMi4xLiBPbmUtT2N0ZXQgTGVuZ3Roc1xuICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MpIDwgMTkyKSB7XG4gICAgICAgIHBhY2tldF9sZW5ndGggPSBpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgICB1dGlsLnByaW50X2RlYnVnKFwiMSBieXRlIGxlbmd0aDpcIiArIHBhY2tldF9sZW5ndGgpO1xuICAgICAgICAvLyA0LjIuMi4yLiBUd28tT2N0ZXQgTGVuZ3Roc1xuICAgICAgfSBlbHNlIGlmIChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKSA+PSAxOTIgJiYgaW5wdXQuY2hhckNvZGVBdChteXBvcykgPCAyMjQpIHtcbiAgICAgICAgcGFja2V0X2xlbmd0aCA9ICgoaW5wdXQuY2hhckNvZGVBdChteXBvcysrKSAtIDE5MikgPDwgOCkgKyAoaW5wdXQuY2hhckNvZGVBdChteXBvcysrKSkgKyAxOTI7XG4gICAgICAgIHV0aWwucHJpbnRfZGVidWcoXCIyIGJ5dGUgbGVuZ3RoOlwiICsgcGFja2V0X2xlbmd0aCk7XG4gICAgICAgIC8vIDQuMi4yLjQuIFBhcnRpYWwgQm9keSBMZW5ndGhzXG4gICAgICB9IGVsc2UgaWYgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MpID4gMjIzICYmIGlucHV0LmNoYXJDb2RlQXQobXlwb3MpIDwgMjU1KSB7XG4gICAgICAgIHBhY2tldF9sZW5ndGggPSAxIDw8IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspICYgMHgxRik7XG4gICAgICAgIHV0aWwucHJpbnRfZGVidWcoXCI0IGJ5dGUgbGVuZ3RoOlwiICsgcGFja2V0X2xlbmd0aCk7XG4gICAgICAgIC8vIEVFRUssIHdlJ3JlIHJlYWRpbmcgdGhlIGZ1bGwgZGF0YSBoZXJlLi4uXG4gICAgICAgIHZhciBteXBvczIgPSBteXBvcyArIHBhY2tldF9sZW5ndGg7XG4gICAgICAgIGJvZHlkYXRhID0gaW5wdXQuc3Vic3RyaW5nKG15cG9zLCBteXBvcyArIHBhY2tldF9sZW5ndGgpO1xuICAgICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KG15cG9zMikgPCAxOTIpIHtcbiAgICAgICAgICAgIHZhciB0bXBsZW4gPSBpbnB1dC5jaGFyQ29kZUF0KG15cG9zMisrKTtcbiAgICAgICAgICAgIHBhY2tldF9sZW5ndGggKz0gdG1wbGVuO1xuICAgICAgICAgICAgYm9keWRhdGEgKz0gaW5wdXQuc3Vic3RyaW5nKG15cG9zMiwgbXlwb3MyICsgdG1wbGVuKTtcbiAgICAgICAgICAgIG15cG9zMiArPSB0bXBsZW47XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9IGVsc2UgaWYgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKSA+PSAxOTIgJiYgaW5wdXQuY2hhckNvZGVBdChteXBvczIpIDwgMjI0KSB7XG4gICAgICAgICAgICB2YXIgdG1wbGVuID0gKChpbnB1dC5jaGFyQ29kZUF0KG15cG9zMisrKSAtIDE5MikgPDwgOCkgKyAoaW5wdXQuY2hhckNvZGVBdChteXBvczIrKykpICsgMTkyO1xuICAgICAgICAgICAgcGFja2V0X2xlbmd0aCArPSB0bXBsZW47XG4gICAgICAgICAgICBib2R5ZGF0YSArPSBpbnB1dC5zdWJzdHJpbmcobXlwb3MyLCBteXBvczIgKyB0bXBsZW4pO1xuICAgICAgICAgICAgbXlwb3MyICs9IHRtcGxlbjtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaW5wdXQuY2hhckNvZGVBdChteXBvczIpID4gMjIzICYmIGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKSA8IDI1NSkge1xuICAgICAgICAgICAgdmFyIHRtcGxlbiA9IDEgPDwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKyspICYgMHgxRik7XG4gICAgICAgICAgICBwYWNrZXRfbGVuZ3RoICs9IHRtcGxlbjtcbiAgICAgICAgICAgIGJvZHlkYXRhICs9IGlucHV0LnN1YnN0cmluZyhteXBvczIsIG15cG9zMiArIHRtcGxlbik7XG4gICAgICAgICAgICBteXBvczIgKz0gdG1wbGVuO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBteXBvczIrKztcbiAgICAgICAgICAgIHZhciB0bXBsZW4gPSAoaW5wdXQuY2hhckNvZGVBdChteXBvczIrKykgPDwgMjQpIHwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKyspIDw8IDE2KSB8IChpbnB1dFtteXBvczIrK11cbiAgICAgICAgICAgICAgLmNoYXJDb2RlQXQoKSA8PCA4KSB8IGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKyspO1xuICAgICAgICAgICAgYm9keWRhdGEgKz0gaW5wdXQuc3Vic3RyaW5nKG15cG9zMiwgbXlwb3MyICsgdG1wbGVuKTtcbiAgICAgICAgICAgIHBhY2tldF9sZW5ndGggKz0gdG1wbGVuO1xuICAgICAgICAgICAgbXlwb3MyICs9IHRtcGxlbjtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZWFsX3BhY2tldF9sZW5ndGggPSBteXBvczI7XG4gICAgICAgIC8vIDQuMi4yLjMuIEZpdmUtT2N0ZXQgTGVuZ3Roc1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbXlwb3MrKztcbiAgICAgICAgcGFja2V0X2xlbmd0aCA9IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspIDw8IDI0KSB8IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspIDw8IDE2KSB8IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspIDw8XG4gICAgICAgICAgOCkgfCBpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGlmIHRoZXJlIHdhcydudCBhIHBhcnRpYWwgYm9keSBsZW5ndGg6IHVzZSB0aGUgc3BlY2lmaWVkXG4gICAgLy8gcGFja2V0X2xlbmd0aFxuICAgIGlmIChyZWFsX3BhY2tldF9sZW5ndGggPT0gLTEpIHtcbiAgICAgIHJlYWxfcGFja2V0X2xlbmd0aCA9IHBhY2tldF9sZW5ndGg7XG4gICAgfVxuXG4gICAgaWYgKGJvZHlkYXRhID09IG51bGwpIHtcbiAgICAgIGJvZHlkYXRhID0gaW5wdXQuc3Vic3RyaW5nKG15cG9zLCBteXBvcyArIHJlYWxfcGFja2V0X2xlbmd0aCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRhZzogdGFnLFxuICAgICAgcGFja2V0OiBib2R5ZGF0YSxcbiAgICAgIG9mZnNldDogbXlwb3MgKyByZWFsX3BhY2tldF9sZW5ndGhcbiAgICB9O1xuICB9XG59XG4iLCIvKipcbiAqIFRoaXMgY2xhc3MgcmVwcmVzZW50cyBhIGxpc3Qgb2Ygb3BlbnBncCBwYWNrZXRzLlxuICogVGFrZSBjYXJlIHdoZW4gaXRlcmF0aW5nIG92ZXIgaXQgLSB0aGUgcGFja2V0cyB0aGVtc2VsdmVzXG4gKiBhcmUgc3RvcmVkIGFzIG51bWVyaWNhbCBpbmRpY2VzLlxuICogQHJlcXVpcmVzIGVudW1zXG4gKiBAcmVxdWlyZXMgcGFja2V0XG4gKiBAcmVxdWlyZXMgcGFja2V0L3BhY2tldFxuICogQG1vZHVsZSBwYWNrZXQvcGFja2V0bGlzdFxuICovXG5cbnZhciBwYWNrZXRQYXJzZXIgPSByZXF1aXJlKCcuL3BhY2tldC5qcycpLFxuICBwYWNrZXRzID0gcmVxdWlyZSgnLi9hbGxfcGFja2V0cy5qcycpLFxuICBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbi8qKlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0bGlzdCgpIHtcbiAgLyoqIFRoZSBudW1iZXIgb2YgcGFja2V0cyBjb250YWluZWQgd2l0aGluIHRoZSBsaXN0LlxuICAgKiBAcmVhZG9ubHlcbiAgICogQHR5cGUge0ludGVnZXJ9ICovXG4gIHRoaXMubGVuZ3RoID0gMDtcblxuICAvKipcbiAgICogUmVhZHMgYSBzdHJlYW0gb2YgYmluYXJ5IGRhdGEgYW5kIGludGVycHJlbnRzIGl0IGFzIGEgbGlzdCBvZiBwYWNrZXRzLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gQSBiaW5hcnkgc3RyaW5nIG9mIGJ5dGVzLlxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgdmFyIGkgPSAwO1xuXG4gICAgd2hpbGUgKGkgPCBieXRlcy5sZW5ndGgpIHtcbiAgICAgIHZhciBwYXJzZWQgPSBwYWNrZXRQYXJzZXIucmVhZChieXRlcywgaSwgYnl0ZXMubGVuZ3RoIC0gaSk7XG4gICAgICBpID0gcGFyc2VkLm9mZnNldDtcblxuICAgICAgdmFyIHRhZyA9IGVudW1zLnJlYWQoZW51bXMucGFja2V0LCBwYXJzZWQudGFnKTtcbiAgICAgIHZhciBwYWNrZXQgPSBuZXcgcGFja2V0c1t0YWddKCk7XG5cbiAgICAgIHRoaXMucHVzaChwYWNrZXQpO1xuXG4gICAgICBwYWNrZXQucmVhZChwYXJzZWQucGFja2V0KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGJpbmFyeSByZXByZXNlbnRhdGlvbiBvZiBvcGVucGdwIG9iamVjdHMgY29udGFpbmVkIHdpdGhpbiB0aGVcbiAgICogY2xhc3MgaW5zdGFuY2UuXG4gICAqIEByZXR1cm5zIHtTdHJpbmd9IEEgYmluYXJ5IHN0cmluZyBvZiBieXRlcyBjb250YWluaW5nIHZhbGlkIG9wZW5wZ3AgcGFja2V0cy5cbiAgICovXG4gIHRoaXMud3JpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGJ5dGVzID0gJyc7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBwYWNrZXRieXRlcyA9IHRoaXNbaV0ud3JpdGUoKTtcbiAgICAgIGJ5dGVzICs9IHBhY2tldFBhcnNlci53cml0ZUhlYWRlcih0aGlzW2ldLnRhZywgcGFja2V0Ynl0ZXMubGVuZ3RoKTtcbiAgICAgIGJ5dGVzICs9IHBhY2tldGJ5dGVzO1xuICAgIH1cblxuICAgIHJldHVybiBieXRlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgcGFja2V0IHRvIHRoZSBsaXN0LiBUaGlzIGlzIHRoZSBvbmx5IHN1cHBvcnRlZCBtZXRob2Qgb2YgZG9pbmcgc287XG4gICAqIHdyaXRpbmcgdG8gcGFja2V0bGlzdFtpXSBkaXJlY3RseSB3aWxsIHJlc3VsdCBpbiBhbiBlcnJvci5cbiAgICovXG4gIHRoaXMucHVzaCA9IGZ1bmN0aW9uIChwYWNrZXQpIHtcbiAgICBpZiAoIXBhY2tldCkgcmV0dXJuO1xuXG4gICAgcGFja2V0LnBhY2tldHMgPSBwYWNrZXQucGFja2V0cyB8fCBuZXcgcGFja2V0bGlzdCgpO1xuXG4gICAgdGhpc1t0aGlzLmxlbmd0aF0gPSBwYWNrZXQ7XG4gICAgdGhpcy5sZW5ndGgrKztcbiAgfVxuXG4gIC8qKlxuICAqIENyZWF0ZXMgYSBuZXcgcGFja2V0TGlzdCB3aXRoIGFsbCBwYWNrZXRzIHRoYXQgcGFzcyB0aGUgdGVzdCBpbXBsZW1lbnRlZCBieSB0aGUgcHJvdmlkZWQgZnVuY3Rpb24uXG4gICovXG4gIHRoaXMuZmlsdGVyID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG5cbiAgICB2YXIgZmlsdGVyZWQgPSBuZXcgcGFja2V0bGlzdCgpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoY2FsbGJhY2sodGhpc1tpXSwgaSwgdGhpcykpIHtcbiAgICAgICAgZmlsdGVyZWQucHVzaCh0aGlzW2ldKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmlsdGVyZWQ7XG4gIH1cblxuICAvKipcbiAgKiBDcmVhdGVzIGEgbmV3IHBhY2tldExpc3Qgd2l0aCBhbGwgcGFja2V0cyBmcm9tIHRoZSBnaXZlbiB0eXBlc1xuICAqL1xuICB0aGlzLmZpbHRlckJ5VGFnID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICB2YXIgZmlsdGVyZWQgPSBuZXcgcGFja2V0bGlzdCgpO1xuICAgIHZhciB0aGF0ID0gdGhpcztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFyZ3Muc29tZShmdW5jdGlvbihwYWNrZXRUeXBlKSB7cmV0dXJuIHRoYXRbaV0udGFnID09IHBhY2tldFR5cGV9KSkge1xuICAgICAgICBmaWx0ZXJlZC5wdXNoKHRoaXNbaV0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmaWx0ZXJlZDtcbiAgfSBcblxuICAvKipcbiAgKiBFeGVjdXRlcyB0aGUgcHJvdmlkZWQgY2FsbGJhY2sgb25jZSBmb3IgZWFjaCBlbGVtZW50XG4gICovXG4gIHRoaXMuZm9yRWFjaCA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgY2FsbGJhY2sodGhpc1tpXSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlcyBwYWNrZXQgdHJlZSBhbmQgcmV0dXJucyBmaXJzdCBtYXRjaGluZyBwYWNrZXRcbiAgICogQHBhcmFtICB7bW9kdWxlOmVudW1zLnBhY2tldH0gdHlwZSBUaGUgcGFja2V0IHR5cGVcbiAgICogQHJldHVybiB7bW9kdWxlOnBhY2tldC9wYWNrZXR8bnVsbH0gICAgICBcbiAgICovXG4gIHRoaXMuZmluZFBhY2tldCA9IGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgdmFyIHBhY2tldGxpc3QgPSB0aGlzLmZpbHRlckJ5VGFnKHR5cGUpO1xuICAgIGlmIChwYWNrZXRsaXN0Lmxlbmd0aCkge1xuICAgICAgcmV0dXJuIHBhY2tldGxpc3RbMF07XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBmb3VuZCA9IG51bGw7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKHRoaXNbaV0ucGFja2V0cy5sZW5ndGgpIHtcbiAgICAgICAgICBmb3VuZCA9IHRoaXNbaV0ucGFja2V0cy5maW5kUGFja2V0KHR5cGUpO1xuICAgICAgICAgIGlmIChmb3VuZCkgcmV0dXJuIGZvdW5kO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYXJyYXkgb2YgZm91bmQgaW5kaWNlcyBieSB0YWdcbiAgICovXG4gIHRoaXMuaW5kZXhPZlRhZyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgdmFyIHRhZ0luZGV4ID0gW107XG4gICAgdmFyIHRoYXQgPSB0aGlzO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFyZ3Muc29tZShmdW5jdGlvbihwYWNrZXRUeXBlKSB7cmV0dXJuIHRoYXRbaV0udGFnID09IHBhY2tldFR5cGV9KSkge1xuICAgICAgICB0YWdJbmRleC5wdXNoKGkpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGFnSW5kZXg7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzbGljZSBvZiBwYWNrZXRsaXN0XG4gICAqL1xuICB0aGlzLnNsaWNlID0gZnVuY3Rpb24gKGJlZ2luLCBlbmQpIHtcbiAgICBpZiAoIWVuZCkge1xuICAgICAgZW5kID0gdGhpcy5sZW5ndGhcbiAgICB9XG4gICAgdmFyIHBhcnQgPSBuZXcgcGFja2V0bGlzdCgpO1xuICAgIGZvciAodmFyIGkgPSBiZWdpbjsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICBwYXJ0LnB1c2godGhpc1tpXSk7XG4gICAgfVxuICAgIHJldHVybiBwYXJ0O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbmNhdGVuYXRlcyBwYWNrZXRsaXN0IG9yIGFycmF5IG9mIHBhY2tldHNcbiAgICovXG4gIHRoaXMuY29uY2F0ID0gZnVuY3Rpb24gKHBhY2tldGxpc3QpIHtcbiAgICBpZiAocGFja2V0bGlzdCkge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYWNrZXRsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMucHVzaChwYWNrZXRsaXN0W2ldKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgS2V5IE1hdGVyaWFsIFBhY2tldCAoVGFnIDUsNiw3LDE0KTxici8+XG4gKiA8YnIvPlxuICogUkZDNDQ4MCA1LjU6XG4gKiBBIGtleSBtYXRlcmlhbCBwYWNrZXQgY29udGFpbnMgYWxsIHRoZSBpbmZvcm1hdGlvbiBhYm91dCBhIHB1YmxpYyBvclxuICogcHJpdmF0ZSBrZXkuICBUaGVyZSBhcmUgZm91ciB2YXJpYW50cyBvZiB0aGlzIHBhY2tldCB0eXBlLCBhbmQgdHdvXG4gKiBtYWpvciB2ZXJzaW9ucy4gIENvbnNlcXVlbnRseSwgdGhpcyBzZWN0aW9uIGlzIGNvbXBsZXguXG4gKiBAcmVxdWlyZXMgY3J5cHRvXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEByZXF1aXJlcyB0eXBlL2tleWlkXG4gKiBAcmVxdWlyZXMgdHlwZS9tcGlcbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIHBhY2tldC9wdWJsaWNfa2V5XG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKSxcbiAgdHlwZV9rZXlpZCA9IHJlcXVpcmUoJy4uL3R5cGUva2V5aWQuanMnKSxcbiAgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKTtcblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwdWJsaWNfa2V5KCkge1xuICB0aGlzLnZlcnNpb24gPSA0O1xuICAvKiogS2V5IGNyZWF0aW9uIGRhdGUuXG4gICAqIEB0eXBlIHtEYXRlfSAqL1xuICB0aGlzLmNyZWF0ZWQgPSBuZXcgRGF0ZSgpO1xuICAvKiogQSBsaXN0IG9mIG11bHRpcHJlY2lzaW9uIGludGVnZXJzXG4gICAqIEB0eXBlIHttb2R1bGU6dHlwZS9tcGl9ICovXG4gIHRoaXMubXBpID0gW107XG4gIC8qKiBQdWJsaWMga2V5IGFsZ29yaXRobVxuICAgKiBAdHlwZSB7bW9kdWxlOmVudW1zLnB1YmxpY0tleX0gKi9cbiAgdGhpcy5hbGdvcml0aG0gPSAncnNhX3NpZ24nO1xuICAvLyB0aW1lIGluIGRheXMgKFYzIG9ubHkpXG4gIHRoaXMuZXhwaXJhdGlvblRpbWVWMyA9IDA7XG5cblxuICAvKipcbiAgICogSW50ZXJuYWwgUGFyc2VyIGZvciBwdWJsaWMga2V5cyBhcyBzcGVjaWZpZWQgaW4gUkZDIDQ4ODAgc2VjdGlvbiBcbiAgICogNS41LjIgUHVibGljLUtleSBQYWNrZXQgRm9ybWF0c1xuICAgKiBjYWxsZWQgYnkgcmVhZF90YWcmbHQ7bnVtJmd0O1xuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgSW5wdXQgc3RyaW5nIHRvIHJlYWQgdGhlIHBhY2tldCBmcm9tXG4gICAqIEByZXR1cm4ge09iamVjdH0gVGhpcyBvYmplY3Qgd2l0aCBhdHRyaWJ1dGVzIHNldCBieSB0aGUgcGFyc2VyXG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbiAoYnl0ZXMpIHtcbiAgICB2YXIgcG9zID0gMDtcbiAgICAvLyBBIG9uZS1vY3RldCB2ZXJzaW9uIG51bWJlciAoMyBvciA0KS5cbiAgICB0aGlzLnZlcnNpb24gPSBieXRlcy5jaGFyQ29kZUF0KHBvcysrKTtcblxuICAgIGlmICh0aGlzLnZlcnNpb24gPT0gMyB8fCB0aGlzLnZlcnNpb24gPT0gNCkge1xuICAgICAgLy8gLSBBIGZvdXItb2N0ZXQgbnVtYmVyIGRlbm90aW5nIHRoZSB0aW1lIHRoYXQgdGhlIGtleSB3YXMgY3JlYXRlZC5cbiAgICAgIHRoaXMuY3JlYXRlZCA9IHV0aWwucmVhZERhdGUoYnl0ZXMuc3Vic3RyKHBvcywgNCkpO1xuICAgICAgcG9zICs9IDQ7XG5cbiAgICAgIGlmICh0aGlzLnZlcnNpb24gPT0gMykge1xuICAgICAgICAvLyAtIEEgdHdvLW9jdGV0IG51bWJlciBkZW5vdGluZyB0aGUgdGltZSBpbiBkYXlzIHRoYXQgdGhpcyBrZXkgaXNcbiAgICAgICAgLy8gICB2YWxpZC4gIElmIHRoaXMgbnVtYmVyIGlzIHplcm8sIHRoZW4gaXQgZG9lcyBub3QgZXhwaXJlLlxuICAgICAgICB0aGlzLmV4cGlyYXRpb25UaW1lVjMgPSB1dGlsLnJlYWROdW1iZXIoYnl0ZXMuc3Vic3RyKHBvcywgMikpO1xuICAgICAgICBwb3MgKz0gMjtcbiAgICAgIH1cblxuICAgICAgLy8gLSBBIG9uZS1vY3RldCBudW1iZXIgZGVub3RpbmcgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtIG9mIHRoaXMga2V5LlxuICAgICAgdGhpcy5hbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgYnl0ZXMuY2hhckNvZGVBdChwb3MrKykpO1xuXG4gICAgICB2YXIgbXBpY291bnQgPSBjcnlwdG8uZ2V0UHVibGljTXBpQ291bnQodGhpcy5hbGdvcml0aG0pO1xuICAgICAgdGhpcy5tcGkgPSBbXTtcblxuICAgICAgdmFyIGJtcGkgPSBieXRlcy5zdWJzdHIocG9zKTtcbiAgICAgIHZhciBwID0gMDtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtcGljb3VudCAmJiBwIDwgYm1waS5sZW5ndGg7IGkrKykge1xuXG4gICAgICAgIHRoaXMubXBpW2ldID0gbmV3IHR5cGVfbXBpKCk7XG5cbiAgICAgICAgcCArPSB0aGlzLm1waVtpXS5yZWFkKGJtcGkuc3Vic3RyKHApKVxuXG4gICAgICAgIGlmIChwID4gYm1waS5sZW5ndGgpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Vycm9yIHJlYWRpbmcgTVBJIEA6JyArIHApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBwICsgNjtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdWZXJzaW9uICcgKyB2ZXJzaW9uICsgJyBvZiB0aGUga2V5IHBhY2tldCBpcyB1bnN1cHBvcnRlZC4nKTtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIEFsaWFzIG9mIHJlYWQoKVxuICAgKiBAZnVuY3Rpb24gbW9kdWxlOnBhY2tldC9wdWJsaWNfa2V5I3JlYWRQdWJsaWNLZXlcbiAgICogQHNlZSBtb2R1bGU6cGFja2V0L3B1YmxpY19rZXkjcmVhZFxuICAgKi9cbiAgdGhpcy5yZWFkUHVibGljS2V5ID0gdGhpcy5yZWFkO1xuXG4gIC8qKlxuICAgKiBTYW1lIGFzIHdyaXRlX3ByaXZhdGVfa2V5LCBidXQgaGFzIGxlc3MgaW5mb3JtYXRpb24gYmVjYXVzZSBvZiBcbiAgICogcHVibGljIGtleS5cbiAgICogQHJldHVybiB7T2JqZWN0fSB7Ym9keTogW3N0cmluZ11PcGVuUEdQIHBhY2tldCBib2R5IGNvbnRlbnRzLFxuICAgKiBoZWFkZXI6IFtzdHJpbmddIE9wZW5QR1AgcGFja2V0IGhlYWRlciwgc3RyaW5nOiBbc3RyaW5nXSBoZWFkZXIrYm9keX1cbiAgICovXG4gIHRoaXMud3JpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgLy8gVmVyc2lvblxuICAgIHZhciByZXN1bHQgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMudmVyc2lvbik7XG4gICAgcmVzdWx0ICs9IHV0aWwud3JpdGVEYXRlKHRoaXMuY3JlYXRlZCk7XG4gICAgaWYgKHRoaXMudmVyc2lvbiA9PSAzKSB7XG4gICAgICByZXN1bHQgKz0gdXRpbC53cml0ZU51bWJlcih0aGlzLmV4cGlyYXRpb25UaW1lVjMsIDIpO1xuICAgIH1cbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5wdWJsaWNLZXksIHRoaXMuYWxnb3JpdGhtKSk7XG5cbiAgICB2YXIgbXBpY291bnQgPSBjcnlwdG8uZ2V0UHVibGljTXBpQ291bnQodGhpcy5hbGdvcml0aG0pO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtcGljb3VudDsgaSsrKSB7XG4gICAgICByZXN1bHQgKz0gdGhpcy5tcGlbaV0ud3JpdGUoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIC8qKlxuICAgKiBBbGlhcyBvZiB3cml0ZSgpXG4gICAqIEBmdW5jdGlvbiBtb2R1bGU6cGFja2V0L3B1YmxpY19rZXkjd3JpdGVQdWJsaWNLZXlcbiAgICogQHNlZSBtb2R1bGU6cGFja2V0L3B1YmxpY19rZXkjd3JpdGVcbiAgICovXG4gIHRoaXMud3JpdGVQdWJsaWNLZXkgPSB0aGlzLndyaXRlO1xuXG4gIC8qKlxuICAgKiBXcml0ZSBhbiBvbGQgdmVyc2lvbiBwYWNrZXQgLSBpdCdzIHVzZWQgYnkgc29tZSBvZiB0aGUgaW50ZXJuYWwgcm91dGluZXMuXG4gICAqL1xuICB0aGlzLndyaXRlT2xkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBieXRlcyA9IHRoaXMud3JpdGVQdWJsaWNLZXkoKTtcblxuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4OTkpICtcbiAgICAgIHV0aWwud3JpdGVOdW1iZXIoYnl0ZXMubGVuZ3RoLCAyKSArXG4gICAgICBieXRlcztcbiAgfTtcblxuICAvKipcbiAgICogQ2FsY3VsYXRlcyB0aGUga2V5IGlkIG9mIHRoZSBrZXkgXG4gICAqIEByZXR1cm4ge1N0cmluZ30gQSA4IGJ5dGUga2V5IGlkXG4gICAqL1xuICB0aGlzLmdldEtleUlkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBrZXlpZCA9IG5ldyB0eXBlX2tleWlkKCk7XG4gICAgaWYgKHRoaXMudmVyc2lvbiA9PSA0KSB7XG4gICAgICBrZXlpZC5yZWFkKHRoaXMuZ2V0RmluZ2VycHJpbnQoKS5zdWJzdHIoMTIsIDgpKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMudmVyc2lvbiA9PSAzKSB7XG4gICAgICBrZXlpZC5yZWFkKHRoaXMubXBpWzBdLndyaXRlKCkuc3Vic3RyKC04KSk7XG4gICAgfVxuICAgIHJldHVybiBrZXlpZDtcbiAgfTtcblxuICAvKipcbiAgICogQ2FsY3VsYXRlcyB0aGUgZmluZ2VycHJpbnQgb2YgdGhlIGtleVxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IEEgc3RyaW5nIGNvbnRhaW5pbmcgdGhlIGZpbmdlcnByaW50XG4gICAqL1xuICB0aGlzLmdldEZpbmdlcnByaW50ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciB0b0hhc2ggPSAnJztcbiAgICBpZiAodGhpcy52ZXJzaW9uID09IDQpIHtcbiAgICAgIHRvSGFzaCA9IHRoaXMud3JpdGVPbGQoKTtcbiAgICAgIHJldHVybiBjcnlwdG8uaGFzaC5zaGExKHRvSGFzaCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLnZlcnNpb24gPT0gMykge1xuICAgICAgdmFyIG1waWNvdW50ID0gY3J5cHRvLmdldFB1YmxpY01waUNvdW50KHRoaXMuYWxnb3JpdGhtKTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbXBpY291bnQ7IGkrKykge1xuICAgICAgICB0b0hhc2ggKz0gdGhpcy5tcGlbaV0udG9CeXRlcygpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGNyeXB0by5oYXNoLm1kNSh0b0hhc2gpXG4gICAgfVxuICB9O1xufTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgUGFja2V0cyAoVGFnIDEpPGJyLz5cbiAqIDxici8+XG4gKiBSRkM0ODgwIDUuMTogQSBQdWJsaWMtS2V5IEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXQgaG9sZHMgdGhlIHNlc3Npb24ga2V5XG4gKiB1c2VkIHRvIGVuY3J5cHQgYSBtZXNzYWdlLiBaZXJvIG9yIG1vcmUgUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXlcbiAqIHBhY2tldHMgYW5kL29yIFN5bW1ldHJpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IHBhY2tldHMgbWF5IHByZWNlZGUgYVxuICogU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQsIHdoaWNoIGhvbGRzIGFuIGVuY3J5cHRlZCBtZXNzYWdlLiBUaGVcbiAqIG1lc3NhZ2UgaXMgZW5jcnlwdGVkIHdpdGggdGhlIHNlc3Npb24ga2V5LCBhbmQgdGhlIHNlc3Npb24ga2V5IGlzIGl0c2VsZlxuICogZW5jcnlwdGVkIGFuZCBzdG9yZWQgaW4gdGhlIEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXQocykuIFRoZVxuICogU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQgaXMgcHJlY2VkZWQgYnkgb25lIFB1YmxpYy1LZXkgRW5jcnlwdGVkXG4gKiBTZXNzaW9uIEtleSBwYWNrZXQgZm9yIGVhY2ggT3BlblBHUCBrZXkgdG8gd2hpY2ggdGhlIG1lc3NhZ2UgaXMgZW5jcnlwdGVkLlxuICogVGhlIHJlY2lwaWVudCBvZiB0aGUgbWVzc2FnZSBmaW5kcyBhIHNlc3Npb24ga2V5IHRoYXQgaXMgZW5jcnlwdGVkIHRvIHRoZWlyXG4gKiBwdWJsaWMga2V5LCBkZWNyeXB0cyB0aGUgc2Vzc2lvbiBrZXksIGFuZCB0aGVuIHVzZXMgdGhlIHNlc3Npb24ga2V5IHRvXG4gKiBkZWNyeXB0IHRoZSBtZXNzYWdlLlxuICogQHJlcXVpcmVzIGNyeXB0b1xuICogQHJlcXVpcmVzIGVudW1zXG4gKiBAcmVxdWlyZXMgdHlwZS9rZXlpZFxuICogQHJlcXVpcmVzIHR5cGUvbXBpXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSBwYWNrZXQvcHVibGljX2tleV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXlcbiAqL1xuXG52YXIgdHlwZV9rZXlpZCA9IHJlcXVpcmUoJy4uL3R5cGUva2V5aWQuanMnKSxcbiAgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKSxcbiAgdHlwZV9tcGkgPSByZXF1aXJlKCcuLi90eXBlL21waS5qcycpLFxuICBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG4gIGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHB1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5KCkge1xuICB0aGlzLnZlcnNpb24gPSAzO1xuXG4gIHRoaXMucHVibGljS2V5SWQgPSBuZXcgdHlwZV9rZXlpZCgpO1xuICB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSA9ICdyc2FfZW5jcnlwdCc7XG5cbiAgdGhpcy5zZXNzaW9uS2V5ID0gbnVsbDtcbiAgdGhpcy5zZXNzaW9uS2V5QWxnb3JpdGhtID0gJ2FlczI1Nic7XG5cbiAgLyoqIEB0eXBlIHtBcnJheTxtb2R1bGU6dHlwZS9tcGk+fSAqL1xuICB0aGlzLmVuY3J5cHRlZCA9IFtdO1xuXG4gIC8qKlxuICAgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIHB1YmxpY2tleSBlbmNyeXB0ZWQgc2Vzc2lvbiBrZXkgcGFja2V0ICh0YWcgMSkuXG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBhIHRhZyAxIHBhY2tldFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgaW5wdXQgc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuIExlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mXG4gICAqICAgICAgICAgICAgaW5wdXQgYXQgcG9zaXRpb25cbiAgICogQHJldHVybiB7bW9kdWxlOnBhY2tldC9wdWJsaWNfa2V5X2VuY3J5cHRlZF9zZXNzaW9uX2tleX0gT2JqZWN0IHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbiAoYnl0ZXMpIHtcblxuICAgIHRoaXMudmVyc2lvbiA9IGJ5dGVzLmNoYXJDb2RlQXQoMCk7XG4gICAgdGhpcy5wdWJsaWNLZXlJZC5yZWFkKGJ5dGVzLnN1YnN0cigxKSk7XG4gICAgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgYnl0ZXMuY2hhckNvZGVBdCg5KSk7XG5cbiAgICB2YXIgaSA9IDEwO1xuXG4gICAgdmFyIGludGVnZXJDb3VudCA9IChmdW5jdGlvbihhbGdvKSB7XG4gICAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHQnOlxuICAgICAgICBjYXNlICdyc2FfZW5jcnlwdF9zaWduJzpcbiAgICAgICAgICByZXR1cm4gMTtcblxuICAgICAgICBjYXNlICdlbGdhbWFsJzpcbiAgICAgICAgICByZXR1cm4gMjtcblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYWxnb3JpdGhtLlwiKTtcbiAgICAgIH1cbiAgICB9KSh0aGlzLnB1YmxpY0tleUFsZ29yaXRobSk7XG5cbiAgICB0aGlzLmVuY3J5cHRlZCA9IFtdO1xuXG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCBpbnRlZ2VyQ291bnQ7IGorKykge1xuICAgICAgdmFyIG1waSA9IG5ldyB0eXBlX21waSgpO1xuICAgICAgaSArPSBtcGkucmVhZChieXRlcy5zdWJzdHIoaSkpO1xuICAgICAgdGhpcy5lbmNyeXB0ZWQucHVzaChtcGkpO1xuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogQ3JlYXRlIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgdGFnIDEgcGFja2V0XG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHVibGljS2V5SWRcbiAgICogICAgICAgICAgICAgVGhlIHB1YmxpYyBrZXkgaWQgY29ycmVzcG9uZGluZyB0byBwdWJsaWNNUElzIGtleSBhcyBzdHJpbmdcbiAgICogQHBhcmFtIHtBcnJheTxtb2R1bGU6dHlwZS9tcGk+fSBwdWJsaWNNUElzXG4gICAqICAgICAgICAgICAgTXVsdGlwcmVjaXNpb24gaW50ZWdlciBvYmplY3RzIGRlc2NyaWJpbmcgdGhlIHB1YmxpYyBrZXlcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBwdWJhbGdvXG4gICAqICAgICAgICAgICAgVGhlIGNvcnJlc3BvbmRpbmcgcHVibGljIGtleSBhbGdvcml0aG0gLy8gU2VlIFJGQzQ4ODAgOS4xXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gc3ltbWFsZ29cbiAgICogICAgICAgICAgICBUaGUgc3ltbWV0cmljIGNpcGhlciBhbGdvcml0aG0gdXNlZCB0byBlbmNyeXB0IHRoZSBkYXRhIFxuICAgKiAgICAgICAgICAgIHdpdGhpbiBhbiBlbmNyeXB0ZWRkYXRhcGFja2V0IG9yIGVuY3J5cHRlZGludGVncml0eS1cbiAgICogICAgICAgICAgICBwcm90ZWN0ZWRkYXRhcGFja2V0IFxuICAgKiAgICAgICAgICAgIGZvbGxvd2luZyB0aGlzIHBhY2tldCAvL1NlZSBSRkM0ODgwIDkuMlxuICAgKiBAcGFyYW0ge1N0cmluZ30gc2Vzc2lvbmtleVxuICAgKiAgICAgICAgICAgIEEgc3RyaW5nIG9mIHJhbmRvbWJ5dGVzIHJlcHJlc2VudGluZyB0aGUgc2Vzc2lvbiBrZXlcbiAgICogQHJldHVybiB7U3RyaW5nfSBUaGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB0aGlzLndyaXRlID0gZnVuY3Rpb24gKCkge1xuXG4gICAgdmFyIHJlc3VsdCA9IFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy52ZXJzaW9uKTtcbiAgICByZXN1bHQgKz0gdGhpcy5wdWJsaWNLZXlJZC53cml0ZSgpO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuICAgICAgZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSkpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmVuY3J5cHRlZC5sZW5ndGg7IGkrKykge1xuICAgICAgcmVzdWx0ICs9IHRoaXMuZW5jcnlwdGVkW2ldLndyaXRlKClcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uIChrZXkpIHtcbiAgICB2YXIgZGF0YSA9IFN0cmluZy5mcm9tQ2hhckNvZGUoXG4gICAgICBlbnVtcy53cml0ZShlbnVtcy5zeW1tZXRyaWMsIHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSkpO1xuXG4gICAgZGF0YSArPSB0aGlzLnNlc3Npb25LZXk7XG4gICAgdmFyIGNoZWNrc3VtID0gdXRpbC5jYWxjX2NoZWNrc3VtKHRoaXMuc2Vzc2lvbktleSk7XG4gICAgZGF0YSArPSB1dGlsLndyaXRlTnVtYmVyKGNoZWNrc3VtLCAyKTtcblxuICAgIHZhciBtcGkgPSBuZXcgdHlwZV9tcGkoKTtcbiAgICBtcGkuZnJvbUJ5dGVzKGNyeXB0by5wa2NzMS5lbWUuZW5jb2RlKFxuICAgICAgZGF0YSxcbiAgICAgIGtleS5tcGlbMF0uYnl0ZUxlbmd0aCgpKSk7XG5cbiAgICB0aGlzLmVuY3J5cHRlZCA9IGNyeXB0by5wdWJsaWNLZXlFbmNyeXB0KFxuICAgICAgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0sXG4gICAgICBrZXkubXBpLFxuICAgICAgbXBpKTtcbiAgfTtcblxuICAvKipcbiAgICogRGVjcnlwdHMgdGhlIHNlc3Npb24ga2V5IChvbmx5IGZvciBwdWJsaWMga2V5IGVuY3J5cHRlZCBzZXNzaW9uIGtleVxuICAgKiBwYWNrZXRzICh0YWcgMSlcbiAgICogXG4gICAqIEBwYXJhbSB7bW9kdWxlOnBhY2tldC9zZWNyZXRfa2V5fSBrZXlcbiAgICogICAgICAgICAgICBQcml2YXRlIGtleSB3aXRoIHNlY01QSXMgdW5sb2NrZWRcbiAgICogQHJldHVybiB7U3RyaW5nfSBUaGUgdW5lbmNyeXB0ZWQgc2Vzc2lvbiBrZXlcbiAgICovXG4gIHRoaXMuZGVjcnlwdCA9IGZ1bmN0aW9uIChrZXkpIHtcbiAgICB2YXIgcmVzdWx0ID0gY3J5cHRvLnB1YmxpY0tleURlY3J5cHQoXG4gICAgICB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSxcbiAgICAgIGtleS5tcGksXG4gICAgICB0aGlzLmVuY3J5cHRlZCkudG9CeXRlcygpO1xuXG4gICAgdmFyIGNoZWNrc3VtID0gdXRpbC5yZWFkTnVtYmVyKHJlc3VsdC5zdWJzdHIocmVzdWx0Lmxlbmd0aCAtIDIpKTtcblxuICAgIHZhciBkZWNvZGVkID0gY3J5cHRvLnBrY3MxLmVtZS5kZWNvZGUoXG4gICAgICByZXN1bHQsXG4gICAgICBrZXkubXBpWzBdLmJ5dGVMZW5ndGgoKSk7XG5cbiAgICB2YXIga2V5ID0gZGVjb2RlZC5zdWJzdHJpbmcoMSwgZGVjb2RlZC5sZW5ndGggLSAyKTtcblxuICAgIGlmIChjaGVja3N1bSAhPSB1dGlsLmNhbGNfY2hlY2tzdW0oa2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDaGVja3N1bSBtaXNtYXRjaCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNlc3Npb25LZXkgPSBrZXk7XG4gICAgICB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0gPVxuICAgICAgICBlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgZGVjb2RlZC5jaGFyQ29kZUF0KDApKTtcbiAgICB9XG4gIH07XG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBAcmVxdWlyZXMgcGFja2V0L3B1YmxpY19rZXlcbiAqIEBtb2R1bGUgcGFja2V0L3B1YmxpY19zdWJrZXlcbiAqL1xuXG52YXIgcHVibGljS2V5ID0gcmVxdWlyZSgnLi9wdWJsaWNfa2V5LmpzJyk7XG5cbi8qKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAZXh0ZW5kcyBtb2R1bGU6cGFja2V0L3B1YmxpY19rZXlcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwdWJsaWNfc3Via2V5KCkge1xuICBwdWJsaWNLZXkuY2FsbCh0aGlzKTtcbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogSW1wbGVtZW50YXRpb24gb2YgdGhlIEtleSBNYXRlcmlhbCBQYWNrZXQgKFRhZyA1LDYsNywxNCk8YnIvPlxuICogPGJyLz5cbiAqIFJGQzQ0ODAgNS41OlxuICogQSBrZXkgbWF0ZXJpYWwgcGFja2V0IGNvbnRhaW5zIGFsbCB0aGUgaW5mb3JtYXRpb24gYWJvdXQgYSBwdWJsaWMgb3JcbiAqIHByaXZhdGUga2V5LiAgVGhlcmUgYXJlIGZvdXIgdmFyaWFudHMgb2YgdGhpcyBwYWNrZXQgdHlwZSwgYW5kIHR3b1xuICogbWFqb3IgdmVyc2lvbnMuICBDb25zZXF1ZW50bHksIHRoaXMgc2VjdGlvbiBpcyBjb21wbGV4LlxuICogQHJlcXVpcmVzIGNyeXB0b1xuICogQHJlcXVpcmVzIGVudW1zXG4gKiBAcmVxdWlyZXMgcGFja2V0L3B1YmxpY19rZXlcbiAqIEByZXF1aXJlcyB0eXBlL21waVxuICogQHJlcXVpcmVzIHR5cGUvczJrXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSBwYWNrZXQvc2VjcmV0X2tleVxuICovXG5cbnZhciBwdWJsaWNLZXkgPSByZXF1aXJlKCcuL3B1YmxpY19rZXkuanMnKSxcbiAgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKSxcbiAgdHlwZV9tcGkgPSByZXF1aXJlKCcuLi90eXBlL21waS5qcycpLFxuICB0eXBlX3MyayA9IHJlcXVpcmUoJy4uL3R5cGUvczJrLmpzJyk7XG5cbi8qKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAZXh0ZW5kcyBtb2R1bGU6cGFja2V0L3B1YmxpY19rZXlcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBzZWNyZXRfa2V5KCkge1xuICBwdWJsaWNLZXkuY2FsbCh0aGlzKTtcbiAgLy8gZW5jcnlwdGVkIHNlY3JldC1rZXkgZGF0YVxuICB0aGlzLmVuY3J5cHRlZCA9IG51bGw7XG4gIC8vIGluZGljYXRvciBpZiBzZWNyZXQta2V5IGRhdGEgaXMgYXZhaWxhYmxlIGluIGRlY3J5cHRlZCBmb3JtXG4gIHRoaXMuaXNEZWNyeXB0ZWQgPSBmYWxzZTtcblxuXG4gIGZ1bmN0aW9uIGdldF9oYXNoX2xlbihoYXNoKSB7XG4gICAgaWYgKGhhc2ggPT0gJ3NoYTEnKVxuICAgICAgcmV0dXJuIDIwO1xuICAgIGVsc2VcbiAgICAgIHJldHVybiAyO1xuICB9XG5cbiAgZnVuY3Rpb24gZ2V0X2hhc2hfZm4oaGFzaCkge1xuICAgIGlmIChoYXNoID09ICdzaGExJylcbiAgICAgIHJldHVybiBjcnlwdG8uaGFzaC5zaGExO1xuICAgIGVsc2VcbiAgICAgIHJldHVybiBmdW5jdGlvbihjKSB7XG4gICAgICAgIHJldHVybiB1dGlsLndyaXRlTnVtYmVyKHV0aWwuY2FsY19jaGVja3N1bShjKSwgMik7XG4gICAgfTtcbiAgfVxuXG4gIC8vIEhlbHBlciBmdW5jdGlvblxuXG4gIGZ1bmN0aW9uIHBhcnNlX2NsZWFydGV4dF9tcGkoaGFzaF9hbGdvcml0aG0sIGNsZWFydGV4dCwgYWxnb3JpdGhtKSB7XG4gICAgdmFyIGhhc2hsZW4gPSBnZXRfaGFzaF9sZW4oaGFzaF9hbGdvcml0aG0pLFxuICAgICAgaGFzaGZuID0gZ2V0X2hhc2hfZm4oaGFzaF9hbGdvcml0aG0pO1xuXG4gICAgdmFyIGhhc2h0ZXh0ID0gY2xlYXJ0ZXh0LnN1YnN0cihjbGVhcnRleHQubGVuZ3RoIC0gaGFzaGxlbik7XG4gICAgY2xlYXJ0ZXh0ID0gY2xlYXJ0ZXh0LnN1YnN0cigwLCBjbGVhcnRleHQubGVuZ3RoIC0gaGFzaGxlbik7XG5cbiAgICB2YXIgaGFzaCA9IGhhc2hmbihjbGVhcnRleHQpO1xuXG4gICAgaWYgKGhhc2ggIT0gaGFzaHRleHQpXG4gICAgICByZXR1cm4gbmV3IEVycm9yKFwiSGFzaCBtaXNtYXRjaC5cIik7XG5cbiAgICB2YXIgbXBpcyA9IGNyeXB0by5nZXRQcml2YXRlTXBpQ291bnQoYWxnb3JpdGhtKTtcblxuICAgIHZhciBqID0gMDtcbiAgICB2YXIgbXBpID0gW107XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1waXMgJiYgaiA8IGNsZWFydGV4dC5sZW5ndGg7IGkrKykge1xuICAgICAgbXBpW2ldID0gbmV3IHR5cGVfbXBpKCk7XG4gICAgICBqICs9IG1waVtpXS5yZWFkKGNsZWFydGV4dC5zdWJzdHIoaikpO1xuICAgIH1cblxuICAgIHJldHVybiBtcGk7XG4gIH1cblxuICBmdW5jdGlvbiB3cml0ZV9jbGVhcnRleHRfbXBpKGhhc2hfYWxnb3JpdGhtLCBhbGdvcml0aG0sIG1waSkge1xuICAgIHZhciBieXRlcyA9ICcnO1xuICAgIHZhciBkaXNjYXJkID0gY3J5cHRvLmdldFB1YmxpY01waUNvdW50KGFsZ29yaXRobSk7XG5cbiAgICBmb3IgKHZhciBpID0gZGlzY2FyZDsgaSA8IG1waS5sZW5ndGg7IGkrKykge1xuICAgICAgYnl0ZXMgKz0gbXBpW2ldLndyaXRlKCk7XG4gICAgfVxuXG5cbiAgICBieXRlcyArPSBnZXRfaGFzaF9mbihoYXNoX2FsZ29yaXRobSkoYnl0ZXMpO1xuXG4gICAgcmV0dXJuIGJ5dGVzO1xuICB9XG5cblxuICAvLyA1LjUuMy4gIFNlY3JldC1LZXkgUGFja2V0IEZvcm1hdHNcblxuICAvKipcbiAgICogSW50ZXJuYWwgcGFyc2VyIGZvciBwcml2YXRlIGtleXMgYXMgc3BlY2lmaWVkIGluIFJGQyA0ODgwIHNlY3Rpb24gNS41LjNcbiAgICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzIElucHV0IHN0cmluZyB0byByZWFkIHRoZSBwYWNrZXQgZnJvbVxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgLy8gLSBBIFB1YmxpYy1LZXkgb3IgUHVibGljLVN1YmtleSBwYWNrZXQsIGFzIGRlc2NyaWJlZCBhYm92ZS5cbiAgICB2YXIgbGVuID0gdGhpcy5yZWFkUHVibGljS2V5KGJ5dGVzKTtcblxuICAgIGJ5dGVzID0gYnl0ZXMuc3Vic3RyKGxlbik7XG5cblxuICAgIC8vIC0gT25lIG9jdGV0IGluZGljYXRpbmcgc3RyaW5nLXRvLWtleSB1c2FnZSBjb252ZW50aW9ucy4gIFplcm9cbiAgICAvLyAgIGluZGljYXRlcyB0aGF0IHRoZSBzZWNyZXQta2V5IGRhdGEgaXMgbm90IGVuY3J5cHRlZC4gIDI1NSBvciAyNTRcbiAgICAvLyAgIGluZGljYXRlcyB0aGF0IGEgc3RyaW5nLXRvLWtleSBzcGVjaWZpZXIgaXMgYmVpbmcgZ2l2ZW4uICBBbnlcbiAgICAvLyAgIG90aGVyIHZhbHVlIGlzIGEgc3ltbWV0cmljLWtleSBlbmNyeXB0aW9uIGFsZ29yaXRobSBpZGVudGlmaWVyLlxuICAgIHZhciBpc0VuY3J5cHRlZCA9IGJ5dGVzLmNoYXJDb2RlQXQoMCk7XG5cbiAgICBpZiAoaXNFbmNyeXB0ZWQpIHtcbiAgICAgIHRoaXMuZW5jcnlwdGVkID0gYnl0ZXM7XG4gICAgfSBlbHNlIHtcblxuICAgICAgLy8gLSBQbGFpbiBvciBlbmNyeXB0ZWQgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgY29tcHJpc2luZyB0aGUgc2VjcmV0XG4gICAgICAvLyAgIGtleSBkYXRhLiAgVGhlc2UgYWxnb3JpdGhtLXNwZWNpZmljIGZpZWxkcyBhcmUgYXMgZGVzY3JpYmVkXG4gICAgICAvLyAgIGJlbG93LlxuICAgICAgdmFyIHBhcnNlZE1QSSA9IHBhcnNlX2NsZWFydGV4dF9tcGkoJ21vZCcsIGJ5dGVzLnN1YnN0cigxKSwgdGhpcy5hbGdvcml0aG0pO1xuICAgICAgaWYgKHBhcnNlZE1QSSBpbnN0YW5jZW9mIEVycm9yKVxuICAgICAgICB0aHJvdyBwYXJzZWRNUEk7XG4gICAgICB0aGlzLm1waSA9IHRoaXMubXBpLmNvbmNhdChwYXJzZWRNUEkpO1xuICAgICAgdGhpcy5pc0RlY3J5cHRlZCA9IHRydWU7XG4gICAgfVxuXG4gIH07XG5cbiAgLyoqIENyZWF0ZXMgYW4gT3BlblBHUCBrZXkgcGFja2V0IGZvciB0aGUgZ2l2ZW4ga2V5LlxuICAgICogQHJldHVybiB7U3RyaW5nfSBBIHN0cmluZyBvZiBieXRlcyBjb250YWluaW5nIHRoZSBzZWNyZXQga2V5IE9wZW5QR1AgcGFja2V0XG4gICAgKi9cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYnl0ZXMgPSB0aGlzLndyaXRlUHVibGljS2V5KCk7XG5cbiAgICBpZiAoIXRoaXMuZW5jcnlwdGVkKSB7XG4gICAgICBieXRlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuXG4gICAgICBieXRlcyArPSB3cml0ZV9jbGVhcnRleHRfbXBpKCdtb2QnLCB0aGlzLmFsZ29yaXRobSwgdGhpcy5tcGkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBieXRlcyArPSB0aGlzLmVuY3J5cHRlZDtcbiAgICB9XG5cbiAgICByZXR1cm4gYnl0ZXM7XG4gIH07XG5cblxuXG5cbiAgLyoqIEVuY3J5cHQgdGhlIHBheWxvYWQuIEJ5IGRlZmF1bHQsIHdlIHVzZSBhZXMyNTYgYW5kIGl0ZXJhdGVkLCBzYWx0ZWQgc3RyaW5nXG4gICAqIHRvIGtleSBzcGVjaWZpZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IHBhc3NwaHJhc2VcbiAgICovXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uIChwYXNzcGhyYXNlKSB7XG5cbiAgICB2YXIgczJrID0gbmV3IHR5cGVfczJrKCksXG4gICAgICBzeW1tZXRyaWMgPSAnYWVzMjU2JyxcbiAgICAgIGNsZWFydGV4dCA9IHdyaXRlX2NsZWFydGV4dF9tcGkoJ3NoYTEnLCB0aGlzLmFsZ29yaXRobSwgdGhpcy5tcGkpLFxuICAgICAga2V5ID0gcHJvZHVjZUVuY3J5cHRpb25LZXkoczJrLCBwYXNzcGhyYXNlLCBzeW1tZXRyaWMpLFxuICAgICAgYmxvY2tMZW4gPSBjcnlwdG8uY2lwaGVyW3N5bW1ldHJpY10uYmxvY2tTaXplLFxuICAgICAgaXYgPSBjcnlwdG8ucmFuZG9tLmdldFJhbmRvbUJ5dGVzKGJsb2NrTGVuKTtcblxuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSAnJztcbiAgICB0aGlzLmVuY3J5cHRlZCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDI1NCk7XG4gICAgdGhpcy5lbmNyeXB0ZWQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5zeW1tZXRyaWMsIHN5bW1ldHJpYykpO1xuICAgIHRoaXMuZW5jcnlwdGVkICs9IHMyay53cml0ZSgpO1xuICAgIHRoaXMuZW5jcnlwdGVkICs9IGl2O1xuXG4gICAgdGhpcy5lbmNyeXB0ZWQgKz0gY3J5cHRvLmNmYi5ub3JtYWxFbmNyeXB0KHN5bW1ldHJpYywga2V5LCBjbGVhcnRleHQsIGl2KTtcbiAgfTtcblxuICBmdW5jdGlvbiBwcm9kdWNlRW5jcnlwdGlvbktleShzMmssIHBhc3NwaHJhc2UsIGFsZ29yaXRobSkge1xuICAgIHJldHVybiBzMmsucHJvZHVjZV9rZXkocGFzc3BocmFzZSxcbiAgICAgIGNyeXB0by5jaXBoZXJbYWxnb3JpdGhtXS5rZXlTaXplKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNyeXB0cyB0aGUgcHJpdmF0ZSBrZXkgTVBJcyB3aGljaCBhcmUgbmVlZGVkIHRvIHVzZSB0aGUga2V5LlxuICAgKiBAbGluayBtb2R1bGU6cGFja2V0L3NlY3JldF9rZXkuaXNEZWNyeXB0ZWQgc2hvdWxkIGJlXG4gICAqIGZhbHNlIG90aGVyd2lzZSBhIGNhbGwgdG8gdGhpcyBmdW5jdGlvbiBpcyBub3QgbmVlZGVkXG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyX3Bhc3NwaHJhc2UgVGhlIHBhc3NwaHJhc2UgZm9yIHRoaXMgcHJpdmF0ZSBrZXkgXG4gICAqIGFzIHN0cmluZ1xuICAgKiBAcmV0dXJuIHtCb29sZWFufSBUcnVlIGlmIHRoZSBwYXNzcGhyYXNlIHdhcyBjb3JyZWN0IG9yIE1QSSBhbHJlYWR5XG4gICAqICAgICAgICAgICAgICAgICAgIGRlY3J5cHRlZDsgZmFsc2UgaWYgbm90XG4gICAqL1xuICB0aGlzLmRlY3J5cHQgPSBmdW5jdGlvbiAocGFzc3BocmFzZSkge1xuICAgIGlmICh0aGlzLmlzRGVjcnlwdGVkKVxuICAgICAgcmV0dXJuIHRydWU7XG5cbiAgICB2YXIgaSA9IDAsXG4gICAgICBzeW1tZXRyaWMsXG4gICAgICBrZXk7XG5cbiAgICB2YXIgczJrX3VzYWdlID0gdGhpcy5lbmNyeXB0ZWQuY2hhckNvZGVBdChpKyspO1xuXG4gICAgLy8gLSBbT3B0aW9uYWxdIElmIHN0cmluZy10by1rZXkgdXNhZ2Ugb2N0ZXQgd2FzIDI1NSBvciAyNTQsIGEgb25lLVxuICAgIC8vICAgb2N0ZXQgc3ltbWV0cmljIGVuY3J5cHRpb24gYWxnb3JpdGhtLlxuICAgIGlmIChzMmtfdXNhZ2UgPT0gMjU1IHx8IHMya191c2FnZSA9PSAyNTQpIHtcbiAgICAgIHN5bW1ldHJpYyA9IHRoaXMuZW5jcnlwdGVkLmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgIHN5bW1ldHJpYyA9IGVudW1zLnJlYWQoZW51bXMuc3ltbWV0cmljLCBzeW1tZXRyaWMpO1xuXG4gICAgICAvLyAtIFtPcHRpb25hbF0gSWYgc3RyaW5nLXRvLWtleSB1c2FnZSBvY3RldCB3YXMgMjU1IG9yIDI1NCwgYVxuICAgICAgLy8gICBzdHJpbmctdG8ta2V5IHNwZWNpZmllci4gIFRoZSBsZW5ndGggb2YgdGhlIHN0cmluZy10by1rZXlcbiAgICAgIC8vICAgc3BlY2lmaWVyIGlzIGltcGxpZWQgYnkgaXRzIHR5cGUsIGFzIGRlc2NyaWJlZCBhYm92ZS5cbiAgICAgIHZhciBzMmsgPSBuZXcgdHlwZV9zMmsoKTtcbiAgICAgIGkgKz0gczJrLnJlYWQodGhpcy5lbmNyeXB0ZWQuc3Vic3RyKGkpKTtcblxuICAgICAga2V5ID0gcHJvZHVjZUVuY3J5cHRpb25LZXkoczJrLCBwYXNzcGhyYXNlLCBzeW1tZXRyaWMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzeW1tZXRyaWMgPSBzMmtfdXNhZ2U7XG4gICAgICBzeW1tZXRyaWMgPSBlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgc3ltbWV0cmljKTtcbiAgICAgIGtleSA9IGNyeXB0by5oYXNoLm1kNShwYXNzcGhyYXNlKTtcbiAgICB9XG5cblxuICAgIC8vIC0gW09wdGlvbmFsXSBJZiBzZWNyZXQgZGF0YSBpcyBlbmNyeXB0ZWQgKHN0cmluZy10by1rZXkgdXNhZ2Ugb2N0ZXRcbiAgICAvLyAgIG5vdCB6ZXJvKSwgYW4gSW5pdGlhbCBWZWN0b3IgKElWKSBvZiB0aGUgc2FtZSBsZW5ndGggYXMgdGhlXG4gICAgLy8gICBjaXBoZXIncyBibG9jayBzaXplLlxuICAgIHZhciBpdiA9IHRoaXMuZW5jcnlwdGVkLnN1YnN0cihpLFxuICAgICAgY3J5cHRvLmNpcGhlcltzeW1tZXRyaWNdLmJsb2NrU2l6ZSk7XG5cbiAgICBpICs9IGl2Lmxlbmd0aDtcblxuICAgIHZhciBjbGVhcnRleHQsXG4gICAgICBjaXBoZXJ0ZXh0ID0gdGhpcy5lbmNyeXB0ZWQuc3Vic3RyKGkpO1xuXG4gICAgY2xlYXJ0ZXh0ID0gY3J5cHRvLmNmYi5ub3JtYWxEZWNyeXB0KHN5bW1ldHJpYywga2V5LCBjaXBoZXJ0ZXh0LCBpdik7XG5cbiAgICB2YXIgaGFzaCA9IHMya191c2FnZSA9PSAyNTQgP1xuICAgICAgJ3NoYTEnIDpcbiAgICAgICdtb2QnO1xuXG4gICAgdmFyIHBhcnNlZE1QSSA9IHBhcnNlX2NsZWFydGV4dF9tcGkoaGFzaCwgY2xlYXJ0ZXh0LCB0aGlzLmFsZ29yaXRobSk7XG4gICAgaWYgKHBhcnNlZE1QSSBpbnN0YW5jZW9mIEVycm9yKVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIHRoaXMubXBpID0gdGhpcy5tcGkuY29uY2F0KHBhcnNlZE1QSSk7XG4gICAgdGhpcy5pc0RlY3J5cHRlZCA9IHRydWU7XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgdGhpcy5nZW5lcmF0ZSA9IGZ1bmN0aW9uIChiaXRzKSB7XG4gICAgdGhpcy5tcGkgPSBjcnlwdG8uZ2VuZXJhdGVNcGkodGhpcy5hbGdvcml0aG0sIGJpdHMpO1xuICAgIHRoaXMuaXNEZWNyeXB0ZWQgPSB0cnVlO1xuICB9O1xuXG59XG5cbm1vZHVsZS5leHBvcnRzLnByb3RvdHlwZSA9IG5ldyBwdWJsaWNLZXkoKTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQHJlcXVpcmVzIHBhY2tldC9zZWNyZXRfa2V5XG4gKiBAbW9kdWxlIHBhY2tldC9zZWNyZXRfc3Via2V5XG4gKi9cblxudmFyIHNlY3JldEtleSA9IHJlcXVpcmUoJy4vc2VjcmV0X2tleS5qcycpO1xuXG4vKipcbiAqIEBjb25zdHJ1Y3RvclxuICogQGV4dGVuZHMgbW9kdWxlOnBhY2tldC9zZWNyZXRfa2V5XG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gc2VjcmV0X3N1YmtleSgpIHtcbiAgc2VjcmV0S2V5LmNhbGwodGhpcyk7XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEltcGxlbWVudGF0aW9uIG9mIHRoZSBTaWduYXR1cmUgUGFja2V0IChUYWcgMik8YnIvPlxuICogPGJyLz5cbiAqIFJGQzQ0ODAgNS4yOlxuICogQSBTaWduYXR1cmUgcGFja2V0IGRlc2NyaWJlcyBhIGJpbmRpbmcgYmV0d2VlbiBzb21lIHB1YmxpYyBrZXkgYW5kXG4gKiBzb21lIGRhdGEuICBUaGUgbW9zdCBjb21tb24gc2lnbmF0dXJlcyBhcmUgYSBzaWduYXR1cmUgb2YgYSBmaWxlIG9yIGFcbiAqIGJsb2NrIG9mIHRleHQsIGFuZCBhIHNpZ25hdHVyZSB0aGF0IGlzIGEgY2VydGlmaWNhdGlvbiBvZiBhIFVzZXIgSUQuXG4gKiBAcmVxdWlyZXMgY3J5cHRvXG4gKiBAcmVxdWlyZXMgZW51bXNcbiAqIEByZXF1aXJlcyBwYWNrZXQvcGFja2V0XG4gKiBAcmVxdWlyZXMgdHlwZS9rZXlpZFxuICogQHJlcXVpcmVzIHR5cGUvbXBpXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSBwYWNrZXQvc2lnbmF0dXJlXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIHBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0LmpzJyksXG4gIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcbiAgY3J5cHRvID0gcmVxdWlyZSgnLi4vY3J5cHRvJyksXG4gIHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKSxcbiAgdHlwZV9rZXlpZCA9IHJlcXVpcmUoJy4uL3R5cGUva2V5aWQuanMnKTtcblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBzaWduYXR1cmUoKSB7XG5cbiAgdGhpcy52ZXJzaW9uID0gNDtcbiAgdGhpcy5zaWduYXR1cmVUeXBlID0gbnVsbDtcbiAgdGhpcy5oYXNoQWxnb3JpdGhtID0gbnVsbDtcbiAgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBudWxsO1xuXG4gIHRoaXMuc2lnbmF0dXJlRGF0YSA9IG51bGw7XG4gIHRoaXMuc2lnbmVkSGFzaFZhbHVlID0gbnVsbDtcbiAgdGhpcy5tcGkgPSBudWxsO1xuXG4gIHRoaXMuY3JlYXRlZCA9IG5ldyBEYXRlKCk7XG4gIHRoaXMuc2lnbmF0dXJlRXhwaXJhdGlvblRpbWUgPSBudWxsO1xuICB0aGlzLnNpZ25hdHVyZU5ldmVyRXhwaXJlcyA9IHRydWU7XG4gIHRoaXMuZXhwb3J0YWJsZSA9IG51bGw7XG4gIHRoaXMudHJ1c3RMZXZlbCA9IG51bGw7XG4gIHRoaXMudHJ1c3RBbW91bnQgPSBudWxsO1xuICB0aGlzLnJlZ3VsYXJFeHByZXNzaW9uID0gbnVsbDtcbiAgdGhpcy5yZXZvY2FibGUgPSBudWxsO1xuICB0aGlzLmtleUV4cGlyYXRpb25UaW1lID0gbnVsbDtcbiAgdGhpcy5rZXlOZXZlckV4cGlyZXMgPSBudWxsO1xuICB0aGlzLnByZWZlcnJlZFN5bW1ldHJpY0FsZ29yaXRobXMgPSBudWxsO1xuICB0aGlzLnJldm9jYXRpb25LZXlDbGFzcyA9IG51bGw7XG4gIHRoaXMucmV2b2NhdGlvbktleUFsZ29yaXRobSA9IG51bGw7XG4gIHRoaXMucmV2b2NhdGlvbktleUZpbmdlcnByaW50ID0gbnVsbDtcbiAgdGhpcy5pc3N1ZXJLZXlJZCA9IG5ldyB0eXBlX2tleWlkKCk7XG4gIHRoaXMubm90YXRpb24gPSBudWxsO1xuICB0aGlzLnByZWZlcnJlZEhhc2hBbGdvcml0aG1zID0gbnVsbDtcbiAgdGhpcy5wcmVmZXJyZWRDb21wcmVzc2lvbkFsZ29yaXRobXMgPSBudWxsO1xuICB0aGlzLmtleVNlcnZlclByZWZlcmVuY2VzID0gbnVsbDtcbiAgdGhpcy5wcmVmZXJyZWRLZXlTZXJ2ZXIgPSBudWxsO1xuICB0aGlzLmlzUHJpbWFyeVVzZXJJRCA9IG51bGw7XG4gIHRoaXMucG9saWN5VVJJID0gbnVsbDtcbiAgdGhpcy5rZXlGbGFncyA9IG51bGw7XG4gIHRoaXMuc2lnbmVyc1VzZXJJZCA9IG51bGw7XG4gIHRoaXMucmVhc29uRm9yUmV2b2NhdGlvbkZsYWcgPSBudWxsO1xuICB0aGlzLnJlYXNvbkZvclJldm9jYXRpb25TdHJpbmcgPSBudWxsO1xuICB0aGlzLmZlYXR1cmVzID0gbnVsbDtcbiAgdGhpcy5zaWduYXR1cmVUYXJnZXRQdWJsaWNLZXlBbGdvcml0aG0gPSBudWxsO1xuICB0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2hBbGdvcml0aG0gPSBudWxsO1xuICB0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2ggPSBudWxsO1xuICB0aGlzLmVtYmVkZGVkU2lnbmF0dXJlID0gbnVsbDtcblxuICB0aGlzLnZlcmlmaWVkID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIHBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgc2lnbmF0dXJlIHBhY2tldCAodGFnIDIpLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXMgcGF5bG9hZCBvZiBhIHRhZyAyIHBhY2tldFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIHBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgYnl0ZXMgc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuIGxlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mIGJ5dGVzIGF0IHBvc2l0aW9uXG4gICAqIEByZXR1cm4ge21vZHVsZTpwYWNrZXQvc2lnbmF0dXJlfSBvYmplY3QgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uIChieXRlcykge1xuICAgIHZhciBpID0gMDtcblxuICAgIHRoaXMudmVyc2lvbiA9IGJ5dGVzLmNoYXJDb2RlQXQoaSsrKTtcbiAgICAvLyBzd2l0Y2ggb24gdmVyc2lvbiAoMyBhbmQgNClcbiAgICBzd2l0Y2ggKHRoaXMudmVyc2lvbikge1xuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyBPbmUtb2N0ZXQgbGVuZ3RoIG9mIGZvbGxvd2luZyBoYXNoZWQgbWF0ZXJpYWwuIE1VU1QgYmUgNS5cbiAgICAgICAgaWYgKGJ5dGVzLmNoYXJDb2RlQXQoaSsrKSAhPSA1KVxuICAgICAgICAgIHV0aWwucHJpbnRfZGVidWcoXCJwYWNrZXQvc2lnbmF0dXJlLmpzXFxuXCIgK1xuICAgICAgICAgICAgJ2ludmFsaWQgT25lLW9jdGV0IGxlbmd0aCBvZiBmb2xsb3dpbmcgaGFzaGVkIG1hdGVyaWFsLicgK1xuICAgICAgICAgICAgJ01VU1QgYmUgNS4gQDonICsgKGkgLSAxKSk7XG5cbiAgICAgICAgdmFyIHNpZ3BvcyA9IGk7XG4gICAgICAgIC8vIE9uZS1vY3RldCBzaWduYXR1cmUgdHlwZS5cbiAgICAgICAgdGhpcy5zaWduYXR1cmVUeXBlID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICAgIC8vIEZvdXItb2N0ZXQgY3JlYXRpb24gdGltZS5cbiAgICAgICAgdGhpcy5jcmVhdGVkID0gdXRpbC5yZWFkRGF0ZShieXRlcy5zdWJzdHIoaSwgNCkpO1xuICAgICAgICBpICs9IDQ7XG5cbiAgICAgICAgLy8gc3RvcmluZyBkYXRhIGFwcGVuZGVkIHRvIGRhdGEgd2hpY2ggZ2V0cyB2ZXJpZmllZFxuICAgICAgICB0aGlzLnNpZ25hdHVyZURhdGEgPSBieXRlcy5zdWJzdHJpbmcoc2lncG9zLCBpKTtcblxuICAgICAgICAvLyBFaWdodC1vY3RldCBLZXkgSUQgb2Ygc2lnbmVyLlxuICAgICAgICB0aGlzLmlzc3VlcktleUlkLnJlYWQoYnl0ZXMuc3Vic3RyaW5nKGksIGkgKyA4KSk7XG4gICAgICAgIGkgKz0gODtcblxuICAgICAgICAvLyBPbmUtb2N0ZXQgcHVibGljLWtleSBhbGdvcml0aG0uXG4gICAgICAgIHRoaXMucHVibGljS2V5QWxnb3JpdGhtID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICAgIC8vIE9uZS1vY3RldCBoYXNoIGFsZ29yaXRobS5cbiAgICAgICAgdGhpcy5oYXNoQWxnb3JpdGhtID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNDpcbiAgICAgICAgdGhpcy5zaWduYXR1cmVUeXBlID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuICAgICAgICB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSA9IGJ5dGVzLmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgICAgdGhpcy5oYXNoQWxnb3JpdGhtID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICAgIGZ1bmN0aW9uIHN1YnBhY2tldHMoYnl0ZXMpIHtcbiAgICAgICAgICAvLyBUd28tb2N0ZXQgc2NhbGFyIG9jdGV0IGNvdW50IGZvciBmb2xsb3dpbmcgc3VicGFja2V0IGRhdGEuXG4gICAgICAgICAgdmFyIHN1YnBhY2tldF9sZW5ndGggPSB1dGlsLnJlYWROdW1iZXIoXG4gICAgICAgICAgICBieXRlcy5zdWJzdHIoMCwgMikpO1xuXG4gICAgICAgICAgdmFyIGkgPSAyO1xuXG4gICAgICAgICAgLy8gc3VicGFja2V0IGRhdGEgc2V0ICh6ZXJvIG9yIG1vcmUgc3VicGFja2V0cylcbiAgICAgICAgICB2YXIgc3VicGFja2VkX3JlYWQgPSAwO1xuICAgICAgICAgIHdoaWxlIChpIDwgMiArIHN1YnBhY2tldF9sZW5ndGgpIHtcblxuICAgICAgICAgICAgdmFyIGxlbiA9IHBhY2tldC5yZWFkU2ltcGxlTGVuZ3RoKGJ5dGVzLnN1YnN0cihpKSk7XG4gICAgICAgICAgICBpICs9IGxlbi5vZmZzZXQ7XG5cbiAgICAgICAgICAgIHRoaXMucmVhZF9zdWJfcGFja2V0KGJ5dGVzLnN1YnN0cihpLCBsZW4ubGVuKSk7XG5cbiAgICAgICAgICAgIGkgKz0gbGVuLmxlbjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGhhc2hlZCBzdWJwYWNrZXRzXG4gICAgICAgIGkgKz0gc3VicGFja2V0cy5jYWxsKHRoaXMsIGJ5dGVzLnN1YnN0cihpKSwgdHJ1ZSk7XG5cbiAgICAgICAgLy8gQSBWNCBzaWduYXR1cmUgaGFzaGVzIHRoZSBwYWNrZXQgYm9keVxuICAgICAgICAvLyBzdGFydGluZyBmcm9tIGl0cyBmaXJzdCBmaWVsZCwgdGhlIHZlcnNpb24gbnVtYmVyLCB0aHJvdWdoIHRoZSBlbmRcbiAgICAgICAgLy8gb2YgdGhlIGhhc2hlZCBzdWJwYWNrZXQgZGF0YS4gIFRodXMsIHRoZSBmaWVsZHMgaGFzaGVkIGFyZSB0aGVcbiAgICAgICAgLy8gc2lnbmF0dXJlIHZlcnNpb24sIHRoZSBzaWduYXR1cmUgdHlwZSwgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtLCB0aGVcbiAgICAgICAgLy8gaGFzaCBhbGdvcml0aG0sIHRoZSBoYXNoZWQgc3VicGFja2V0IGxlbmd0aCwgYW5kIHRoZSBoYXNoZWRcbiAgICAgICAgLy8gc3VicGFja2V0IGJvZHkuXG4gICAgICAgIHRoaXMuc2lnbmF0dXJlRGF0YSA9IGJ5dGVzLnN1YnN0cigwLCBpKTtcblxuICAgICAgICAvLyB1bmhhc2hlZCBzdWJwYWNrZXRzXG4gICAgICAgIGkgKz0gc3VicGFja2V0cy5jYWxsKHRoaXMsIGJ5dGVzLnN1YnN0cihpKSwgZmFsc2UpO1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdWZXJzaW9uICcgKyB2ZXJzaW9uICsgJyBvZiB0aGUgc2lnbmF0dXJlIGlzIHVuc3VwcG9ydGVkLicpO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICAvLyBUd28tb2N0ZXQgZmllbGQgaG9sZGluZyBsZWZ0IDE2IGJpdHMgb2Ygc2lnbmVkIGhhc2ggdmFsdWUuXG4gICAgdGhpcy5zaWduZWRIYXNoVmFsdWUgPSBieXRlcy5zdWJzdHIoaSwgMik7XG4gICAgaSArPSAyO1xuXG4gICAgdGhpcy5zaWduYXR1cmUgPSBieXRlcy5zdWJzdHIoaSk7XG4gIH07XG5cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zaWduYXR1cmVEYXRhICtcbiAgICAgIHV0aWwud3JpdGVOdW1iZXIoMCwgMikgKyAvLyBOdW1iZXIgb2YgdW5zaWduZWQgc3VicGFja2V0cy5cbiAgICAgIHRoaXMuc2lnbmVkSGFzaFZhbHVlICtcbiAgICAgIHRoaXMuc2lnbmF0dXJlO1xuICB9O1xuXG4gIC8qKlxuICAgKiBTaWducyBwcm92aWRlZCBkYXRhLiBUaGlzIG5lZWRzIHRvIGJlIGRvbmUgcHJpb3IgdG8gc2VyaWFsaXphdGlvbi5cbiAgICogQHBhcmFtIHttb2R1bGU6cGFja2V0L3NlY3JldF9rZXl9IGtleSBwcml2YXRlIGtleSB1c2VkIHRvIHNpZ24gdGhlIG1lc3NhZ2UuIFxuICAgKiBAcGFyYW0ge09iamVjdH0gZGF0YSBDb250YWlucyBwYWNrZXRzIHRvIGJlIHNpZ25lZC5cbiAgICovXG4gIHRoaXMuc2lnbiA9IGZ1bmN0aW9uIChrZXksIGRhdGEpIHtcbiAgICB2YXIgc2lnbmF0dXJlVHlwZSA9IGVudW1zLndyaXRlKGVudW1zLnNpZ25hdHVyZSwgdGhpcy5zaWduYXR1cmVUeXBlKSxcbiAgICAgIHB1YmxpY0tleUFsZ29yaXRobSA9IGVudW1zLndyaXRlKGVudW1zLnB1YmxpY0tleSwgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0pLFxuICAgICAgaGFzaEFsZ29yaXRobSA9IGVudW1zLndyaXRlKGVudW1zLmhhc2gsIHRoaXMuaGFzaEFsZ29yaXRobSk7XG5cbiAgICB2YXIgcmVzdWx0ID0gU3RyaW5nLmZyb21DaGFyQ29kZSg0KTtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShzaWduYXR1cmVUeXBlKTtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShwdWJsaWNLZXlBbGdvcml0aG0pO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGhhc2hBbGdvcml0aG0pO1xuXG4gICAgdGhpcy5pc3N1ZXJLZXlJZCA9IGtleS5nZXRLZXlJZCgpO1xuXG4gICAgLy8gQWRkIGhhc2hlZCBzdWJwYWNrZXRzXG4gICAgcmVzdWx0ICs9IHRoaXMud3JpdGVfYWxsX3N1Yl9wYWNrZXRzKCk7XG5cbiAgICB0aGlzLnNpZ25hdHVyZURhdGEgPSByZXN1bHQ7XG5cbiAgICB2YXIgdHJhaWxlciA9IHRoaXMuY2FsY3VsYXRlVHJhaWxlcigpO1xuXG4gICAgdmFyIHRvSGFzaCA9IHRoaXMudG9TaWduKHNpZ25hdHVyZVR5cGUsIGRhdGEpICtcbiAgICAgIHRoaXMuc2lnbmF0dXJlRGF0YSArIHRyYWlsZXI7XG5cbiAgICB2YXIgaGFzaCA9IGNyeXB0by5oYXNoLmRpZ2VzdChoYXNoQWxnb3JpdGhtLCB0b0hhc2gpO1xuXG4gICAgdGhpcy5zaWduZWRIYXNoVmFsdWUgPSBoYXNoLnN1YnN0cigwLCAyKTtcblxuICAgIHRoaXMuc2lnbmF0dXJlID0gY3J5cHRvLnNpZ25hdHVyZS5zaWduKGhhc2hBbGdvcml0aG0sXG4gICAgICBwdWJsaWNLZXlBbGdvcml0aG0sIGtleS5tcGksIHRvSGFzaCk7XG4gIH07XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgc3RyaW5nIG9mIGJ5dGVzIHdpdGggYWxsIHN1YnBhY2tldCBkYXRhXG4gICAqIEByZXR1cm4ge1N0cmluZ30gYSBzdHJpbmctcmVwcmVzZW50YXRpb24gb2YgYSBhbGwgc3VicGFja2V0IGRhdGFcbiAgICovXG4gIHRoaXMud3JpdGVfYWxsX3N1Yl9wYWNrZXRzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBzdWIgPSBlbnVtcy5zaWduYXR1cmVTdWJwYWNrZXQ7XG4gICAgdmFyIHJlc3VsdCA9ICcnO1xuICAgIHZhciBieXRlcyA9ICcnO1xuICAgIGlmICh0aGlzLmNyZWF0ZWQgIT09IG51bGwpIHtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5zaWduYXR1cmVfY3JlYXRpb25fdGltZSwgdXRpbC53cml0ZURhdGUodGhpcy5jcmVhdGVkKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLnNpZ25hdHVyZUV4cGlyYXRpb25UaW1lICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIuc2lnbmF0dXJlX2V4cGlyYXRpb25fdGltZSwgdXRpbC53cml0ZU51bWJlcih0aGlzLnNpZ25hdHVyZUV4cGlyYXRpb25UaW1lLCA0KSk7XG4gICAgfVxuICAgIGlmICh0aGlzLmV4cG9ydGFibGUgIT09IG51bGwpIHtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5leHBvcnRhYmxlX2NlcnRpZmljYXRpb24sIFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy5leHBvcnRhYmxlID8gMSA6IDApKTtcbiAgICB9XG4gICAgaWYgKHRoaXMudHJ1c3RMZXZlbCAhPT0gbnVsbCkge1xuICAgICAgYnl0ZXMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMudHJ1c3RMZXZlbCkgKyBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMudHJ1c3RBbW91bnQpO1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnRydXN0X3NpZ25hdHVyZSwgYnl0ZXMpO1xuICAgIH1cbiAgICBpZiAodGhpcy5yZWd1bGFyRXhwcmVzc2lvbiAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnJlZ3VsYXJfZXhwcmVzc2lvbiwgdGhpcy5yZWd1bGFyRXhwcmVzc2lvbik7XG4gICAgfVxuICAgIGlmICh0aGlzLnJldm9jYWJsZSAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnJldm9jYWJsZSwgU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnJldm9jYWJsZSA/IDEgOiAwKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLmtleUV4cGlyYXRpb25UaW1lICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIua2V5X2V4cGlyYXRpb25fdGltZSwgdXRpbC53cml0ZU51bWJlcih0aGlzLmtleUV4cGlyYXRpb25UaW1lLCA0KSk7XG4gICAgfVxuICAgIGlmICh0aGlzLnByZWZlcnJlZFN5bW1ldHJpY0FsZ29yaXRobXMgIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gdXRpbC5iaW4yc3RyKHRoaXMucHJlZmVycmVkU3ltbWV0cmljQWxnb3JpdGhtcyk7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIucHJlZmVycmVkX3N5bW1ldHJpY19hbGdvcml0aG1zLCBieXRlcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLnJldm9jYXRpb25LZXlDbGFzcyAhPT0gbnVsbCkge1xuICAgICAgYnl0ZXMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMucmV2b2NhdGlvbktleUNsYXNzKTtcbiAgICAgIGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy5yZXZvY2F0aW9uS2V5QWxnb3JpdGhtKTtcbiAgICAgIGJ5dGVzICs9IHRoaXMucmV2b2NhdGlvbktleUZpbmdlcnByaW50O1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnJldm9jYXRpb25fa2V5LCBieXRlcyk7XG4gICAgfVxuICAgIGlmICghdGhpcy5pc3N1ZXJLZXlJZC5pc051bGwoKSkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLmlzc3VlciwgdGhpcy5pc3N1ZXJLZXlJZC53cml0ZSgpKTtcbiAgICB9XG4gICAgaWYgKHRoaXMubm90YXRpb24gIT09IG51bGwpIHtcbiAgICAgIGZvciAodmFyIG5hbWUgaW4gdGhpcy5ub3RhdGlvbikge1xuICAgICAgICBpZiAodGhpcy5ub3RhdGlvbi5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgICAgICAgIHZhciB2YWx1ZSA9IHRoaXMubm90YXRpb25bbmFtZV07XG4gICAgICAgICAgYnl0ZXMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4ODApO1xuICAgICAgICAgIGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG4gICAgICAgICAgYnl0ZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKTtcbiAgICAgICAgICBieXRlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuICAgICAgICAgIC8vIDIgb2N0ZXRzIG9mIG5hbWUgbGVuZ3RoXG4gICAgICAgICAgYnl0ZXMgKz0gdXRpbC53cml0ZU51bWJlcihuYW1lLmxlbmd0aCwgMik7XG4gICAgICAgICAgLy8gMiBvY3RldHMgb2YgdmFsdWUgbGVuZ3RoXG4gICAgICAgICAgYnl0ZXMgKz0gdXRpbC53cml0ZU51bWJlcih2YWx1ZS5sZW5ndGgsIDIpO1xuICAgICAgICAgIGJ5dGVzICs9IG5hbWUgKyB2YWx1ZTtcbiAgICAgICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIubm90YXRpb25fZGF0YSwgYnl0ZXMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBcbiAgICBpZiAodGhpcy5wcmVmZXJyZWRIYXNoQWxnb3JpdGhtcyAhPT0gbnVsbCkge1xuICAgICAgYnl0ZXMgPSB1dGlsLmJpbjJzdHIodGhpcy5wcmVmZXJyZWRIYXNoQWxnb3JpdGhtcyk7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIucHJlZmVycmVkX2hhc2hfYWxnb3JpdGhtcywgYnl0ZXMpO1xuICAgIH1cbiAgICBpZiAodGhpcy5wcmVmZXJyZWRDb21wcmVzc2lvbkFsZ29yaXRobXMgIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gdXRpbC5iaW4yc3RyKHRoaXMucHJlZmVycmVkQ29tcHJlc3Npb25BbGdvcml0aG1zKTtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5wcmVmZXJyZWRfaGFzaF9hbGdvcml0aG1zLCBieXRlcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLmtleVNlcnZlclByZWZlcmVuY2VzICE9PSBudWxsKSB7XG4gICAgICBieXRlcyA9IHV0aWwuYmluMnN0cih0aGlzLmtleVNlcnZlclByZWZlcmVuY2VzKTtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5rZXlfc2VydmVyX3ByZWZlcmVuY2VzLCBieXRlcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLnByZWZlcnJlZEtleVNlcnZlciAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnByZWZlcnJlZF9rZXlfc2VydmVyLCB0aGlzLnByZWZlcnJlZEtleVNlcnZlcik7XG4gICAgfVxuICAgIGlmICh0aGlzLmlzUHJpbWFyeVVzZXJJRCAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnByaW1hcnlfdXNlcl9pZCwgU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLmlzUHJpbWFyeVVzZXJJRCA/IDEgOiAwKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLnBvbGljeVVSSSAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnBvbGljeV91cmksIHRoaXMucG9saWN5VVJJKTsgXG4gICAgfVxuICAgIGlmICh0aGlzLmtleUZsYWdzICE9PSBudWxsKSB7XG4gICAgICBieXRlcyA9IHV0aWwuYmluMnN0cih0aGlzLmtleUZsYWdzKTtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5rZXlfZmxhZ3MsIGJ5dGVzKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuc2lnbmVyc1VzZXJJZCAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnNpZ25lcnNfdXNlcl9pZCwgdGhpcy5zaWduZXJzVXNlcklkKTsgXG4gICAgfVxuICAgIGlmICh0aGlzLnJlYXNvbkZvclJldm9jYXRpb25GbGFnICE9PSBudWxsKSB7XG4gICAgICBieXRlcyA9IFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy5yZWFzb25Gb3JSZXZvY2F0aW9uRmxhZyk7XG4gICAgICBieXRlcyArPSB0aGlzLnJlYXNvbkZvclJldm9jYXRpb25TdHJpbmc7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIucmVhc29uX2Zvcl9yZXZvY2F0aW9uLCBieXRlcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLmZlYXR1cmVzICE9PSBudWxsKSB7XG4gICAgICBieXRlcyA9IHV0aWwuYmluMnN0cih0aGlzLmZlYXR1cmVzKTtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5mZWF0dXJlcywgYnl0ZXMpO1xuICAgIH1cbiAgICBpZiAodGhpcy5zaWduYXR1cmVUYXJnZXRQdWJsaWNLZXlBbGdvcml0aG0gIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnNpZ25hdHVyZVRhcmdldFB1YmxpY0tleUFsZ29yaXRobSk7XG4gICAgICBieXRlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuc2lnbmF0dXJlVGFyZ2V0SGFzaEFsZ29yaXRobSk7XG4gICAgICBieXRlcyArPSB0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2g7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIuc2lnbmF0dXJlX3RhcmdldCwgYnl0ZXMpO1xuICAgIH1cbiAgICBpZiAodGhpcy5lbWJlZGRlZFNpZ25hdHVyZSAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLmVtYmVkZGVkX3NpZ25hdHVyZSwgdGhpcy5lbWJlZGRlZFNpZ25hdHVyZS53cml0ZSgpKTtcbiAgICB9XG4gICAgcmVzdWx0ID0gdXRpbC53cml0ZU51bWJlcihyZXN1bHQubGVuZ3RoLCAyKSArIHJlc3VsdDtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIC8qKlxuICAgKiBjcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgc3ViIHNpZ25hdHVyZSBwYWNrZXQgKFNlZSBSRkMgNDg4MCA1LjIuMy4xKVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHR5cGUgc3VicGFja2V0IHNpZ25hdHVyZSB0eXBlLiBTaWduYXR1cmUgdHlwZXMgYXMgZGVzY3JpYmVkIFxuICAgKiBpbiBSRkM0ODgwIFNlY3Rpb24gNS4yLjMuMlxuICAgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBkYXRhIHRvIGJlIGluY2x1ZGVkXG4gICAqIEByZXR1cm4ge1N0cmluZ30gYSBzdHJpbmctcmVwcmVzZW50YXRpb24gb2YgYSBzdWIgc2lnbmF0dXJlIHBhY2tldCAoU2VlIFJGQyA0ODgwIDUuMi4zLjEpXG4gICAqL1xuICBmdW5jdGlvbiB3cml0ZV9zdWJfcGFja2V0KHR5cGUsIGRhdGEpIHtcbiAgICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgICByZXN1bHQgKz0gcGFja2V0LndyaXRlU2ltcGxlTGVuZ3RoKGRhdGEubGVuZ3RoICsgMSk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUodHlwZSk7XG4gICAgcmVzdWx0ICs9IGRhdGE7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8vIFY0IHNpZ25hdHVyZSBzdWIgcGFja2V0c1xuXG4gIHRoaXMucmVhZF9zdWJfcGFja2V0ID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgdmFyIG15cG9zID0gMDtcblxuICAgIGZ1bmN0aW9uIHJlYWRfYXJyYXkocHJvcCwgYnl0ZXMpIHtcbiAgICAgIHRoaXNbcHJvcF0gPSBbXTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzW3Byb3BdLnB1c2goYnl0ZXMuY2hhckNvZGVBdChpKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVGhlIGxlZnR3b3N0IGJpdCBkZW5vdGVzIGEgXCJjcml0aWNhbFwiIHBhY2tldCwgYnV0IHdlIGlnbm9yZSBpdC5cbiAgICB2YXIgdHlwZSA9IGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKykgJiAweDdGO1xuXG4gICAgLy8gc3VicGFja2V0IHR5cGVcbiAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgLy8gU2lnbmF0dXJlIENyZWF0aW9uIFRpbWVcbiAgICAgICAgdGhpcy5jcmVhdGVkID0gdXRpbC5yZWFkRGF0ZShieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM6XG4gICAgICAgIC8vIFNpZ25hdHVyZSBFeHBpcmF0aW9uIFRpbWUgaW4gc2Vjb25kc1xuICAgICAgICB2YXIgc2Vjb25kcyA9IHV0aWwucmVhZE51bWJlcihieXRlcy5zdWJzdHIobXlwb3MpKTtcblxuICAgICAgICB0aGlzLnNpZ25hdHVyZU5ldmVyRXhwaXJlcyA9IHNlY29uZHMgPT0gMDtcbiAgICAgICAgdGhpcy5zaWduYXR1cmVFeHBpcmF0aW9uVGltZSA9IHNlY29uZHM7XG5cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDQ6XG4gICAgICAgIC8vIEV4cG9ydGFibGUgQ2VydGlmaWNhdGlvblxuICAgICAgICB0aGlzLmV4cG9ydGFibGUgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspID09IDE7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA1OlxuICAgICAgICAvLyBUcnVzdCBTaWduYXR1cmVcbiAgICAgICAgdGhpcy50cnVzdExldmVsID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKTtcbiAgICAgICAgdGhpcy50cnVzdEFtb3VudCA9IGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA2OlxuICAgICAgICAvLyBSZWd1bGFyIEV4cHJlc3Npb25cbiAgICAgICAgdGhpcy5yZWd1bGFyRXhwcmVzc2lvbiA9IGJ5dGVzLnN1YnN0cihteXBvcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA3OlxuICAgICAgICAvLyBSZXZvY2FibGVcbiAgICAgICAgdGhpcy5yZXZvY2FibGUgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspID09IDE7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA5OlxuICAgICAgICAvLyBLZXkgRXhwaXJhdGlvbiBUaW1lIGluIHNlY29uZHNcbiAgICAgICAgdmFyIHNlY29uZHMgPSB1dGlsLnJlYWROdW1iZXIoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG5cbiAgICAgICAgdGhpcy5rZXlFeHBpcmF0aW9uVGltZSA9IHNlY29uZHM7XG4gICAgICAgIHRoaXMua2V5TmV2ZXJFeHBpcmVzID0gc2Vjb25kcyA9PSAwO1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAxMTpcbiAgICAgICAgLy8gUHJlZmVycmVkIFN5bW1ldHJpYyBBbGdvcml0aG1zXG4gICAgICAgIHRoaXMucHJlZmVycmVkU3ltbWV0cmljQWxnb3JpdGhtcyA9IFtdO1xuXG4gICAgICAgIHdoaWxlIChteXBvcyAhPSBieXRlcy5sZW5ndGgpIHtcbiAgICAgICAgICB0aGlzLnByZWZlcnJlZFN5bW1ldHJpY0FsZ29yaXRobXMucHVzaChieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAxMjpcbiAgICAgICAgLy8gUmV2b2NhdGlvbiBLZXlcbiAgICAgICAgLy8gKDEgb2N0ZXQgb2YgY2xhc3MsIDEgb2N0ZXQgb2YgcHVibGljLWtleSBhbGdvcml0aG0gSUQsIDIwXG4gICAgICAgIC8vIG9jdGV0cyBvZlxuICAgICAgICAvLyBmaW5nZXJwcmludClcbiAgICAgICAgdGhpcy5yZXZvY2F0aW9uS2V5Q2xhc3MgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgICB0aGlzLnJldm9jYXRpb25LZXlBbGdvcml0aG0gPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgICB0aGlzLnJldm9jYXRpb25LZXlGaW5nZXJwcmludCA9IGJ5dGVzLnN1YnN0cihteXBvcywgMjApO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAxNjpcbiAgICAgICAgLy8gSXNzdWVyXG4gICAgICAgIHRoaXMuaXNzdWVyS2V5SWQucmVhZChieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgMjA6XG4gICAgICAgIC8vIE5vdGF0aW9uIERhdGFcbiAgICAgICAgLy8gV2UgZG9uJ3Qga25vdyBob3cgdG8gaGFuZGxlIGFueXRoaW5nIGJ1dCBhIHRleHQgZmxhZ2dlZCBkYXRhLlxuICAgICAgICBpZiAoYnl0ZXMuY2hhckNvZGVBdChteXBvcykgPT0gMHg4MCkge1xuXG4gICAgICAgICAgLy8gV2UgZXh0cmFjdCBrZXkvdmFsdWUgdHVwbGUgZnJvbSB0aGUgYnl0ZSBzdHJlYW0uXG4gICAgICAgICAgbXlwb3MgKz0gNDtcbiAgICAgICAgICB2YXIgbSA9IHV0aWwucmVhZE51bWJlcihieXRlcy5zdWJzdHIobXlwb3MsIDIpKTtcbiAgICAgICAgICBteXBvcyArPSAyXG4gICAgICAgICAgdmFyIG4gPSB1dGlsLnJlYWROdW1iZXIoYnl0ZXMuc3Vic3RyKG15cG9zLCAyKSk7XG4gICAgICAgICAgbXlwb3MgKz0gMlxuXG4gICAgICAgICAgdmFyIG5hbWUgPSBieXRlcy5zdWJzdHIobXlwb3MsIG0pLFxuICAgICAgICAgICAgdmFsdWUgPSBieXRlcy5zdWJzdHIobXlwb3MgKyBtLCBuKTtcblxuICAgICAgICAgIHRoaXMubm90YXRpb24gPSB0aGlzLm5vdGF0aW9uIHx8IHt9O1xuICAgICAgICAgIHRoaXMubm90YXRpb25bbmFtZV0gPSB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIHRocm93IG5ldyBFcnJvcihcIlVuc3VwcG9ydGVkIG5vdGF0aW9uIGZsYWcuXCIpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjE6XG4gICAgICAgIC8vIFByZWZlcnJlZCBIYXNoIEFsZ29yaXRobXNcbiAgICAgICAgcmVhZF9hcnJheS5jYWxsKHRoaXMsICdwcmVmZXJyZWRIYXNoQWxnb3JpdGhtcycsIGJ5dGVzLnN1YnN0cihteXBvcykpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjI6XG4gICAgICAgIC8vIFByZWZlcnJlZCBDb21wcmVzc2lvbiBBbGdvcml0aG1zXG4gICAgICAgIHJlYWRfYXJyYXkuY2FsbCh0aGlzLCAncHJlZmVycmVkQ29tcHJlc3Npb25BbGdvcml0aG1zICcsIGJ5dGVzLnN1YnN0cihteXBvcykpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjM6XG4gICAgICAgIC8vIEtleSBTZXJ2ZXIgUHJlZmVyZW5jZXNcbiAgICAgICAgcmVhZF9hcnJheS5jYWxsKHRoaXMsICdrZXlTZXJ2ZXJQcmVmZXJlbmNlc3MnLCBieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI0OlxuICAgICAgICAvLyBQcmVmZXJyZWQgS2V5IFNlcnZlclxuICAgICAgICB0aGlzLnByZWZlcnJlZEtleVNlcnZlciA9IGJ5dGVzLnN1YnN0cihteXBvcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyNTpcbiAgICAgICAgLy8gUHJpbWFyeSBVc2VyIElEXG4gICAgICAgIHRoaXMuaXNQcmltYXJ5VXNlcklEID0gYnl0ZXNbbXlwb3MrK10gIT0gMDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI2OlxuICAgICAgICAvLyBQb2xpY3kgVVJJXG4gICAgICAgIHRoaXMucG9saWN5VVJJID0gYnl0ZXMuc3Vic3RyKG15cG9zKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI3OlxuICAgICAgICAvLyBLZXkgRmxhZ3NcbiAgICAgICAgcmVhZF9hcnJheS5jYWxsKHRoaXMsICdrZXlGbGFncycsIGJ5dGVzLnN1YnN0cihteXBvcykpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjg6XG4gICAgICAgIC8vIFNpZ25lcidzIFVzZXIgSURcbiAgICAgICAgdGhpcy5zaWduZXJzVXNlcklkICs9IGJ5dGVzLnN1YnN0cihteXBvcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyOTpcbiAgICAgICAgLy8gUmVhc29uIGZvciBSZXZvY2F0aW9uXG4gICAgICAgIHRoaXMucmVhc29uRm9yUmV2b2NhdGlvbkZsYWcgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgICB0aGlzLnJlYXNvbkZvclJldm9jYXRpb25TdHJpbmcgPSBieXRlcy5zdWJzdHIobXlwb3MpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzA6XG4gICAgICAgIC8vIEZlYXR1cmVzXG4gICAgICAgIHJlYWRfYXJyYXkuY2FsbCh0aGlzLCAnZmVhdHVyZXMnLCBieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDMxOlxuICAgICAgICAvLyBTaWduYXR1cmUgVGFyZ2V0XG4gICAgICAgIC8vICgxIG9jdGV0IHB1YmxpYy1rZXkgYWxnb3JpdGhtLCAxIG9jdGV0IGhhc2ggYWxnb3JpdGhtLCBOIG9jdGV0cyBoYXNoKVxuICAgICAgICB0aGlzLnNpZ25hdHVyZVRhcmdldFB1YmxpY0tleUFsZ29yaXRobSA9IGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKyk7XG4gICAgICAgIHRoaXMuc2lnbmF0dXJlVGFyZ2V0SGFzaEFsZ29yaXRobSA9IGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKyk7XG5cbiAgICAgICAgdmFyIGxlbiA9IGNyeXB0by5nZXRIYXNoQnl0ZUxlbmd0aCh0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2hBbGdvcml0aG0pO1xuXG4gICAgICAgIHRoaXMuc2lnbmF0dXJlVGFyZ2V0SGFzaCA9IGJ5dGVzLnN1YnN0cihteXBvcywgbGVuKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDMyOlxuICAgICAgICAvLyBFbWJlZGRlZCBTaWduYXR1cmVcbiAgICAgICAgdGhpcy5lbWJlZGRlZFNpZ25hdHVyZSA9IG5ldyBzaWduYXR1cmUoKTtcbiAgICAgICAgdGhpcy5lbWJlZGRlZFNpZ25hdHVyZS5yZWFkKGJ5dGVzLnN1YnN0cihteXBvcykpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVua25vd24gc2lnbmF0dXJlIHN1YnBhY2tldCB0eXBlIFwiICsgdHlwZSArIFwiIEA6XCIgKyBteXBvcyk7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfTtcblxuICAvLyBQcm9kdWNlcyBkYXRhIHRvIHByb2R1Y2Ugc2lnbmF0dXJlIG9uXG4gIHRoaXMudG9TaWduID0gZnVuY3Rpb24gKHR5cGUsIGRhdGEpIHtcbiAgICB2YXIgdCA9IGVudW1zLnNpZ25hdHVyZTtcblxuICAgIHN3aXRjaCAodHlwZSkge1xuICAgICAgY2FzZSB0LmJpbmFyeTpcbiAgICAgIGNhc2UgdC50ZXh0OlxuICAgICAgICByZXR1cm4gZGF0YS5nZXRCeXRlcygpO1xuXG4gICAgICBjYXNlIHQuc3RhbmRhbG9uZTpcbiAgICAgICAgcmV0dXJuICcnO1xuXG4gICAgICBjYXNlIHQuY2VydF9nZW5lcmljOlxuICAgICAgY2FzZSB0LmNlcnRfcGVyc29uYTpcbiAgICAgIGNhc2UgdC5jZXJ0X2Nhc3VhbDpcbiAgICAgIGNhc2UgdC5jZXJ0X3Bvc2l0aXZlOlxuICAgICAgY2FzZSB0LmNlcnRfcmV2b2NhdGlvbjpcbiAgICAgICAgdmFyIHBhY2tldCwgdGFnO1xuXG4gICAgICAgIGlmIChkYXRhLnVzZXJpZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgdGFnID0gMHhCNDtcbiAgICAgICAgICBwYWNrZXQgPSBkYXRhLnVzZXJpZDtcbiAgICAgICAgfSBlbHNlIGlmIChkYXRhLnVzZXJhdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRhZyA9IDB4RDE7XG4gICAgICAgICAgcGFja2V0ID0gZGF0YS51c2VyYXR0cmlidXRlO1xuICAgICAgICB9IGVsc2UgdGhyb3cgbmV3IEVycm9yKCdFaXRoZXIgYSB1c2VyaWQgb3IgdXNlcmF0dHJpYnV0ZSBwYWNrZXQgbmVlZHMgdG8gYmUgJyArXG4gICAgICAgICAgICAnc3VwcGxpZWQgZm9yIGNlcnRpZmljYXRpb24uJyk7XG5cbiAgICAgICAgdmFyIGJ5dGVzID0gcGFja2V0LndyaXRlKCk7XG5cbiAgICAgICAgaWYgKHRoaXMudmVyc2lvbiA9PSA0KSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMudG9TaWduKHQua2V5LCBkYXRhKSArXG4gICAgICAgICAgU3RyaW5nLmZyb21DaGFyQ29kZSh0YWcpICtcbiAgICAgICAgICB1dGlsLndyaXRlTnVtYmVyKGJ5dGVzLmxlbmd0aCwgNCkgK1xuICAgICAgICAgIGJ5dGVzOyBcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnZlcnNpb24gPT0gMykge1xuICAgICAgICAgIHJldHVybiB0aGlzLnRvU2lnbih0LmtleSwgZGF0YSkgK1xuICAgICAgICAgIGJ5dGVzO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlIHQuc3Via2V5X2JpbmRpbmc6XG4gICAgICBjYXNlIHQua2V5X2JpbmRpbmc6XG4gICAgICAgIHJldHVybiB0aGlzLnRvU2lnbih0LmtleSwgZGF0YSkgKyB0aGlzLnRvU2lnbih0LmtleSwge1xuICAgICAgICAgIGtleTogZGF0YS5iaW5kXG4gICAgICAgIH0pO1xuXG4gICAgICBjYXNlIHQua2V5OlxuICAgICAgICBpZiAoZGF0YS5rZXkgPT0gdW5kZWZpbmVkKVxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignS2V5IHBhY2tldCBpcyByZXF1aXJlZCBmb3IgdGhpcyBzaWd0YXR1cmUuJyk7XG5cbiAgICAgICAgcmV0dXJuIGRhdGEua2V5LndyaXRlT2xkKCk7XG5cbiAgICAgIGNhc2UgdC5rZXlfcmV2b2NhdGlvbjpcbiAgICAgIGNhc2UgdC5zdWJrZXlfcmV2b2NhdGlvbjpcbiAgICAgICAgcmV0dXJuIHRoaXMudG9TaWduKHQua2V5LCBkYXRhKTtcbiAgICAgIGNhc2UgdC50aW1lc3RhbXA6XG4gICAgICAgIHJldHVybiAnJztcbiAgICAgIGNhc2UgdC50aGlyZF9wYXJ0eTpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdOb3QgaW1wbGVtZW50ZWQnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gc2lnbmF0dXJlIHR5cGUuJylcbiAgICB9XG4gIH1cblxuXG4gIHRoaXMuY2FsY3VsYXRlVHJhaWxlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBjYWxjdWxhdGluZyB0aGUgdHJhaWxlclxuICAgIHZhciB0cmFpbGVyID0gJyc7XG4gICAgLy8gVjMgc2lnbmF0dXJlcyBkb24ndCBoYXZlIGEgdHJhaWxlclxuICAgIGlmICh0aGlzLnZlcnNpb24gPT0gMykgcmV0dXJuIHRyYWlsZXI7XG4gICAgdHJhaWxlciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDQpOyAvLyBWZXJzaW9uXG4gICAgdHJhaWxlciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4RkYpO1xuICAgIHRyYWlsZXIgKz0gdXRpbC53cml0ZU51bWJlcih0aGlzLnNpZ25hdHVyZURhdGEubGVuZ3RoLCA0KTtcbiAgICByZXR1cm4gdHJhaWxlclxuICB9XG5cblxuICAvKipcbiAgICogdmVyaWZ5cyB0aGUgc2lnbmF0dXJlIHBhY2tldC4gTm90ZTogbm90IHNpZ25hdHVyZSB0eXBlcyBhcmUgaW1wbGVtZW50ZWRcbiAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBkYXRhIGRhdGEgd2hpY2ggb24gdGhlIHNpZ25hdHVyZSBhcHBsaWVzXG4gICAqIEBwYXJhbSB7bW9kdWxlOnBhY2tldC9wdWJsaWNfc3Via2V5fG1vZHVsZTpwYWNrZXQvcHVibGljX2tleX0ga2V5IHRoZSBwdWJsaWMga2V5IHRvIHZlcmlmeSB0aGUgc2lnbmF0dXJlXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgbWVzc2FnZSBpcyB2ZXJpZmllZCwgZWxzZSBmYWxzZS5cbiAgICovXG4gIHRoaXMudmVyaWZ5ID0gZnVuY3Rpb24gKGtleSwgZGF0YSkge1xuICAgIHZhciBzaWduYXR1cmVUeXBlID0gZW51bXMud3JpdGUoZW51bXMuc2lnbmF0dXJlLCB0aGlzLnNpZ25hdHVyZVR5cGUpLFxuICAgICAgcHVibGljS2V5QWxnb3JpdGhtID0gZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSksXG4gICAgICBoYXNoQWxnb3JpdGhtID0gZW51bXMud3JpdGUoZW51bXMuaGFzaCwgdGhpcy5oYXNoQWxnb3JpdGhtKTtcblxuICAgIHZhciBieXRlcyA9IHRoaXMudG9TaWduKHNpZ25hdHVyZVR5cGUsIGRhdGEpLFxuICAgICAgdHJhaWxlciA9IHRoaXMuY2FsY3VsYXRlVHJhaWxlcigpO1xuXG5cbiAgICB2YXIgbXBpY291bnQgPSAwO1xuICAgIC8vIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIFJTQSBzaWduYXR1cmVzOlxuICAgIC8vICAgICAgLSBtdWx0aXByZWNpc2lvbiBudW1iZXIgKE1QSSkgb2YgUlNBIHNpZ25hdHVyZSB2YWx1ZSBtKipkIG1vZCBuLlxuICAgIGlmIChwdWJsaWNLZXlBbGdvcml0aG0gPiAwICYmIHB1YmxpY0tleUFsZ29yaXRobSA8IDQpXG4gICAgICBtcGljb3VudCA9IDE7XG4gICAgLy8gICAgQWxnb3JpdGhtLVNwZWNpZmljIEZpZWxkcyBmb3IgRFNBIHNpZ25hdHVyZXM6XG4gICAgLy8gICAgICAtIE1QSSBvZiBEU0EgdmFsdWUgci5cbiAgICAvLyAgICAgIC0gTVBJIG9mIERTQSB2YWx1ZSBzLlxuICAgIGVsc2UgaWYgKHB1YmxpY0tleUFsZ29yaXRobSA9PSAxNylcbiAgICAgIG1waWNvdW50ID0gMjtcblxuICAgIHZhciBtcGkgPSBbXSxcbiAgICAgIGkgPSAwO1xuICAgIGZvciAodmFyIGogPSAwOyBqIDwgbXBpY291bnQ7IGorKykge1xuICAgICAgbXBpW2pdID0gbmV3IHR5cGVfbXBpKCk7XG4gICAgICBpICs9IG1waVtqXS5yZWFkKHRoaXMuc2lnbmF0dXJlLnN1YnN0cihpKSk7XG4gICAgfVxuXG4gICAgdGhpcy52ZXJpZmllZCA9IGNyeXB0by5zaWduYXR1cmUudmVyaWZ5KHB1YmxpY0tleUFsZ29yaXRobSxcbiAgICAgIGhhc2hBbGdvcml0aG0sIG1waSwga2V5Lm1waSxcbiAgICAgIGJ5dGVzICsgdGhpcy5zaWduYXR1cmVEYXRhICsgdHJhaWxlcik7XG5cbiAgICByZXR1cm4gdGhpcy52ZXJpZmllZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmllcyBzaWduYXR1cmUgZXhwaXJhdGlvbiBkYXRlXG4gICAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUgaWYgZXhwaXJlZFxuICAgKi9cbiAgdGhpcy5pc0V4cGlyZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLnNpZ25hdHVyZU5ldmVyRXhwaXJlcykge1xuICAgICAgcmV0dXJuIERhdGUubm93KCkgPiAodGhpcy5jcmVhdGVkLmdldFRpbWUoKSArIHRoaXMuc2lnbmF0dXJlRXhwaXJhdGlvblRpbWUqMTAwMCk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgU3ltLiBFbmNyeXB0ZWQgSW50ZWdyaXR5IFByb3RlY3RlZCBEYXRhXG4gKiBQYWNrZXQgKFRhZyAxOCk8YnIvPlxuICogPGJyLz5cbiAqIFJGQzQ4ODAgNS4xMzogVGhlIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIEludGVncml0eSBQcm90ZWN0ZWQgRGF0YSBwYWNrZXQgaXNcbiAqIGEgdmFyaWFudCBvZiB0aGUgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBwYWNrZXQuIEl0IGlzIGEgbmV3IGZlYXR1cmVcbiAqIGNyZWF0ZWQgZm9yIE9wZW5QR1AgdGhhdCBhZGRyZXNzZXMgdGhlIHByb2JsZW0gb2YgZGV0ZWN0aW5nIGEgbW9kaWZpY2F0aW9uIHRvXG4gKiBlbmNyeXB0ZWQgZGF0YS4gSXQgaXMgdXNlZCBpbiBjb21iaW5hdGlvbiB3aXRoIGEgTW9kaWZpY2F0aW9uIERldGVjdGlvbiBDb2RlXG4gKiBwYWNrZXQuXG4gKiBAcmVxdWlyZXMgY3J5cHRvXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSBwYWNrZXQvc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHN5bV9lbmNyeXB0ZWRfaW50ZWdyaXR5X3Byb3RlY3RlZCgpIHtcbiAgLyoqIFRoZSBlbmNyeXB0ZWQgcGF5bG9hZC4gKi9cbiAgdGhpcy5lbmNyeXB0ZWQgPSBudWxsOyAvLyBzdHJpbmdcbiAgLyoqXG4gICAqIElmIGFmdGVyIGRlY3J5cHRpbmcgdGhlIHBhY2tldCB0aGlzIGlzIHNldCB0byB0cnVlLFxuICAgKiBhIG1vZGlmaWNhdGlvbiBoYXMgYmVlbiBkZXRlY3RlZCBhbmQgdGh1cyB0aGUgY29udGVudHNcbiAgICogc2hvdWxkIGJlIGRpc2NhcmRlZC5cbiAgICogQHR5cGUge0Jvb2xlYW59XG4gICAqL1xuICB0aGlzLm1vZGlmaWNhdGlvbiA9IGZhbHNlO1xuICB0aGlzLnBhY2tldHMgPSBudWxsO1xuXG5cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgLy8gLSBBIG9uZS1vY3RldCB2ZXJzaW9uIG51bWJlci4gVGhlIG9ubHkgY3VycmVudGx5IGRlZmluZWQgdmFsdWUgaXMgMS5cbiAgICB2YXIgdmVyc2lvbiA9IGJ5dGVzLmNoYXJDb2RlQXQoMCk7XG5cbiAgICBpZiAodmVyc2lvbiAhPSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcGFja2V0IHZlcnNpb24uJyk7XG4gICAgfVxuXG4gICAgLy8gLSBFbmNyeXB0ZWQgZGF0YSwgdGhlIG91dHB1dCBvZiB0aGUgc2VsZWN0ZWQgc3ltbWV0cmljLWtleSBjaXBoZXJcbiAgICAvLyAgIG9wZXJhdGluZyBpbiBDaXBoZXIgRmVlZGJhY2sgbW9kZSB3aXRoIHNoaWZ0IGFtb3VudCBlcXVhbCB0byB0aGVcbiAgICAvLyAgIGJsb2NrIHNpemUgb2YgdGhlIGNpcGhlciAoQ0ZCLW4gd2hlcmUgbiBpcyB0aGUgYmxvY2sgc2l6ZSkuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSBieXRlcy5zdWJzdHIoMSk7XG4gIH07XG5cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uICgpIHtcblxuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKDEpIC8vIFZlcnNpb25cbiAgICArIHRoaXMuZW5jcnlwdGVkO1xuICB9O1xuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uIChzZXNzaW9uS2V5QWxnb3JpdGhtLCBrZXkpIHtcbiAgICB2YXIgYnl0ZXMgPSB0aGlzLnBhY2tldHMud3JpdGUoKVxuXG4gICAgdmFyIHByZWZpeHJhbmRvbSA9IGNyeXB0by5nZXRQcmVmaXhSYW5kb20oc2Vzc2lvbktleUFsZ29yaXRobSk7XG4gICAgdmFyIHByZWZpeCA9IHByZWZpeHJhbmRvbSArIHByZWZpeHJhbmRvbS5jaGFyQXQocHJlZml4cmFuZG9tLmxlbmd0aCAtIDIpICsgcHJlZml4cmFuZG9tLmNoYXJBdChwcmVmaXhyYW5kb20ubGVuZ3RoIC1cbiAgICAgIDEpXG5cbiAgICB2YXIgdG9oYXNoID0gYnl0ZXM7XG5cblxuICAgIC8vIE1vZGlmaWNhdGlvbiBkZXRlY3Rpb24gY29kZSBwYWNrZXQuXG4gICAgdG9oYXNoICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHhEMyk7XG4gICAgdG9oYXNoICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHgxNCk7XG5cblxuICAgIHRvaGFzaCArPSBjcnlwdG8uaGFzaC5zaGExKHByZWZpeCArIHRvaGFzaCk7XG5cblxuICAgIHRoaXMuZW5jcnlwdGVkID0gY3J5cHRvLmNmYi5lbmNyeXB0KHByZWZpeHJhbmRvbSxcbiAgICAgIHNlc3Npb25LZXlBbGdvcml0aG0sIHRvaGFzaCwga2V5LCBmYWxzZSkuc3Vic3RyaW5nKDAsXG4gICAgICBwcmVmaXgubGVuZ3RoICsgdG9oYXNoLmxlbmd0aCk7XG4gIH07XG5cbiAgLyoqXG4gICAqIERlY3J5cHRzIHRoZSBlbmNyeXB0ZWQgZGF0YSBjb250YWluZWQgaW4gdGhpcyBvYmplY3QgcmVhZF9wYWNrZXQgbXVzdFxuICAgKiBoYXZlIGJlZW4gY2FsbGVkIGJlZm9yZVxuICAgKiBcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBzZXNzaW9uS2V5QWxnb3JpdGhtXG4gICAqICAgICAgICAgICAgVGhlIHNlbGVjdGVkIHN5bW1ldHJpYyBlbmNyeXB0aW9uIGFsZ29yaXRobSB0byBiZSB1c2VkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBrZXkgVGhlIGtleSBvZiBjaXBoZXIgYmxvY2tzaXplIGxlbmd0aCB0byBiZSB1c2VkXG4gICAqIEByZXR1cm4ge1N0cmluZ30gVGhlIGRlY3J5cHRlZCBkYXRhIG9mIHRoaXMgcGFja2V0XG4gICAqL1xuICB0aGlzLmRlY3J5cHQgPSBmdW5jdGlvbiAoc2Vzc2lvbktleUFsZ29yaXRobSwga2V5KSB7XG4gICAgdmFyIGRlY3J5cHRlZCA9IGNyeXB0by5jZmIuZGVjcnlwdChcbiAgICAgIHNlc3Npb25LZXlBbGdvcml0aG0sIGtleSwgdGhpcy5lbmNyeXB0ZWQsIGZhbHNlKTtcblxuXG4gICAgLy8gdGhlcmUgbXVzdCBiZSBhIG1vZGlmaWNhdGlvbiBkZXRlY3Rpb24gY29kZSBwYWNrZXQgYXMgdGhlXG4gICAgLy8gbGFzdCBwYWNrZXQgYW5kIGV2ZXJ5dGhpbmcgZ2V0cyBoYXNoZWQgZXhjZXB0IHRoZSBoYXNoIGl0c2VsZlxuICAgIHRoaXMuaGFzaCA9IGNyeXB0by5oYXNoLnNoYTEoXG4gICAgICBjcnlwdG8uY2ZiLm1kYyhzZXNzaW9uS2V5QWxnb3JpdGhtLCBrZXksIHRoaXMuZW5jcnlwdGVkKSArIGRlY3J5cHRlZC5zdWJzdHJpbmcoMCwgZGVjcnlwdGVkLmxlbmd0aCAtIDIwKSk7XG5cblxuICAgIHZhciBtZGMgPSBkZWNyeXB0ZWQuc3Vic3RyKGRlY3J5cHRlZC5sZW5ndGggLSAyMCwgMjApO1xuXG4gICAgaWYgKHRoaXMuaGFzaCAhPSBtZGMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTW9kaWZpY2F0aW9uIGRldGVjdGVkLicpO1xuICAgIH0gZWxzZVxuICAgICAgdGhpcy5wYWNrZXRzLnJlYWQoZGVjcnlwdGVkLnN1YnN0cigwLCBkZWNyeXB0ZWQubGVuZ3RoIC0gMjIpKTtcbiAgfTtcbn07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIFB1YmxpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IFBhY2tldHMgKFRhZyAxKTxici8+XG4gKiA8YnIvPlxuICogUkZDNDg4MCA1LjE6IEEgUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgcGFja2V0IGhvbGRzIHRoZSBzZXNzaW9uIGtleVxuICogdXNlZCB0byBlbmNyeXB0IGEgbWVzc2FnZS4gWmVybyBvciBtb3JlIFB1YmxpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5XG4gKiBwYWNrZXRzIGFuZC9vciBTeW1tZXRyaWMtS2V5IEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXRzIG1heSBwcmVjZWRlIGFcbiAqIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgUGFja2V0LCB3aGljaCBob2xkcyBhbiBlbmNyeXB0ZWQgbWVzc2FnZS4gVGhlXG4gKiBtZXNzYWdlIGlzIGVuY3J5cHRlZCB3aXRoIHRoZSBzZXNzaW9uIGtleSwgYW5kIHRoZSBzZXNzaW9uIGtleSBpcyBpdHNlbGZcbiAqIGVuY3J5cHRlZCBhbmQgc3RvcmVkIGluIHRoZSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgcGFja2V0KHMpLiBUaGVcbiAqIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgUGFja2V0IGlzIHByZWNlZGVkIGJ5IG9uZSBQdWJsaWMtS2V5IEVuY3J5cHRlZFxuICogU2Vzc2lvbiBLZXkgcGFja2V0IGZvciBlYWNoIE9wZW5QR1Aga2V5IHRvIHdoaWNoIHRoZSBtZXNzYWdlIGlzIGVuY3J5cHRlZC5cbiAqIFRoZSByZWNpcGllbnQgb2YgdGhlIG1lc3NhZ2UgZmluZHMgYSBzZXNzaW9uIGtleSB0aGF0IGlzIGVuY3J5cHRlZCB0byB0aGVpclxuICogcHVibGljIGtleSwgZGVjcnlwdHMgdGhlIHNlc3Npb24ga2V5LCBhbmQgdGhlbiB1c2VzIHRoZSBzZXNzaW9uIGtleSB0b1xuICogZGVjcnlwdCB0aGUgbWVzc2FnZS5cbiAqIEByZXF1aXJlcyBjcnlwdG9cbiAqIEByZXF1aXJlcyBlbnVtc1xuICogQHJlcXVpcmVzIHR5cGUvczJrXG4gKiBAbW9kdWxlIHBhY2tldC9zeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5XG4gKi9cblxudmFyIHR5cGVfczJrID0gcmVxdWlyZSgnLi4vdHlwZS9zMmsuanMnKSxcbiAgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKTtcblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBzeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5KCkge1xuICB0aGlzLnRhZyA9IDM7XG4gIHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0gPSBudWxsO1xuICB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0gPSAnYWVzMjU2JztcbiAgdGhpcy5lbmNyeXB0ZWQgPSBudWxsO1xuICB0aGlzLnMyayA9IG5ldyB0eXBlX3MyaygpO1xuXG4gIC8qKlxuICAgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIHN5bW1ldHJpYyBlbmNyeXB0ZWQgc2Vzc2lvbiBrZXkgcGFja2V0ICh0YWcgMykuXG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBhIHRhZyAxIHBhY2tldFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgaW5wdXQgc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuXG4gICAqICAgICAgICAgICAgTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2ZcbiAgICogICAgICAgICAgICBpbnB1dCBhdCBwb3NpdGlvblxuICAgKiBAcmV0dXJuIHttb2R1bGU6cGFja2V0L3N5bV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXl9IE9iamVjdCByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICAvLyBBIG9uZS1vY3RldCB2ZXJzaW9uIG51bWJlci4gVGhlIG9ubHkgY3VycmVudGx5IGRlZmluZWQgdmVyc2lvbiBpcyA0LlxuICAgIHRoaXMudmVyc2lvbiA9IGJ5dGVzLmNoYXJDb2RlQXQoMCk7XG5cbiAgICAvLyBBIG9uZS1vY3RldCBudW1iZXIgZGVzY3JpYmluZyB0aGUgc3ltbWV0cmljIGFsZ29yaXRobSB1c2VkLlxuICAgIHZhciBhbGdvID0gZW51bXMucmVhZChlbnVtcy5zeW1tZXRyaWMsIGJ5dGVzLmNoYXJDb2RlQXQoMSkpO1xuXG4gICAgLy8gQSBzdHJpbmctdG8ta2V5IChTMkspIHNwZWNpZmllciwgbGVuZ3RoIGFzIGRlZmluZWQgYWJvdmUuXG4gICAgdmFyIHMya2xlbmd0aCA9IHRoaXMuczJrLnJlYWQoYnl0ZXMuc3Vic3RyKDIpKTtcblxuICAgIC8vIE9wdGlvbmFsbHksIHRoZSBlbmNyeXB0ZWQgc2Vzc2lvbiBrZXkgaXRzZWxmLCB3aGljaCBpcyBkZWNyeXB0ZWRcbiAgICAvLyB3aXRoIHRoZSBzdHJpbmctdG8ta2V5IG9iamVjdC5cbiAgICB2YXIgZG9uZSA9IHMya2xlbmd0aCArIDI7XG5cbiAgICBpZiAoZG9uZSA8IGJ5dGVzLmxlbmd0aCkge1xuICAgICAgdGhpcy5lbmNyeXB0ZWQgPSBieXRlcy5zdWJzdHIoZG9uZSk7XG4gICAgICB0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtID0gYWxnb1xuICAgIH0gZWxzZVxuICAgICAgdGhpcy5zZXNzaW9uS2V5QWxnb3JpdGhtID0gYWxnbztcbiAgfTtcblxuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFsZ28gPSB0aGlzLmVuY3J5cHRlZCA9PSBudWxsID9cbiAgICAgIHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSA6XG4gICAgICB0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtO1xuXG4gICAgdmFyIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnZlcnNpb24pICtcbiAgICAgIFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuc3ltbWV0cmljLCBhbGdvKSkgK1xuICAgICAgdGhpcy5zMmsud3JpdGUoKTtcblxuICAgIGlmICh0aGlzLmVuY3J5cHRlZCAhPSBudWxsKVxuICAgICAgYnl0ZXMgKz0gdGhpcy5lbmNyeXB0ZWQ7XG4gICAgcmV0dXJuIGJ5dGVzO1xuICB9O1xuXG4gIC8qKlxuICAgKiBEZWNyeXB0cyB0aGUgc2Vzc2lvbiBrZXkgKG9ubHkgZm9yIHB1YmxpYyBrZXkgZW5jcnlwdGVkIHNlc3Npb24ga2V5XG4gICAqIHBhY2tldHMgKHRhZyAxKVxuICAgKiBcbiAgICogQHJldHVybiB7U3RyaW5nfSBUaGUgdW5lbmNyeXB0ZWQgc2Vzc2lvbiBrZXlcbiAgICovXG4gIHRoaXMuZGVjcnlwdCA9IGZ1bmN0aW9uKHBhc3NwaHJhc2UpIHtcbiAgICB2YXIgYWxnbyA9IHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0gIT0gbnVsbCA/XG4gICAgICB0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtIDpcbiAgICAgIHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobTtcblxuXG4gICAgdmFyIGxlbmd0aCA9IGNyeXB0by5jaXBoZXJbYWxnb10ua2V5U2l6ZTtcbiAgICB2YXIga2V5ID0gdGhpcy5zMmsucHJvZHVjZV9rZXkocGFzc3BocmFzZSwgbGVuZ3RoKTtcblxuICAgIGlmICh0aGlzLmVuY3J5cHRlZCA9PSBudWxsKSB7XG4gICAgICB0aGlzLnNlc3Npb25LZXkgPSBrZXk7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGRlY3J5cHRlZCA9IGNyeXB0by5jZmIuZGVjcnlwdChcbiAgICAgICAgdGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSwga2V5LCB0aGlzLmVuY3J5cHRlZCwgdHJ1ZSk7XG5cbiAgICAgIHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSA9IGVudW1zLnJlYWQoZW51bXMuc3ltbWV0cmljLFxuICAgICAgICBkZWNyeXB0ZWRbMF0ua2V5Q29kZUF0KCkpO1xuXG4gICAgICB0aGlzLnNlc3Npb25LZXkgPSBkZWNyeXB0ZWQuc3Vic3RyKDEpO1xuICAgIH1cbiAgfTtcblxuICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihwYXNzcGhyYXNlKSB7XG4gICAgdmFyIGxlbmd0aCA9IGNyeXB0by5nZXRLZXlMZW5ndGgodGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSk7XG4gICAgdmFyIGtleSA9IHRoaXMuczJrLnByb2R1Y2Vfa2V5KHBhc3NwaHJhc2UsIGxlbmd0aCk7XG5cbiAgICB2YXIgcHJpdmF0ZV9rZXkgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuICAgICAgZW51bXMud3JpdGUoZW51bXMuc3ltbWV0cmljLCB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0pKSArXG5cbiAgICBjcnlwdG8uZ2V0UmFuZG9tQnl0ZXMoXG4gICAgICBjcnlwdG8uZ2V0S2V5TGVuZ3RoKHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSkpO1xuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSBjcnlwdG8uY2ZiLmVuY3J5cHQoXG4gICAgICBjcnlwdG8uZ2V0UHJlZml4UmFuZG9tKHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0pLFxuICAgICAgdGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSwga2V5LCBwcml2YXRlX2tleSwgdHJ1ZSk7XG4gIH07XG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQgKFRhZyA5KTxici8+XG4gKiA8YnIvPlxuICogUkZDNDg4MCA1Ljc6IFRoZSBTeW1tZXRyaWNhbGx5IEVuY3J5cHRlZCBEYXRhIHBhY2tldCBjb250YWlucyBkYXRhIGVuY3J5cHRlZFxuICogd2l0aCBhIHN5bW1ldHJpYy1rZXkgYWxnb3JpdGhtLiBXaGVuIGl0IGhhcyBiZWVuIGRlY3J5cHRlZCwgaXQgY29udGFpbnMgb3RoZXJcbiAqIHBhY2tldHMgKHVzdWFsbHkgYSBsaXRlcmFsIGRhdGEgcGFja2V0IG9yIGNvbXByZXNzZWQgZGF0YSBwYWNrZXQsIGJ1dCBpblxuICogdGhlb3J5IG90aGVyIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgcGFja2V0cyBvciBzZXF1ZW5jZXMgb2YgcGFja2V0c1xuICogdGhhdCBmb3JtIHdob2xlIE9wZW5QR1AgbWVzc2FnZXMpLlxuICogQHJlcXVpcmVzIGNyeXB0b1xuICogQG1vZHVsZSBwYWNrZXQvc3ltbWV0cmljYWxseV9lbmNyeXB0ZWRcbiAqL1xuXG52YXIgY3J5cHRvID0gcmVxdWlyZSgnLi4vY3J5cHRvJyk7XG5cbi8qKlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQoKSB7XG4gIHRoaXMuZW5jcnlwdGVkID0gbnVsbDtcbiAgLyoqIERlY3J5cHRlZCBwYWNrZXRzIGNvbnRhaW5lZCB3aXRoaW4uIFxuICAgKiBAdHlwZSB7bW9kdWxlOnBhY2tldC9wYWNrZXRsaXN0fSAqL1xuICB0aGlzLnBhY2tldHMgPSAgbnVsbDtcblxuICB0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuICAgIHRoaXMuZW5jcnlwdGVkID0gYnl0ZXM7XG4gIH07XG5cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLmVuY3J5cHRlZDtcbiAgfTtcblxuICAvKipcbiAgICogU3ltbWV0cmljYWxseSBkZWNyeXB0IHRoZSBwYWNrZXQgZGF0YVxuICAgKiBcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBzZXNzaW9uS2V5QWxnb3JpdGhtXG4gICAqICAgICAgICAgICAgIFN5bW1ldHJpYyBrZXkgYWxnb3JpdGhtIHRvIHVzZSAvLyBTZWUgUkZDNDg4MCA5LjJcbiAgICogQHBhcmFtIHtTdHJpbmd9IGtleVxuICAgKiAgICAgICAgICAgICBLZXkgYXMgc3RyaW5nIHdpdGggdGhlIGNvcnJlc3BvbmRpbmcgbGVuZ3RoIHRvIHRoZVxuICAgKiAgICAgICAgICAgIGFsZ29yaXRobVxuICAgKi9cbiAgdGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24oc2Vzc2lvbktleUFsZ29yaXRobSwga2V5KSB7XG4gICAgdmFyIGRlY3J5cHRlZCA9IGNyeXB0by5jZmIuZGVjcnlwdChcbiAgICAgIHNlc3Npb25LZXlBbGdvcml0aG0sIGtleSwgdGhpcy5lbmNyeXB0ZWQsIHRydWUpO1xuXG4gICAgdGhpcy5wYWNrZXRzLnJlYWQoZGVjcnlwdGVkKTtcbiAgfTtcblxuICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihhbGdvLCBrZXkpIHtcbiAgICB2YXIgZGF0YSA9IHRoaXMucGFja2V0cy53cml0ZSgpO1xuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSBjcnlwdG8uY2ZiLmVuY3J5cHQoXG4gICAgICBjcnlwdG8uZ2V0UHJlZml4UmFuZG9tKGFsZ28pLCBhbGdvLCBkYXRhLCBrZXksIHRydWUpO1xuICB9O1xufTtcbiIsIi8qKlxuICogQG1vZHVsZSBwYWNrZXQvdHJ1c3RcbiAqL1xuXG4vKipcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHRydXN0KCkge1xuXG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgVXNlciBBdHRyaWJ1dGUgUGFja2V0IChUYWcgMTcpPGJyLz5cbiAqIDxici8+XG4gKiBUaGUgVXNlciBBdHRyaWJ1dGUgcGFja2V0IGlzIGEgdmFyaWF0aW9uIG9mIHRoZSBVc2VyIElEIHBhY2tldC4gIEl0XG4gKiBpcyBjYXBhYmxlIG9mIHN0b3JpbmcgbW9yZSB0eXBlcyBvZiBkYXRhIHRoYW4gdGhlIFVzZXIgSUQgcGFja2V0LFxuICogd2hpY2ggaXMgbGltaXRlZCB0byB0ZXh0LiAgTGlrZSB0aGUgVXNlciBJRCBwYWNrZXQsIGEgVXNlciBBdHRyaWJ1dGVcbiAqIHBhY2tldCBtYXkgYmUgY2VydGlmaWVkIGJ5IHRoZSBrZXkgb3duZXIgKFwic2VsZi1zaWduZWRcIikgb3IgYW55IG90aGVyXG4gKiBrZXkgb3duZXIgd2hvIGNhcmVzIHRvIGNlcnRpZnkgaXQuICBFeGNlcHQgYXMgbm90ZWQsIGEgVXNlciBBdHRyaWJ1dGVcbiAqIHBhY2tldCBtYXkgYmUgdXNlZCBhbnl3aGVyZSB0aGF0IGEgVXNlciBJRCBwYWNrZXQgbWF5IGJlIHVzZWQuXG4gKiA8YnIvPlxuICogV2hpbGUgVXNlciBBdHRyaWJ1dGUgcGFja2V0cyBhcmUgbm90IGEgcmVxdWlyZWQgcGFydCBvZiB0aGUgT3BlblBHUFxuICogc3RhbmRhcmQsIGltcGxlbWVudGF0aW9ucyBTSE9VTEQgcHJvdmlkZSBhdCBsZWFzdCBlbm91Z2hcbiAqIGNvbXBhdGliaWxpdHkgdG8gcHJvcGVybHkgaGFuZGxlIGEgY2VydGlmaWNhdGlvbiBzaWduYXR1cmUgb24gdGhlXG4gKiBVc2VyIEF0dHJpYnV0ZSBwYWNrZXQuICBBIHNpbXBsZSB3YXkgdG8gZG8gdGhpcyBpcyBieSB0cmVhdGluZyB0aGVcbiAqIFVzZXIgQXR0cmlidXRlIHBhY2tldCBhcyBhIFVzZXIgSUQgcGFja2V0IHdpdGggb3BhcXVlIGNvbnRlbnRzLCBidXRcbiAqIGFuIGltcGxlbWVudGF0aW9uIG1heSB1c2UgYW55IG1ldGhvZCBkZXNpcmVkLlxuICogbW9kdWxlIHBhY2tldC91c2VyX2F0dHJpYnV0ZVxuICogQG1vZHVsZSBwYWNrZXQvdXNlcl9hdHRyaWJ1dGVcbiAqL1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKSxcbiAgcGFja2V0ID0gcmVxdWlyZSgnLi9wYWNrZXQuanMnKTtcblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiB1c2VyX2F0dHJpYnV0ZSgpIHtcbiAgdGhpcy50YWcgPSAxNztcbiAgdGhpcy5hdHRyaWJ1dGVzID0gW107XG5cbiAgLyoqXG4gICAqIHBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgdXNlciBhdHRyaWJ1dGUgcGFja2V0ICh0YWcgMTcpLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgcGF5bG9hZCBvZiBhIHRhZyAxNyBwYWNrZXRcbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgdmFyIGkgPSAwO1xuICAgIHdoaWxlIChpIDwgYnl0ZXMubGVuZ3RoKSB7XG4gICAgICB2YXIgbGVuID0gcGFja2V0LnJlYWRTaW1wbGVMZW5ndGgoYnl0ZXMuc3Vic3RyKGkpKTtcbiAgICAgIGkgKz0gbGVuLm9mZnNldDtcblxuICAgICAgdGhpcy5hdHRyaWJ1dGVzLnB1c2goYnl0ZXMuc3Vic3RyKGksIGxlbi5sZW4pKTtcbiAgICAgIGkgKz0gbGVuLmxlbjtcbiAgICB9XG4gIH07XG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgVXNlciBJRCBQYWNrZXQgKFRhZyAxMyk8YnIvPlxuICogPGJyLz5cbiAqIEEgVXNlciBJRCBwYWNrZXQgY29uc2lzdHMgb2YgVVRGLTggdGV4dCB0aGF0IGlzIGludGVuZGVkIHRvIHJlcHJlc2VudFxuICogdGhlIG5hbWUgYW5kIGVtYWlsIGFkZHJlc3Mgb2YgdGhlIGtleSBob2xkZXIuICBCeSBjb252ZW50aW9uLCBpdFxuICogaW5jbHVkZXMgYW4gUkZDIDI4MjIgW1JGQzI4MjJdIG1haWwgbmFtZS1hZGRyLCBidXQgdGhlcmUgYXJlIG5vXG4gKiByZXN0cmljdGlvbnMgb24gaXRzIGNvbnRlbnQuICBUaGUgcGFja2V0IGxlbmd0aCBpbiB0aGUgaGVhZGVyXG4gKiBzcGVjaWZpZXMgdGhlIGxlbmd0aCBvZiB0aGUgVXNlciBJRC5cbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIHBhY2tldC91c2VyaWRcbiAqL1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKTtcblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiB1c2VyaWQoKSB7XG4gIC8qKiBBIHN0cmluZyBjb250YWluaW5nIHRoZSB1c2VyIGlkLiBVc3VhbGx5IGluIHRoZSBmb3JtXG4gICAqIEpvaG4gRG9lIDxqb2huQGV4YW1wbGUuY29tPlxuICAgKiBAdHlwZSB7U3RyaW5nfSBcbiAgICovXG4gIHRoaXMudXNlcmlkID0gJyc7XG5cblxuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSB1c2VyIGlkIHBhY2tldCAodGFnIDEzKS5cbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IHBheWxvYWQgb2YgYSB0YWcgMTMgcGFja2V0XG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbiAoYnl0ZXMpIHtcbiAgICB0aGlzLnVzZXJpZCA9IHV0aWwuZGVjb2RlX3V0ZjgoYnl0ZXMpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB1c2VyIGlkIHBhY2tldFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IHN0cmluZyByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdXRpbC5lbmNvZGVfdXRmOCh0aGlzLnVzZXJpZCk7XG4gIH07XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEltcGxlbWVudGF0aW9uIG9mIHR5cGUga2V5IGlkIChSRkM0ODgwIDMuMyk8YnIvPlxuICogPGJyLz5cbiAqIEEgS2V5IElEIGlzIGFuIGVpZ2h0LW9jdGV0IHNjYWxhciB0aGF0IGlkZW50aWZpZXMgYSBrZXkuXG4gKiBJbXBsZW1lbnRhdGlvbnMgU0hPVUxEIE5PVCBhc3N1bWUgdGhhdCBLZXkgSURzIGFyZSB1bmlxdWUuICBUaGVcbiAqIHNlY3Rpb24gXCJFbmhhbmNlZCBLZXkgRm9ybWF0c1wiIGJlbG93IGRlc2NyaWJlcyBob3cgS2V5IElEcyBhcmVcbiAqIGZvcm1lZC5cbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIHR5cGUva2V5aWRcbiAqL1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKTtcblxuLyoqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBrZXlpZCgpIHtcblxuICB0aGlzLmJ5dGVzID0gJyc7XG5cblxuICAvKipcbiAgICogUGFyc2luZyBtZXRob2QgZm9yIGEga2V5IGlkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBJbnB1dCB0byByZWFkIHRoZSBrZXkgaWQgZnJvbSBcbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgdGhpcy5ieXRlcyA9IGJ5dGVzLnN1YnN0cigwLCA4KTtcbiAgfTtcblxuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuYnl0ZXM7XG4gIH07XG5cbiAgdGhpcy50b0hleCA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB1dGlsLmhleHN0cmR1bXAodGhpcy5ieXRlcyk7XG4gIH07XG5cbiAgdGhpcy5lcXVhbHMgPSBmdW5jdGlvbihrZXlpZCkge1xuICAgIHJldHVybiB0aGlzLmJ5dGVzID09IGtleWlkLmJ5dGVzO1xuICB9O1xuXG4gIHRoaXMuaXNOdWxsID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuYnl0ZXMgPT09ICcnO1xuICB9O1xufTtcblxubW9kdWxlLmV4cG9ydHMubWFwVG9IZXggPSBmdW5jdGlvbihrZXlJZCkge1xuICByZXR1cm4ga2V5SWQudG9IZXgoKTtcbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8vIEhpbnQ6IFdlIGhvbGQgb3VyIE1QSXMgYXMgYW4gYXJyYXkgb2Ygb2N0ZXRzIGluIGJpZyBlbmRpYW4gZm9ybWF0IHByZWNlZWRpbmcgYSB0d29cbi8vIG9jdGV0IHNjYWxhcjogTVBJOiBbYSxiLGMsZCxlLGZdXG4vLyAtIE1QSSBzaXplOiAoYSA8PCA4KSB8IGIgXG4vLyAtIE1QSSA9IGMgfCBkIDw8IDggfCBlIDw8ICgoTVBJLmxlbmd0aCAtMikqOCkgfCBmICgoTVBJLmxlbmd0aCAtMikqOClcblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiB0eXBlIE1QSSAoUkZDNDg4MCAzLjIpPGJyLz5cbiAqIDxici8+XG4gKiBNdWx0aXByZWNpc2lvbiBpbnRlZ2VycyAoYWxzbyBjYWxsZWQgTVBJcykgYXJlIHVuc2lnbmVkIGludGVnZXJzIHVzZWRcbiAqIHRvIGhvbGQgbGFyZ2UgaW50ZWdlcnMgc3VjaCBhcyB0aGUgb25lcyB1c2VkIGluIGNyeXB0b2dyYXBoaWNcbiAqIGNhbGN1bGF0aW9ucy5cbiAqIEFuIE1QSSBjb25zaXN0cyBvZiB0d28gcGllY2VzOiBhIHR3by1vY3RldCBzY2FsYXIgdGhhdCBpcyB0aGUgbGVuZ3RoXG4gKiBvZiB0aGUgTVBJIGluIGJpdHMgZm9sbG93ZWQgYnkgYSBzdHJpbmcgb2Ygb2N0ZXRzIHRoYXQgY29udGFpbiB0aGVcbiAqIGFjdHVhbCBpbnRlZ2VyLlxuICogQHJlcXVpcmVzIGNyeXB0by9wdWJsaWNfa2V5L2pzYm5cbiAqIEByZXF1aXJlcyB1dGlsXG4gKiBAbW9kdWxlIHR5cGUvbXBpXG4gKi9cblxudmFyIEJpZ0ludGVnZXIgPSByZXF1aXJlKCcuLi9jcnlwdG8vcHVibGljX2tleS9qc2JuLmpzJyksXG4gIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyk7XG5cbi8qKlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gbXBpKCkge1xuICAvKiogQW4gaW1wbGVtZW50YXRpb24gZGVwZW5kZW50IGludGVnZXIgKi9cbiAgdGhpcy5kYXRhID0gbnVsbDtcblxuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSBtcGkgKFJGQyA0ODgwIDMuMikuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBQYXlsb2FkIG9mIG1waSBkYXRhXG4gICAqIEByZXR1cm4ge0ludGVnZXJ9IExlbmd0aCBvZiBkYXRhIHJlYWRcbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uIChieXRlcykge1xuICAgIHZhciBiaXRzID0gKGJ5dGVzLmNoYXJDb2RlQXQoMCkgPDwgOCkgfCBieXRlcy5jaGFyQ29kZUF0KDEpO1xuXG4gICAgLy8gQWRkaXRpb25hbCBydWxlczpcbiAgICAvL1xuICAgIC8vICAgIFRoZSBzaXplIG9mIGFuIE1QSSBpcyAoKE1QSS5sZW5ndGggKyA3KSAvIDgpICsgMiBvY3RldHMuXG4gICAgLy9cbiAgICAvLyAgICBUaGUgbGVuZ3RoIGZpZWxkIG9mIGFuIE1QSSBkZXNjcmliZXMgdGhlIGxlbmd0aCBzdGFydGluZyBmcm9tIGl0c1xuICAgIC8vXHQgIG1vc3Qgc2lnbmlmaWNhbnQgbm9uLXplcm8gYml0LiAgVGh1cywgdGhlIE1QSSBbMDAgMDIgMDFdIGlzIG5vdFxuICAgIC8vICAgIGZvcm1lZCBjb3JyZWN0bHkuICBJdCBzaG91bGQgYmUgWzAwIDAxIDAxXS5cblxuICAgIC8vIFRPRE86IFZlcmlmaWNhdGlvbiBvZiB0aGlzIHNpemUgbWV0aG9kISBUaGlzIHNpemUgY2FsY3VsYXRpb24gYXNcbiAgICAvLyBcdFx0IHNwZWNpZmllZCBhYm92ZSBpcyBub3QgYXBwbGljYWJsZSBpbiBKYXZhU2NyaXB0XG4gICAgdmFyIGJ5dGVsZW4gPSBNYXRoLmNlaWwoYml0cyAvIDgpO1xuXG4gICAgdmFyIHJhdyA9IGJ5dGVzLnN1YnN0cigyLCBieXRlbGVuKTtcbiAgICB0aGlzLmZyb21CeXRlcyhyYXcpO1xuXG4gICAgcmV0dXJuIDIgKyBieXRlbGVuO1xuICB9O1xuXG4gIHRoaXMuZnJvbUJ5dGVzID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgdGhpcy5kYXRhID0gbmV3IEJpZ0ludGVnZXIodXRpbC5oZXhzdHJkdW1wKGJ5dGVzKSwgMTYpO1xuICB9O1xuXG4gIHRoaXMudG9CeXRlcyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy53cml0ZSgpLnN1YnN0cigyKTtcbiAgfTtcblxuICB0aGlzLmJ5dGVMZW5ndGggPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMudG9CeXRlcygpLmxlbmd0aDtcbiAgfTtcblxuICAvKipcbiAgICogQ29udmVydHMgdGhlIG1waSBvYmplY3QgdG8gYSBzdHJpbmcgYXMgc3BlY2lmaWVkIGluIFJGQzQ4ODAgMy4yXG4gICAqIEByZXR1cm4ge1N0cmluZ30gbXBpIEJ5dGUgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIHRoaXMud3JpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YS50b01QSSgpO1xuICB9O1xuXG4gIHRoaXMudG9CaWdJbnRlZ2VyID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmRhdGEuY2xvbmUoKTtcbiAgfTtcblxuICB0aGlzLmZyb21CaWdJbnRlZ2VyID0gZnVuY3Rpb24gKGJuKSB7XG4gICAgdGhpcy5kYXRhID0gYm4uY2xvbmUoKTtcbiAgfTtcbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogSW1wbGVtZW50YXRpb24gb2YgdGhlIFN0cmluZy10by1rZXkgc3BlY2lmaWVyIChSRkM0ODgwIDMuNyk8YnIvPlxuICogPGJyLz5cbiAqIFN0cmluZy10by1rZXkgKFMySykgc3BlY2lmaWVycyBhcmUgdXNlZCB0byBjb252ZXJ0IHBhc3NwaHJhc2Ugc3RyaW5nc1xuICogaW50byBzeW1tZXRyaWMta2V5IGVuY3J5cHRpb24vZGVjcnlwdGlvbiBrZXlzLiAgVGhleSBhcmUgdXNlZCBpbiB0d29cbiAqIHBsYWNlcywgY3VycmVudGx5OiB0byBlbmNyeXB0IHRoZSBzZWNyZXQgcGFydCBvZiBwcml2YXRlIGtleXMgaW4gdGhlXG4gKiBwcml2YXRlIGtleXJpbmcsIGFuZCB0byBjb252ZXJ0IHBhc3NwaHJhc2VzIHRvIGVuY3J5cHRpb24ga2V5cyBmb3JcbiAqIHN5bW1ldHJpY2FsbHkgZW5jcnlwdGVkIG1lc3NhZ2VzLlxuICogQHJlcXVpcmVzIGNyeXB0b1xuICogQHJlcXVpcmVzIGVudW1zXG4gKiBAcmVxdWlyZXMgdXRpbFxuICogQG1vZHVsZSB0eXBlL3Mya1xuICovXG5cbnZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG4gIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHMyaygpIHtcbiAgLyoqIEB0eXBlIHttb2R1bGU6ZW51bXMuaGFzaH0gKi9cbiAgdGhpcy5hbGdvcml0aG0gPSAnc2hhMjU2JztcbiAgLyoqIEB0eXBlIHttb2R1bGU6ZW51bXMuczJrfSAqL1xuICB0aGlzLnR5cGUgPSAnaXRlcmF0ZWQnO1xuICB0aGlzLmMgPSA5NjtcbiAgLyoqIEVpZ2h0IGJ5dGVzIG9mIHNhbHQgaW4gYSBiaW5hcnkgc3RyaW5nLlxuICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgKi9cbiAgdGhpcy5zYWx0ID0gY3J5cHRvLnJhbmRvbS5nZXRSYW5kb21CeXRlcyg4KTtcblxuXG4gIC8vIEV4cG9uZW50IGJpYXMsIGRlZmluZWQgaW4gUkZDNDg4MFxuICB2YXIgZXhwYmlhcyA9IDY7XG5cbiAgdGhpcy5nZXRfY291bnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICgxNiArICh0aGlzLmMgJiAxNSkpIDw8ICgodGhpcy5jID4+IDQpICsgZXhwYmlhcyk7XG4gIH07XG5cbiAgLyoqXG4gICAqIFBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgc3RyaW5nLXRvLWtleSBzcGVjaWZpZXIgKFJGQyA0ODgwIDMuNykuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBQYXlsb2FkIG9mIHN0cmluZy10by1rZXkgc3BlY2lmaWVyXG4gICAqIEByZXR1cm4ge0ludGVnZXJ9IEFjdHVhbCBsZW5ndGggb2YgdGhlIG9iamVjdFxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgdmFyIGkgPSAwO1xuICAgIHRoaXMudHlwZSA9IGVudW1zLnJlYWQoZW51bXMuczJrLCBieXRlcy5jaGFyQ29kZUF0KGkrKykpO1xuICAgIHRoaXMuYWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5oYXNoLCBieXRlcy5jaGFyQ29kZUF0KGkrKykpO1xuXG4gICAgc3dpdGNoICh0aGlzLnR5cGUpIHtcbiAgICAgIGNhc2UgJ3NpbXBsZSc6XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdzYWx0ZWQnOlxuICAgICAgICB0aGlzLnNhbHQgPSBieXRlcy5zdWJzdHIoaSwgOCk7XG4gICAgICAgIGkgKz0gODtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ2l0ZXJhdGVkJzpcbiAgICAgICAgdGhpcy5zYWx0ID0gYnl0ZXMuc3Vic3RyKGksIDgpO1xuICAgICAgICBpICs9IDg7XG5cbiAgICAgICAgLy8gT2N0ZXQgMTA6IGNvdW50LCBhIG9uZS1vY3RldCwgY29kZWQgdmFsdWVcbiAgICAgICAgdGhpcy5jID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnZ251JzpcbiAgICAgICAgaWYgKGJ5dGVzLnN1YnN0cihpLCAzKSA9PSBcIkdOVVwiKSB7XG4gICAgICAgICAgaSArPSAzOyAvLyBHTlVcbiAgICAgICAgICB2YXIgZ251RXh0VHlwZSA9IDEwMDAgKyBieXRlcy5jaGFyQ29kZUF0KGkrKyk7XG4gICAgICAgICAgaWYgKGdudUV4dFR5cGUgPT0gMTAwMSkge1xuICAgICAgICAgICAgdGhpcy50eXBlID0gZ251RXh0VHlwZTtcbiAgICAgICAgICAgIC8vIEdudVBHIGV4dGVuc2lvbiBtb2RlIDEwMDEgLS0gZG9uJ3Qgd3JpdGUgc2VjcmV0IGtleSBhdCBhbGxcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5rbm93biBzMmsgZ251IHByb3RlY3Rpb24gbW9kZS5cIik7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVua25vd24gczJrIHR5cGUuXCIpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmtub3duIHMyayB0eXBlLlwiKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgcmV0dXJuIGk7XG4gIH07XG5cblxuICAvKipcbiAgICogd3JpdGVzIGFuIHMyayBoYXNoIGJhc2VkIG9uIHRoZSBpbnB1dHMuXG4gICAqIEByZXR1cm4ge1N0cmluZ30gUHJvZHVjZWQga2V5IG9mIGhhc2hBbGdvcml0aG0gaGFzaCBsZW5ndGhcbiAgICovXG4gIHRoaXMud3JpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5zMmssIHRoaXMudHlwZSkpO1xuICAgIGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuaGFzaCwgdGhpcy5hbGdvcml0aG0pKTtcblxuICAgIHN3aXRjaCAodGhpcy50eXBlKSB7XG4gICAgICBjYXNlICdzaW1wbGUnOlxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3NhbHRlZCc6XG4gICAgICAgIGJ5dGVzICs9IHRoaXMuc2FsdDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdpdGVyYXRlZCc6XG4gICAgICAgIGJ5dGVzICs9IHRoaXMuc2FsdDtcbiAgICAgICAgYnl0ZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLmMpO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICByZXR1cm4gYnl0ZXM7XG4gIH07XG5cbiAgLyoqXG4gICAqIFByb2R1Y2VzIGEga2V5IHVzaW5nIHRoZSBzcGVjaWZpZWQgcGFzc3BocmFzZSBhbmQgdGhlIGRlZmluZWQgXG4gICAqIGhhc2hBbGdvcml0aG0gXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwYXNzcGhyYXNlIFBhc3NwaHJhc2UgY29udGFpbmluZyB1c2VyIGlucHV0XG4gICAqIEByZXR1cm4ge1N0cmluZ30gUHJvZHVjZWQga2V5IHdpdGggYSBsZW5ndGggY29ycmVzcG9uZGluZyB0byBcbiAgICogaGFzaEFsZ29yaXRobSBoYXNoIGxlbmd0aFxuICAgKi9cbiAgdGhpcy5wcm9kdWNlX2tleSA9IGZ1bmN0aW9uIChwYXNzcGhyYXNlLCBudW1CeXRlcykge1xuICAgIHBhc3NwaHJhc2UgPSB1dGlsLmVuY29kZV91dGY4KHBhc3NwaHJhc2UpO1xuXG4gICAgZnVuY3Rpb24gcm91bmQocHJlZml4LCBzMmspIHtcbiAgICAgIHZhciBhbGdvcml0aG0gPSBlbnVtcy53cml0ZShlbnVtcy5oYXNoLCBzMmsuYWxnb3JpdGhtKTtcblxuICAgICAgc3dpdGNoIChzMmsudHlwZSkge1xuICAgICAgICBjYXNlICdzaW1wbGUnOlxuICAgICAgICAgIHJldHVybiBjcnlwdG8uaGFzaC5kaWdlc3QoYWxnb3JpdGhtLCBwcmVmaXggKyBwYXNzcGhyYXNlKTtcblxuICAgICAgICBjYXNlICdzYWx0ZWQnOlxuICAgICAgICAgIHJldHVybiBjcnlwdG8uaGFzaC5kaWdlc3QoYWxnb3JpdGhtLFxuICAgICAgICAgICAgcHJlZml4ICsgczJrLnNhbHQgKyBwYXNzcGhyYXNlKTtcblxuICAgICAgICBjYXNlICdpdGVyYXRlZCc6XG4gICAgICAgICAgdmFyIGlzcCA9IFtdLFxuICAgICAgICAgICAgY291bnQgPSBzMmsuZ2V0X2NvdW50KCk7XG4gICAgICAgICAgZGF0YSA9IHMyay5zYWx0ICsgcGFzc3BocmFzZTtcblxuICAgICAgICAgIHdoaWxlIChpc3AubGVuZ3RoICogZGF0YS5sZW5ndGggPCBjb3VudClcbiAgICAgICAgICAgIGlzcC5wdXNoKGRhdGEpO1xuXG4gICAgICAgICAgaXNwID0gaXNwLmpvaW4oJycpO1xuXG4gICAgICAgICAgaWYgKGlzcC5sZW5ndGggPiBjb3VudClcbiAgICAgICAgICAgIGlzcCA9IGlzcC5zdWJzdHIoMCwgY291bnQpO1xuXG4gICAgICAgICAgcmV0dXJuIGNyeXB0by5oYXNoLmRpZ2VzdChhbGdvcml0aG0sIHByZWZpeCArIGlzcCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHJlc3VsdCA9ICcnLFxuICAgICAgcHJlZml4ID0gJyc7XG5cbiAgICB3aGlsZSAocmVzdWx0Lmxlbmd0aCA8PSBudW1CeXRlcykge1xuICAgICAgcmVzdWx0ICs9IHJvdW5kKHByZWZpeCwgdGhpcyk7XG4gICAgICBwcmVmaXggKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0LnN1YnN0cigwLCBudW1CeXRlcyk7XG4gIH07XG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBUaGlzIG9iamVjdCBjb250YWlucyB1dGlsaXR5IGZ1bmN0aW9uc1xuICogQHJlcXVpcmVzIGNvbmZpZ1xuICogQG1vZHVsZSB1dGlsL3V0aWxcbiAqL1xuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICByZWFkTnVtYmVyOiBmdW5jdGlvbiAoYnl0ZXMpIHtcbiAgICB2YXIgbiA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBuIDw8PSA4O1xuICAgICAgbiArPSBieXRlcy5jaGFyQ29kZUF0KGkpO1xuICAgIH1cblxuICAgIHJldHVybiBuO1xuICB9LFxuXG4gIHdyaXRlTnVtYmVyOiBmdW5jdGlvbiAobiwgYnl0ZXMpIHtcbiAgICB2YXIgYiA9ICcnO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXM7IGkrKykge1xuICAgICAgYiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChuID4+ICg4ICogKGJ5dGVzIC0gaSAtIDEpKSkgJiAweEZGKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYjtcbiAgfSxcblxuICByZWFkRGF0ZTogZnVuY3Rpb24gKGJ5dGVzKSB7XG4gICAgdmFyIG4gPSB0aGlzLnJlYWROdW1iZXIoYnl0ZXMpO1xuICAgIHZhciBkID0gbmV3IERhdGUoKTtcbiAgICBkLnNldFRpbWUobiAqIDEwMDApO1xuICAgIHJldHVybiBkO1xuICB9LFxuXG4gIHdyaXRlRGF0ZTogZnVuY3Rpb24gKHRpbWUpIHtcbiAgICB2YXIgbnVtZXJpYyA9IE1hdGgucm91bmQodGltZS5nZXRUaW1lKCkgLyAxMDAwKTtcblxuICAgIHJldHVybiB0aGlzLndyaXRlTnVtYmVyKG51bWVyaWMsIDQpO1xuICB9LFxuXG4gIGVtYWlsUmVnRXg6IC9eWythLXpBLVowLTlfLi1dK0AoW2EtekEtWjAtOS1dK1xcLikrW2EtekEtWjAtOV17Miw2fSQvLFxuXG4gIGhleGR1bXA6IGZ1bmN0aW9uIChzdHIpIHtcbiAgICB2YXIgciA9IFtdO1xuICAgIHZhciBlID0gc3RyLmxlbmd0aDtcbiAgICB2YXIgYyA9IDA7XG4gICAgdmFyIGg7XG4gICAgdmFyIGkgPSAwO1xuICAgIHdoaWxlIChjIDwgZSkge1xuICAgICAgaCA9IHN0ci5jaGFyQ29kZUF0KGMrKykudG9TdHJpbmcoMTYpO1xuICAgICAgd2hpbGUgKGgubGVuZ3RoIDwgMikgaCA9IFwiMFwiICsgaDtcbiAgICAgIHIucHVzaChcIiBcIiArIGgpO1xuICAgICAgaSsrO1xuICAgICAgaWYgKGkgJSAzMiA9PSAwKVxuICAgICAgICByLnB1c2goXCJcXG4gICAgICAgICAgIFwiKTtcbiAgICB9XG4gICAgcmV0dXJuIHIuam9pbignJyk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIENyZWF0ZSBoZXhzdHJpbmcgZnJvbSBhIGJpbmFyeVxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyB0byBjb252ZXJ0XG4gICAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIGNvbnRhaW5pbmcgdGhlIGhleGFkZWNpbWFsIHZhbHVlc1xuICAgKi9cbiAgaGV4c3RyZHVtcDogZnVuY3Rpb24gKHN0cikge1xuICAgIGlmIChzdHIgPT0gbnVsbClcbiAgICAgIHJldHVybiBcIlwiO1xuICAgIHZhciByID0gW107XG4gICAgdmFyIGUgPSBzdHIubGVuZ3RoO1xuICAgIHZhciBjID0gMDtcbiAgICB2YXIgaDtcbiAgICB3aGlsZSAoYyA8IGUpIHtcbiAgICAgIGggPSBzdHIuY2hhckNvZGVBdChjKyspLnRvU3RyaW5nKDE2KTtcbiAgICAgIHdoaWxlIChoLmxlbmd0aCA8IDIpIGggPSBcIjBcIiArIGg7XG4gICAgICByLnB1c2goXCJcIiArIGgpO1xuICAgIH1cbiAgICByZXR1cm4gci5qb2luKCcnKTtcbiAgfSxcblxuICAvKipcbiAgICogQ3JlYXRlIGJpbmFyeSBzdHJpbmcgZnJvbSBhIGhleCBlbmNvZGVkIHN0cmluZ1xuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIEhleCBzdHJpbmcgdG8gY29udmVydFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFN0cmluZyBjb250YWluaW5nIHRoZSBiaW5hcnkgdmFsdWVzXG4gICAqL1xuICBoZXgyYmluOiBmdW5jdGlvbiAoaGV4KSB7XG4gICAgdmFyIHN0ciA9ICcnO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaGV4Lmxlbmd0aDsgaSArPSAyKVxuICAgICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUocGFyc2VJbnQoaGV4LnN1YnN0cihpLCAyKSwgMTYpKTtcbiAgICByZXR1cm4gc3RyO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDcmVhdGluZyBhIGhleCBzdHJpbmcgZnJvbSBhbiBiaW5hcnkgYXJyYXkgb2YgaW50ZWdlcnMgKDAuLjI1NSlcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0ciBBcnJheSBvZiBieXRlcyB0byBjb252ZXJ0XG4gICAqIEByZXR1cm4ge1N0cmluZ30gSGV4YWRlY2ltYWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIGFycmF5XG4gICAqL1xuICBoZXhpZHVtcDogZnVuY3Rpb24gKHN0cikge1xuICAgIHZhciByID0gW107XG4gICAgdmFyIGUgPSBzdHIubGVuZ3RoO1xuICAgIHZhciBjID0gMDtcbiAgICB2YXIgaDtcbiAgICB3aGlsZSAoYyA8IGUpIHtcbiAgICAgIGggPSBzdHJbYysrXS50b1N0cmluZygxNik7XG4gICAgICB3aGlsZSAoaC5sZW5ndGggPCAyKSBoID0gXCIwXCIgKyBoO1xuICAgICAgci5wdXNoKFwiXCIgKyBoKTtcbiAgICB9XG4gICAgcmV0dXJuIHIuam9pbignJyk7XG4gIH0sXG5cblxuICAvKipcbiAgICogQ29udmVydCBhIG5hdGl2ZSBqYXZhc2NyaXB0IHN0cmluZyB0byBhIHN0cmluZyBvZiB1dGY4IGJ5dGVzXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgVGhlIHN0cmluZyB0byBjb252ZXJ0XG4gICAqIEByZXR1cm4ge1N0cmluZ30gQSB2YWxpZCBzcXVlbmNlIG9mIHV0ZjggYnl0ZXNcbiAgICovXG4gIGVuY29kZV91dGY4OiBmdW5jdGlvbiAoc3RyKSB7XG4gICAgcmV0dXJuIHVuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChzdHIpKTtcbiAgfSxcblxuICAvKipcbiAgICogQ29udmVydCBhIHN0cmluZyBvZiB1dGY4IGJ5dGVzIHRvIGEgbmF0aXZlIGphdmFzY3JpcHQgc3RyaW5nXG4gICAqIEBwYXJhbSB7U3RyaW5nfSB1dGY4IEEgdmFsaWQgc3F1ZW5jZSBvZiB1dGY4IGJ5dGVzXG4gICAqIEByZXR1cm4ge1N0cmluZ30gQSBuYXRpdmUgamF2YXNjcmlwdCBzdHJpbmdcbiAgICovXG4gIGRlY29kZV91dGY4OiBmdW5jdGlvbiAodXRmOCkge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KGVzY2FwZSh1dGY4KSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIHV0Zjg7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGFuIGFycmF5IG9mIGludGVnZXJzKDAuMjU1KSB0byBhIHN0cmluZ1xuICAgKiBAcGFyYW0ge0FycmF5PEludGVnZXI+fSBiaW4gQW4gYXJyYXkgb2YgKGJpbmFyeSkgaW50ZWdlcnMgdG8gY29udmVydFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGFycmF5XG4gICAqL1xuICBiaW4yc3RyOiBmdW5jdGlvbiAoYmluKSB7XG4gICAgdmFyIHJlc3VsdCA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBiaW4ubGVuZ3RoOyBpKyspIHtcbiAgICAgIHJlc3VsdC5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYmluW2ldKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdC5qb2luKCcnKTtcbiAgfSxcblxuICBfc3RyMmJpbjogZnVuY3Rpb24gKHN0ciwgcmVzdWx0KSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICAgIHJlc3VsdFtpXSA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBzdHJpbmcgdG8gYW4gYXJyYXkgb2YgaW50ZWdlcnMoMC4yNTUpXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIHRvIGNvbnZlcnRcbiAgICogQHJldHVybiB7QXJyYXk8SW50ZWdlcj59IEFuIGFycmF5IG9mIChiaW5hcnkpIGludGVnZXJzXG4gICAqL1xuICBzdHIyYmluOiBmdW5jdGlvbiAoc3RyKSB7XG4gICAgcmV0dXJuIHRoaXMuX3N0cjJiaW4oc3RyLCBuZXcgQXJyYXkoc3RyLmxlbmd0aCkpO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBzdHJpbmcgdG8gYSBVaW50OEFycmF5XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIHRvIGNvbnZlcnRcbiAgICogQHJldHVybiB7VWludDhBcnJheX0gVGhlIGFycmF5IG9mIChiaW5hcnkpIGludGVnZXJzXG4gICAqL1xuICBzdHIyVWludDhBcnJheTogZnVuY3Rpb24gKHN0cikge1xuICAgIHJldHVybiB0aGlzLl9zdHIyYmluKHN0ciwgbmV3IFVpbnQ4QXJyYXkobmV3IEFycmF5QnVmZmVyKHN0ci5sZW5ndGgpKSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBVaW50OEFycmF5IHRvIGEgc3RyaW5nLiBUaGlzIGN1cnJlbnRseSBmdW5jdGlvbnMgXG4gICAqIHRoZSBzYW1lIGFzIGJpbjJzdHIuXG4gICAqIEBmdW5jdGlvbiBtb2R1bGU6dXRpbC91dGlsLlVpbnQ4QXJyYXkyc3RyXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gYmluIEFuIGFycmF5IG9mIChiaW5hcnkpIGludGVnZXJzIHRvIGNvbnZlcnRcbiAgICogQHJldHVybiB7U3RyaW5nfSBTdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGFycmF5XG4gICAqL1xuICBVaW50OEFycmF5MnN0cjogZnVuY3Rpb24gKGJpbikge1xuICAgIHJldHVybiB0aGlzLmJpbjJzdHIoYmluKTtcbiAgfSxcblxuICAvKipcbiAgICogQ2FsY3VsYXRlcyBhIDE2Yml0IHN1bSBvZiBhIHN0cmluZyBieSBhZGRpbmcgZWFjaCBjaGFyYWN0ZXJcbiAgICogY29kZXMgbW9kdWx1cyA2NTUzNVxuICAgKiBAcGFyYW0ge1N0cmluZ30gdGV4dCBTdHJpbmcgdG8gY3JlYXRlIGEgc3VtIG9mXG4gICAqIEByZXR1cm4ge0ludGVnZXJ9IEFuIGludGVnZXIgY29udGFpbmluZyB0aGUgc3VtIG9mIGFsbCBjaGFyYWN0ZXJcbiAgICogY29kZXMgJSA2NTUzNVxuICAgKi9cbiAgY2FsY19jaGVja3N1bTogZnVuY3Rpb24gKHRleHQpIHtcbiAgICB2YXIgY2hlY2tzdW0gPSB7XG4gICAgICBzOiAwLFxuICAgICAgYWRkOiBmdW5jdGlvbiAoc2FkZCkge1xuICAgICAgICB0aGlzLnMgPSAodGhpcy5zICsgc2FkZCkgJSA2NTUzNjtcbiAgICAgIH1cbiAgICB9O1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGV4dC5sZW5ndGg7IGkrKykge1xuICAgICAgY2hlY2tzdW0uYWRkKHRleHQuY2hhckNvZGVBdChpKSk7XG4gICAgfVxuICAgIHJldHVybiBjaGVja3N1bS5zO1xuICB9LFxuXG4gIC8qKlxuICAgKiBIZWxwZXIgZnVuY3Rpb24gdG8gcHJpbnQgYSBkZWJ1ZyBtZXNzYWdlLiBEZWJ1ZyBcbiAgICogbWVzc2FnZXMgYXJlIG9ubHkgcHJpbnRlZCBpZlxuICAgKiBAbGluayBtb2R1bGU6Y29uZmlnL2NvbmZpZy5kZWJ1ZyBpcyBzZXQgdG8gdHJ1ZS5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0ciBTdHJpbmcgb2YgdGhlIGRlYnVnIG1lc3NhZ2VcbiAgICovXG4gIHByaW50X2RlYnVnOiBmdW5jdGlvbiAoc3RyKSB7XG4gICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgY29uc29sZS5sb2coc3RyKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEhlbHBlciBmdW5jdGlvbiB0byBwcmludCBhIGRlYnVnIG1lc3NhZ2UuIERlYnVnIFxuICAgKiBtZXNzYWdlcyBhcmUgb25seSBwcmludGVkIGlmXG4gICAqIEBsaW5rIG1vZHVsZTpjb25maWcvY29uZmlnLmRlYnVnIGlzIHNldCB0byB0cnVlLlxuICAgKiBEaWZmZXJlbnQgdGhhbiBwcmludF9kZWJ1ZyBiZWNhdXNlIHdpbGwgY2FsbCBoZXhzdHJkdW1wIGlmZiBuZWNlc3NhcnkuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIG9mIHRoZSBkZWJ1ZyBtZXNzYWdlXG4gICAqL1xuICBwcmludF9kZWJ1Z19oZXhzdHJfZHVtcDogZnVuY3Rpb24gKHN0ciwgc3RyVG9IZXgpIHtcbiAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICBzdHIgPSBzdHIgKyB0aGlzLmhleHN0cmR1bXAoc3RyVG9IZXgpO1xuICAgICAgY29uc29sZS5sb2coc3RyKTtcbiAgICB9XG4gIH0sXG5cbiAgZ2V0TGVmdE5CaXRzOiBmdW5jdGlvbiAoc3RyaW5nLCBiaXRjb3VudCkge1xuICAgIHZhciByZXN0ID0gYml0Y291bnQgJSA4O1xuICAgIGlmIChyZXN0ID09IDApXG4gICAgICByZXR1cm4gc3RyaW5nLnN1YnN0cmluZygwLCBiaXRjb3VudCAvIDgpO1xuICAgIHZhciBieXRlcyA9IChiaXRjb3VudCAtIHJlc3QpIC8gOCArIDE7XG4gICAgdmFyIHJlc3VsdCA9IHN0cmluZy5zdWJzdHJpbmcoMCwgYnl0ZXMpO1xuICAgIHJldHVybiB0aGlzLnNoaWZ0UmlnaHQocmVzdWx0LCA4IC0gcmVzdCk7IC8vICtTdHJpbmcuZnJvbUNoYXJDb2RlKHN0cmluZy5jaGFyQ29kZUF0KGJ5dGVzIC0xKSA8PCAoOC1yZXN0KSAmIDB4RkYpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBTaGlmdGluZyBhIHN0cmluZyB0byBuIGJpdHMgcmlnaHRcbiAgICogQHBhcmFtIHtTdHJpbmd9IHZhbHVlIFRoZSBzdHJpbmcgdG8gc2hpZnRcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBiaXRjb3VudCBBbW91bnQgb2YgYml0cyB0byBzaGlmdCAoTVVTVCBiZSBzbWFsbGVyIFxuICAgKiB0aGFuIDkpXG4gICAqIEByZXR1cm4ge1N0cmluZ30gUmVzdWx0aW5nIHN0cmluZy4gXG4gICAqL1xuICBzaGlmdFJpZ2h0OiBmdW5jdGlvbiAodmFsdWUsIGJpdGNvdW50KSB7XG4gICAgdmFyIHRlbXAgPSB1dGlsLnN0cjJiaW4odmFsdWUpO1xuICAgIGlmIChiaXRjb3VudCAlIDggIT0gMCkge1xuICAgICAgZm9yICh2YXIgaSA9IHRlbXAubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgdGVtcFtpXSA+Pj0gYml0Y291bnQgJSA4O1xuICAgICAgICBpZiAoaSA+IDApXG4gICAgICAgICAgdGVtcFtpXSB8PSAodGVtcFtpIC0gMV0gPDwgKDggLSAoYml0Y291bnQgJSA4KSkpICYgMHhGRjtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4gdXRpbC5iaW4yc3RyKHRlbXApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIGFsZ29yaXRobSB0eXBlIGFzIHN0cmluZ1xuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFN0cmluZyByZXByZXNlbnRpbmcgdGhlIG1lc3NhZ2UgdHlwZVxuICAgKi9cbiAgZ2V0X2hhc2hBbGdvcml0aG1TdHJpbmc6IGZ1bmN0aW9uIChhbGdvKSB7XG4gICAgc3dpdGNoIChhbGdvKSB7XG4gICAgICBjYXNlIDE6XG4gICAgICAgIHJldHVybiBcIk1ENVwiO1xuICAgICAgY2FzZSAyOlxuICAgICAgICByZXR1cm4gXCJTSEExXCI7XG4gICAgICBjYXNlIDM6XG4gICAgICAgIHJldHVybiBcIlJJUEVNRDE2MFwiO1xuICAgICAgY2FzZSA4OlxuICAgICAgICByZXR1cm4gXCJTSEEyNTZcIjtcbiAgICAgIGNhc2UgOTpcbiAgICAgICAgcmV0dXJuIFwiU0hBMzg0XCI7XG4gICAgICBjYXNlIDEwOlxuICAgICAgICByZXR1cm4gXCJTSEE1MTJcIjtcbiAgICAgIGNhc2UgMTE6XG4gICAgICAgIHJldHVybiBcIlNIQTIyNFwiO1xuICAgIH1cbiAgICByZXR1cm4gXCJ1bmtub3duXCI7XG4gIH1cbn07XG4iXX0= +; \ No newline at end of file diff --git a/resources/openpgp.min.js b/resources/openpgp.min.js index 73c21487..b3015e60 100644 --- a/resources/openpgp.min.js +++ b/resources/openpgp.min.js @@ -1,474 +1,6 @@ -function DSA(){this.select_hash_algorithm=function(b){var a=openpgp.config.config.prefer_hash_algorithm;switch(Math.round(b.bitLength()/8)){case 20:return 2!=a&&11a?2:a;case 28:return 11a?11:a;case 32:return 10a?8:a;default:return util.print_debug("DSA select hash algorithm: returning null for an unknown length of q"),null}};this.sign=function(b,a,c,d,e,f){b=util.getLeftNBits(openpgp_crypto_hashData(b,a),e.bitLength());b=new BigInteger(util.hexstrdump(b),16);a=openpgp_crypto_getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), -e.subtract(BigInteger.ONE));c=c.modPow(a,d).mod(e);e=a.modInverse(e).multiply(b.add(f.multiply(c))).mod(e);f=[];f[0]=c.toMPI();f[1]=e.toMPI();return f};this.verify=function(b,a,c,d,e,f,g,h){b=util.getLeftNBits(openpgp_crypto_hashData(b,d),f.bitLength());b=new BigInteger(util.hexstrdump(b),16);if(0this.s){if(1==this.t)return this[0]-this.DV;if(0==this.t)return-1}else{if(1==this.t)return this[0];if(0==this.t)return 0}return(this[1]&(1<<32-this.DB)-1)<>24}function bnShortValue(){return 0==this.t?this.s:this[0]<<16>>16}function bnpChunkSize(b){return Math.floor(Math.LN2*this.DB/Math.log(b))} -function bnSigNum(){return 0>this.s?-1:0>=this.t||1==this.t&&0>=this[0]?0:1}function bnpToRadix(b){null==b&&(b=10);if(0==this.signum()||2>b||36j?"-"==b.charAt(h)&&0==this.signum()&&(e=!0):(g=a*g+j,++f>=c&&(this.dMultiply(d),this.dAddOffset(g,0),g=f=0))}0b)this.fromInt(1);else{this.fromNumber(b,c);this.testBit(b-1)||this.bitwiseTo(BigInteger.ONE.shiftLeft(b-1),op_or,this);for(this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(a);)this.dAddOffset(2,0),this.bitLength()>b&&this.subTo(BigInteger.ONE.shiftLeft(b-1),this)}else{var c=[],d=b&7;c.length=(b>>3)+1;a.nextBytes(c);c[0]=0>c)!=(this.s&this.DM)>>c)a[e++]=d|this.s<c?(d=(this[b]&(1<>(c+=this.DB-8)):(d=this[b]>>(c-=8)&255,0>=c&&(c+=this.DB,--b)),0this.compareTo(b)?this:b}function bnMax(b){return 0b?this.rShiftTo(-b,a):this.lShiftTo(b,a);return a}function bnShiftRight(b){var a=nbi();0>b?this.lShiftTo(-b,a):this.rShiftTo(b,a);return a} -function lbit(b){if(0==b)return-1;var a=0;0==(b&65535)&&(b>>=16,a+=16);0==(b&255)&&(b>>=8,a+=8);0==(b&15)&&(b>>=4,a+=4);0==(b&3)&&(b>>=2,a+=2);0==(b&1)&&++a;return a}function bnGetLowestSetBit(){for(var b=0;bthis.s?this.t*this.DB:-1}function cbit(b){for(var a=0;0!=b;)b&=b-1,++a;return a}function bnBitCount(){for(var b=0,a=this.s&this.DM,c=0;c=this.t?0!=this.s:0!=(this[a]&1<>=this.DB;if(b.t>=this.DB;d+=this.s}else{for(d+=this.s;c>=this.DB;d+=b.s}a.s=0>d?-1:0;0d&&(a[c++]=this.DV+d);a.t=c;a.clamp()}function bnAdd(b){var a=nbi();this.addTo(b,a);return a}function bnSubtract(b){var a=nbi();this.subTo(b,a);return a} -function bnMultiply(b){var a=nbi();this.multiplyTo(b,a);return a}function bnSquare(){var b=nbi();this.squareTo(b);return b}function bnDivide(b){var a=nbi();this.divRemTo(b,a,null);return a}function bnRemainder(b){var a=nbi();this.divRemTo(b,null,a);return a}function bnDivideAndRemainder(b){var a=nbi(),c=nbi();this.divRemTo(b,a,c);return[a,c]}function bnpDMultiply(b){this[this.t]=this.am(0,b-1,this,0,0,this.t);++this.t;this.clamp()} -function bnpDAddOffset(b,a){if(0!=b){for(;this.t<=a;)this[this.t++]=0;for(this[a]+=b;this[a]>=this.DV;)this[a]-=this.DV,++a>=this.t&&(this[this.t++]=0),++this[a]}}function NullExp(){}function nNop(b){return b}function nMulTo(b,a,c){b.multiplyTo(a,c)}function nSqrTo(b,a){b.squareTo(a)}NullExp.prototype.convert=nNop;NullExp.prototype.revert=nNop;NullExp.prototype.mulTo=nMulTo;NullExp.prototype.sqrTo=nSqrTo;function bnPow(b){return this.exp(b,new NullExp)} -function bnpMultiplyLowerTo(b,a,c){var d=Math.min(this.t+b.t,a);c.s=0;for(c.t=d;0b.s||b.t>2*this.m.t)return b.mod(this.m);if(0>b.compareTo(this.m))return b;var a=nbi();b.copyTo(a);this.reduce(a);return a}function barrettRevert(b){return b} -function barrettReduce(b){b.drShiftTo(this.m.t-1,this.r2);if(b.t>this.m.t+1)b.t=this.m.t+1,b.clamp();this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);for(this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);0>b.compareTo(this.r2);)b.dAddOffset(1,this.m.t+1);for(b.subTo(this.r2,b);0<=b.compareTo(this.m);)b.subTo(this.m,b)}function barrettSqrTo(b,a){b.squareTo(a);this.reduce(a)}function barrettMulTo(b,a,c){b.multiplyTo(a,c);this.reduce(c)}Barrett.prototype.convert=barrettConvert; -Barrett.prototype.revert=barrettRevert;Barrett.prototype.reduce=barrettReduce;Barrett.prototype.mulTo=barrettMulTo;Barrett.prototype.sqrTo=barrettSqrTo; -function bnModPow(b,a){var c=b.bitLength(),d,e=nbv(1),f;if(0>=c)return e;d=18>c?1:48>c?3:144>c?4:768>c?5:6;f=8>c?new Classic(a):a.isEven()?new Barrett(a):new Montgomery(a);var g=[],h=3,j=d-1,k=(1<=j?m=b[l]>>c-j&k:(m=(b[l]&(1<>this.DB+c-j));for(h=d;0==(m&1);)m>>=1,--h;if(0>(c-=h))c+=this.DB,--l;if(r)g[m].copyTo(e), -r=!1;else{for(;1--c&&(c=this.DB-1,--l)}return f.revert(e)} -function bnGCD(b){var a=0>this.s?this.negate():this.clone(),b=0>b.s?b.negate():b.clone();if(0>a.compareTo(b))var c=a,a=b,b=c;var c=a.getLowestSetBit(),d=b.getLowestSetBit();if(0>d)return a;c=b)return 0;var a=this.DV%b,c=0>this.s?b-1:0;if(0h.signum())h.addTo(b,h);else return h;return 0>h.signum()?h.add(b):h} -var lowprimes=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727, -733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],lplim=67108864/lowprimes[lowprimes.length-1]; -function bnIsProbablePrime(b){var a,c=this.abs();if(1==c.t&&c[0]<=lowprimes[lowprimes.length-1]){for(a=0;a>>16))b=c,a+=16;if(0!=(c=b>>8))b=c,a+=8;if(0!=(c=b>>4))b=c,a+=4;if(0!=(c=b>>2))b=c,a+=2;0!=b>>1&&(a+=1);return a}function bnToMPI(){var b=this.toByteArray(),a=8*(b.length-1)+nbits(b[0]),c;c=""+String.fromCharCode((a&65280)>>8);c+=String.fromCharCode(a&255);return c+=util.bin2str(b)} -function bnpMillerRabin(b){var a=this.subtract(BigInteger.ONE),c=a.getLowestSetBit();if(0>=c)return!1;var d=a.shiftRight(c),b=b+1>>1;if(b>lowprimes.length)b=lowprimes.length;for(var e=nbi(),f,g=[],h=0;h>15;0<=--f;){var h=this[b]&32767,j=this[b++]>>15,k=a*h+j*g,h=g*h+((k&32767)<<15)+c[d]+(e&1073741823),e=(h>>>30)+(k>>>15)+a*j+(e>>>30);c[d++]=h&1073741823}return e}function am3(b,a,c,d,e,f){for(var g=a&16383,a=a>>14;0<=--f;){var h=this[b]&16383,j=this[b++]>>14,k=a*h+j*g,h=g*h+((k&16383)<<14)+c[d]+e,e=(h>>28)+(k>>14)+a*j;c[d++]=h&268435455}return e} -j_lm&&"Microsoft Internet Explorer"==navigator.appName?(BigInteger.prototype.am=am2,dbits=30):j_lm&&"Netscape"!=navigator.appName?(BigInteger.prototype.am=am1,dbits=26):(BigInteger.prototype.am=am3,dbits=28);BigInteger.prototype.DB=dbits;BigInteger.prototype.DM=(1<=vv;++vv)BI_RC[rr++]=vv;rr=97;for(vv=10;36>vv;++vv)BI_RC[rr++]=vv;rr=65;for(vv=10;36>vv;++vv)BI_RC[rr++]=vv;function int2char(b){return BI_RM.charAt(b)}function intAt(b,a){var c=BI_RC[b.charCodeAt(a)];return null==c?-1:c}function bnpCopyTo(b){for(var a=this.t-1;0<=a;--a)b[a]=this[a];b.t=this.t;b.s=this.s}function bnpFromInt(b){this.t=1;this.s=0>b?-1:0;0b?this[0]=b+DV:this.t=0}function nbv(b){var a=nbi();a.fromInt(b);return a} -function bnpFromString(b,a){var c;if(16==a)c=4;else if(8==a)c=3;else if(256==a)c=8;else if(2==a)c=1;else if(32==a)c=5;else if(4==a)c=2;else{this.fromRadix(b,a);return}this.s=this.t=0;for(var d=b.length,e=!1,f=0;0<=--d;){var g=8==c?b[d]&255:intAt(b,d);0>g?"-"==b.charAt(d)&&(e=!0):(e=!1,0==f?this[this.t++]=g:f+c>this.DB?(this[this.t-1]|=(g&(1<>this.DB-f):this[this.t-1]|=g<=this.DB&&(f-=this.DB))}if(8==c&&0!=(b[0]&128))this.s=-1,0this.s)return"-"+this.negate().toString(b);if(16==b)b=4;else if(8==b)b=3;else if(2==b)b=1;else if(32==b)b=5;else if(4==b)b=2;else return this.toRadix(b);var a=(1<>g))d=!0,e=int2char(c);for(;0<=f;)g>(g+=this.DB-b)):(c=this[f]>>(g-=b)&a,0>=g&&(g+=this.DB,--f)),0this.s?this.negate():this}function bnCompareTo(b){var a=this.s-b.s;if(0!=a)return a;var c=this.t,a=c-b.t;if(0!=a)return a;for(;0<=--c;)if(0!=(a=this[c]-b[c]))return a;return 0}function nbits(b){var a=1,c;if(0!=(c=b>>>16))b=c,a+=16;if(0!=(c=b>>8))b=c,a+=8;if(0!=(c=b>>4))b=c,a+=4;if(0!=(c=b>>2))b=c,a+=2;0!=b>>1&&(a+=1);return a} -function bnBitLength(){return 0>=this.t?0:this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(b,a){var c;for(c=this.t-1;0<=c;--c)a[c+b]=this[c];for(c=b-1;0<=c;--c)a[c]=0;a.t=this.t+b;a.s=this.s}function bnpDRShiftTo(b,a){for(var c=b;c>d|g,g=(this[h]&e)<=this.t)a.t=0;else{var d=b%this.DB,e=this.DB-d,f=(1<>d;for(var g=c+1;g>d;0>=this.DB;if(b.t>=this.DB;d+=this.s}else{for(d+=this.s;c>=this.DB;d-=b.s}a.s=0>d?-1:0;-1>d?a[c++]=this.DV+d:0=a.DV)b[c+a.t]-=a.DV,b[c+a.t+1]=1}0=d.t)){var e=this.abs();if(e.t>this.F2:0),k=this.FV/j,j=(1<g&&BigInteger.ZERO.subTo(c,c)}}}}function bnMod(b){var a=nbi();this.abs().divRemTo(b,null,a);0>this.s&&0b.s||0<=b.compareTo(this.m)?b.mod(this.m):b}function cRevert(b){return b}function cReduce(b){b.divRemTo(this.m,null,b)}function cMulTo(b,a,c){b.multiplyTo(a,c);this.reduce(c)}function cSqrTo(b,a){b.squareTo(a);this.reduce(a)}Classic.prototype.convert=cConvert;Classic.prototype.revert=cRevert;Classic.prototype.reduce=cReduce;Classic.prototype.mulTo=cMulTo;Classic.prototype.sqrTo=cSqrTo; -function bnpInvDigit(){if(1>this.t)return 0;var b=this[0];if(0==(b&1))return 0;var a=b&3,a=a*(2-(b&15)*a)&15,a=a*(2-(b&255)*a)&255,a=a*(2-((b&65535)*a&65535))&65535,a=a*(2-b*a%this.DV)%this.DV;return 0>15;this.um=(1<b.s&&0>15)*this.mpl&this.um)<<15)&b.DM,c=a+this.m.t;for(b[c]+=this.m.am(0,d,b,a,0,this.m.t);b[c]>=b.DV;)b[c]-=b.DV,b[++c]++}b.clamp();b.drShiftTo(this.m.t,b);0<=b.compareTo(this.m)&&b.subTo(this.m,b)}function montSqrTo(b,a){b.squareTo(a);this.reduce(a)}function montMulTo(b,a,c){b.multiplyTo(a,c);this.reduce(c)}Montgomery.prototype.convert=montConvert; -Montgomery.prototype.revert=montRevert;Montgomery.prototype.reduce=montReduce;Montgomery.prototype.mulTo=montMulTo;Montgomery.prototype.sqrTo=montSqrTo;function bnpIsEven(){return 0==(0b)return BigInteger.ONE;var c=nbi(),d=nbi(),e=a.convert(this),f=nbits(b)-1;for(e.copyTo(c);0<=--f;)if(a.sqrTo(c,d),0<(b&1<b||a.isEven()?new Classic(a):new Montgomery(a);return this.exp(b,c)}BigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo;BigInteger.prototype.subTo=bnpSubTo; -BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpIsEven;BigInteger.prototype.exp=bnpExp;BigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt; -BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);function SecureRandom(){this.nextBytes=function(b){for(var a=0;a>1;d.e=parseInt(c,16);for(d.ee=new BigInteger(c,16);;){for(;!(d.p=new BigInteger(a-f,1,e),0==d.p.subtract(BigInteger.ONE).gcd(d.ee).compareTo(BigInteger.ONE)&&d.p.isProbablePrime(10)););for(;!(d.q=new BigInteger(f,1,e),0==d.q.subtract(BigInteger.ONE).gcd(d.ee).compareTo(BigInteger.ONE)&&d.q.isProbablePrime(10));); -if(0>=d.p.compareTo(d.q)){var g=d.p;d.p=d.q;d.q=g}var g=d.p.subtract(BigInteger.ONE),h=d.q.subtract(BigInteger.ONE),j=g.multiply(h);if(0==j.gcd(d.ee).compareTo(BigInteger.ONE)){d.n=d.p.multiply(d.q);d.d=d.ee.modInverse(j);d.dmp1=d.d.mod(g);d.dmq1=d.d.mod(h);d.u=d.p.modInverse(d.q);break}}return d};this.keyObject=b}function MD5(b){b=md5(b);return util.hex2bin(b)} -function md5cycle(b,a){var c=b[0],d=b[1],e=b[2],f=b[3],c=ff(c,d,e,f,a[0],7,-680876936),f=ff(f,c,d,e,a[1],12,-389564586),e=ff(e,f,c,d,a[2],17,606105819),d=ff(d,e,f,c,a[3],22,-1044525330),c=ff(c,d,e,f,a[4],7,-176418897),f=ff(f,c,d,e,a[5],12,1200080426),e=ff(e,f,c,d,a[6],17,-1473231341),d=ff(d,e,f,c,a[7],22,-45705983),c=ff(c,d,e,f,a[8],7,1770035416),f=ff(f,c,d,e,a[9],12,-1958414417),e=ff(e,f,c,d,a[10],17,-42063),d=ff(d,e,f,c,a[11],22,-1990404162),c=ff(c,d,e,f,a[12],7,1804603682),f=ff(f,c,d,e,a[13],12, --40341101),e=ff(e,f,c,d,a[14],17,-1502002290),d=ff(d,e,f,c,a[15],22,1236535329),c=gg(c,d,e,f,a[1],5,-165796510),f=gg(f,c,d,e,a[6],9,-1069501632),e=gg(e,f,c,d,a[11],14,643717713),d=gg(d,e,f,c,a[0],20,-373897302),c=gg(c,d,e,f,a[5],5,-701558691),f=gg(f,c,d,e,a[10],9,38016083),e=gg(e,f,c,d,a[15],14,-660478335),d=gg(d,e,f,c,a[4],20,-405537848),c=gg(c,d,e,f,a[9],5,568446438),f=gg(f,c,d,e,a[14],9,-1019803690),e=gg(e,f,c,d,a[3],14,-187363961),d=gg(d,e,f,c,a[8],20,1163531501),c=gg(c,d,e,f,a[13],5,-1444681467), -f=gg(f,c,d,e,a[2],9,-51403784),e=gg(e,f,c,d,a[7],14,1735328473),d=gg(d,e,f,c,a[12],20,-1926607734),c=hh(c,d,e,f,a[5],4,-378558),f=hh(f,c,d,e,a[8],11,-2022574463),e=hh(e,f,c,d,a[11],16,1839030562),d=hh(d,e,f,c,a[14],23,-35309556),c=hh(c,d,e,f,a[1],4,-1530992060),f=hh(f,c,d,e,a[4],11,1272893353),e=hh(e,f,c,d,a[7],16,-155497632),d=hh(d,e,f,c,a[10],23,-1094730640),c=hh(c,d,e,f,a[13],4,681279174),f=hh(f,c,d,e,a[0],11,-358537222),e=hh(e,f,c,d,a[3],16,-722521979),d=hh(d,e,f,c,a[6],23,76029189),c=hh(c,d, -e,f,a[9],4,-640364487),f=hh(f,c,d,e,a[12],11,-421815835),e=hh(e,f,c,d,a[15],16,530742520),d=hh(d,e,f,c,a[2],23,-995338651),c=ii(c,d,e,f,a[0],6,-198630844),f=ii(f,c,d,e,a[7],10,1126891415),e=ii(e,f,c,d,a[14],15,-1416354905),d=ii(d,e,f,c,a[5],21,-57434055),c=ii(c,d,e,f,a[12],6,1700485571),f=ii(f,c,d,e,a[3],10,-1894986606),e=ii(e,f,c,d,a[10],15,-1051523),d=ii(d,e,f,c,a[1],21,-2054922799),c=ii(c,d,e,f,a[8],6,1873313359),f=ii(f,c,d,e,a[15],10,-30611744),e=ii(e,f,c,d,a[6],15,-1560198380),d=ii(d,e,f,c,a[13], -21,1309151649),c=ii(c,d,e,f,a[4],6,-145523070),f=ii(f,c,d,e,a[11],10,-1120210379),e=ii(e,f,c,d,a[2],15,718787259),d=ii(d,e,f,c,a[9],21,-343485551);b[0]=add32(c,b[0]);b[1]=add32(d,b[1]);b[2]=add32(e,b[2]);b[3]=add32(f,b[3])}function cmn(b,a,c,d,e,f){a=add32(add32(a,b),add32(d,f));return add32(a<>>32-e,c)}function ff(b,a,c,d,e,f,g){return cmn(a&c|~a&d,b,a,e,f,g)}function gg(b,a,c,d,e,f,g){return cmn(a&d|c&~d,b,a,e,f,g)}function hh(b,a,c,d,e,f,g){return cmn(a^c^d,b,a,e,f,g)} -function ii(b,a,c,d,e,f,g){return cmn(c^(a|~d),b,a,e,f,g)}function md51(b){txt="";var a=b.length,c=[1732584193,-271733879,-1732584194,271733878],d;for(d=64;d<=b.length;d+=64)md5cycle(c,md5blk(b.substring(d-64,d)));var b=b.substring(d-64),e=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(d=0;d>2]|=b.charCodeAt(d)<<(d%4<<3);e[d>>2]|=128<<(d%4<<3);if(55d;d++)e[d]=0}e[14]=8*a;md5cycle(c,e);return c} -function md5blk(b){var a=[],c;for(c=0;64>c;c+=4)a[c>>2]=b.charCodeAt(c)+(b.charCodeAt(c+1)<<8)+(b.charCodeAt(c+2)<<16)+(b.charCodeAt(c+3)<<24);return a}var hex_chr="0123456789abcdef".split("");function rhex(b){for(var a="",c=0;4>c;c++)a+=hex_chr[b>>8*c+4&15]+hex_chr[b>>8*c&15];return a}function hex(b){for(var a=0;a>16)+(a>>16)+(c>>16)<<16|c&65535});var RMDsize=160,X=[];function ROL(b,a){return new Number(b<>>32-a)}function F(b,a,c){return new Number(b^a^c)}function G(b,a,c){return new Number(b&a|~b&c)}function H(b,a,c){return new Number((b|~a)^c)}function I(b,a,c){return new Number(b&c|a&~c)}function J(b,a,c){return new Number(b^(a|~c))} -function mixOneRound(b,a,c,d,e,f,g,h){switch(h){case 0:b+=F(a,c,d)+f+0;break;case 1:b+=G(a,c,d)+f+1518500249;break;case 2:b+=H(a,c,d)+f+1859775393;break;case 3:b+=I(a,c,d)+f+2400959708;break;case 4:b+=J(a,c,d)+f+2840853838;break;case 5:b+=J(a,c,d)+f+1352829926;break;case 6:b+=I(a,c,d)+f+1548603684;break;case 7:b+=H(a,c,d)+f+1836072691;break;case 8:b+=G(a,c,d)+f+2053994217;break;case 9:b+=F(a,c,d)+f+0;break;default:document.write("Bogus round number")}b=ROL(b,g)+e;c=ROL(c,10);h=[];h[0]=b&4294967295; -h[1]=a&4294967295;h[2]=c&4294967295;h[3]=d&4294967295;h[4]=e&4294967295;h[5]=f;h[6]=g;return h}function MDinit(b){b[0]=1732584193;b[1]=4023233417;b[2]=2562383102;b[3]=271733878;b[4]=3285377520} -var ROLs=[[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8],[7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12],[11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5],[11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12],[9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6],[9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11],[9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5],[15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8],[8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]],indexes=[[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],[7,4,13,1,10,6,15,3,12, -0,9,5,2,14,11,8],[3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12],[1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2],[4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12],[6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2],[15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13],[8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14],[12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]]; -function compress(b,a){blockA=[];blockB=[];for(var c,d=0;5>d;d++)blockA[d]=new Number(b[d]),blockB[d]=new Number(b[d]);for(var e=0,f=0;5>f;f++)for(d=0;16>d;d++)c=mixOneRound(blockA[(e+0)%5],blockA[(e+1)%5],blockA[(e+2)%5],blockA[(e+3)%5],blockA[(e+4)%5],a[indexes[f][d]],ROLs[f][d],f),blockA[(e+0)%5]=c[0],blockA[(e+1)%5]=c[1],blockA[(e+2)%5]=c[2],blockA[(e+3)%5]=c[3],blockA[(e+4)%5]=c[4],e+=4;e=0;for(f=5;10>f;f++)for(d=0;16>d;d++)c=mixOneRound(blockB[(e+0)%5],blockB[(e+1)%5],blockB[(e+2)%5],blockB[(e+ -3)%5],blockB[(e+4)%5],a[indexes[f][d]],ROLs[f][d],f),blockB[(e+0)%5]=c[0],blockB[(e+1)%5]=c[1],blockB[(e+2)%5]=c[2],blockB[(e+3)%5]=c[3],blockB[(e+4)%5]=c[4],e+=4;blockB[3]+=blockA[2]+b[1];b[1]=b[2]+blockA[3]+blockB[4];b[2]=b[3]+blockA[4]+blockB[0];b[3]=b[4]+blockA[0]+blockB[1];b[4]=b[0]+blockA[1]+blockB[2];b[0]=blockB[3]}function zeroX(b){for(var a=0;16>a;a++)b[a]=0} -function MDfinish(b,a,c,d){var e=Array(16);zeroX(e);for(var f=0,g=0;g<(c&63);g++)e[g>>>2]^=(a.charCodeAt(f++)&255)<<8*(g&3);e[c>>>2&15]^=1<<8*(c&3)+7;55<(c&63)&&(compress(b,e),e=Array(16),zeroX(e));e[14]=c<<3;e[15]=c>>>29|d<<3;compress(b,e)}function BYTES_TO_DWORD(b){var a=(b.charCodeAt(3)&255)<<24,a=a|(b.charCodeAt(2)&255)<<16,a=a|(b.charCodeAt(1)&255)<<8;return a|=b.charCodeAt(0)&255} -function RMD(b){var a=Array(RMDsize/32),c=Array(RMDsize/8),d,e;MDinit(a);d=b.length;var f=Array(16);zeroX(f);var g=0;for(e=d;63h;h++)f[h]=BYTES_TO_DWORD(b.substr(g,4)),g+=4;compress(a,f)}MDfinish(a,b.substr(g),d,0);for(h=0;h>>2]&255,c[h+1]=a[h>>>2]>>>8&255,c[h+2]=a[h>>>2]>>>16&255,c[h+3]=a[h>>>2]>>>24&255;return c}function RMDstring(b){for(var b=RMD(b),a="",c=0;c>5]|=(a.charCodeAt(d/8)&255)<<24-d%32;return b},c=function(a){var b=[],c=a.length,d,e;for(d=0;d>3]|=e<<24-4*(d%8)}return b},d=function(a){var b="",c=4*a.length,d,e;for(d=0;d>2]>>8*(3-d%4),b+="0123456789abcdef".charAt(e>>4&15)+"0123456789abcdef".charAt(e&15);return b},e=function(a){var b= -"",c=4*a.length,d,e,f;for(d=0;d>2]>>8*(3-d%4)&255)<<16|(a[d+1>>2]>>8*(3-(d+1)%4)&255)<<8|a[d+2>>2]>>8*(3-(d+2)%4)&255;for(e=0;4>e;e+=1)b=8*d+6*e<=32*a.length?b+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(f>>6*(3-e)&63):b+""}return b},f=function(a){for(var b="",c=0;c<32*a.length;c+=8)b+=String.fromCharCode(a[c>>5]>>>24-c%32&255);return b},g=function(a,b){return a<>>32-b},h=function(a,b){return a>>>b|a<<32-b},j=function(a,c){return 32>=c?new b(a.highOrder>>> -c|a.lowOrder<<32-c,a.lowOrder>>>c|a.highOrder<<32-c):new b(a.lowOrder>>>c|a.highOrder<<32-c,a.highOrder>>>c|a.lowOrder<<32-c)},k=function(a,c){return 32>=c?new b(a.highOrder>>>c,a.lowOrder>>>c|a.highOrder<<32-c):new b(0,a.highOrder<<32-c)},l=function(a,b,c){return a&b^~a&c},m=function(a,c,d){return new b(a.highOrder&c.highOrder^~a.highOrder&d.highOrder,a.lowOrder&c.lowOrder^~a.lowOrder&d.lowOrder)},r=function(a,b,c){return a&b^a&c^b&c},p=function(a,c,d){return new b(a.highOrder&c.highOrder^a.highOrder& -d.highOrder^c.highOrder&d.highOrder,a.lowOrder&c.lowOrder^a.lowOrder&d.lowOrder^c.lowOrder&d.lowOrder)},o=function(a){return h(a,2)^h(a,13)^h(a,22)},y=function(a){var c=j(a,28),d=j(a,34),a=j(a,39);return new b(c.highOrder^d.highOrder^a.highOrder,c.lowOrder^d.lowOrder^a.lowOrder)},v=function(a){return h(a,6)^h(a,11)^h(a,25)},w=function(a){var c=j(a,14),d=j(a,18),a=j(a,41);return new b(c.highOrder^d.highOrder^a.highOrder,c.lowOrder^d.lowOrder^a.lowOrder)},A=function(a){return h(a,7)^h(a,18)^a>>>3}, -t=function(a){var c=j(a,1),d=j(a,8),a=k(a,7);return new b(c.highOrder^d.highOrder^a.highOrder,c.lowOrder^d.lowOrder^a.lowOrder)},u=function(a){return h(a,17)^h(a,19)^a>>>10},P=function(a){var c=j(a,19),d=j(a,61),a=k(a,6);return new b(c.highOrder^d.highOrder^a.highOrder,c.lowOrder^d.lowOrder^a.lowOrder)},C=function(a,b){var c=(a&65535)+(b&65535);return((a>>>16)+(b>>>16)+(c>>>16)&65535)<<16|c&65535},Q=function(a,b,c,d){var e=(a&65535)+(b&65535)+(c&65535)+(d&65535);return((a>>>16)+(b>>>16)+(c>>>16)+ -(d>>>16)+(e>>>16)&65535)<<16|e&65535},E=function(a,b,c,d,e){var f=(a&65535)+(b&65535)+(c&65535)+(d&65535)+(e&65535);return((a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(e>>>16)+(f>>>16)&65535)<<16|f&65535},x=function(a,c){var d,e,f;d=(a.lowOrder&65535)+(c.lowOrder&65535);e=(a.lowOrder>>>16)+(c.lowOrder>>>16)+(d>>>16);f=(e&65535)<<16|d&65535;d=(a.highOrder&65535)+(c.highOrder&65535)+(e>>>16);e=(a.highOrder>>>16)+(c.highOrder>>>16)+(d>>>16);return new b((e&65535)<<16|d&65535,f)},z=function(a,c,d,e){var f,g, -h;f=(a.lowOrder&65535)+(c.lowOrder&65535)+(d.lowOrder&65535)+(e.lowOrder&65535);g=(a.lowOrder>>>16)+(c.lowOrder>>>16)+(d.lowOrder>>>16)+(e.lowOrder>>>16)+(f>>>16);h=(g&65535)<<16|f&65535;f=(a.highOrder&65535)+(c.highOrder&65535)+(d.highOrder&65535)+(e.highOrder&65535)+(g>>>16);g=(a.highOrder>>>16)+(c.highOrder>>>16)+(d.highOrder>>>16)+(e.highOrder>>>16)+(f>>>16);return new b((g&65535)<<16|f&65535,h)},V=function(a,c,d,e,f){var g,h,j;g=(a.lowOrder&65535)+(c.lowOrder&65535)+(d.lowOrder&65535)+(e.lowOrder& -65535)+(f.lowOrder&65535);h=(a.lowOrder>>>16)+(c.lowOrder>>>16)+(d.lowOrder>>>16)+(e.lowOrder>>>16)+(f.lowOrder>>>16)+(g>>>16);j=(h&65535)<<16|g&65535;g=(a.highOrder&65535)+(c.highOrder&65535)+(d.highOrder&65535)+(e.highOrder&65535)+(f.highOrder&65535)+(h>>>16);h=(a.highOrder>>>16)+(c.highOrder>>>16)+(d.highOrder>>>16)+(e.highOrder>>>16)+(f.highOrder>>>16)+(g>>>16);return new b((h&65535)<<16|g&65535,j)},K=function(a,b){var c=[],d,e,f,h,j,k,l,m,o,s=[1732584193,4023233417,2562383102,271733878,3285377520], -p=[1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708, -2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782];a[b>>5]|=128<<24-b%32;a[(b+65>>9<<4)+15]=b;o=a.length;for(l=0;lm;m+=1)c[m]= -16>m?a[m+l]:g(c[m-3]^c[m-8]^c[m-14]^c[m-16],1),k=20>m?E(g(d,5),e&f^~e&h,j,p[m],c[m]):40>m?E(g(d,5),e^f^h,j,p[m],c[m]):60>m?E(g(d,5),r(e,f,h),j,p[m],c[m]):E(g(d,5),e^f^h,j,p[m],c[m]),j=h,h=f,f=g(e,30),e=d,d=k;s[0]=C(d,s[0]);s[1]=C(e,s[1]);s[2]=C(f,s[2]);s[3]=C(h,s[3]);s[4]=C(j,s[4])}return s},D=function(a,c,d){var e,f,g,h,j,k,K,B,D,s,ea,Y,L,fa,ca,N,ga,ha,ia,ja,ka,la,ma,na,q,oa,Z=[],sa;if("SHA-224"===d||"SHA-256"===d)ea=64,e=(c+65>>9<<4)+15,fa=16,ca=1,q=Number,N=C,ga=Q,ha=E,ia=A,ja=u,ka=o,la=v,na=r, -ma=l,oa=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804, -4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],s="SHA-224"===d?[3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428]:[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225];else if("SHA-384"===d||"SHA-512"===d)ea=80,e=(c+128>>10<<5)+31,fa=32,ca=2,q=b,N=x,ga=z,ha=V,ia=t,ja=P,ka=y,la=w,na= -p,ma=m,oa=[new q(1116352408,3609767458),new q(1899447441,602891725),new q(3049323471,3964484399),new q(3921009573,2173295548),new q(961987163,4081628472),new q(1508970993,3053834265),new q(2453635748,2937671579),new q(2870763221,3664609560),new q(3624381080,2734883394),new q(310598401,1164996542),new q(607225278,1323610764),new q(1426881987,3590304994),new q(1925078388,4068182383),new q(2162078206,991336113),new q(2614888103,633803317),new q(3248222580,3479774868),new q(3835390401,2666613458),new q(4022224774, -944711139),new q(264347078,2341262773),new q(604807628,2007800933),new q(770255983,1495990901),new q(1249150122,1856431235),new q(1555081692,3175218132),new q(1996064986,2198950837),new q(2554220882,3999719339),new q(2821834349,766784016),new q(2952996808,2566594879),new q(3210313671,3203337956),new q(3336571891,1034457026),new q(3584528711,2466948901),new q(113926993,3758326383),new q(338241895,168717936),new q(666307205,1188179964),new q(773529912,1546045734),new q(1294757372,1522805485),new q(1396182291, -2643833823),new q(1695183700,2343527390),new q(1986661051,1014477480),new q(2177026350,1206759142),new q(2456956037,344077627),new q(2730485921,1290863460),new q(2820302411,3158454273),new q(3259730800,3505952657),new q(3345764771,106217008),new q(3516065817,3606008344),new q(3600352804,1432725776),new q(4094571909,1467031594),new q(275423344,851169720),new q(430227734,3100823752),new q(506948616,1363258195),new q(659060556,3750685593),new q(883997877,3785050280),new q(958139571,3318307427),new q(1322822218, -3812723403),new q(1537002063,2003034995),new q(1747873779,3602036899),new q(1955562222,1575990012),new q(2024104815,1125592928),new q(2227730452,2716904306),new q(2361852424,442776044),new q(2428436474,593698344),new q(2756734187,3733110249),new q(3204031479,2999351573),new q(3329325298,3815920427),new q(3391569614,3928383900),new q(3515267271,566280711),new q(3940187606,3454069534),new q(4118630271,4000239992),new q(116418474,1914138554),new q(174292421,2731055270),new q(289380356,3203993006),new q(460393269, -320620315),new q(685471733,587496836),new q(852142971,1086792851),new q(1017036298,365543100),new q(1126000580,2618297676),new q(1288033470,3409855158),new q(1501505948,4234509866),new q(1607167915,987167468),new q(1816402316,1246189591)],s="SHA-384"===d?[new q(3418070365,3238371032),new q(1654270250,914150663),new q(2438529370,812702999),new q(355462360,4144912697),new q(1731405415,4290775857),new q(41048885895,1750603025),new q(3675008525,1694076839),new q(1203062813,3204075428)]:[new q(1779033703, -4089235720),new q(3144134277,2227873595),new q(1013904242,4271175723),new q(2773480762,1595750129),new q(1359893119,2917565137),new q(2600822924,725511199),new q(528734635,4215389547),new q(1541459225,327033209)];a[c>>5]|=128<<24-c%32;a[e]=c;sa=a.length;for(Y=0;YL?new q(a[L*ca+Y],a[L*ca+Y+1]):ga(ja(Z[L-2]),Z[L-7],ia(Z[L-15]),Z[L-16]),B=ha(K,la(h),ma(h,j,k),oa[L],Z[L]),D=N(ka(c),na(c,e,f)),K=k,k=j,j=h,h=N(g, -B),g=f,f=e,e=c,c=N(B,D);s[0]=N(c,s[0]);s[1]=N(e,s[1]);s[2]=N(f,s[2]);s[3]=N(g,s[3]);s[4]=N(h,s[4]);s[5]=N(j,s[5]);s[6]=N(k,s[6]);s[7]=N(K,s[7])}switch(d){case "SHA-224":return[s[0],s[1],s[2],s[3],s[4],s[5],s[6]];case "SHA-256":return s;case "SHA-384":return[s[0].highOrder,s[0].lowOrder,s[1].highOrder,s[1].lowOrder,s[2].highOrder,s[2].lowOrder,s[3].highOrder,s[3].lowOrder,s[4].highOrder,s[4].lowOrder,s[5].highOrder,s[5].lowOrder];case "SHA-512":return[s[0].highOrder,s[0].lowOrder,s[1].highOrder,s[1].lowOrder, -s[2].highOrder,s[2].lowOrder,s[3].highOrder,s[3].lowOrder,s[4].highOrder,s[4].lowOrder,s[5].highOrder,s[5].lowOrder,s[6].highOrder,s[6].lowOrder,s[7].highOrder,s[7].lowOrder];default:return[]}},B=function(b,d){this.strToHash=this.strBinLen=this.sha512=this.sha384=this.sha256=this.sha224=this.sha1=null;if("HEX"===d){if(0!==b.length%2)return"TEXT MUST BE IN BYTE INCREMENTS";this.strBinLen=4*b.length;this.strToHash=c(b)}else if("ASCII"===d||"undefined"===typeof d)this.strBinLen=8*b.length,this.strToHash= -a(b);else return"UNKNOWN TEXT INPUT TYPE"};B.prototype={getHash:function(a,b){var c=null,g=this.strToHash.slice();switch(b){case "HEX":c=d;break;case "B64":c=e;break;case "ASCII":c=f;break;default:return"FORMAT NOT RECOGNIZED"}switch(a){case "SHA-1":if(null===this.sha1)this.sha1=K(g,this.strBinLen);return c(this.sha1);case "SHA-224":if(null===this.sha224)this.sha224=D(g,this.strBinLen,a);return c(this.sha224);case "SHA-256":if(null===this.sha256)this.sha256=D(g,this.strBinLen,a);return c(this.sha256); -case "SHA-384":if(null===this.sha384)this.sha384=D(g,this.strBinLen,a);return c(this.sha384);case "SHA-512":if(null===this.sha512)this.sha512=D(g,this.strBinLen,a);return c(this.sha512);default:return"HASH NOT RECOGNIZED"}},getHMAC:function(b,g,h,j){var k,l,m,o,p;l=[];var r=[];switch(j){case "HEX":j=d;break;case "B64":j=e;break;case "ASCII":j=f;break;default:return"FORMAT NOT RECOGNIZED"}switch(h){case "SHA-1":k=64;p=160;break;case "SHA-224":k=64;p=224;break;case "SHA-256":k=64;p=256;break;case "SHA-384":k= -128;p=384;break;case "SHA-512":k=128;p=512;break;default:return"HASH NOT RECOGNIZED"}if("HEX"===g){if(0!==b.length%2)return"KEY MUST BE IN BYTE INCREMENTS";g=c(b);o=4*b.length}else if("ASCII"===g)g=a(b),o=8*b.length;else return"UNKNOWN KEY INPUT TYPE";b=8*k;m=k/4-1;ko/8&&(g[m]&=4294967040);for(k=0;k<=m;k+=1)l[k]=g[k]^909522486,r[k]=g[k]^1549556828;"SHA-1"===h?(l=K(l.concat(this.strToHash),b+this.strBinLen),l=K(r.concat(l),b+p)):(l=D(l.concat(this.strToHash), -b+this.strBinLen,h),l=D(r.concat(l),b+p,h));return j(l)}};return B}();function str_sha1(b){return(new jsSHA(b,"ASCII")).getHash("SHA-1","ASCII")}function str_sha224(b){return(new jsSHA(b,"ASCII")).getHash("SHA-224","ASCII")}function str_sha256(b){return(new jsSHA(b,"ASCII")).getHash("SHA-256","ASCII")}function str_sha384(b){return(new jsSHA(b,"ASCII")).getHash("SHA-384","ASCII")}function str_sha512(b){return(new jsSHA(b,"ASCII")).getHash("SHA-512","ASCII")} -function openpgp_cfb_encrypt(b,a,c,d,e,f){var g=Array(d),h=Array(d),b=b+b.charAt(d-2)+b.charAt(d-1);util.print_debug("prefixrandom:"+util.hexstrdump(b));for(var j="",k=0;ka*g;){for(var e=b(f,c),f=d.substring(g*a,g*a+a),k=0;ka*g;){for(var j=b(f,c),f=d.substring(g*a+0,g*a+a+0),e=0;ea-b;)window.crypto.getRandomValues(c);return b+Math.abs(c[0]&Math.pow(2,d)-1)}function openpgp_crypto_getSecureRandomOctet(){var b=new Uint32Array(1);window.crypto.getRandomValues(b);return b[0]&255} -function openpgp_crypto_getRandomBigInteger(b){if(0>b)return null;var a=openpgp_crypto_getRandomBytes(Math.floor((b+7)/8));0=a.compareTo(b))){for(var c=a.subtract(b),d=openpgp_crypto_getRandomBigInteger(c.bitLength());d>c;)d=openpgp_crypto_getRandomBigInteger(c.bitLength());return b.add(d)}} -function openpgp_crypto_testRSA(b){var a=new RSA,c=new openpgp_type_mpi;c.create(openpgp_encoding_eme_pkcs1_encode("ABABABAB",128));c=a.encrypt(c.toBigInteger(),b.ee,b.n);a.decrypt(c,b.d,b.p,b.q,b.u)} -function openpgp_crypto_generateKeyPair(b,a,c,d,e){var f,g,h=new Date,h=h.getTime()/1E3,h=String.fromCharCode(Math.floor(h/16777216%256))+String.fromCharCode(Math.floor(h/65536%256))+String.fromCharCode(Math.floor(h/256%256))+String.fromCharCode(Math.floor(h%256));switch(b){case 1:a=(new RSA).generate(a,"10001");f=(new openpgp_packet_keymaterial).write_private_key(b,a,c,d,e,h);g=(new openpgp_packet_keymaterial).write_public_key(b,a,h);break;default:util.print_error("Unknown keytype "+b)}return{privateKey:f, -publicKey:g}} -function openpgp_crypto_symmetricEncrypt(b,a,c,d,e){switch(a){case 0:return d;case 2:return openpgp_cfb_encrypt(b,desede,d,8,c,e).substring(0,d.length+10);case 3:return openpgp_cfb_encrypt(b,cast5_encrypt,d,8,c,e).substring(0,d.length+10);case 4:return openpgp_cfb_encrypt(b,BFencrypt,d,8,c,e).substring(0,d.length+10);case 7:case 8:case 9:return openpgp_cfb_encrypt(b,AESencrypt,d,16,keyExpansion(c),e).substring(0,d.length+18);case 10:return openpgp_cfb_encrypt(b,TFencrypt,d,16,c,e).substring(0,d.length+ -18);case 1:return util.print_error("IDEA Algorithm not implemented"),null;default:return null}} -function openpgp_crypto_symmetricDecrypt(b,a,c,d){util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nalgo:"+b+"\nencrypteddata:",c);var e=0;d||(e=2);switch(b){case 0:return c;case 2:return openpgp_cfb_decrypt(desede,8,a,c,d).substring(e,c.length+e-10);case 3:return openpgp_cfb_decrypt(cast5_encrypt,8,a,c,d).substring(e,c.length+e-10);case 4:return openpgp_cfb_decrypt(BFencrypt,8,a,c,d).substring(e,c.length+e-10);case 7:case 8:case 9:return openpgp_cfb_decrypt(AESencrypt,16,keyExpansion(a), -c,d).substring(e,c.length+e-18);case 10:return openpgp_cfb_decrypt(TFencrypt,16,a,c,d).substring(e,c.length+e-18);case 1:util.print_error(""+(1==b?"IDEA Algorithm not implemented":"Twofish Algorithm not implemented"))}return null} -var Rcon=[1,2,4,8,16,32,64,128,27,54,108,216,171,77,154,47,94,188,99,198,151,53,106,212,179,125,250,239,197,145],S=[99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80, -60,159,168,81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,137,13,191,230,66,104,65, -153,45,15,176,84,187,22],T1=[2774754246,2222750968,2574743534,2373680118,234025727,3177933782,2976870366,1422247313,1345335392,50397442,2842126286,2099981142,436141799,1658312629,3870010189,2591454956,1170918031,2642575903,1086966153,2273148410,368769775,3948501426,3376891790,200339707,3970805057,1742001331,4255294047,3937382213,3214711843,4154762323,2524082916,1539358875,3266819957,486407649,2928907069,1780885068,1513502316,1094664062,49805301,1338821763,1546925160,4104496465,887481809,150073849, -2473685474,1943591083,1395732834,1058346282,201589768,1388824469,1696801606,1589887901,672667696,2711000631,251987210,3046808111,151455502,907153956,2608889883,1038279391,652995533,1764173646,3451040383,2675275242,453576978,2659418909,1949051992,773462580,756751158,2993581788,3998898868,4221608027,4132590244,1295727478,1641469623,3467883389,2066295122,1055122397,1898917726,2542044179,4115878822,1758581177,0,753790401,1612718144,536673507,3367088505,3982187446,3194645204,1187761037,3653156455,1262041458, -3729410708,3561770136,3898103984,1255133061,1808847035,720367557,3853167183,385612781,3309519750,3612167578,1429418854,2491778321,3477423498,284817897,100794884,2172616702,4031795360,1144798328,3131023141,3819481163,4082192802,4272137053,3225436288,2324664069,2912064063,3164445985,1211644016,83228145,3753688163,3249976951,1977277103,1663115586,806359072,452984805,250868733,1842533055,1288555905,336333848,890442534,804056259,3781124030,2727843637,3427026056,957814574,1472513171,4071073621,2189328124, -1195195770,2892260552,3881655738,723065138,2507371494,2690670784,2558624025,3511635870,2145180835,1713513028,2116692564,2878378043,2206763019,3393603212,703524551,3552098411,1007948840,2044649127,3797835452,487262998,1994120109,1004593371,1446130276,1312438900,503974420,3679013266,168166924,1814307912,3831258296,1573044895,1859376061,4021070915,2791465668,2828112185,2761266481,937747667,2339994098,854058965,1137232011,1496790894,3077402074,2358086913,1691735473,3528347292,3769215305,3027004632,4199962284, -133494003,636152527,2942657994,2390391540,3920539207,403179536,3585784431,2289596656,1864705354,1915629148,605822008,4054230615,3350508659,1371981463,602466507,2094914977,2624877800,555687742,3712699286,3703422305,2257292045,2240449039,2423288032,1111375484,3300242801,2858837708,3628615824,84083462,32962295,302911004,2741068226,1597322602,4183250862,3501832553,2441512471,1489093017,656219450,3114180135,954327513,335083755,3013122091,856756514,3144247762,1893325225,2307821063,2811532339,3063651117, -572399164,2458355477,552200649,1238290055,4283782570,2015897680,2061492133,2408352771,4171342169,2156497161,386731290,3669999461,837215959,3326231172,3093850320,3275833730,2962856233,1999449434,286199582,3417354363,4233385128,3602627437,974525996],T2=[1667483301,2088564868,2004348569,2071721613,4076011277,1802229437,1869602481,3318059348,808476752,16843267,1734856361,724260477,4278118169,3621238114,2880130534,1987505306,3402272581,2189565853,3385428288,2105408135,4210749205,1499050731,1195871945, -4042324747,2913812972,3570709351,2728550397,2947499498,2627478463,2762232823,1920132246,3233848155,3082253762,4261273884,2475900334,640044138,909536346,1061125697,4160222466,3435955023,875849820,2779075060,3857043764,4059166984,1903288979,3638078323,825320019,353708607,67373068,3351745874,589514341,3284376926,404238376,2526427041,84216335,2593796021,117902857,303178806,2155879323,3806519101,3958099238,656887401,2998042573,1970662047,151589403,2206408094,741103732,437924910,454768173,1852759218,1515893998, -2694863867,1381147894,993752653,3604395873,3014884814,690573947,3823361342,791633521,2223248279,1397991157,3520182632,0,3991781676,538984544,4244431647,2981198280,1532737261,1785386174,3419114822,3200149465,960066123,1246401758,1280088276,1482207464,3486483786,3503340395,4025468202,2863288293,4227591446,1128498885,1296931543,859006549,2240090516,1162185423,4193904912,33686534,2139094657,1347461360,1010595908,2678007226,2829601763,1364304627,2745392638,1077969088,2408514954,2459058093,2644320700,943222856, -4126535940,3166462943,3065411521,3671764853,555827811,269492272,4294960410,4092853518,3537026925,3452797260,202119188,320022069,3974939439,1600110305,2543269282,1145342156,387395129,3301217111,2812761586,2122251394,1027439175,1684326572,1566423783,421081643,1936975509,1616953504,2172721560,1330618065,3705447295,572671078,707417214,2425371563,2290617219,1179028682,4008625961,3099093971,336865340,3739133817,1583267042,185275933,3688607094,3772832571,842163286,976909390,168432670,1229558491,101059594, -606357612,1549580516,3267534685,3553869166,2896970735,1650640038,2442213800,2509582756,3840201527,2038035083,3890730290,3368586051,926379609,1835915959,2374828428,3587551588,1313774802,2846444E3,1819072692,1448520954,4109693703,3941256997,1701169839,2054878350,2930657257,134746136,3132780501,2021191816,623200879,774790258,471611428,2795919345,3031724999,3334903633,3907570467,3722289532,1953818780,522141217,1263245021,3183305180,2341145990,2324303749,1886445712,1044282434,3048567236,1718013098,1212715224, -50529797,4143380225,235805714,1633796771,892693087,1465364217,3115936208,2256934801,3250690392,488454695,2661164985,3789674808,4177062675,2560109491,286335539,1768542907,3654920560,2391672713,2492740519,2610638262,505297954,2273777042,3924412704,3469641545,1431677695,673730680,3755976058,2357986191,2711706104,2307459456,218962455,3216991706,3873888049,1111655622,1751699640,1094812355,2576951728,757946999,252648977,2964356043,1414834428,3149622742,370551866],T3=[1673962851,2096661628,2012125559,2079755643, -4076801522,1809235307,1876865391,3314635973,811618352,16909057,1741597031,727088427,4276558334,3618988759,2874009259,1995217526,3398387146,2183110018,3381215433,2113570685,4209972730,1504897881,1200539975,4042984432,2906778797,3568527316,2724199842,2940594863,2619588508,2756966308,1927583346,3231407040,3077948087,4259388669,2470293139,642542118,913070646,1065238847,4160029431,3431157708,879254580,2773611685,3855693029,4059629809,1910674289,3635114968,828527409,355090197,67636228,3348452039,591815971, -3281870531,405809176,2520228246,84545285,2586817946,118360327,304363026,2149292928,3806281186,3956090603,659450151,2994720178,1978310517,152181513,2199756419,743994412,439627290,456535323,1859957358,1521806938,2690382752,1386542674,997608763,3602342358,3011366579,693271337,3822927587,794718511,2215876484,1403450707,3518589137,0,3988860141,541089824,4242743292,2977548465,1538714971,1792327274,3415033547,3194476990,963791673,1251270218,1285084236,1487988824,3481619151,3501943760,4022676207,2857362858, -4226619131,1132905795,1301993293,862344499,2232521861,1166724933,4192801017,33818114,2147385727,1352724560,1014514748,2670049951,2823545768,1369633617,2740846243,1082179648,2399505039,2453646738,2636233885,946882616,4126213365,3160661948,3061301686,3668932058,557998881,270544912,4293204735,4093447923,3535760850,3447803085,202904588,321271059,3972214764,1606345055,2536874647,1149815876,388905239,3297990596,2807427751,2130477694,1031423805,1690872932,1572530013,422718233,1944491379,1623236704,2165938305, -1335808335,3701702620,574907938,710180394,2419829648,2282455944,1183631942,4006029806,3094074296,338181140,3735517662,1589437022,185998603,3685578459,3772464096,845436466,980700730,169090570,1234361161,101452294,608726052,1555620956,3265224130,3552407251,2890133420,1657054818,2436475025,2503058581,3839047652,2045938553,3889509095,3364570056,929978679,1843050349,2365688973,3585172693,1318900302,2840191145,1826141292,1454176854,4109567988,3939444202,1707781989,2062847610,2923948462,135272456,3127891386, -2029029496,625635109,777810478,473441308,2790781350,3027486644,3331805638,3905627112,3718347997,1961401460,524165407,1268178251,3177307325,2332919435,2316273034,1893765232,1048330814,3044132021,1724688998,1217452104,50726147,4143383030,236720654,1640145761,896163637,1471084887,3110719673,2249691526,3248052417,490350365,2653403550,3789109473,4176155640,2553000856,287453969,1775418217,3651760345,2382858638,2486413204,2603464347,507257374,2266337927,3922272489,3464972750,1437269845,676362280,3752164063, -2349043596,2707028129,2299101321,219813645,3211123391,3872862694,1115997762,1758509160,1099088705,2569646233,760903469,253628687,2960903088,1420360788,3144537787,371997206],T4=[3332727651,4169432188,4003034999,4136467323,4279104242,3602738027,3736170351,2438251973,1615867952,33751297,3467208551,1451043627,3877240574,3043153879,1306962859,3969545846,2403715786,530416258,2302724553,4203183485,4011195130,3001768281,2395555655,4211863792,1106029997,3009926356,1610457762,1173008303,599760028,1408738468, -3835064946,2606481600,1975695287,3776773629,1034851219,1282024998,1817851446,2118205247,4110612471,2203045068,1750873140,1374987685,3509904869,4178113009,3801313649,2876496088,1649619249,708777237,135005188,2505230279,1181033251,2640233411,807933976,933336726,168756485,800430746,235472647,607523346,463175808,3745374946,3441880043,1315514151,2144187058,3936318837,303761673,496927619,1484008492,875436570,908925723,3702681198,3035519578,1543217312,2767606354,1984772923,3076642518,2110698419,1383803177, -3711886307,1584475951,328696964,2801095507,3110654417,0,3240947181,1080041504,3810524412,2043195825,3069008731,3569248874,2370227147,1742323390,1917532473,2497595978,2564049996,2968016984,2236272591,3144405200,3307925487,1340451498,3977706491,2261074755,2597801293,1716859699,294946181,2328839493,3910203897,67502594,4269899647,2700103760,2017737788,632987551,1273211048,2733855057,1576969123,2160083008,92966799,1068339858,566009245,1883781176,4043634165,1675607228,2009183926,2943736538,1113792801,540020752, -3843751935,4245615603,3211645650,2169294285,403966988,641012499,3274697964,3202441055,899848087,2295088196,775493399,2472002756,1441965991,4236410494,2051489085,3366741092,3135724893,841685273,3868554099,3231735904,429425025,2664517455,2743065820,1147544098,1417554474,1001099408,193169544,2362066502,3341414126,1809037496,675025940,2809781982,3168951902,371002123,2910247899,3678134496,1683370546,1951283770,337512970,2463844681,201983494,1215046692,3101973596,2673722050,3178157011,1139780780,3299238498, -967348625,832869781,3543655652,4069226873,3576883175,2336475336,1851340599,3669454189,25988493,2976175573,2631028302,1239460265,3635702892,2902087254,4077384948,3475368682,3400492389,4102978170,1206496942,270010376,1876277946,4035475576,1248797989,1550986798,941890588,1475454630,1942467764,2538718918,3408128232,2709315037,3902567540,1042358047,2531085131,1641856445,226921355,260409994,3767562352,2084716094,1908716981,3433719398,2430093384,100991747,4144101110,470945294,3265487201,1784624437,2935576407, -1775286713,395413126,2572730817,975641885,666476190,3644383713,3943954680,733190296,573772049,3535497577,2842745305,126455438,866620564,766942107,1008868894,361924487,3374377449,2269761230,2868860245,1350051880,2776293343,59739276,1509466529,159418761,437718285,1708834751,3610371814,2227585602,3501746280,2193834305,699439513,1517759789,504434447,2076946608,2835108948,1842789307,742004246];function B0(b){return b&255}function B1(b){return b>>8&255}function B2(b){return b>>16&255} -function B3(b){return b>>24&255}function F1(b,a,c,d){return B1(T1[b&255])|B1(T1[a>>8&255])<<8|B1(T1[c>>16&255])<<16|B1(T1[d>>>24])<<24}function packBytes(b){var a,c,d=b.length,e=Array(d/4);if(b&&!(d%4)){for(a=0,c=0;cc;d++,c++)f[b][c]=j[d];4==c&&(b++,c=0)}for(;bc;d++,c++)f[b][c]=j[d];4==c&&(b++,c=0)}}this.rounds=e;this.rk=f;return this} -function AESencrypt(b,a){var c,d,e,f,g,h=packBytes(b),j=a.rounds,k=h[0],l=h[1],m=h[2];g=h[3];for(c=0;c>8&255]^T3[f>>16&255]^T4[g>>>24],l=T1[e&255]^T2[f>>8&255]^T3[g>>16&255]^T4[d>>>24],m=T1[f&255]^T2[g>>8&255]^T3[d>>16&255]^T4[e>>>24],g=T1[g&255]^T2[d>>8&255]^T3[e>>16&255]^T4[f>>>24];c=j-1;d=k^a.rk[c][0];e=l^a.rk[c][1];f=m^a.rk[c][2];g^=a.rk[c][3];h[0]=F1(d,e,f,g)^a.rk[j][0];h[1]=F1(e,f,g,d)^a.rk[j][1];h[2]=F1(f, -g,d,e)^a.rk[j][2];h[3]=F1(g,d,e,f)^a.rk[j][3];return unpackBytes(h)}function Blowfish(){}Blowfish.prototype.BLOCKSIZE=8; -Blowfish.prototype.SBOXES=[[3509652390,2564797868,805139163,3491422135,3101798381,1780907670,3128725573,4046225305,614570311,3012652279,134345442,2240740374,1667834072,1901547113,2757295779,4103290238,227898511,1921955416,1904987480,2182433518,2069144605,3260701109,2620446009,720527379,3318853667,677414384,3393288472,3101374703,2390351024,1614419982,1822297739,2954791486,3608508353,3174124327,2024746970,1432378464,3864339955,2857741204,1464375394,1676153920,1439316330,715854006,3033291828,289532110, -2706671279,2087905683,3018724369,1668267050,732546397,1947742710,3462151702,2609353502,2950085171,1814351708,2050118529,680887927,999245976,1800124847,3300911131,1713906067,1641548236,4213287313,1216130144,1575780402,4018429277,3917837745,3693486850,3949271944,596196993,3549867205,258830323,2213823033,772490370,2760122372,1774776394,2652871518,566650946,4142492826,1728879713,2882767088,1783734482,3629395816,2517608232,2874225571,1861159788,326777828,3124490320,2130389656,2716951837,967770486,1724537150, -2185432712,2364442137,1164943284,2105845187,998989502,3765401048,2244026483,1075463327,1455516326,1322494562,910128902,469688178,1117454909,936433444,3490320968,3675253459,1240580251,122909385,2157517691,634681816,4142456567,3825094682,3061402683,2540495037,79693498,3249098678,1084186820,1583128258,426386531,1761308591,1047286709,322548459,995290223,1845252383,2603652396,3431023940,2942221577,3202600964,3727903485,1712269319,422464435,3234572375,1170764815,3523960633,3117677531,1434042557,442511882, -3600875718,1076654713,1738483198,4213154764,2393238008,3677496056,1014306527,4251020053,793779912,2902807211,842905082,4246964064,1395751752,1040244610,2656851899,3396308128,445077038,3742853595,3577915638,679411651,2892444358,2354009459,1767581616,3150600392,3791627101,3102740896,284835224,4246832056,1258075500,768725851,2589189241,3069724005,3532540348,1274779536,3789419226,2764799539,1660621633,3471099624,4011903706,913787905,3497959166,737222580,2514213453,2928710040,3937242737,1804850592,3499020752, -2949064160,2386320175,2390070455,2415321851,4061277028,2290661394,2416832540,1336762016,1754252060,3520065937,3014181293,791618072,3188594551,3933548030,2332172193,3852520463,3043980520,413987798,3465142937,3030929376,4245938359,2093235073,3534596313,375366246,2157278981,2479649556,555357303,3870105701,2008414854,3344188149,4221384143,3956125452,2067696032,3594591187,2921233993,2428461,544322398,577241275,1471733935,610547355,4027169054,1432588573,1507829418,2025931657,3646575487,545086370,48609733, -2200306550,1653985193,298326376,1316178497,3007786442,2064951626,458293330,2589141269,3591329599,3164325604,727753846,2179363840,146436021,1461446943,4069977195,705550613,3059967265,3887724982,4281599278,3313849956,1404054877,2845806497,146425753,1854211946],[1266315497,3048417604,3681880366,3289982499,290971E4,1235738493,2632868024,2414719590,3970600049,1771706367,1449415276,3266420449,422970021,1963543593,2690192192,3826793022,1062508698,1531092325,1804592342,2583117782,2714934279,4024971509,1294809318, -4028980673,1289560198,2221992742,1669523910,35572830,157838143,1052438473,1016535060,1802137761,1753167236,1386275462,3080475397,2857371447,1040679964,2145300060,2390574316,1461121720,2956646967,4031777805,4028374788,33600511,2920084762,1018524850,629373528,3691585981,3515945977,2091462646,2486323059,586499841,988145025,935516892,3367335476,2599673255,2839830854,265290510,3972581182,2759138881,3795373465,1005194799,847297441,406762289,1314163512,1332590856,1866599683,4127851711,750260880,613907577, -1450815602,3165620655,3734664991,3650291728,3012275730,3704569646,1427272223,778793252,1343938022,2676280711,2052605720,1946737175,3164576444,3914038668,3967478842,3682934266,1661551462,3294938066,4011595847,840292616,3712170807,616741398,312560963,711312465,1351876610,322626781,1910503582,271666773,2175563734,1594956187,70604529,3617834859,1007753275,1495573769,4069517037,2549218298,2663038764,504708206,2263041392,3941167025,2249088522,1514023603,1998579484,1312622330,694541497,2582060303,2151582166, -1382467621,776784248,2618340202,3323268794,2497899128,2784771155,503983604,4076293799,907881277,423175695,432175456,1378068232,4145222326,3954048622,3938656102,3820766613,2793130115,2977904593,26017576,3274890735,3194772133,1700274565,1756076034,4006520079,3677328699,720338349,1533947780,354530856,688349552,3973924725,1637815568,332179504,3949051286,53804574,2852348879,3044236432,1282449977,3583942155,3416972820,4006381244,1617046695,2628476075,3002303598,1686838959,431878346,2686675385,1700445008, -1080580658,1009431731,832498133,3223435511,2605976345,2271191193,2516031870,1648197032,4164389018,2548247927,300782431,375919233,238389289,3353747414,2531188641,2019080857,1475708069,455242339,2609103871,448939670,3451063019,1395535956,2413381860,1841049896,1491858159,885456874,4264095073,4001119347,1565136089,3898914787,1108368660,540939232,1173283510,2745871338,3681308437,4207628240,3343053890,4016749493,1699691293,1103962373,3625875870,2256883143,3830138730,1031889488,3479347698,1535977030,4236805024, -3251091107,2132092099,1774941330,1199868427,1452454533,157007616,2904115357,342012276,595725824,1480756522,206960106,497939518,591360097,863170706,2375253569,3596610801,1814182875,2094937945,3421402208,1082520231,3463918190,2785509508,435703966,3908032597,1641649973,2842273706,3305899714,1510255612,2148256476,2655287854,3276092548,4258621189,236887753,3681803219,274041037,1734335097,3815195456,3317970021,1899903192,1026095262,4050517792,356393447,2410691914,3873677099,3682840055],[3913112168,2491498743, -4132185628,2489919796,1091903735,1979897079,3170134830,3567386728,3557303409,857797738,1136121015,1342202287,507115054,2535736646,337727348,3213592640,1301675037,2528481711,1895095763,1721773893,3216771564,62756741,2142006736,835421444,2531993523,1442658625,3659876326,2882144922,676362277,1392781812,170690266,3921047035,1759253602,3611846912,1745797284,664899054,1329594018,3901205900,3045908486,2062866102,2865634940,3543621612,3464012697,1080764994,553557557,3656615353,3996768171,991055499,499776247, -1265440854,648242737,3940784050,980351604,3713745714,1749149687,3396870395,4211799374,3640570775,1161844396,3125318951,1431517754,545492359,4268468663,3499529547,1437099964,2702547544,3433638243,2581715763,2787789398,1060185593,1593081372,2418618748,4260947970,69676912,2159744348,86519011,2512459080,3838209314,1220612927,3339683548,133810670,1090789135,1078426020,1569222167,845107691,3583754449,4072456591,1091646820,628848692,1613405280,3757631651,526609435,236106946,48312990,2942717905,3402727701, -1797494240,859738849,992217954,4005476642,2243076622,3870952857,3732016268,765654824,3490871365,2511836413,1685915746,3888969200,1414112111,2273134842,3281911079,4080962846,172450625,2569994100,980381355,4109958455,2819808352,2716589560,2568741196,3681446669,3329971472,1835478071,660984891,3704678404,4045999559,3422617507,3040415634,1762651403,1719377915,3470491036,2693910283,3642056355,3138596744,1364962596,2073328063,1983633131,926494387,3423689081,2150032023,4096667949,1749200295,3328846651,309677260, -2016342300,1779581495,3079819751,111262694,1274766160,443224088,298511866,1025883608,3806446537,1145181785,168956806,3641502830,3584813610,1689216846,3666258015,3200248200,1692713982,2646376535,4042768518,1618508792,1610833997,3523052358,4130873264,2001055236,3610705100,2202168115,4028541809,2961195399,1006657119,2006996926,3186142756,1430667929,3210227297,1314452623,4074634658,4101304120,2273951170,1399257539,3367210612,3027628629,1190975929,2062231137,2333990788,2221543033,2438960610,1181637006, -548689776,2362791313,3372408396,3104550113,3145860560,296247880,1970579870,3078560182,3769228297,1714227617,3291629107,3898220290,166772364,1251581989,493813264,448347421,195405023,2709975567,677966185,3703036547,1463355134,2715995803,1338867538,1343315457,2802222074,2684532164,233230375,2599980071,2000651841,3277868038,1638401717,4028070440,3237316320,6314154,819756386,300326615,590932579,1405279636,3267499572,3150704214,2428286686,3959192993,3461946742,1862657033,1266418056,963775037,2089974820, -2263052895,1917689273,448879540,3550394620,3981727096,150775221,3627908307,1303187396,508620638,2975983352,2726630617,1817252668,1876281319,1457606340,908771278,3720792119,3617206836,2455994898,1729034894,1080033504],[976866871,3556439503,2881648439,1522871579,1555064734,1336096578,3548522304,2579274686,3574697629,3205460757,3593280638,3338716283,3079412587,564236357,2993598910,1781952180,1464380207,3163844217,3332601554,1699332808,1393555694,1183702653,3581086237,1288719814,691649499,2847557200, -2895455976,3193889540,2717570544,1781354906,1676643554,2592534050,3230253752,1126444790,2770207658,2633158820,2210423226,2615765581,2414155088,3127139286,673620729,2805611233,1269405062,4015350505,3341807571,4149409754,1057255273,2012875353,2162469141,2276492801,2601117357,993977747,3918593370,2654263191,753973209,36408145,2530585658,25011837,3520020182,2088578344,530523599,2918365339,1524020338,1518925132,3760827505,3759777254,1202760957,3985898139,3906192525,674977740,4174734889,2031300136,2019492241, -3983892565,4153806404,3822280332,352677332,2297720250,60907813,90501309,3286998549,1016092578,2535922412,2839152426,457141659,509813237,4120667899,652014361,1966332200,2975202805,55981186,2327461051,676427537,3255491064,2882294119,3433927263,1307055953,942726286,933058658,2468411793,3933900994,4215176142,1361170020,2001714738,2830558078,3274259782,1222529897,1679025792,2729314320,3714953764,1770335741,151462246,3013232138,1682292957,1483529935,471910574,1539241949,458788160,3436315007,1807016891, -3718408830,978976581,1043663428,3165965781,1927990952,4200891579,2372276910,3208408903,3533431907,1412390302,2931980059,4132332400,1947078029,3881505623,4168226417,2941484381,1077988104,1320477388,886195818,18198404,3786409E3,2509781533,112762804,3463356488,1866414978,891333506,18488651,661792760,1628790961,3885187036,3141171499,876946877,2693282273,1372485963,791857591,2686433993,3759982718,3167212022,3472953795,2716379847,445679433,3561995674,3504004811,3574258232,54117162,3331405415,2381918588, -3769707343,4154350007,1140177722,4074052095,668550556,3214352940,367459370,261225585,2610173221,4209349473,3468074219,3265815641,314222801,3066103646,3808782860,282218597,3406013506,3773591054,379116347,1285071038,846784868,2669647154,3771962079,3550491691,2305946142,453669953,1268987020,3317592352,3279303384,3744833421,2610507566,3859509063,266596637,3847019092,517658769,3462560207,3443424879,370717030,4247526661,2224018117,4143653529,4112773975,2788324899,2477274417,1456262402,2901442914,1517677493, -1846949527,2295493580,3734397586,2176403920,1280348187,1908823572,3871786941,846861322,1172426758,3287448474,3383383037,1655181056,3139813346,901632758,1897031941,2986607138,3066810236,3447102507,1393639104,373351379,950779232,625454576,3124240540,4148612726,2007998917,544563296,2244738638,2330496472,2058025392,1291430526,424198748,50039436,29584100,3605783033,2429876329,2791104160,1057563949,3255363231,3075367218,3463963227,1469046755,985887462]]; -Blowfish.prototype.PARRAY=[608135816,2242054355,320440878,57701188,2752067618,698298832,137296536,3964562569,1160258022,953160567,3193202383,887688300,3232508343,3380367581,1065670069,3041331479,2450970073,2306472731];Blowfish.prototype.NN=16;Blowfish.prototype._clean=function(b){0>b&&(b=(b&2147483647)+2147483648);return b};Blowfish.prototype._F=function(b){var a,c,d;d=b&255;b>>>=8;c=b&255;b>>>=8;a=b&255;b=this.sboxes[0][b>>>8&255]+this.sboxes[1][a];b^=this.sboxes[2][c];return b+=this.sboxes[3][d]}; -Blowfish.prototype._encrypt_block=function(b){var a=b[0],c=b[1],d;for(d=0;d>>24-8*a&255,b[a+d]=c[1]>>>24-8*a&255;return b}; -Blowfish.prototype._decrypt_block=function(b){var a=b[0],c=b[1],d;for(d=this.NN+1;1e;++e)d=d<<8|b[c]&255,++c>=b.length&&(c=0);this.parray[a]=this.PARRAY[a]^d}this.sboxes=[];for(a=0;4>a;++a){this.sboxes[a]=[];for(c=0;256>c;++c)this.sboxes[a][c]=this.SBOXES[a][c]}b=[0,0];for(a=0;aa;++a)for(c=0;256>c;c+=2)this._encrypt_block(b),this.sboxes[a][c+0]=b[0],this.sboxes[a][c+1]=b[1]}; -function BFencrypt(b,a){var c=new Blowfish;c.init(util.str2bin(a));return c.encrypt_block(b)}function cast5_encrypt(b,a){var c=new openpgp_symenc_cast5;c.setKey(util.str2bin(a));return c.encrypt(b)} -function openpgp_symenc_cast5(){function b(a,b,c){a=b+a;c=a<>>32-c;return(f[0][c>>>24]^f[1][c>>>16&255])-f[2][c>>>8&255]+f[3][c&255]}function a(a,b,c){a^=b;c=a<>>32-c;return f[0][c>>>24]-f[1][c>>>16&255]+f[2][c>>>8&255]^f[3][c&255]}function c(a,b,c){a=b-a;c=a<>>32-c;return(f[0][c>>>24]+f[1][c>>>16&255]^f[2][c>>>8&255])-f[3][c&255]}this.BlockSize=8;this.KeySize=16;this.setKey=function(a){this.masking=Array(16);this.rotate=Array(16);this.reset();if(a.length==this.KeySize)this.keySchedule(a); -else return util.print_error("cast5.js: CAST-128: keys must be 16 bytes"),!1;return!0};this.reset=function(){for(var a=0;16>a;a++)this.masking[a]=0,this.rotate[a]=0};this.getBlockSize=function(){return BlockSize};this.encrypt=function(d){for(var e=Array(d.length),f=0;f>>24&255;e[f+1]=l>>>16&255;e[f+2]=l>>>8&255;e[f+3]=l&255;e[f+4]=k>>>24&255;e[f+5]=k>>>16&255;e[f+6]=k>>>8&255;e[f+7]=k&255}return e};this.decrypt=function(d){for(var e=Array(d.length),f=0;f>>24&255;e[f+1]=l>>>16&255;e[f+2]=l>>>8&255;e[f+3]=l&255;e[f+4]=k>>>24&255;e[f+5]=k>>16&255;e[f+6]=k>>8&255;e[f+7]=k&255}return e};var d=Array(4);d[0]=Array(4);d[0][0]=[4,0,13,15,12,14,8];d[0][1]=[5,2,16,18,17,19,10];d[0][2]=[6,3,23,22,21,20,9];d[0][3]=[7,1,26,25,27,24,11];d[1]=Array(4);d[1][0]=[0, -6,21,23,20,22,16];d[1][1]=[1,4,0,2,1,3,18];d[1][2]=[2,5,7,6,5,4,17];d[1][3]=[3,7,10,9,11,8,19];d[2]=Array(4);d[2][0]=[4,0,13,15,12,14,8];d[2][1]=[5,2,16,18,17,19,10];d[2][2]=[6,3,23,22,21,20,9];d[2][3]=[7,1,26,25,27,24,11];d[3]=Array(4);d[3][0]=[0,6,21,23,20,22,16];d[3][1]=[1,4,0,2,1,3,18];d[3][2]=[2,5,7,6,5,4,17];d[3][3]=[3,7,10,9,11,8,19];var e=Array(4);e[0]=Array(4);e[0][0]=[24,25,23,22,18];e[0][1]=[26,27,21,20,22];e[0][2]=[28,29,19,18,25];e[0][3]=[30,31,17,16,28];e[1]=Array(4);e[1][0]=[3,2,12, -13,8];e[1][1]=[1,0,14,15,13];e[1][2]=[7,6,8,9,3];e[1][3]=[5,4,10,11,7];e[2]=Array(4);e[2][0]=[19,18,28,29,25];e[2][1]=[17,16,30,31,28];e[2][2]=[23,22,24,25,18];e[2][3]=[21,20,26,27,22];e[3]=Array(4);e[3][0]=[8,9,7,6,3];e[3][1]=[10,11,5,4,7];e[3][2]=[12,13,3,2,8];e[3][3]=[14,15,1,0,13];this.keySchedule=function(a){for(var b=Array(8),c=Array(32),k=0;4>k;k++){var l=4*k;b[k]=a[l]<<24|a[l+1]<<16|a[l+2]<<8|a[l+3]}for(var a=[6,7,4,5],m=k=0;2>m;m++)for(var r=0;4>r;r++){for(l=0;4>l;l++){var p=d[r][l],o=b[p[1]], -o=o^f[4][b[p[2]>>>2]>>>24-8*(p[2]&3)&255],o=o^f[5][b[p[3]>>>2]>>>24-8*(p[3]&3)&255],o=o^f[6][b[p[4]>>>2]>>>24-8*(p[4]&3)&255],o=o^f[7][b[p[5]>>>2]>>>24-8*(p[5]&3)&255],o=o^f[a[l]][b[p[6]>>>2]>>>24-8*(p[6]&3)&255];b[p[0]]=o}for(l=0;4>l;l++)p=e[r][l],o=f[4][b[p[0]>>>2]>>>24-8*(p[0]&3)&255],o^=f[5][b[p[1]>>>2]>>>24-8*(p[1]&3)&255],o^=f[6][b[p[2]>>>2]>>>24-8*(p[2]&3)&255],o^=f[7][b[p[3]>>>2]>>>24-8*(p[3]&3)&255],o^=f[4+l][b[p[4]>>>2]>>>24-8*(p[4]&3)&255],c[k]=o,k++}for(k=0;16>k;k++)this.masking[k]=c[k], -this.rotate[k]=c[16+k]&31};var f=Array(8);f[0]=[821772500,2678128395,1810681135,1059425402,505495343,2617265619,1610868032,3483355465,3218386727,2294005173,3791863952,2563806837,1852023008,365126098,3269944861,584384398,677919599,3229601881,4280515016,2002735330,1136869587,3744433750,2289869850,2731719981,2714362070,879511577,1639411079,575934255,717107937,2857637483,576097850,2731753936,1725645E3,2810460463,5111599,767152862,2543075244,1251459544,1383482551,3052681127,3089939183,3612463449,1878520045, -1510570527,2189125840,2431448366,582008916,3163445557,1265446783,1354458274,3529918736,3202711853,3073581712,3912963487,3029263377,1275016285,4249207360,2905708351,3304509486,1442611557,3585198765,2712415662,2731849581,3248163920,2283946226,208555832,2766454743,1331405426,1447828783,3315356441,3108627284,2957404670,2981538698,3339933917,1669711173,286233437,1465092821,1782121619,3862771680,710211251,980974943,1651941557,430374111,2051154026,704238805,4128970897,3144820574,2857402727,948965521,3333752299, -2227686284,718756367,2269778983,2731643755,718440111,2857816721,3616097120,1113355533,2478022182,410092745,1811985197,1944238868,2696854588,1415722873,1682284203,1060277122,1998114690,1503841958,82706478,2315155686,1068173648,845149890,2167947013,1768146376,1993038550,3566826697,3390574031,940016341,3355073782,2328040721,904371731,1205506512,4094660742,2816623006,825647681,85914773,2857843460,1249926541,1417871568,3287612,3211054559,3126306446,1975924523,1353700161,2814456437,2438597621,1800716203, -722146342,2873936343,1151126914,4160483941,2877670899,458611604,2866078500,3483680063,770352098,2652916994,3367839148,3940505011,3585973912,3809620402,718646636,2504206814,2914927912,3631288169,2857486607,2860018678,575749918,2857478043,718488780,2069512688,3548183469,453416197,1106044049,3032691430,52586708,3378514636,3459808877,3211506028,1785789304,218356169,3571399134,3759170522,1194783844,1523787992,3007827094,1975193539,2555452411,1341901877,3045838698,3776907964,3217423946,2802510864,2889438986, -1057244207,1636348243,3761863214,1462225785,2632663439,481089165,718503062,24497053,3332243209,3344655856,3655024856,3960371065,1195698900,2971415156,3710176158,2115785917,4027663609,3525578417,2524296189,2745972565,3564906415,1372086093,1452307862,2780501478,1476592880,3389271281,18495466,2378148571,901398090,891748256,3279637769,3157290713,2560960102,1447622437,4284372637,216884176,2086908623,1879786977,3588903153,2242455666,2938092967,3559082096,2810645491,758861177,1121993112,215018983,642190776, -4169236812,1196255959,2081185372,3508738393,941322904,4124243163,2877523539,1848581667,2205260958,3180453958,2589345134,3694731276,550028657,2519456284,3789985535,2973870856,2093648313,443148163,46942275,2734146937,1117713533,1115362972,1523183689,3717140224,1551984063];f[1]=[522195092,4010518363,1776537470,960447360,4267822970,4005896314,1435016340,1929119313,2913464185,1310552629,3579470798,3724818106,2579771631,1594623892,417127293,2715217907,2696228731,1508390405,3994398868,3925858569,3695444102, -4019471449,3129199795,3770928635,3520741761,990456497,4187484609,2783367035,21106139,3840405339,631373633,3783325702,532942976,396095098,3548038825,4267192484,2564721535,2011709262,2039648873,620404603,3776170075,2898526339,3612357925,4159332703,1645490516,223693667,1567101217,3362177881,1029951347,3470931136,3570957959,1550265121,119497089,972513919,907948164,3840628539,1613718692,3594177948,465323573,2659255085,654439692,2575596212,2699288441,3127702412,277098644,624404830,4100943870,2717858591, -546110314,2403699828,3655377447,1321679412,4236791657,1045293279,4010672264,895050893,2319792268,494945126,1914543101,2777056443,3894764339,2219737618,311263384,4275257268,3458730721,669096869,3584475730,3835122877,3319158237,3949359204,2005142349,2713102337,2228954793,3769984788,569394103,3855636576,1425027204,108000370,2736431443,3671869269,3043122623,1750473702,2211081108,762237499,3972989403,2798899386,3061857628,2943854345,867476300,964413654,1591880597,1594774276,2179821409,552026980,3026064248, -3726140315,2283577634,3110545105,2152310760,582474363,1582640421,1383256631,2043843868,3322775884,1217180674,463797851,2763038571,480777679,2718707717,2289164131,3118346187,214354409,200212307,3810608407,3025414197,2674075964,3997296425,1847405948,1342460550,510035443,4080271814,815934613,833030224,1620250387,1945732119,2703661145,3966000196,1388869545,3456054182,2687178561,2092620194,562037615,1356438536,3409922145,3261847397,1688467115,2150901366,631725691,3840332284,549916902,3455104640,394546491, -837744717,2114462948,751520235,2221554606,2415360136,3999097078,2063029875,803036379,2702586305,821456707,3019566164,360699898,4018502092,3511869016,3677355358,2402471449,812317050,49299192,2570164949,3259169295,2816732080,3331213574,3101303564,2156015656,3705598920,3546263921,143268808,3200304480,1638124008,3165189453,3341807610,578956953,2193977524,3638120073,2333881532,807278310,658237817,2969561766,1641658566,11683945,3086995007,148645947,1138423386,4158756760,1981396783,2401016740,3699783584, -380097457,2680394679,2803068651,3334260286,441530178,4016580796,1375954390,761952171,891809099,2183123478,157052462,3683840763,1592404427,341349109,2438483839,1417898363,644327628,2233032776,2353769706,2201510100,220455161,1815641738,182899273,2995019788,3627381533,3702638151,2890684138,1052606899,588164016,1681439879,4038439418,2405343923,4229449282,167996282,1336969661,1688053129,2739224926,1543734051,1046297529,1138201970,2121126012,115334942,1819067631,1902159161,1941945968,2206692869,1159982321]; -f[2]=[2381300288,637164959,3952098751,3893414151,1197506559,916448331,2350892612,2932787856,3199334847,4009478890,3905886544,1373570990,2450425862,4037870920,3778841987,2456817877,286293407,124026297,3001279700,1028597854,3115296800,4208886496,2691114635,2188540206,1430237888,1218109995,3572471700,308166588,570424558,2187009021,2455094765,307733056,1310360322,3135275007,1384269543,2388071438,863238079,2359263624,2801553128,3380786597,2831162807,1470087780,1728663345,4072488799,1090516929,532123132, -2389430977,1132193179,2578464191,3051079243,1670234342,1434557849,2711078940,1241591150,3314043432,3435360113,3091448339,1812415473,2198440252,267246943,796911696,3619716990,38830015,1526438404,2806502096,374413614,2943401790,1489179520,1603809326,1920779204,168801282,260042626,2358705581,1563175598,2397674057,1356499128,2217211040,514611088,2037363785,2186468373,4022173083,2792511869,2913485016,1173701892,4200428547,3896427269,1334932762,2455136706,602925377,2835607854,1613172210,41346230,2499634548, -2457437618,2188827595,41386358,4172255629,1313404830,2405527007,3801973774,2217704835,873260488,2528884354,2478092616,4012915883,2555359016,2006953883,2463913485,575479328,2218240648,2099895446,660001756,2341502190,3038761536,3888151779,3848713377,3286851934,1022894237,1620365795,3449594689,1551255054,15374395,3570825345,4249311020,4151111129,3181912732,310226346,1133119310,530038928,136043402,2476768958,3107506709,2544909567,1036173560,2367337196,1681395281,1758231547,3641649032,306774401,1575354324, -3716085866,1990386196,3114533736,2455606671,1262092282,3124342505,2768229131,4210529083,1833535011,423410938,660763973,2187129978,1639812E3,3508421329,3467445492,310289298,272797111,2188552562,2456863912,310240523,677093832,1013118031,901835429,3892695601,1116285435,3036471170,1337354835,243122523,520626091,277223598,4244441197,4194248841,1766575121,594173102,316590669,742362309,3536858622,4176435350,3838792410,2501204839,1229605004,3115755532,1552908988,2312334149,979407927,3959474601,1148277331, -176638793,3614686272,2083809052,40992502,1340822838,2731552767,3535757508,3560899520,1354035053,122129617,7215240,2732932949,3118912700,2718203926,2539075635,3609230695,3725561661,1928887091,2882293555,1988674909,2063640240,2491088897,1459647954,4189817080,2302804382,1113892351,2237858528,1927010603,4002880361,1856122846,1594404395,2944033133,3855189863,3474975698,1643104450,4054590833,3431086530,1730235576,2984608721,3084664418,2131803598,4178205752,267404349,1617849798,1616132681,1462223176,736725533, -2327058232,551665188,2945899023,1749386277,2575514597,1611482493,674206544,2201269090,3642560800,728599968,1680547377,2620414464,1388111496,453204106,4156223445,1094905244,2754698257,2201108165,3757000246,2704524545,3922940700,3996465027];f[3]=[2645754912,532081118,2814278639,3530793624,1246723035,1689095255,2236679235,4194438865,2116582143,3859789411,157234593,2045505824,4245003587,1687664561,4083425123,605965023,672431967,1336064205,3376611392,214114848,4258466608,3232053071,489488601,605322005, -3998028058,264917351,1912574028,756637694,436560991,202637054,135989450,85393697,2152923392,3896401662,2895836408,2145855233,3535335007,115294817,3147733898,1922296357,3464822751,4117858305,1037454084,2725193275,2127856640,1417604070,1148013728,1827919605,642362335,2929772533,909348033,1346338451,3547799649,297154785,1917849091,4161712827,2883604526,3968694238,1469521537,3780077382,3375584256,1763717519,136166297,4290970789,1295325189,2134727907,2798151366,1566297257,3672928234,2677174161,2672173615, -965822077,2780786062,289653839,1133871874,3491843819,35685304,1068898316,418943774,672553190,642281022,2346158704,1954014401,3037126780,4079815205,2030668546,3840588673,672283427,1776201016,359975446,3750173538,555499703,2769985273,1324923,69110472,152125443,3176785106,3822147285,1340634837,798073664,1434183902,15393959,216384236,1303690150,3881221631,3711134124,3960975413,106373927,2578434224,1455997841,1801814300,1578393881,1854262133,3188178946,3258078583,2302670060,1539295533,3505142565,3078625975, -2372746020,549938159,3278284284,2620926080,181285381,2865321098,3970029511,68876850,488006234,1728155692,2608167508,836007927,2435231793,919367643,3339422534,3655756360,1457871481,40520939,1380155135,797931188,234455205,2255801827,3990488299,397000196,739833055,3077865373,2871719860,4022553888,772369276,390177364,3853951029,557662966,740064294,1640166671,1699928825,3535942136,622006121,3625353122,68743880,1742502,219489963,1664179233,1577743084,1236991741,410585305,2366487942,823226535,1050371084, -3426619607,3586839478,212779912,4147118561,1819446015,1911218849,530248558,3486241071,3252585495,2886188651,3410272728,2342195030,20547779,2982490058,3032363469,3631753222,312714466,1870521650,1493008054,3491686656,615382978,4103671749,2534517445,1932181,2196105170,278426614,6369430,3274544417,2913018367,697336853,2143000447,2946413531,701099306,1558357093,2805003052,3500818408,2321334417,3567135975,216290473,3591032198,23009561,1996984579,3735042806,2024298078,3739440863,569400510,2339758983,3016033873, -3097871343,3639523026,3844324983,3256173865,795471839,2951117563,4101031090,4091603803,3603732598,971261452,534414648,428311343,3389027175,2844869880,694888862,1227866773,2456207019,3043454569,2614353370,3749578031,3676663836,459166190,4132644070,1794958188,51825668,2252611902,3084671440,2036672799,3436641603,1099053433,2469121526,3059204941,1323291266,2061838604,1018778475,2233344254,2553501054,334295216,3556750194,1065731521,183467730];f[4]=[2127105028,745436345,2601412319,2788391185,3093987327, -500390133,1155374404,389092991,150729210,3891597772,3523549952,1935325696,716645080,946045387,2901812282,1774124410,3869435775,4039581901,3293136918,3438657920,948246080,363898952,3867875531,1286266623,1598556673,68334250,630723836,1104211938,1312863373,613332731,2377784574,1101634306,441780740,3129959883,1917973735,2510624549,3238456535,2544211978,3308894634,1299840618,4076074851,1756332096,3977027158,297047435,3790297736,2265573040,3621810518,1311375015,1667687725,47300608,3299642885,2474112369, -201668394,1468347890,576830978,3594690761,3742605952,1958042578,1747032512,3558991340,1408974056,3366841779,682131401,1033214337,1545599232,4265137049,206503691,103024618,2855227313,1337551222,2428998917,2963842932,4015366655,3852247746,2796956967,3865723491,3747938335,247794022,3755824572,702416469,2434691994,397379957,851939612,2314769512,218229120,1380406772,62274761,214451378,3170103466,2276210409,3845813286,28563499,446592073,1693330814,3453727194,29968656,3093872512,220656637,2470637031,77972100, -1667708854,1358280214,4064765667,2395616961,325977563,4277240721,4220025399,3605526484,3355147721,811859167,3069544926,3962126810,652502677,3075892249,4132761541,3498924215,1217549313,3250244479,3858715919,3053989961,1538642152,2279026266,2875879137,574252750,3324769229,2651358713,1758150215,141295887,2719868960,3515574750,4093007735,4194485238,1082055363,3417560400,395511885,2966884026,179534037,3646028556,3738688086,1092926436,2496269142,257381841,3772900718,1636087230,1477059743,2499234752,3811018894, -2675660129,3285975680,90732309,1684827095,1150307763,1723134115,3237045386,1769919919,1240018934,815675215,750138730,2239792499,1234303040,1995484674,138143821,675421338,1145607174,1936608440,3238603024,2345230278,2105974004,323969391,779555213,3004902369,2861610098,1017501463,2098600890,2628620304,2940611490,2682542546,1171473753,3656571411,3687208071,4091869518,393037935,159126506,1662887367,1147106178,391545844,3452332695,1891500680,3016609650,1851642611,546529401,1167818917,3194020571,2848076033, -3953471836,575554290,475796850,4134673196,450035699,2351251534,844027695,1080539133,86184846,1554234488,3692025454,1972511363,2018339607,1491841390,1141460869,1061690759,4244549243,2008416118,2351104703,2868147542,1598468138,722020353,1027143159,212344630,1387219594,1725294528,3745187956,2500153616,458938280,4129215917,1828119673,544571780,3503225445,2297937496,1241802790,267843827,2694610800,1397140384,1558801448,3782667683,1806446719,929573330,2234912681,400817706,616011623,4121520928,3603768725, -1761550015,1968522284,4053731006,4192232858,4005120285,872482584,3140537016,3894607381,2287405443,1963876937,3663887957,1584857E3,2975024454,1833426440,4025083860];f[5]=[4143615901,749497569,1285769319,3795025788,2514159847,23610292,3974978748,844452780,3214870880,3751928557,2213566365,1676510905,448177848,3730751033,4086298418,2307502392,871450977,3222878141,4110862042,3831651966,2735270553,1310974780,2043402188,1218528103,2736035353,4274605013,2702448458,3936360550,2693061421,162023535,2827510090, -687910808,23484817,3784910947,3371371616,779677500,3503626546,3473927188,4157212626,3500679282,4248902014,2466621104,3899384794,1958663117,925738300,1283408968,3669349440,1840910019,137959847,2679828185,1239142320,1315376211,1547541505,1690155329,739140458,3128809933,3933172616,3876308834,905091803,1548541325,4040461708,3095483362,144808038,451078856,676114313,2861728291,2469707347,993665471,373509091,2599041286,4025009006,4170239449,2149739950,3275793571,3749616649,2794760199,1534877388,572371878, -2590613551,1753320020,3467782511,1405125690,4270405205,633333386,3026356924,3475123903,632057672,2846462855,1404951397,3882875879,3915906424,195638627,2385783745,3902872553,1233155085,3355999740,2380578713,2702246304,2144565621,3663341248,3894384975,2502479241,4248018925,3094885567,1594115437,572884632,3385116731,767645374,1331858858,1475698373,3793881790,3532746431,1321687957,619889600,1121017241,3440213920,2070816767,2833025776,1933951238,4095615791,890643334,3874130214,859025556,360630002,925594799, -1764062180,3920222280,4078305929,979562269,2810700344,4087740022,1949714515,546639971,1165388173,3069891591,1495988560,922170659,1291546247,2107952832,1813327274,3406010024,3306028637,4241950635,153207855,2313154747,1608695416,1150242611,1967526857,721801357,1220138373,3691287617,3356069787,2112743302,3281662835,1111556101,1778980689,250857638,2298507990,673216130,2846488510,3207751581,3562756981,3008625920,3417367384,2198807050,529510932,3547516680,3426503187,2364944742,102533054,2294910856,1617093527, -1204784762,3066581635,1019391227,1069574518,1317995090,1691889997,3661132003,510022745,3238594800,1362108837,1817929911,2184153760,805817662,1953603311,3699844737,120799444,2118332377,207536705,2282301548,4120041617,145305846,2508124933,3086745533,3261524335,1877257368,2977164480,3160454186,2503252186,4221677074,759945014,254147243,2767453419,3801518371,629083197,2471014217,907280572,3900796746,940896768,2751021123,2625262786,3161476951,3661752313,3260732218,1425318020,2977912069,1496677566,3988592072, -2140652971,3126511541,3069632175,977771578,1392695845,1698528874,1411812681,1369733098,1343739227,3620887944,1142123638,67414216,3102056737,3088749194,1626167401,2546293654,3941374235,697522451,33404913,143560186,2595682037,994885535,1247667115,3859094837,2699155541,3547024625,4114935275,2968073508,3199963069,2732024527,1237921620,951448369,1898488916,1211705605,2790989240,2233243581,3598044975];f[6]=[2246066201,858518887,1714274303,3485882003,713916271,2879113490,3730835617,539548191,36158695,1298409750, -419087104,1358007170,749914897,2989680476,1261868530,2995193822,2690628854,3443622377,3780124940,3796824509,2976433025,4259637129,1551479E3,512490819,1296650241,951993153,2436689437,2460458047,144139966,3136204276,310820559,3068840729,643875328,1969602020,1680088954,2185813161,3283332454,672358534,198762408,896343282,276269502,3014846926,84060815,197145886,376173866,3943890818,3813173521,3545068822,1316698879,1598252827,2633424951,1233235075,859989710,2358460855,3503838400,3409603720,1203513385,1193654839, -2792018475,2060853022,207403770,1144516871,3068631394,1121114134,177607304,3785736302,326409831,1929119770,2983279095,4183308101,3474579288,3200513878,3228482096,119610148,1170376745,3378393471,3163473169,951863017,3337026068,3135789130,2907618374,1183797387,2015970143,4045674555,2182986399,2952138740,3928772205,384012900,2454997643,10178499,2879818989,2596892536,111523738,2995089006,451689641,3196290696,235406569,1441906262,3890558523,3013735005,4158569349,1644036924,376726067,1006849064,3664579700, -2041234796,1021632941,1374734338,2566452058,371631263,4007144233,490221539,206551450,3140638584,1053219195,1853335209,3412429660,3562156231,735133835,1623211703,3104214392,2738312436,4096837757,3366392578,3110964274,3956598718,3196820781,2038037254,3877786376,2339753847,300912036,3766732888,2372630639,1516443558,4200396704,1574567987,4069441456,4122592016,2699739776,146372218,2748961456,2043888151,35287437,2596680554,655490400,1132482787,110692520,1031794116,2188192751,1324057718,1217253157,919197030, -686247489,3261139658,1028237775,3135486431,3059715558,2460921700,986174950,2661811465,4062904701,2752986992,3709736643,367056889,1353824391,731860949,1650113154,1778481506,784341916,357075625,3608602432,1074092588,2480052770,3811426202,92751289,877911070,3600361838,1231880047,480201094,3756190983,3094495953,434011822,87971354,363687820,1717726236,1901380172,3926403882,2481662265,400339184,1490350766,2661455099,1389319756,2558787174,784598401,1983468483,30828846,3550527752,2716276238,3841122214,1765724805, -1955612312,1277890269,1333098070,1564029816,2704417615,1026694237,3287671188,1260819201,3349086767,1016692350,1582273796,1073413053,1995943182,694588404,1025494639,3323872702,3551898420,4146854327,453260480,1316140391,1435673405,3038941953,3486689407,1622062951,403978347,817677117,950059133,4246079218,3278066075,1486738320,1417279718,481875527,2549965225,3933690356,760697757,1452955855,3897451437,1177426808,1702951038,4085348628,2447005172,1084371187,3516436277,3068336338,1073369276,1027665953,3284188590, -1230553676,1368340146,2226246512,267243139,2274220762,4070734279,2497715176,2423353163,2504755875];f[7]=[3793104909,3151888380,2817252029,895778965,2005530807,3871412763,237245952,86829237,296341424,3851759377,3974600970,2475086196,709006108,1994621201,2972577594,937287164,3734691505,168608556,3189338153,2225080640,3139713551,3033610191,3025041904,77524477,185966941,1208824168,2344345178,1721625922,3354191921,1066374631,1927223579,1971335949,2483503697,1551748602,2881383779,2856329572,3003241482, -48746954,1398218158,2050065058,313056748,4255789917,393167848,1912293076,940740642,3465845460,3091687853,2522601570,2197016661,1727764327,364383054,492521376,1291706479,3264136376,1474851438,1685747964,2575719748,1619776915,1814040067,970743798,1561002147,2925768690,2123093554,1880132620,3151188041,697884420,2550985770,2607674513,2659114323,110200136,1489731079,997519150,1378877361,3527870668,478029773,2766872923,1022481122,431258168,1112503832,897933369,2635587303,669726182,3383752315,918222264, -163866573,3246985393,3776823163,114105080,1903216136,761148244,3571337562,1690750982,3166750252,1037045171,1888456500,2010454850,642736655,616092351,365016990,1185228132,4174898510,1043824992,2023083429,2241598885,3863320456,3279669087,3674716684,108438443,2132974366,830746235,606445527,4173263986,2204105912,1844756978,2532684181,4245352700,2969441100,3796921661,1335562986,4061524517,2720232303,2679424040,634407289,885462008,3294724487,3933892248,2094100220,339117932,4048830727,3202280980,1458155303, -2689246273,1022871705,2464987878,3714515309,353796843,2822958815,4256850100,4052777845,551748367,618185374,3778635579,4020649912,1904685140,3069366075,2670879810,3407193292,2954511620,4058283405,2219449317,3135758300,1120655984,3447565834,1474845562,3577699062,550456716,3466908712,2043752612,881257467,869518812,2005220179,938474677,3305539448,3850417126,1315485940,3318264702,226533026,965733244,321539988,1136104718,804158748,573969341,3708209826,937399083,3290727049,2901666755,1461057207,4013193437, -4066861423,3242773476,2421326174,1581322155,3028952165,786071460,3900391652,3918438532,1485433313,4023619836,3708277595,3678951060,953673138,1467089153,1930354364,1533292819,2492563023,1346121658,1685000834,1965281866,3765933717,4190206607,2052792609,3515332758,690371149,3125873887,2180283551,2903598061,3933952357,436236910,289419410,14314871,1242357089,2904507907,1616633776,2666382180,585885352,3471299210,2699507360,1432659641,277164553,3354103607,770115018,2303809295,3741942315,3177781868,2853364978, -2269453327,3774259834,987383833,1290892879,225909803,1741533526,890078084,1496906255,1111072499,916028167,243534141,1252605537,2204162171,531204876,290011180,3916834213,102027703,237315147,209093447,1486785922,220223953,2758195998,4175039106,82940208,3127791296,2569425252,518464269,1353887104,3941492737,2377294467,3935040926]} -function desede(b,a){var c=a.substring(0,8),d=a.substring(8,16),e=a.substring(16,24);return util.str2bin(des(des_createKeys(e),des(des_createKeys(d),des(des_createKeys(c),util.bin2str(b),!0,0,null,null),!1,0,null,null),!0,0,null,null))} -function des(b,a,c,d,e,f){var g=[16843776,0,65536,16843780,16842756,66564,4,65536,1024,16843776,16843780,1024,16778244,16842756,16777216,4,1028,16778240,16778240,66560,66560,16842752,16842752,16778244,65540,16777220,16777220,65540,0,1028,66564,16777216,65536,16843780,4,16842752,16843776,16777216,16777216,1024,16842756,65536,66560,16777220,1024,4,16778244,66564,16843780,65540,16842752,16778244,16777220,1028,66564,16843776,1028,16778240,16778240,0,65540,66560,0,16842756],h=[-2146402272,-2147450880, -32768,1081376,1048576,32,-2146435040,-2147450848,-2147483616,-2146402272,-2146402304,-2147483648,-2147450880,1048576,32,-2146435040,1081344,1048608,-2147450848,0,-2147483648,32768,1081376,-2146435072,1048608,-2147483616,0,1081344,32800,-2146402304,-2146435072,32800,0,1081376,-2146435040,1048576,-2147450848,-2146435072,-2146402304,32768,-2146435072,-2147450880,32,-2146402272,1081376,32,32768,-2147483648,32800,-2146402304,1048576,-2147483616,1048608,-2147450848,-2147483616,1048608,1081344,0,-2147450880, -32800,-2147483648,-2146435040,-2146402272,1081344],j=[520,134349312,0,134348808,134218240,0,131592,134218240,131080,134217736,134217736,131072,134349320,131080,134348800,520,134217728,8,134349312,512,131584,134348800,134348808,131592,134218248,131584,131072,134218248,8,134349320,512,134217728,134349312,134217728,131080,520,131072,134349312,134218240,0,512,131080,134349320,134218240,134217736,512,0,134348808,134218248,131072,134217728,134349320,8,131592,131584,134217736,134348800,134218248,520,134348800, -131592,8,134348808,131584],k=[8396801,8321,8321,128,8396928,8388737,8388609,8193,0,8396800,8396800,8396929,129,0,8388736,8388609,1,8192,8388608,8396801,128,8388608,8193,8320,8388737,1,8320,8388736,8192,8396928,8396929,129,8388736,8388609,8396800,8396929,129,0,0,8396800,8320,8388736,8388737,1,8396801,8321,8321,128,8396929,129,1,8192,8388609,8193,8396928,8388737,8193,8320,8388608,8396801,128,8388608,8192,8396928],l=[256,34078976,34078720,1107296512,524288,256,1073741824,34078720,1074266368,524288,33554688, -1074266368,1107296512,1107820544,524544,1073741824,33554432,1074266112,1074266112,0,1073742080,1107820800,1107820800,33554688,1107820544,1073742080,0,1107296256,34078976,33554432,1107296256,524544,524288,1107296512,256,33554432,1073741824,34078720,1107296512,1074266368,33554688,1073741824,1107820544,34078976,1074266368,256,33554432,1107820544,1107820800,524544,1107296256,1107820800,34078720,0,1074266112,1107296256,524544,33554688,1073742080,524288,0,1074266112,34078976,1073742080],m=[536870928,541065216, -16384,541081616,541065216,16,541081616,4194304,536887296,4210704,4194304,536870928,4194320,536887296,536870912,16400,0,4194320,536887312,16384,4210688,536887312,16,541065232,541065232,0,4210704,541081600,16400,4210688,541081600,536870912,536887296,16,541065232,4210688,541081616,4194304,16400,536870928,4194304,536887296,536870912,16400,536870928,541081616,4210688,541065216,4210704,541081600,0,541065232,16,16384,541065216,4210704,16384,4194320,536887312,0,541081600,536870912,4194320,536887312],r=[2097152, -69206018,67110914,0,2048,67110914,2099202,69208064,69208066,2097152,0,67108866,2,67108864,69206018,2050,67110912,2099202,2097154,67110912,67108866,69206016,69208064,2097154,69206016,2048,2050,69208066,2099200,2,67108864,2099200,67108864,2099200,2097152,67110914,67110914,69206018,69206018,2,2097154,67108864,67110912,2097152,69208064,2050,2099202,69208064,2050,67108866,69208066,69206016,2099200,0,2,69208066,0,2099202,69206016,2048,67108866,67110912,2048,2097154],p=[268439616,4096,262144,268701760,268435456, -268439616,64,268435456,262208,268697600,268701760,266240,268701696,266304,4096,64,268697600,268435520,268439552,4160,266240,262208,268697664,268701696,4160,0,0,268697664,268435520,268439552,266304,262144,266304,262144,268701696,4096,64,268697664,4096,266304,268439552,64,268435520,268697600,268697664,268435456,262144,268439616,0,268701760,262208,268435520,268697600,268439552,268439616,0,268701760,266240,266240,4160,4160,262208,268435456,268701696],o=0,y,v,w,A,t,u,P,C,Q,E,x,z,V,K=a.length,D=0,B=32== -b.length?3:9;P=3==B?c?[0,32,2]:[30,-2,-2]:c?[0,32,2,62,30,-2,64,96,2]:[94,62,-2,32,64,2,30,-2,-2];if(c)a=des_addPadding(a,f),K=a.length;tempresult=result="";1==d&&(C=e.charCodeAt(o++)<<24|e.charCodeAt(o++)<<16|e.charCodeAt(o++)<<8|e.charCodeAt(o++),E=e.charCodeAt(o++)<<24|e.charCodeAt(o++)<<16|e.charCodeAt(o++)<<8|e.charCodeAt(o++),o=0);for(;o>>4^u)&252645135;u^=v;t^=v<<4;v=(t>>>16^u)&65535;u^=v;t^=v<<16;v=(u>>>2^t)&858993459;t^=v;u^=v<<2;v=(u>>>8^t)&16711935;t^=v;u^=v<<8;v=(t>>>1^u)&1431655765;u^=v;t^=v<<1;t=t<<1|t>>>31;u=u<<1|u>>>31;for(y=0;y>>4|u<<28)^b[e+1],v=t,t=u,u=v^(h[w>>>24&63]|k[w>>>16&63]|m[w>>>8&63]|p[w&63]|g[A>>>24&63]|j[A>>>16&63]|l[A>>>8&63]|r[A&63]);v=t;t=u;u=v}t=t>>>1|t<<31;u=u>>>1|u<<31;v=(t>>> -1^u)&1431655765;u^=v;t^=v<<1;v=(u>>>8^t)&16711935;t^=v;u^=v<<8;v=(u>>>2^t)&858993459;t^=v;u^=v<<2;v=(t>>>16^u)&65535;u^=v;t^=v<<16;v=(t>>>4^u)&252645135;u^=v;t^=v<<4;1==d&&(c?(C=t,E=u):(t^=Q,u^=x));tempresult+=String.fromCharCode(t>>>24,t>>>16&255,t>>>8&255,t&255,u>>>24,u>>>16&255,u>>>8&255,u&255);D+=8;512==D&&(result+=tempresult,tempresult="",D=0)}result+=tempresult;c||(result=des_removePadding(result,f));return result} -function des_createKeys(b){pc2bytes0=[0,4,536870912,536870916,65536,65540,536936448,536936452,512,516,536871424,536871428,66048,66052,536936960,536936964];pc2bytes1=[0,1,1048576,1048577,67108864,67108865,68157440,68157441,256,257,1048832,1048833,67109120,67109121,68157696,68157697];pc2bytes2=[0,8,2048,2056,16777216,16777224,16779264,16779272,0,8,2048,2056,16777216,16777224,16779264,16779272];pc2bytes3=[0,2097152,134217728,136314880,8192,2105344,134225920,136323072,131072,2228224,134348800,136445952, -139264,2236416,134356992,136454144];pc2bytes4=[0,262144,16,262160,0,262144,16,262160,4096,266240,4112,266256,4096,266240,4112,266256];pc2bytes5=[0,1024,32,1056,0,1024,32,1056,33554432,33555456,33554464,33555488,33554432,33555456,33554464,33555488];pc2bytes6=[0,268435456,524288,268959744,2,268435458,524290,268959746,0,268435456,524288,268959744,2,268435458,524290,268959746];pc2bytes7=[0,65536,2048,67584,536870912,536936448,536872960,536938496,131072,196608,133120,198656,537001984,537067520,537004032, -537069568];pc2bytes8=[0,262144,0,262144,2,262146,2,262146,33554432,33816576,33554432,33816576,33554434,33816578,33554434,33816578];pc2bytes9=[0,268435456,8,268435464,0,268435456,8,268435464,1024,268436480,1032,268436488,1024,268436480,1032,268436488];pc2bytes10=[0,32,0,32,1048576,1048608,1048576,1048608,8192,8224,8192,8224,1056768,1056800,1056768,1056800];pc2bytes11=[0,16777216,512,16777728,2097152,18874368,2097664,18874880,67108864,83886080,67109376,83886592,69206016,85983232,69206528,85983744]; -pc2bytes12=[0,4096,134217728,134221824,524288,528384,134742016,134746112,16,4112,134217744,134221840,524304,528400,134742032,134746128];pc2bytes13=[0,4,256,260,0,4,256,260,1,5,257,261,1,5,257,261];for(var a=8>>4^right)&252645135; -right^=j;left^=j<<4;j=(right>>>-16^left)&65535;left^=j;right^=j<<-16;j=(left>>>2^right)&858993459;right^=j;left^=j<<2;j=(right>>>-16^left)&65535;left^=j;right^=j<<-16;j=(left>>>1^right)&1431655765;right^=j;left^=j<<1;j=(right>>>8^left)&16711935;left^=j;right^=j<<8;j=(left>>>1^right)&1431655765;right^=j;left^=j<<1;j=left<<8|right>>>20&240;left=right<<24|right<<8&16711680|right>>>8&65280|right>>>24&240;right=j;for(i=0;i>>26,right=right<<2|right>>>26):(left=left<< -1|left>>>27,right=right<<1|right>>>27),left&=-15,right&=-15,e=pc2bytes0[left>>>28]|pc2bytes1[left>>>24&15]|pc2bytes2[left>>>20&15]|pc2bytes3[left>>>16&15]|pc2bytes4[left>>>12&15]|pc2bytes5[left>>>8&15]|pc2bytes6[left>>>4&15],f=pc2bytes7[right>>>28]|pc2bytes8[right>>>24&15]|pc2bytes9[right>>>20&15]|pc2bytes10[right>>>16&15]|pc2bytes11[right>>>12&15]|pc2bytes12[right>>>8&15]|pc2bytes13[right>>>4&15],j=(f>>>16^e)&65535,c[h++]=e^j,c[h++]=f^j<<16}return c} -function des_addPadding(b,a){var c=8-b.length%8;2==a&&8>c?b+=" ".substr(0,c):1==a?b+=String.fromCharCode(c,c,c,c,c,c,c,c).substr(0,c):!a&&8>c&&(b+="\x00\x00\x00\x00\x00\x00\x00\x00".substr(0,c));return b}function des_removePadding(b,a){if(2==a)b=b.replace(/ *$/g,"");else if(1==a)var c=b.charCodeAt(b.length-1),b=b.substr(0,b.length-c);else a||(b=b.replace(/\0*$/g,""));return b} -function TFencrypt(b,a){var c=[].concat(b),d=createTwofish();d.open(util.str2bin(a),0);c=d.encrypt(c,0);d.close();return c}var MAXINT=4294967295;function rotb(b,a){return(b<>>8-a)&255}function rotw(b,a){return(b<>>32-a)&MAXINT}function getW(b,a){return b[a]|b[a+1]<<8|b[a+2]<<16|b[a+3]<<24}function setW(b,a,c){b.splice(a,4,c&255,c>>>8&255,c>>>16&255,c>>>24&255)}function setWInv(b,a,c){b.splice(a,4,c>>>24&255,c>>>16&255,c>>>8&255,c&255)}function getB(b,a){return b>>>8*a&255} -function getNrBits(b){for(var a=0;0>>=1;return a}function getMask(b){return(1<d;d++)e=c>>>24,c=c<<8&MAXINT|a>>>24,a=a<<8&MAXINT,f=e<<1,e&128&&(f^=333),c^=e^f<<16,f^=e>>>1,e&1&&(f^=166),c^=f<<24|f<<8;return c}function d(a,b){var c,e,f;c=b>>4;e=b&15;f=t[a][c^ -e];c=u[a][Q[e]^E[c]];return C[a][Q[c]^E[f]]<<4|P[a][f^c]}function e(a,b){var c=getB(a,0),d=getB(a,1),f=getB(a,2),g=getB(a,3);switch(v){case 4:c=x[1][c]^getB(b[3],0),d=x[0][d]^getB(b[3],1),f=x[0][f]^getB(b[3],2),g=x[1][g]^getB(b[3],3);case 3:c=x[1][c]^getB(b[2],0),d=x[1][d]^getB(b[2],1),f=x[0][f]^getB(b[2],2),g=x[0][g]^getB(b[2],3);case 2:c=x[0][x[0][c]^getB(b[1],0)]^getB(b[0],0),d=x[0][x[1][d]^getB(b[1],1)]^getB(b[0],1),f=x[1][x[0][f]^getB(b[1],2)]^getB(b[0],2),g=x[1][x[1][g]^getB(b[1],3)]^getB(b[0], -3)}return z[0][c]^z[1][d]^z[2][f]^z[3][g]}c=a;var m,r,p,o;p=[];o=[];var y=[],v,w=[],A,t=[[8,1,7,13,6,15,3,2,0,11,5,9,14,12,10,4],[2,8,11,13,15,7,6,14,3,1,9,4,0,10,12,5]],u=[[14,12,11,8,1,2,3,5,15,4,10,6,7,0,9,13],[1,14,2,11,4,12,3,7,6,13,10,5,15,9,0,8]],P=[[11,10,5,14,6,13,9,0,12,8,15,3,2,4,7,1],[4,12,7,5,1,6,9,10,0,14,13,8,2,11,3,15]],C=[[13,7,15,4,1,2,6,14,9,11,3,0,8,5,12,10],[11,9,5,1,12,3,13,14,6,4,7,15,2,0,8,10]],Q=[0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15],E=[0,9,2,11,4,13,6,15,8,1,10,3,12,5,14, -7],x=[[],[]],z=[[],[],[],[]];c=c.slice(0,32);for(a=c.length;16!=a&&24!=a&&32!=a;)c[a++]=0;for(a=0;a>2]=getW(c,a);for(a=0;256>a;a++)x[0][a]=d(0,a),x[1][a]=d(1,a);for(a=0;256>a;a++)m=x[1][a],r=m^m>>2^[0,90,180,238][m&3],A=m^m>>1^m>>2^[0,238,180,90][m&3],z[0][a]=m+(r<<8)+(A<<16)+(A<<24),z[2][a]=r+(A<<8)+(m<<16)+(A<<24),m=x[0][a],r=m^m>>2^[0,90,180,238][m&3],A=m^m>>1^m>>2^[0,238,180,90][m&3],z[1][a]=A+(A<<8)+(r<<16)+(m<<24),z[3][a]=r+(m<<8)+(A<<16)+(r<<24);v=y.length/2;for(a=0;aa;a+=2)m=16843009*a,r=m+16843009,m=e(m,p),r=rotw(e(r,o),8),f[a]=m+r&MAXINT,f[a+1]=rotw(m+2*r,9);for(a=0;256>a;a++)switch(m=r=p=o=a,v){case 4:m=x[1][m]^getB(w[3],0),r=x[0][r]^getB(w[3],1),p=x[0][p]^getB(w[3],2),o=x[1][o]^getB(w[3],3);case 3:m=x[1][m]^getB(w[2],0),r=x[1][r]^getB(w[2],1),p=x[0][p]^getB(w[2],2),o=x[0][o]^getB(w[2],3);case 2:g[0][a]=z[0][x[0][x[0][m]^getB(w[1],0)]^getB(w[0],0)],g[1][a]=z[1][x[0][x[1][r]^getB(w[1],1)]^getB(w[0], -1)],g[2][a]=z[2][x[1][x[0][p]^getB(w[1],2)]^getB(w[0],2)],g[3][a]=z[3][x[1][x[1][o]^getB(w[1],3)]^getB(w[0],3)]}},close:function(){f=[];g=[[],[],[],[]]},encrypt:function(c,g){d=c;e=g;for(var k=[getW(d,e)^f[0],getW(d,e+4)^f[1],getW(d,e+8)^f[2],getW(d,e+12)^f[3]],l=0;8>l;l++){var m=l,r=k,p=b(r[0]),o=a(r[1]);r[2]=rotw(r[2]^p+o+f[4*m+8]&MAXINT,31);r[3]=rotw(r[3],1)^p+2*o+f[4*m+9]&MAXINT;p=b(r[2]);o=a(r[3]);r[0]=rotw(r[0]^p+o+f[4*m+10]&MAXINT,31);r[1]=rotw(r[1],1)^p+2*o+f[4*m+11]&MAXINT}setW(d,e,k[2]^ -f[4]);setW(d,e+4,k[3]^f[5]);setW(d,e+8,k[0]^f[6]);setW(d,e+12,k[1]^f[7]);e+=16;return d},decrypt:function(c,g){d=c;e=g;for(var k=[getW(d,e)^f[4],getW(d,e+4)^f[5],getW(d,e+8)^f[6],getW(d,e+12)^f[7]],l=7;0<=l;l--){var m=l,r=k,p=b(r[0]),o=a(r[1]);r[2]=rotw(r[2],1)^p+o+f[4*m+10]&MAXINT;r[3]=rotw(r[3]^p+2*o+f[4*m+11]&MAXINT,31);p=b(r[2]);o=a(r[3]);r[0]=rotw(r[0],1)^p+o+f[4*m+8]&MAXINT;r[1]=rotw(r[1]^p+2*o+f[4*m+9]&MAXINT,31)}setW(d,e,k[2]^f[0]);setW(d,e+4,k[3]^f[1]);setW(d,e+8,k[0]^f[2]);setW(d,e+12,k[1]^ -f[3]);e+=16},finalize:function(){return d}}}JXG={exists:function(b){return function(a){return!(a===b||null===a)}}()};JXG.decompress=function(b){return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(b))).unzip()[0][0])};JXG.Util={}; -JXG.Util.Unzip=function(b){function a(){aa+=8;return D>=1;0==B&&(B=a(),b=B&1,B=B>>1|128);return b}function d(a){for(var b=0,d=a;d--;)b=b<<1|c();a&&(b=C[b]>>8-a);return b}function e(a){P++;A[t++]=a;p.push(String.fromCharCode(a));32768==t&&(t=0)}function f(){this.b1=this.b0=0;this.jump=null;this.jumppos=-1}function g(){for(;;){if(W[M]>=ra)return-1;if(qa[W[M]]==M)return W[M]++;W[M]++}}function h(){var a=U[T],b;o&&document.write("
      len:"+M+" treepos:"+ -T);if(17==M)return-1;T++;M++;b=g();o&&document.write("
      IsPat "+b);if(0<=b)a.b0=b,o&&document.write("
      b0 "+a.b0);else if(a.b0=32768,o&&document.write("
      b0 "+a.b0),h())return-1;b=g();if(0<=b)a.b1=b,o&&document.write("
      b1 "+a.b1),a.jump=null;else if(a.b1=32768,o&&document.write("
      b1 "+a.b1),a.jump=U[T],a.jumppos=T,h())return-1;M--;return 0}function j(a,b,c,d){o&&document.write("currentTree "+a+" numval "+b+" lengths "+c+" show "+d);U=a;T=0;qa=c;ra=b;for(a=0;17>a;a++)W[a]=0;M=0;if(h())return o&& -alert("invalid huffman tree\n"),-1;if(o){document.write("
      Tree: "+U.length);for(a=0;32>a;a++)document.write("Places["+a+"].b0="+U[a].b0+"
      "),document.write("Places["+a+"].b1="+U[a].b1+"
      ")}return 0}function k(a){for(var b,d,e=0,f=a[e];;)if(b=c(),o&&document.write("b="+b),b){if(!(f.b1&32768))return o&&document.write("ret1"),f.b1;f=f.jump;b=a.length;for(d=0;d>1,23h)e(h);else if(256== -h)break;else{var p;h-=257;m=d(E[h])+Q[h];h=C[d(5)]>>3;8h;h++)r[h]=0;for(h=0;hdistanceTree");for(h=0;h"+O[h].b0+" "+O[h].b1+" "+O[h].jump+" "+O[h].jumppos)}m=g+p;l=0;var u=-1;for(o&&document.write("
      n="+ -m+" bits: "+aa+"
      ");l"+u+" i:"+l+" decode: "+h+" bits "+aa+"
      "),16>h)r[l++]=h;else if(16==h){var v;h=3+d(2);if(l+h>m)return t=0,1;for(v=l?r[l-1]:0;h--;)r[l++]=v}else{h=17==h?3+d(3):11+d(7);if(l+h>m)return t=0,1;for(;h--;)r[l++]=0}m=ba.length;for(l=0;lliteralTree");a:for(;;)if(h= -k(ba),256<=h){h-=256;if(0==h)break;h--;m=d(E[h])+Q[h];h=k(O);8t-p)break a;g=A[t-p&32767];e(g)}}else e(h)}}while(!b);t=0;B=1;return 0}function m(){o&&alert("NEXTFILE");p=[];var b=[];u=!1;b[0]=a();b[1]=a();o&&alert("type: "+b[0]+" "+b[1]);120==b[0]&&218==b[1]&&(o&&alert("GEONExT-GZIP"),l(),o&&alert(p.join("")),w[v]=Array(2),w[v][0]=p.join(""),w[v][1]="geonext.gxt",v++);120==b[0]&&156==b[1]&&(o&&alert("ZLIB"),l(),o&&alert(p.join("")),w[v]= -Array(2),w[v][0]=p.join(""),w[v][1]="ZLIB",v++);31==b[0]&&139==b[1]&&(o&&alert("GZIP"),r(),o&&alert(p.join("")),w[v]=Array(2),w[v][0]=p.join(""),w[v][1]="file",v++);if(80==b[0]&&75==b[1]&&(u=!0,b[2]=a(),b[3]=a(),3==b[2]&&4==b[3])){b[0]=a();b[1]=a();o&&alert("ZIP-Version: "+b[1]+" "+b[0]/10+"."+b[0]%10);y=a();y|=a()<<8;o&&alert("gpflags: "+y);b=a();b|=a()<<8;o&&alert("method: "+b);a();a();a();a();var c=a(),c=c|a()<<8,c=c|a()<<16,c=c|a()<<24,d=a(),d=d|a()<<8,d=d|a()<<16,d=d|a()<<24,e=a(),e=e|a()<<8, -e=e|a()<<16,e=e|a()<<24;o&&alert("local CRC: "+c+"\nlocal Size: "+e+"\nlocal CompSize: "+d);c=a();c|=a()<<8;d=a();d|=a()<<8;o&&alert("filelen "+c);g=0;for(R=[];c--;){var f=a();"/"==f|":"==f?g=0:g>2,c=(c&3)<<4|d>>4,g=(d&15)<<2|e>>6,h=e&63,isNaN(d)?g=h=64:isNaN(e)&&(h=64),a.push([this._keyStr.charAt(f),this._keyStr.charAt(c),this._keyStr.charAt(g),this._keyStr.charAt(h)].join(""));return a.join("")},decode:function(b,a){for(var c=[],d,e,f,g,h, -j=0,b=b.replace(/[^A-Za-z0-9\+\/\=]/g,"");j>4,e=(e&15)<<4|g>>2,f=(g&3)<<6|h,c.push(String.fromCharCode(d)),64!=g&&c.push(String.fromCharCode(e)),64!=h&&c.push(String.fromCharCode(f));c=c.join("");a&&(c=JXG.Util.Base64._utf8_decode(c));return c},_utf8_encode:function(b){for(var b=b.replace(/\r\n/g,"\n"),a="",c=0;cd?a+=String.fromCharCode(d):(127d?a+=String.fromCharCode(d>>6|192):(a+=String.fromCharCode(d>>12|224),a+=String.fromCharCode(d>>6&63|128)),a+=String.fromCharCode(d&63|128))}return a},_utf8_decode:function(b){for(var a=[],c=0,d=0,e=0,f=0;cd?(a.push(String.fromCharCode(d)),c++):191d?(e=b.charCodeAt(c+1),a.push(String.fromCharCode((d&31)<<6|e&63)),c+=2):(e=b.charCodeAt(c+1),f=b.charCodeAt(c+2),a.push(String.fromCharCode((d&15)<<12| -(e&63)<<6|f&63)),c+=3);return a.join("")},_destrip:function(b,a){var c=[],d,e,f=[];null==a&&(a=76);b.replace(/ /g,"");d=b.length/a;for(e=0;ed?(a.push(String.fromCharCode(d)),c++):191d?(e=b.charCodeAt(c+1),a.push(String.fromCharCode((d&31)<<6|e&63)),c+=2):(e=b.charCodeAt(c+1),f=b.charCodeAt(c+2),a.push(String.fromCharCode((d&15)<<12|(e&63)<<6|f&63)),c+=3);return a.join("")}; -JXG.Util.genUUID=function(){for(var b="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),a=Array(36),c=0,d,e=0;36>e;e++)8==e||13==e||18==e||23==e?a[e]="-":14==e?a[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,a[e]=b[19==e?d&3|8:d]);return a.join("")}; -function openpgp_config(){this.config=null;this.default_config={prefer_hash_algorithm:8,encryption_cipher:9,compression:1,show_version:!0,show_comment:!0,integrity_protect:!0,composition_behavior:0,keyserver:"keyserver.linux.it"};this.versionstring="OpenPGP.js v.1.20131204";this.commentstring="http://openpgpjs.org";this.debug=!1;this.read=function(){var b=JSON.parse(window.localStorage.getItem("config"));null==b?(this.config=this.default_config,this.write()):this.config=b};this.write=function(){window.localStorage.setItem("config", -JSON.stringify(this.config))}}var b64s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -function s2r(b){var a,c,d,e="",f=0,g=0,h=b.length;for(d=0;d>2&63),a=(c&3)<<4):1==g?(e+=b64s.charAt(a|c>>4&15),a=(c&15)<<2):2==g&&(e+=b64s.charAt(a|c>>6&3),f+=1,0==f%60&&(e+="\n"),e+=b64s.charAt(c&63)),f+=1,0==f%60&&(e+="\n"),g+=1,3==g&&(g=0);0>6-e&255)),e=e+2&7,f=a<>16)+String.fromCharCode(b>>8&255)+String.fromCharCode(b&255);return openpgp_encoding_base64_encode(b)}function verifyCheckSum(b,a){var c=getCheckSum(b);return c[0]==a[0]&&c[1]==a[1]&&c[2]==a[2]} -var crc_table=[0,8801531,25875725,17603062,60024545,51751450,35206124,44007191,128024889,120049090,103502900,112007375,70412248,78916387,95990485,88014382,264588937,256049778,240098180,248108927,207005800,215016595,232553829,224014750,140824496,149062475,166599357,157832774,200747345,191980970,176028764,184266919,520933865,529177874,512099556,503334943,480196360,471432179,487973381,496217854,414011600,405478443,422020573,430033190,457094705,465107658,448029500,439496647,281648992,273666971,289622637, -298124950,324696449,333198714,315665548,307683447,392699481,401494690,383961940,375687087,352057528,343782467,359738805,368533838,1041867730,1050668841,1066628831,1058355748,1032471859,1024199112,1006669886,1015471301,968368875,960392720,942864358,951368477,975946762,984451313,1000411399,992435708,836562267,828023200,810956886,818967725,844041146,852051777,868605623,860066380,914189410,922427545,938981743,930215316,904825475,896059E3,878993294,887231349,555053627,563297984,547333942,538569677,579245274, -570480673,588005847,596249900,649392898,640860153,658384399,666397428,623318499,631331096,615366894,606833685,785398962,777416777,794487231,802989380,759421523,767923880,751374174,743392165,695319947,704115056,687564934,679289981,719477610,711202705,728272487,737067676,2083735460,2092239711,2109313705,2101337682,2141233477,2133257662,2116711496,2125215923,2073216669,2064943718,2048398224,2057199467,2013339772,2022141063,2039215473,2030942602,1945504045,1936737750,1920785440,1929023707,1885728716, -1893966647,1911503553,1902736954,1951893524,1959904495,1977441561,1968902626,2009362165,2000822798,1984871416,1992881923,1665111629,1673124534,1656046400,1647513531,1621913772,1613380695,1629922721,1637935450,1688082292,1679317903,1695859321,1704103554,1728967061,1737211246,1720132760,1711368291,1828378820,1820103743,1836060105,1844855090,1869168165,1877963486,1860430632,1852155859,1801148925,1809650950,1792118E3,1784135691,1757986588,1750004711,1765960209,1774462698,1110107254,1118611597,1134571899, -1126595968,1102643863,1094667884,1077139354,1085643617,1166763343,1158490548,1140961346,1149762745,1176011694,1184812885,1200772771,1192499800,1307552511,1298785796,1281720306,1289958153,1316768798,1325007077,1341561107,1332794856,1246636998,1254647613,1271201483,1262662192,1239272743,1230733788,1213667370,1221678289,1562785183,1570797924,1554833554,1546300521,1588974462,1580441477,1597965939,1605978760,1518843046,1510078557,1527603627,1535847760,1494504007,1502748348,1486784330,1478020017,1390639894, -1382365165,1399434779,1408230112,1366334967,1375129868,1358579962,1350304769,1430452783,1438955220,1422405410,1414423513,1456544974,1448562741,1465633219,1474135352]; -function createcrc24(b){for(var a=11994318,c=0;16>16^b.charCodeAt(c))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+1))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+2))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+3))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+4))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+5))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+6))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+7))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+8))&255],a=a<<8^crc_table[(a>> -16^b.charCodeAt(c+9))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+10))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+11))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+12))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+13))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+14))&255],a=a<<8^crc_table[(a>>16^b.charCodeAt(c+15))&255],c+=16;for(var d=c;d>16^b.charCodeAt(c++))&255];return a&16777215}function openpgp_encoding_base64_encode(b){return s2r(b)} -function openpgp_encoding_base64_decode(b){return r2s(b)}function openpgp_encoding_html_encode(b){return null==b?"":$("
      ").text(b).html()}function openpgp_encoding_eme_pkcs1_encode(b,a){if(b.length>a-11)return-1;var c;c=""+String.fromCharCode(0);c+=String.fromCharCode(2);for(var d=0;db.length||0!=b.charCodeAt(0)||2!=b.charCodeAt(1))return-1;for(var c=2;0!=b.charCodeAt(c)&&b.length>c;)c++;return b.substring(c+1,b.length)}hash_headers=[,[48,32,48,12,6,8,42,134,72,134,247,13,2,5,5,0,4,16],[48,33,48,9,6,5,43,14,3,2,26,5,0,4,20],[48,33,48,9,6,5,43,36,3,2,1,5,0,4,20]];hash_headers[8]=[48,49,48,13,6,9,96,134,72,1,101,3,4,2,1,5,0,4,32]; -hash_headers[9]=[48,65,48,13,6,9,96,134,72,1,101,3,4,2,2,5,0,4,48];hash_headers[10]=[48,81,48,13,6,9,96,134,72,1,101,3,4,2,3,5,0,4,64];hash_headers[11]=[48,49,48,13,6,9,96,134,72,1,101,3,4,2,4,5,0,4,28]; -function openpgp_encoding_emsa_pkcs1_encode(b,a,c){var d;d=""+String.fromCharCode(0);d+=String.fromCharCode(1);for(var e=0;ej.signatureType||3==j.tagType||4==j.tagType||8==j.tagType||9==j.tagType||10==j.tagType||11==j.tagType||18==j.tagType||19==j.tagType)if(e[e.length]=new openpgp_msg_message,e[f].messagePacket=j,e[f].type=a.type,9==j.tagType||1==j.tagType||3==j.tagType||18==j.tagType)if(9==j.tagType){util.print_error("unexpected openpgp packet"); -break}else if(1==j.tagType){util.print_debug("session key found:\n "+j.toString());var k=!0;e[f].sessionKeys=[];for(var l=0;k;)e[f].sessionKeys[l]=j,g+=j.packetLength+j.headerLength,h-=j.packetLength+j.headerLength,j=openpgp_packet.read_packet(b,g,h),1!=j.tagType&&3!=j.tagType&&(k=!1),l++;18==j.tagType||9==j.tagType?(util.print_debug("encrypted data found:\n "+j.toString()),e[f].encryptedData=j,g+=j.packetLength+j.headerLength,h-=j.packetLength+j.headerLength,f++):util.print_debug("something is wrong: "+ -j.tagType)}else{if(18==j.tagType){util.print_debug("symmetric encrypted data");break}}else 2==j.tagType&&3>j.signatureType?(g+=j.packetLength+j.headerLength,h-=j.packetLength+j.headerLength,e[f].text=d,e[f].signature=j,f++):4==j.tagType?(g+=j.packetLength+j.headerLength,h-=j.packetLength+j.headerLength):8==j.tagType?(g+=j.packetLength+j.headerLength,h-=j.packetLength+j.headerLength,j=j.decompress(),e=e.concat(openpgp.read_messages_dearmored({text:j,openpgp:j}))):10==j.tagType?(e.length=0,g+=j.packetLength+ -j.headerLength,h-=j.packetLength+j.headerLength):11==j.tagType?(g+=j.packetLength+j.headerLength,h-=j.packetLength+j.headerLength,d=j.data,e[f].data=j.data,f++):19==j.tagType&&(g+=j.packetLength+j.headerLength,h-=j.packetLength+j.headerLength);else return util.print_error("no message found!"),null}return e}this.tostring="";this.generate_key_pair=function(a,b,d,e){var f=(new openpgp_packet_userid).write_packet(d),b=openpgp_crypto_generateKeyPair(a,b,e,openpgp.config.config.prefer_hash_algorithm,3), -a=b.privateKey,g=(new openpgp_packet_keymaterial).read_priv_key(a.string,3,a.string.length);g.decryptSecretMPIs(e)||util.print_error("Issue creating key. Unable to read resulting private key");e=new openpgp_msg_privatekey;e.privateKeyPacket=g;e.getPreferredSignatureHashAlgorithm=function(){return openpgp.config.config.prefer_hash_algorithm};g=e.privateKeyPacket.publicKey.data;d=util.encode_utf8(d);g=String.fromCharCode(153)+String.fromCharCode(g.length>>8&255)+String.fromCharCode(g.length&255)+g+ -String.fromCharCode(180)+String.fromCharCode(d.length>>24)+String.fromCharCode(d.length>>16&255)+String.fromCharCode(d.length>>8&255)+String.fromCharCode(d.length&255)+d;d=new openpgp_packet_signature;d=d.write_message_signature(16,g,e);b=openpgp_encoding_armor(4,b.publicKey.string+f+d.openpgp);f=openpgp_encoding_armor(5,a.string+f+d.openpgp);return{privateKey:e,privateKeyArmored:f,publicKeyArmored:b}};this.write_signed_message=function(a,b){var d=(new openpgp_packet_signature).write_message_signature(1, -b.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"),a),d={text:b.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"),openpgp:d.openpgp,hash:d.hash};return openpgp_encoding_armor(2,d,null,null)};this.write_signed_and_encrypted_message=function(a,b,d){var e="",f=(new openpgp_packet_literaldata).write_packet(d.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));util.print_debug_hexstr_dump("literal_packet: |"+f+"|\n",f);for(var g=0;g")[0]: -b.trim(),d=d.toLowerCase();if(!util.emailRegEx.test(d))return a;for(b=0;b")[0]:b.trim(),d=d.toLowerCase();if(!util.emailRegEx.test(d))return a;for(b=0;b -b;){var e=openpgp_packet.read_packet(a,b,a.length-b);if(null==e){util.print_error("openpgp.msg.messge decrypt:\n[pub/priv_key]parsing ends here @:"+b+" l:"+d);break}else switch(e.tagType){case 2:if(32==e.signatureType)this.revocationSignatures[this.revocationSignatures.length]=e;else if(15e.signatureType){if(null==this.certificationsignatures)this.certificationSignatures=[];this.certificationSignatures[this.certificationSignatures.length]=e}else util.print_error("openpgp.msg.messge decrypt:\nunknown signature type directly on key "+ -e.signatureType+" @"+b);b+=e.packetLength+e.headerLength;break;case 7:this.subKeys[this.subKeys.length]=e;b+=e.packetLength+e.headerLength;b+=e.read_nodes(this.privateKeyPacket,a,b,a.length-b);break;case 17:this.userAttributes[this.userAttributes.length]=e;b+=e.packetLength+e.headerLength;b+=e.read_nodes(this.privateKeyPacket,a,b,a.length-b);break;case 13:this.userIds[this.userIds.length]=e;b+=e.packetLength+e.headerLength;b+=e.read_nodes(this.privateKeyPacket,a,b,a.length-b);break;default:return this.position= -c-this.privateKeyPacket.packetLength-this.privateKeyPacket.headerLength,this.len=b-c}}this.position=c-this.privateKeyPacket.packetLength-this.privateKeyPacket.headerLength;return this.len=b-c};this.decryptSecretMPIs=function(b){return this.privateKeyPacket.decryptSecretMPIs(b)};this.getSubKeyIds=function(){if(4==this.privateKeyPacket.publicKey.version)var b=[];for(var a=0;ac)return util.print_error("openpgp.packet.encryptedsessionkey.js\ninvalid length"),null;this.version=b.charCodeAt(d++);this.keyId=new openpgp_type_keyid;this.keyId.read_packet(b,d);d+=8;this.publicKeyAlgorithmUsed=b.charCodeAt(d++);switch(this.publicKeyAlgorithmUsed){case 1:case 2:this.MPIs=[];this.MPIs[0]=new openpgp_type_mpi;this.MPIs[0].read(b,d,d-a);break;case 16:this.MPIs= -[];this.MPIs[0]=new openpgp_type_mpi;this.MPIs[0].read(b,d,d-a);d+=this.MPIs[0].packetLength;this.MPIs[1]=new openpgp_type_mpi;this.MPIs[1].read(b,d,d-a);break;default:util.print_error("openpgp.packet.encryptedsessionkey.js\nunknown public key packet algorithm type "+this.publicKeyAlgorithmType)}return this};this.read_symmetric_key_packet=function(b,a,c){this.tagType=3;var d=a;this.version=b[d++];this.symmetricKeyAlgorithmUsed=b[d++];this.s2k=new openpgp_type_s2k;this.s2k.read(b,d);if(s2k.s2kLength+ -d>8&255),d=d+String.fromCharCode(e&255),f=f+b+String.fromCharCode(c),b=new openpgp_type_mpi,a=openpgp_crypto_asymetricEncrypt(c,a,b.create(openpgp_encoding_eme_pkcs1_encode(d,a[0].mpiByteLength))),c=0;ca?result+=String.fromCharCode(a):191a?(result+=String.fromCharCode((a-192>>8)+192),result+=String.fromCharCode(a-192&255)):(result+=String.fromCharCode(255),result+=String.fromCharCode(a>>24&255),result+=String.fromCharCode(a>>16&255),result+=String.fromCharCode(a>>8&255),result+=String.fromCharCode(a&255));return result}this.encode_length=b;this.write_old_packet_header=function(a,b){var d="";256>b?(d+=String.fromCharCode(128|a<<2),d+= -String.fromCharCode(b)):(65536>b?(d+=String.fromCharCode(a<<2|129),d+=String.fromCharCode(b>>8)):(d+=String.fromCharCode(a<<2|130),d+=String.fromCharCode(b>>24&255),d+=String.fromCharCode(b>>16&255),d+=String.fromCharCode(b>>8&255)),d+=String.fromCharCode(b&255));return d};this.write_packet_header=function(a,c){var d;d=""+String.fromCharCode(192|a);return d+=b(c)};this.read_packet=function(a,b,d){if(null==a||a.length<=b||2>a.substring(b).length||0==(a.charCodeAt(b)&128))return util.print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."), -null;var e=b,f=-1,g=-1,g=0;0!=(a.charCodeAt(e)&64)&&(g=1);var h;g?f=a.charCodeAt(e)&63:(f=(a.charCodeAt(e)&63)>>2,h=a.charCodeAt(e)&3);e++;var j=null,k=-1;if(g)if(192>a.charCodeAt(e))packet_length=a.charCodeAt(e++),util.print_debug("1 byte length:"+packet_length);else if(192<=a.charCodeAt(e)&&224>a.charCodeAt(e))packet_length=(a.charCodeAt(e++)-192<<8)+a.charCodeAt(e++)+192,util.print_debug("2 byte length:"+packet_length);else if(223a.charCodeAt(e)){packet_length=1<<(a.charCodeAt(e++)& -31);util.print_debug("4 byte length:"+packet_length);k=e+packet_length;for(j=a.substring(e,e+packet_length);;)if(192>a.charCodeAt(k)){d=a.charCodeAt(k++);packet_length+=d;j+=a.substring(k,k+d);k+=d;break}else if(192<=a.charCodeAt(k)&&224>a.charCodeAt(k)){d=(a.charCodeAt(k++)-192<<8)+a.charCodeAt(k++)+192;packet_length+=d;j+=a.substring(k,k+d);k+=d;break}else if(223a.charCodeAt(k))d=1<<(a.charCodeAt(k++)&31),packet_length+=d,j+=a.substring(k,k+d),k+=d;else{k++;d=a.charCodeAt(k++)<< -24|a.charCodeAt(k++)<<16|a.charCodeAt(k++)<<8|a.charCodeAt(k++);j+=a.substring(k,k+d);packet_length+=d;k+=d;break}}else e++,packet_length=a.charCodeAt(e++)<<24|a.charCodeAt(e++)<<16|a.charCodeAt(e++)<<8|a.charCodeAt(e++);else switch(h){case 0:packet_length=a.charCodeAt(e++);break;case 1:packet_length=a.charCodeAt(e++)<<8|a.charCodeAt(e++);break;case 2:packet_length=a.charCodeAt(e++)<<24|a.charCodeAt(e++)<<16|a.charCodeAt(e++)<<8|a.charCodeAt(e++);break;default:packet_length=d}-1==k&&(k=packet_length); -null==j&&(j=a.substring(e,e+k));switch(f){case 0:break;case 1:f=new openpgp_packet_encryptedsessionkey;if(null!=f.read_pub_key_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 2:f=new openpgp_packet_signature;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 3:f=new openpgp_packet_encryptedsessionkey;if(null!=f.read_symmetric_key_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 4:f=new openpgp_packet_onepasssignature; -if(f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 5:f=new openpgp_packet_keymaterial;f.header=a.substring(b,e);if(null!=f.read_tag5(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 6:f=new openpgp_packet_keymaterial;f.header=a.substring(b,e);if(null!=f.read_tag6(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 7:f=new openpgp_packet_keymaterial;if(null!=f.read_tag7(j,0,packet_length))return f.headerLength= -e-b,f.packetLength=k,f;break;case 8:f=new openpgp_packet_compressed;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 9:f=new openpgp_packet_encrypteddata;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 10:f=new openpgp_packet_marker;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 11:f=new openpgp_packet_literaldata;if(null!=f.read_packet(j,0,packet_length))return f.headerLength= -e-b,f.header=a.substring(b,e),f.packetLength=k,f;break;case 12:break;case 13:f=new openpgp_packet_userid;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 14:f=new openpgp_packet_keymaterial;f.header=a.substring(b,e);if(null!=f.read_tag14(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 17:f=new openpgp_packet_userattribute;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 18:f= -new openpgp_packet_encryptedintegrityprotecteddata;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 19:f=new openpgp_packet_modificationdetectioncode;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;default:return util.print_error("openpgp.packet.js\n[ERROR] openpgp_packet: failed to parse packet @:"+e+"\nchar:'"+util.hexstrdump(a.substring(e))+"'\ninput:"+util.hexstrdump(a)),null}}}var openpgp_packet=new _openpgp_packet; -function openpgp_packet_keymaterial(){this.subKeyRevocationSignature=this.subKeySignature=this.parentNode=this.checksum=this.hasUnencryptedSecretKeyData=this.encryptedMPIData=this.IVLength=this.s2kUsageConventions=this.symmetricEncryptionAlgorithm=this.publicKey=this.secMPIs=this.MPIs=this.expiration=this.version=this.creationTime=this.tagType=this.publicKeyAlgorithm=null;this.read_tag5=function(b,a,c){this.tagType=5;this.read_priv_key(b,a,c);return this};this.read_tag6=function(b,a,c){this.tagType= -6;this.packetLength=c;this.read_pub_key(b,a,c);return this};this.read_tag7=function(b,a,c){this.tagType=7;this.packetLength=c;return this.read_priv_key(b,a,c)};this.read_tag14=function(b,a,c){this.subKeySignature=null;this.subKeyRevocationSignature=[];this.tagType=14;this.packetLength=c;this.read_pub_key(b,a,c);return this};this.toString=function(){var b="";switch(this.tagType){case 6:b+="5.5.1.1. Public-Key Packet (Tag 6)\n length: "+this.packetLength+"\n version: "+ -this.version+"\n creation time: "+this.creationTime+"\n expiration time: "+this.expiration+"\n publicKeyAlgorithm: "+this.publicKeyAlgorithm+"\n";break;case 14:b+="5.5.1.2. Public-Subkey Packet (Tag 14)\n length: "+this.packetLength+"\n version: "+this.version+"\n creation time: "+this.creationTime+"\n expiration time: "+this.expiration+"\n publicKeyAlgorithm: "+this.publicKeyAlgorithm+"\n";break;case 5:b+="5.5.1.3. Secret-Key Packet (Tag 5)\n length: "+ -this.packetLength+"\n version: "+this.publicKey.version+"\n creation time: "+this.publicKey.creationTime+"\n expiration time: "+this.publicKey.expiration+"\n publicKeyAlgorithm: "+this.publicKey.publicKeyAlgorithm+"\n";break;case 7:b+="5.5.1.4. Secret-Subkey Packet (Tag 7)\n length: "+this.packetLength+"\n version[1]: "+(4==this.version)+"\n creationtime[4]: "+this.creationTime+"\n expiration[2]: "+this.expiration+"\n publicKeyAlgorithm: "+ -this.publicKeyAlgorithm+"\n";break;default:b+="unknown key material packet\n"}if(null!=this.MPIs)for(var b=b+"Public Key MPIs:\n",a=0;athis.publicKeyAlgorithm?d=2:16==this.publicKeyAlgorithm?d=3:17==this.publicKeyAlgorithm&&(d=4);this.MPIs=[];for(var e=0;ethis.publicKeyAlgorithm?d=2:16==this.publicKeyAlgorithm?d=3:17==this.publicKeyAlgorithm&&(d=4);this.MPIs=[];for(e=0;ethis.publicKey.publicKeyAlgorithm)this.secMPIs=[],this.secMPIs[0]=new openpgp_type_mpi,this.secMPIs[0].read(b,d,c-2-(d-a)),d+=this.secMPIs[0].packetLength,this.secMPIs[1]=new openpgp_type_mpi,this.secMPIs[1].read(b,d,c-2-(d-a)),d+=this.secMPIs[1].packetLength,this.secMPIs[2]=new openpgp_type_mpi,this.secMPIs[2].read(b,d,c-2-(d-a)),d+=this.secMPIs[2].packetLength,this.secMPIs[3]=new openpgp_type_mpi,this.secMPIs[3].read(b,d,c-2-(d-a)),d+=this.secMPIs[3].packetLength;else if(16==this.publicKey.publicKeyAlgorithm)this.secMPIs= -[],this.secMPIs[0]=new openpgp_type_mpi,this.secMPIs[0].read(b,d,c-2-(d-a)),d+=this.secMPIs[0].packetLength;else if(17==this.publicKey.publicKeyAlgorithm)this.secMPIs=[],this.secMPIs[0]=new openpgp_type_mpi,this.secMPIs[0].read(b,d,c-2-(d-a)),d+=this.secMPIs[0].packetLength;this.checksum=[];this.checksum[0]=b.charCodeAt(d++);this.checksum[1]=b.charCodeAt(d++)}else this.encryptedMPIData=b.substring(d,c);return this};this.decryptSecretMPIs=function(b){if(this.hasUnencryptedSecretKeyData)return this.secMPIs; -var a=this.s2k.produce_key(b),c="";switch(this.symmetricEncryptionAlgorithm){case 1:return util.print_error("openpgp.packet.keymaterial.js\nsymmetric encryption algorithim: IDEA is not implemented"),!1;case 2:c=normal_cfb_decrypt(function(a,b){return des(b,a,1,null,0)},this.IVLength,a,this.encryptedMPIData,this.IV);break;case 3:c=normal_cfb_decrypt(function(a,b){var c=new openpgp_symenc_cast5;c.setKey(b);return c.encrypt(util.str2bin(a))},this.IVLength,util.str2bin(a.substring(0,16)),this.encryptedMPIData, -this.IV);break;case 4:c=normal_cfb_decrypt(function(a,b){return(new Blowfish(b)).encrypt(a)},this.IVLength,a,this.encryptedMPIData,this.IV);break;case 7:case 8:case 9:c=16;8==this.symmetricEncryptionAlgorithm&&(c=24,a=this.s2k.produce_key(b,c));9==this.symmetricEncryptionAlgorithm&&(c=32,a=this.s2k.produce_key(b,c));c=normal_cfb_decrypt(function(a,b){return AESencrypt(util.str2bin(a),b)},this.IVLength,keyExpansion(a.substring(0,c)),this.encryptedMPIData,this.IV);break;case 10:return util.print_error("openpgp.packet.keymaterial.js\nKey material is encrypted with twofish: not implemented"), -!1;default:return util.print_error("openpgp.packet.keymaterial.js\nunknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm),!1}if(null==c)return util.print_error("openpgp.packet.keymaterial.js\ncleartextMPIs was null"),!1;b=c.length;if(254==this.s2kUsageConventions&&str_sha1(c.substring(0,c.length-20))==c.substring(c.length-20))b-=20;else if(254!=this.s2kUsageConventions&&util.calc_checksum(c.substring(0,c.length-2))==(c.charCodeAt(c.length-2)<<8|c.charCodeAt(c.length-1)))b-= -2;else return!1;if(0this.publicKey.publicKeyAlgorithm)a=0,this.secMPIs=[],this.secMPIs[0]=new openpgp_type_mpi,this.secMPIs[0].read(c,0,b),a+=this.secMPIs[0].packetLength,this.secMPIs[1]=new openpgp_type_mpi,this.secMPIs[1].read(c,a,b-a),a+=this.secMPIs[1].packetLength,this.secMPIs[2]=new openpgp_type_mpi,this.secMPIs[2].read(c,a,b-a),a+=this.secMPIs[2].packetLength,this.secMPIs[3]=new openpgp_type_mpi,this.secMPIs[3].read(c,a,b-a),a+=this.secMPIs[3].packetLength; -else if(16==this.publicKey.publicKeyAlgorithm)this.secMPIs=[],this.secMPIs[0]=new openpgp_type_mpi,this.secMPIs[0].read(c,0,c);else if(17==this.publicKey.publicKeyAlgorithm)this.secMPIs=[],this.secMPIs[0]=new openpgp_type_mpi,this.secMPIs[0].read(c,0,b);return!0};this.read_nodes=function(b,a,c,d){this.parentNode=b;if(14==this.tagType){for(var b=c,e=null;a.length!=b;)if(d=a.length-b,e=openpgp_packet.read_packet(a,b,d),null==e){util.print_error("openpgp.packet.keymaterial.js\n[user_keymat_pub]parsing ends here @:"+ -b+" l:"+d);break}else switch(e.tagType){case 2:if(24==e.signatureType){this.subKeySignature=e;b+=e.packetLength+e.headerLength;break}else if(40==e.signatureType){this.subKeyRevocationSignature[this.subKeyRevocationSignature.length]=e;b+=e.packetLength+e.headerLength;break}else util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+e.toString());default:return this.data=a,this.position=c-this.parentNode.packetLength,this.len=b-c}this.data=a;this.position=c-this.parentNode.packetLength; -return this.len=b-c}if(7==this.tagType){for(b=c;a.length!=b;)if(e=openpgp_packet.read_packet(a,b,d-(b-c)),null==e){util.print_error("openpgp.packet.keymaterial.js\n[user_keymat_priv] parsing ends here @:"+b);break}else switch(e.tagType){case 2:24==e.signatureType?this.subKeySignature=e:40==e.signatureType&&(this.subKeyRevocationSignature[this.subKeyRevocationSignature.length]=e);b+=e.packetLength+e.headerLength;break;default:return this.data=a,this.position=c-this.parentNode.packetLength,this.len= -b-c}this.data=a;this.position=c-this.parentNode.packetLength;return this.len=b-c}util.print_error("openpgp.packet.keymaterial.js\nunknown parent node for a key material packet "+b.tagType)};this.verifyKey=function(){if(14==this.tagType){if(null==this.subKeySignature)return 0;if(4==this.subKeySignature.version&&null!=this.subKeySignature.keyNeverExpires&&!this.subKeySignature.keyNeverExpires&&new Date(1E3*this.subKeySignature.keyExpirationTime+this.creationTime.getTime())this.publicKeyAlgorithm){var b=this.MPIs[0].MPI.substring(this.MPIs[0].mpiByteLength- -8);util.print_debug("openpgp.msg.publickey read_nodes:\nV3 key ID: "+b);return b}};this.getFingerprint=function(){if(4==this.version)return tohash=String.fromCharCode(153)+String.fromCharCode(this.packetdata.length>>8&255)+String.fromCharCode(this.packetdata.length&255)+this.packetdata,util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm),str_sha1(tohash,tohash.length);if(3==this.version&&0this.publicKeyAlgorithm)return MD5(this.MPIs[0].MPI)};this.write_private_key=function(b,a,c,d,e,f){this.symmetricEncryptionAlgorithm=e;e=String.fromCharCode(4);e+=f;switch(b){case 1:e+=String.fromCharCode(b);e+=a.n.toMPI();e+=a.ee.toMPI();if(c)switch(e+=String.fromCharCode(254),e+=String.fromCharCode(this.symmetricEncryptionAlgorithm),e+=String.fromCharCode(3),e+=String.fromCharCode(d),b=a.d.toMPI()+a.p.toMPI()+a.q.toMPI()+a.u.toMPI(),a=str_sha1(b),util.print_debug_hexstr_dump("write_private_key sha1: ", -a),f=openpgp_crypto_getRandomBytes(8),util.print_debug_hexstr_dump("write_private_key Salt: ",f),e=e+f+String.fromCharCode(96),util.print_debug("write_private_key c: 96"),c=(new openpgp_type_s2k).write(3,d,c,f,96),this.symmetricEncryptionAlgorithm){case 3:this.IVLength=8;this.IV=openpgp_crypto_getRandomBytes(this.IVLength);ciphertextMPIs=normal_cfb_encrypt(function(a,b){var c=new openpgp_symenc_cast5;c.setKey(b);return c.encrypt(util.str2bin(a))},this.IVLength,util.str2bin(c.substring(0,16)),b+a, -this.IV);e+=this.IV+ciphertextMPIs;break;case 7:case 8:case 9:this.IVLength=16,this.IV=openpgp_crypto_getRandomBytes(this.IVLength),ciphertextMPIs=normal_cfb_encrypt(AESencrypt,this.IVLength,c,b+a,this.IV),e+=this.IV+ciphertextMPIs}else e+=String.fromCharCode(0),e+=a.d.toMPI()+a.p.toMPI()+a.q.toMPI()+a.u.toMPI(),c=util.calc_checksum(a.d.toMPI()+a.p.toMPI()+a.q.toMPI()+a.u.toMPI()),e+=String.fromCharCode(c/256)+String.fromCharCode(c%256),util.print_debug_hexstr_dump("write_private_key basic checksum: "+ -c);break;default:e="",util.print_error("openpgp.packet.keymaterial.js\nerror writing private key, unknown type :"+b)}c=openpgp_packet.write_packet_header(5,e.length);return{string:c+e,header:c,body:e}};this.write_public_key=function(b,a,c){var d=String.fromCharCode(4),d=d+c;switch(b){case 1:d+=String.fromCharCode(1);d+=a.n.toMPI();d+=a.ee.toMPI();break;default:util.print_error("openpgp.packet.keymaterial.js\nerror writing private key, unknown type :"+b)}b=openpgp_packet.write_packet_header(6,d.length); -return{string:b+d,header:b,body:d}}} -function openpgp_packet_literaldata(){this.tagType=11;this.set_data=function(b,a){this.format=a;this.data=b};this.set_data_bytes=function(b,a){this.format=a;a==openpgp_packet_literaldata.formats.utf8&&(b=util.decode_utf8(b));this.data=b};this.get_data_bytes=function(){return this.format==openpgp_packet_literaldata.formats.utf8?util.encode_utf8(this.data):this.data};this.read_packet=function(b,a,c){this.packetLength=c;c=b[a];this.filename=util.decode_utf8(b.substr(a+2,b.charCodeAt(a+1)));this.date= -new Date(1E3*parseInt(b.substr(a+2+b.charCodeAt(a+1),4)));this.set_data_bytes(b.substring(a+6+b.charCodeAt(a+1)),c);return this};this.write_packet=function(b){this.set_data(b,openpgp_packet_literaldata.formats.utf8);this.filename=util.encode_utf8("msg.txt");this.date=new Date;var b=this.get_data_bytes(),a=openpgp_packet.write_packet_header(11,b.length+6+this.filename.length),a=a+this.format,a=a+String.fromCharCode(this.filename.length),a=a+this.filename,a=a+String.fromCharCode(Math.round(this.date.getTime()/ -1E3)>>24&255),a=a+String.fromCharCode(Math.round(this.date.getTime()/1E3)>>16&255),a=a+String.fromCharCode(Math.round(this.date.getTime()/1E3)>>8&255),a=a+String.fromCharCode(Math.round(this.date.getTime()/1E3)&255);return a+b};this.toString=function(){return"5.9. Literal Data Packet (Tag 11)\n length: "+this.packetLength+"\n format: "+this.format+"\n filename:"+this.filename+"\n date: "+this.date+"\n data: |"+this.data+"|\n rdata: |"+this.real_data+"|\n"}} -openpgp_packet_literaldata.formats={binary:"b",text:"t",utf8:"u"};function openpgp_packet_marker(){this.tagType=10;this.read_packet=function(b,a){this.packetLength=3;return 80==b.charCodeAt(a)&&71==b.charCodeAt(a+1)&&80==b.charCodeAt(a+2)?this:null};this.toString=function(){return'5.8. Marker Packet (Obsolete Literal Packet) (Tag 10)\n packet reads: "PGP"\n'}} -function openpgp_packet_modificationdetectioncode(){this.tagType=19;this.hash=null;this.read_packet=function(b,a,c){this.packetLength=c;if(20!=c)return util.print_error("openpgp.packet.modificationdetectioncode.js\ninvalid length for a modification detection code packet!"+c),null;this.hash=b.substring(a,a+20);return this};this.toString=function(){return"5.14 Modification detection code packet\n bytes ("+this.hash.length+"): ["+util.hexstrdump(this.hash)+"]"}} -function openpgp_packet_onepasssignature(){this.tagType=4;this.flags=this.signingKeyId=this.publicKeyAlgorithm=this.hashAlgorithm=this.type=this.version=null;this.read_packet=function(b,a,c){this.packetLength=c;this.version=b.charCodeAt(a++);this.type=b.charCodeAt(a++);this.hashAlgorithm=b.charCodeAt(a++);this.publicKeyAlgorithm=b.charCodeAt(a++);this.signingKeyId=new openpgp_type_keyid;this.signingKeyId.read_packet(b,a);a+=8;this.flags=b.charCodeAt(a++);return this};this.toString=function(){return"5.4. One-Pass Signature Packets (Tag 4)\n length: "+ -this.packetLength+"\n type: "+this.type+"\n keyID: "+this.signingKeyId.toString()+"\n hashA: "+this.hashAlgorithm+"\n pubKeyA:"+this.publicKeyAlgorithm+"\n flags: "+this.flags+"\n version:"+this.version+"\n"};this.write_packet=function(b,a,c,d,e){d=""+openpgp_packet.write_packet_header(4,13);d+=String.fromCharCode(3);d+=String.fromCharCode(b);d+=String.fromCharCode(a);d+=String.fromCharCode(c.privateKeyPacket.publicKey.publicKeyAlgorithm);d+=c.getKeyId();return d=e?d+String.fromCharCode(0): -d+String.fromCharCode(1)}} -function openpgp_packet_signature(){function b(a,b){var d;d=""+openpgp_packet.encode_length(b.length+1);d+=String.fromCharCode(a);return d+b}this.tagType=2;this.embeddedSignature=this.signatureTargetHash=this.signatureTargetHashAlgorithm=this.signatureTargetPublicKeyAlgorithm=this.reasonForRevocationString=this.reasonForRevocationFlag=this.signersUserId=this.keyFlags=this.policyURI=this.isPrimaryUserID=this.preferredKeyServer=this.keyServerPreferences=this.preferredCompressionAlgorithms=this.preferredHashAlgorithms= -this.notationValue=this.notationName=this.notationFlags=this.issuerKeyId=this.revocationKeyFingerprint=this.revocationKeyAlgorithm=this.revocationKeyClass=this.preferredSymmetricAlgorithms=this.keyNeverExpires=this.keyExpirationTime=this.revocable=this.regular_expression=this.trustAmount=this.trustLevel=this.exportable=this.hashAlgorithm=this.publicKeyAlgorithm=this.MPIs=this.signedHashValue=this.signatureNeverExpires=this.signatureExpirationTime=this.signatureData=this.keyId=this.creationTime=this.signatureType= -null;this.verified=!1;this._raw_read_signature_sub_packet=function(a,b,d){0>d&&util.print_debug("openpgp.packet.signature.js\n_raw_read_signature_sub_packet length < 0 @:"+b);var e=b,f=0;192>a.charCodeAt(e)?f=a.charCodeAt(e++):192<=a.charCodeAt(e)&&224>a.charCodeAt(e)?f=(a.charCodeAt(e++)-192<<8)+a.charCodeAt(e++)+192:223a.charCodeAt(e)?f=1<<(a.charCodeAt(e++)&31):255>a.charCodeAt(e)&&(e++,f=a.charCodeAt(e++)<<24|a.charCodeAt(e++)<<16|a.charCodeAt(e++)<<8|a.charCodeAt(e++)); -var g=a.charCodeAt(e++)&127;switch(g){case 2:this.creationTime=new Date(1E3*(a.charCodeAt(e++)<<24|a.charCodeAt(e++)<<16|a.charCodeAt(e++)<<8|a.charCodeAt(e++)));break;case 3:this.signatureExpirationTime=a.charCodeAt(e++)<<24|a.charCodeAt(e++)<<16|a.charCodeAt(e++)<<8|a.charCodeAt(e++);this.signatureNeverExpires=0==this.signature_expiration_time;break;case 4:this.exportable=1==a.charCodeAt(e++);break;case 5:this.trustLevel=a.charCodeAt(e++);this.trustAmount=a.charCodeAt(e++);break;case 6:this.regular_expression= -new String;for(g=0;gg;g++)this.revocationKeyFingerprint=a.charCodeAt(e++);break;case 16:this.issuerKeyId=a.substring(e,e+8);e+=8;break;case 20:this.notationFlags=a.charCodeAt(e++)<<24|a.charCodeAt(e++)<<16|a.charCodeAt(e++)<<8|a.charCodeAt(e++);d=a.charCodeAt(e++)<<8|a.charCodeAt(e++);f=a.charCodeAt(e++)<<8|a.charCodeAt(e++);this.notationName="";for(g=0;g>24&255)+String.fromCharCode(a>>16&255)+String.fromCharCode(a>>8&255)+String.fromCharCode(a&255)),h=b(16,d.getKeyId()),g=g+String.fromCharCode(a.length+h.length>>8&255), -g=g+String.fromCharCode(a.length+h.length&255),g=g+a+h,a=""+String.fromCharCode(4),a=a+String.fromCharCode(255),a=a+String.fromCharCode(g.length>>24),a=a+String.fromCharCode(g.length>>16&255),a=a+String.fromCharCode(g.length>>8&255),a=a+String.fromCharCode(g.length&255),h=String.fromCharCode(0),h=h+String.fromCharCode(0),j=openpgp_crypto_hashData(f,c+g+a);util.print_debug("DSA Signature is calculated with:|"+c+g+a+"|\n"+util.hexstrdump(c+g+a)+"\n hash:"+util.hexstrdump(j));h+=j.charAt(0);h+=j.charAt(1); -h+=openpgp_crypto_signData(f,d.privateKeyPacket.publicKey.publicKeyAlgorithm,e.MPIs,d.privateKeyPacket.secMPIs,c+g+a);return{openpgp:openpgp_packet.write_packet_header(2,(g+h).length)+g+h,hash:util.get_hashAlgorithmString(f)}};this.verify=function(a,b){var d;d=""+String.fromCharCode(this.version);d+=String.fromCharCode(255);d+=String.fromCharCode(this.signatureData.length>>24);d+=String.fromCharCode(this.signatureData.length>>16&255);d+=String.fromCharCode(this.signatureData.length>>8&255);d+=String.fromCharCode(this.signatureData.length& -255);switch(this.signatureType){case 0:this.verified=4==this.version?openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.MPIs,b.obj.publicKeyPacket.MPIs,a+this.signatureData+d):3==this.version?openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.MPIs,b.obj.publicKeyPacket.MPIs,a+this.signatureData):!1;break;case 1:var e=a.replace(/\r\n/g,"\n").replace(/[\t ]+\n/g,"\n").replace(/\n/g,"\r\n");openpgp.config.debug&&(util.print_debug("tohash: "+util.hexdump(e)), -util.print_debug("signatureData: "+util.hexdump(this.signatureData)),util.print_debug("trailer: "+util.hexdump(d)));this.verified=4==this.version?openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.MPIs,b.obj.publicKeyPacket.MPIs,e+this.signatureData+d):3==this.version?openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.MPIs,b.obj.publicKeyPacket.MPIs,e+this.signatureData):!1;break;case 2:this.verified=4==this.version?openpgp_crypto_verifySignature(this.publicKeyAlgorithm, -this.hashAlgorithm,this.MPIs,b.obj.publicKeyPacket.MPIs,this.signatureData+d):!1;break;case 16:case 17:case 18:case 19:case 48:this.verified=openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.MPIs,b.MPIs,a+this.signatureData+d);break;case 24:if(3==this.version){this.verified=!1;break}this.verified=openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.MPIs,b.MPIs,a+this.signatureData+d);break;case 25:case 31:case 32:case 40:this.verified=openpgp_crypto_verifySignature(this.publicKeyAlgorithm, -this.hashAlgorithm,this.MPIs,b.MPIs,a+this.signatureData+d);break;default:util.print_error("openpgp.packet.signature.js\nsignature verification for type"+this.signatureType+" not implemented"),this.verified=!1}return this.verified};this.read_packet=function(a,b,d){this.data=a.substring(b,b+d);if(0>d)return util.print_debug("openpgp.packet.signature.js\nopenpgp_packet_signature read_packet length < 0 @:"+b),null;var e=b;this.packetLength=d;this.version=a.charCodeAt(e++);switch(this.version){case 3:5!= -a.charCodeAt(e++)&&util.print_debug("openpgp.packet.signature.js\ninvalid One-octet length of following hashed material. MUST be 5. @:"+(e-1));d=e;this.signatureType=a.charCodeAt(e++);this.creationTime=new Date(1E3*(a.charCodeAt(e++)<<24|a.charCodeAt(e++)<<16|a.charCodeAt(e++)<<8|a.charCodeAt(e++)));this.signatureData=a.substring(d,e);this.keyId=a.substring(e,e+8);e+=8;this.publicKeyAlgorithm=a.charCodeAt(e++);this.hashAlgorithm=a.charCodeAt(e++);this.signedHashValue=a.charCodeAt(e++)<<8|a.charCodeAt(e++); -d=0;0this.publicKeyAlgorithm?d=1:17==this.publicKeyAlgorithm&&(d=2);this.MPIs=[];for(var f=0;fthis.publicKeyAlgorithm?d=1:17==this.publicKeyAlgorithm&&(d=2);this.MPIs=[];for(f=0;fb.charCodeAt(e)?(packet_length=b.charCodeAt(e++),f=1):192<=b.charCodeAt(e)&&224>b.charCodeAt(e)?(packet_length=(b.charCodeAt(e++)-192<<8)+b.charCodeAt(e++)+192,f=2):223b.charCodeAt(e)? -(packet_length=1<<(b.charCodeAt(e++)&31),f=1):(f=5,e++,packet_length=b.charCodeAt(e++)<<24|b.charCodeAt(e++)<<16|b.charCodeAt(e++)<<8|b.charCodeAt(e++));b.charCodeAt(e++);packet_length--;f++;this.userattributes[0]=[];this.userattributes[0]=b.substring(e,e+packet_length);e+=packet_length;d+=f+packet_length}this.packetLength=e-a;return this};this.read_nodes=function(b,a,c,d){this.parentNode=b;for(var e=c,f=d;a.length!=e;){var g=openpgp_packet.read_packet(a,e,f);if(null==g){util.print_error("openpgp.packet.userattribute.js\n[user_attr] parsing ends here @:"+ -e+" l:"+f);break}else switch(g.tagType){case 2:15g.signatureType?this.certificationSignatures[this.certificationSignatures.length]=g:32==g.signatureType&&(this.certificationRevocationSignatures[this.certificationRevocationSignatures.length]=g);e+=g.packetLength+g.headerLength;f=d-(e-c);break;default:return this.data=a,this.position=c-b.packetLength,this.len=e-c}}this.data=a;this.position=c-b.packetLength;return this.len=e-c};this.toString=function(){for(var b="5.12. User Attribute Packet (Tag 17)\n AttributePackets: (count = "+ -this.userattributes.length+")\n",a=0;ag.signatureType){this.certificationSignatures[this.certificationSignatures.length]=g; -break}else if(48==g.signatureType){this.certificationRevocationSignatures[this.certificationRevocationSignatures.length]=g;break}else if(24==g.signatureType){this.certificationSignatures[this.certificationSignatures.length]=g;break}else util.print_debug("unknown sig t: "+g.signatureType+"@"+(e-(g.packetLength+g.headerLength)));default:return this.data=a,this.position=c-b.packetLength,this.len=e-c-(g.headerLength+g.packetLength)}}this.data=a;this.position=c-b.packetLength;return this.len=e-c-(g.headerLength+ -g.packetLength)}if(5==b.tagType){this.parentNode=b;for(e=c;a.length!=e;)if(g=openpgp_packet.read_packet(a,e,f-(e-c)),null==g){util.print_error("parsing ends here @:"+e+" l:"+f);break}else switch(e+=g.packetLength+g.headerLength,g.tagType){case 2:15g.signatureType?this.certificationSignatures[this.certificationSignatures.length]=g:48==g.signatureType&&(this.certificationRevocationSignatures[this.certificationRevocationSignatures.length]=g);default:return this.data=a,this.position= -c-b.packetLength,this.len=e-c-(g.headerLength+g.packetLength)}}else util.print_error("unknown parent node for a userId packet "+b.tagType)};this.toString=function(){for(var b=" 5.11. User ID Packet (Tag 13)\n text ("+this.text.length+'): "'+this.text.replace("<","<")+'"\n',b=b+"certification signatures:\n",a=0;athis.certificationSignatures[c].creationTime){var f= -String.fromCharCode(153)+b.header.substring(1)+b.data+String.fromCharCode(180)+String.fromCharCode(a.length>>24&255)+String.fromCharCode(a.length>>16&255)+String.fromCharCode(a.length>>8&255)+String.fromCharCode(a.length&255)+a;if(e.verify(f,d)){result[c]=this.certificationSignatures[c].issuerKeyId==b.getKeyId()?6:3;continue}}f=String.fromCharCode(153)+b.header.substring(1)+b.data+String.fromCharCode(180)+String.fromCharCode(a.length>>24&255)+String.fromCharCode(a.length>>16&255)+String.fromCharCode(a.length>> -8&255)+String.fromCharCode(a.length&255)+a;result[c]=this.certificationSignatures[c].verify(f,d)?4:0}}else if(3==this.certificationSignatures[c].version)if(null==this.certificationSignatures[c].keyId)result[c]=0;else if(d=openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[c].keyId),null==d||0==d.length)result[c]=2;else if(d=publicKey.obj.getSigningKey(),null==d)result[c]=0;else{e=this.hasCertificationRevocationSignature(this.certificationSignatures[c].keyId);if(null!=e&&e.creationTime> -this.certificationSignatures[c].creationTime&&(f=String.fromCharCode(153)+this.publicKeyPacket.header.substring(1)+this.publicKeyPacket.data+a,e.verify(f,d))){result[c]=e.keyId==b.getKeyId()?6:3;continue}f=String.fromCharCode(153)+b.header.substring(1)+b.data+a;result[c]=this.certificationSignatures[c].verify(f,d)?4:0}else result[c]=0;return result};this.verify=function(b){b=this.verifyCertificationSignatures(b);return-1!=b.indexOf(6)?2:-1!=b.indexOf(5)?1:0};this.addCertification=function(){};this.revokeCertification= -function(){}}function openpgp_type_keyid(){this.read_packet=function(b,a){this.bytes=b.substring(a,a+8);return this};this.toString=function(){return util.hexstrdump(this.bytes)}} -function openpgp_type_mpi(){this.data=this.mpiByteLength=this.mpiBitLength=this.MPI=null;this.read=function(b,a){var c=a;this.mpiBitLength=b.charCodeAt(c++)<<8|b.charCodeAt(c++);this.mpiByteLength=(this.mpiBitLength-this.mpiBitLength%8)/8;0!=this.mpiBitLength%8&&this.mpiByteLength++;this.MPI=b.substring(c,c+this.mpiByteLength);this.data=b.substring(a,a+2+this.mpiByteLength);this.packetLength=this.mpiByteLength+2;return this};this.toBigInteger=function(){return new BigInteger(util.hexstrdump(this.MPI), -16)};this.toString=function(){var b=" MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x",b=b+util.hexstrdump(this.MPI);return b+"\n"};this.create=function(b){this.MPI=b;var a=8*(b.length-1),c;a:for(var d=b.charCodeAt(0),e=0;9>e;e++)if(0==d>>e){c=e;break a}this.mpiBitLength=a+c;this.mpiByteLength=b.length;return this};this.toBin=function(){var b=String.fromCharCode(this.mpiBitLength>>8&255),b=b+String.fromCharCode(this.mpiBitLength&255);return b+=this.MPI};this.getByteLength=function(){return this.mpiByteLength}} -function openpgp_type_s2k(){this.read=function(b,a){var c=a;this.type=b.charCodeAt(c++);switch(this.type){case 0:this.hashAlgorithm=b.charCodeAt(c++);this.s2kLength=1;break;case 1:this.hashAlgorithm=b.charCodeAt(c++);this.saltValue=b.substring(c,c+8);this.s2kLength=9;break;case 3:this.hashAlgorithm=b.charCodeAt(c++);this.saltValue=b.substring(c,c+8);c+=8;this.EXPBIAS=6;c=b.charCodeAt(c++);this.count=16+(c&15)<<(c>>4)+this.EXPBIAS;this.s2kLength=10;break;case 101:"GNU"==b.substring(c+1,c+4)?(this.hashAlgorithm= -b.charCodeAt(c++),c+=3,c=1E3+b.charCodeAt(c++),1001==c?(this.type=c,this.s2kLength=5):util.print_error("unknown s2k gnu protection mode! "+this.type)):util.print_error("unknown s2k type! "+this.type);break;default:util.print_error("unknown s2k type! "+this.type)}return this};this.write=function(b,a,c,d,e){this.type=b;if(3==this.type)this.saltValue=d,this.hashAlgorithm=a,this.count=16+(e&15)<<(e>>4)+6,this.s2kLength=10;return this.produce_key(c)};this.produce_key=function(b,a){b=util.encode_utf8(b); -if(0==this.type)return openpgp_crypto_hashData(this.hashAlgorithm,b);if(1==this.type)return openpgp_crypto_hashData(this.hashAlgorithm,this.saltValue+b);if(3==this.type){var c=[];for(c[0]=this.saltValue+b;c.length*(this.saltValue+b).lengththis.count&&(c=c.substr(0,this.count));return a&&(24==a||32==a)?openpgp_crypto_hashData(this.hashAlgorithm,c)+openpgp_crypto_hashData(this.hashAlgorithm,String.fromCharCode(0)+c):openpgp_crypto_hashData(this.hashAlgorithm, -c)}return null}} -var Util=function(){this.emailRegEx=/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;this.hexdump=function(a){for(var b=[],e=a.length,f=0,g,h=0;fg.length;)g="0"+g;b.push(" "+g);h++;0==h%32&&b.push("\n ")}return b.join("")};this.hexstrdump=function(a){if(null==a)return"";for(var b=[],e=a.length,f=0,g;fg.length;)g="0"+ -g;b.push(""+g)}return b.join("")};this.hex2bin=function(a){for(var b="",e=0;eg.length;)g="0"+g;b.push(""+g)}return b.join("")};this.encode_utf8=function(a){return unescape(encodeURIComponent(a))};this.decode_utf8=function(a){try{return decodeURIComponent(escape(a))}catch(b){return a}};var b=function(a,b){for(var e=0;e");if(a==this.printLevel.debug)e='

      '+b+"

      ";else{var f;switch(a){case this.printLevel.error:e="FF8888";f="ERROR";break;case this.printLevel.warning:e="FFAA88";f="WARNING";break;case this.printLevel.info:e="88FF88",f="INFO"}e='

      '+ -f+":"+b+"

      "}showMessages(e)};this.getLeftNBits=function(a,b){var e=b%8;return 0==e?a.substring(0,b/8):this.shiftRight(a.substring(0,(b-e)/8+1),8-e)};this.shiftRight=function(a,b){var e=util.str2bin(a);if(0!=b%8)for(var f=e.length-1;0<=f;f--)e[f]>>=b%8,0>=1,0==I&&(I=b(),a=1&I,I=I>>1|128),a}function e(a){for(var b=0,c=a;c--;)b=b<<1|d();return a&&(b=A[b]>>8-a),b}function f(){y=0}function g(a){r++,x[y++]=a,t.push(String.fromCharCode(a)),32768==y&&(y=0)}function h(){this.b0=0,this.b1=0,this.jump=null,this.jumppos=-1}function i(){for(;;){if(S[R]>=U)return-1;if(T[S[R]]==R)return S[R]++;S[R]++}}function j(){var a,b=Q[P];if(u&&document.write("
      len:"+R+" treepos:"+P),17==R)return-1;if(P++,R++,a=i(),u&&document.write("
      IsPat "+a),a>=0)b.b0=a,u&&document.write("
      b0 "+b.b0);else if(b.b0=32768,u&&document.write("
      b0 "+b.b0),j())return-1;if(a=i(),a>=0)b.b1=a,u&&document.write("
      b1 "+b.b1),b.jump=null;else if(b.b1=32768,u&&document.write("
      b1 "+b.b1),b.jump=Q[P],b.jumppos=P,j())return-1;return R--,0}function k(a,b,c,d){var e;for(u&&document.write("currentTree "+a+" numval "+b+" lengths "+c+" show "+d),Q=a,P=0,T=c,U=b,e=0;17>e;e++)S[e]=0;if(R=0,j())return u&&alert("invalid huffman tree\n"),-1;if(u){document.write("
      Tree: "+Q.length);for(var f=0;32>f;f++)document.write("Places["+f+"].b0="+Q[f].b0+"
      "),document.write("Places["+f+"].b1="+Q[f].b1+"
      ")}return 0}function l(a){for(var b,c,e,f=0,g=a[f];;)if(e=d(),u&&document.write("b="+e),e){if(!(32768&g.b1))return u&&document.write("ret1"),g.b1;for(g=g.jump,b=a.length,c=0;b>c;c++)if(a[c]===g){f=c;break}}else{if(!(32768&g.b0))return u&&document.write("ret2"),g.b0;f++,g=a[f]}}function m(){var a,i,j,m,n;do{switch(a=d(),j=e(2)){case 0:u&&alert("Stored\n");break;case 1:u&&alert("Fixed Huffman codes\n");break;case 2:u&&alert("Dynamic Huffman codes\n");break;case 3:u&&alert("Reserved block type!!\n");break;default:u&&alert("Unexpected value %d!\n",j)}if(0==j){var o,p;for(c(),o=b(),o|=b()<<8,p=b(),p|=b()<<8,65535&(o^~p)&&document.write("BlockLen checksum mismatch\n");o--;)i=b(),g(i)}else if(1==j)for(var q;;)if(q=A[e(7)]>>1,q>23?(q=q<<1|d(),q>199?(q-=128,q=q<<1|d()):(q-=48,q>143&&(q+=136))):q+=256,256>q)g(q);else{if(256==q)break;var n,r;for(q-=257,n=e(C[q])+B[q],q=A[e(5)]>>3,E[q]>8?(r=e(8),r|=e(E[q]-8)<<8):r=e(E[q]),r+=D[q],q=0;n>q;q++){var i=x[y-r&32767];g(i)}}else if(2==j){var q,s,t,v,w,z=new Array(320);for(t=257+e(5),v=1+e(5),w=4+e(4),q=0;19>q;q++)z[q]=0;for(q=0;w>q;q++)z[F[q]]=e(3);for(n=O.length,m=0;n>m;m++)O[m]=new h;if(k(O,19,z,0))return f(),1;if(u){document.write("
      distanceTree");for(var G=0;G"+O[G].b0+" "+O[G].b1+" "+O[G].jump+" "+O[G].jumppos)}s=t+v,m=0;var H=-1;for(u&&document.write("
      n="+s+" bits: "+J+"
      ");s>m;)if(H++,q=l(O),u&&document.write("
      "+H+" i:"+m+" decode: "+q+" bits "+J+"
      "),16>q)z[m++]=q;else if(16==q){var I;if(q=3+e(2),m+q>s)return f(),1;for(I=m?z[m-1]:0;q--;)z[m++]=I}else{if(q=17==q?3+e(3):11+e(7),m+q>s)return f(),1;for(;q--;)z[m++]=0}for(n=N.length,m=0;n>m;m++)N[m]=new h;if(k(N,t,z,0))return f(),1;for(n=N.length,m=0;n>m;m++)O[m]=new h;var K=new Array;for(m=t;mliteralTree");a:for(;;)if(q=l(N),q>=256){var n,r;if(q-=256,0==q)break;for(q--,n=e(C[q])+B[q],q=l(O),E[q]>8?(r=e(8),r|=e(E[q]-8)<<8):r=e(E[q]),r+=D[q];n--;){if(0>y-r)break a;var i=x[y-r&32767];g(i)}}else g(q)}}while(!a);return f(),c(),0}function n(){u&&alert("NEXTFILE"),t=[];var a=[];if(z=!1,a[0]=b(),a[1]=b(),u&&alert("type: "+a[0]+" "+a[1]),a[0]==parseInt("78",16)&&a[1]==parseInt("da",16)&&(u&&alert("GEONExT-GZIP"),m(),u&&alert(t.join("")),w[v]=new Array(2),w[v][0]=t.join(""),w[v][1]="geonext.gxt",v++),a[0]==parseInt("78",16)&&a[1]==parseInt("9c",16)&&(u&&alert("ZLIB"),m(),u&&alert(t.join("")),w[v]=new Array(2),w[v][0]=t.join(""),w[v][1]="ZLIB",v++),a[0]==parseInt("1f",16)&&a[1]==parseInt("8b",16)&&(u&&alert("GZIP"),o(),u&&alert(t.join("")),w[v]=new Array(2),w[v][0]=t.join(""),w[v][1]="file",v++),a[0]==parseInt("50",16)&&a[1]==parseInt("4b",16)&&(z=!0,a[2]=b(),a[3]=b(),a[2]==parseInt("3",16)&&a[3]==parseInt("4",16))){a[0]=b(),a[1]=b(),u&&alert("ZIP-Version: "+a[1]+" "+a[0]/10+"."+a[0]%10),p=b(),p|=b()<<8,u&&alert("gpflags: "+p);var c=b();c|=b()<<8,u&&alert("method: "+c),b(),b(),b(),b();var d=b();d|=b()<<8,d|=b()<<16,d|=b()<<24;var e=b();e|=b()<<8,e|=b()<<16,e|=b()<<24;var f=b();f|=b()<<8,f|=b()<<16,f|=b()<<24,u&&alert("local CRC: "+d+"\nlocal Size: "+f+"\nlocal CompSize: "+e);var g=b();g|=b()<<8;var h=b();for(h|=b()<<8,u&&alert("filelen "+g),j=0,L=[];g--;){var i=b();"/"==i|":"==i?j=0:K-1>j&&(L[j++]=String.fromCharCode(i))}u&&alert("nameBuf: "+L),s||(s=L);for(var j=0;h>j;)i=b(),j++;q=4294967295,r=0,0==f&&"/"==fileOut.charAt(s.length-1)&&u&&alert("skipdir"),8==c&&(m(),u&&alert(t.join("")),w[v]=new Array(2),w[v][0]=t.join(""),w[v][1]=L.join(""),v++),o()}}function o(){var a,c,d,e,f,g,h=[];if(8&p&&(h[0]=b(),h[1]=b(),h[2]=b(),h[3]=b(),h[0]==parseInt("50",16)&&h[1]==parseInt("4b",16)&&h[2]==parseInt("07",16)&&h[3]==parseInt("08",16)?(a=b(),a|=b()<<8,a|=b()<<16,a|=b()<<24):a=h[0]|h[1]<<8|h[2]<<16|h[3]<<24,c=b(),c|=b()<<8,c|=b()<<16,c|=b()<<24,d=b(),d|=b()<<8,d|=b()<<16,d|=b()<<24,u&&alert("CRC:")),z&&n(),h[0]=b(),8!=h[0])return u&&alert("Unknown compression method!"),0;if(p=b(),u&&p&~parseInt("1f",16)&&alert("Unknown flags set!"),b(),b(),b(),b(),b(),e=b(),4&p)for(h[0]=b(),h[2]=b(),R=h[0]+256*h[1],u&&alert("Extra field size: "+R),f=0;R>f;f++)b();if(8&p){for(f=0,L=[];g=b();)("7"==g||":"==g)&&(f=0),K-1>f&&(L[f++]=g);u&&alert("original file name: "+L)}if(16&p)for(;g=b(););2&p&&(b(),b()),m(),a=b(),a|=b()<<8,a|=b()<<16,a|=b()<<24,d=b(),d|=b()<<8,d|=b()<<16,d|=b()<<24,z&&n()}var p,q,r,s,t=[],u=!1,v=0,w=[],x=new Array(32768),y=0,z=!1,A=[0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255],B=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],C=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99],D=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],E=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],F=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],G=a,H=0,I=1,J=0,K=256,L=[],M=288,N=new Array(M),O=new Array(32),P=0,Q=null,R=(new Array(64),new Array(64),0),S=new Array(17);S[0]=0;var T,U;JXG.Util.Unzip.prototype.unzipFile=function(a){var b;for(this.unzip(),b=0;b>2,f=(3&b)<<4|c>>4,g=(15&c)<<2|d>>6,h=63&d,isNaN(c)?g=h=64:isNaN(d)&&(h=64),i.push([this._keyStr.charAt(e),this._keyStr.charAt(f),this._keyStr.charAt(g),this._keyStr.charAt(h)].join(""));return i.join("")},decode:function(a,b){var c,d,e,f,g,h,i,j=[],k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,d=(15&g)<<4|h>>2,e=(3&h)<<6|i,j.push(String.fromCharCode(c)),64!=h&&j.push(String.fromCharCode(d)),64!=i&&j.push(String.fromCharCode(e));return j=j.join(""),b&&(j=JXG.Util.Base64._utf8_decode(j)),j},_utf8_encode:function(a){a=a.replace(/\r\n/g,"\n");for(var b="",c=0;cd?b+=String.fromCharCode(d):d>127&&2048>d?(b+=String.fromCharCode(d>>6|192),b+=String.fromCharCode(63&d|128)):(b+=String.fromCharCode(d>>12|224),b+=String.fromCharCode(d>>6&63|128),b+=String.fromCharCode(63&d|128))}return b},_utf8_decode:function(a){for(var b=[],c=0,d=0,e=0,f=0;cd?(b.push(String.fromCharCode(d)),c++):d>191&&224>d?(e=a.charCodeAt(c+1),b.push(String.fromCharCode((31&d)<<6|63&e)),c+=2):(e=a.charCodeAt(c+1),f=a.charCodeAt(c+2),b.push(String.fromCharCode((15&d)<<12|(63&e)<<6|63&f)),c+=3);return b.join("")},_destrip:function(a,b){var c,d,e=[],f=[];for(null==b&&(b=76),a.replace(/ /g,""),c=a.length/b,d=0;c>d;d++)e[d]=a.substr(d*b,b);for(c!=a.length/b&&(e[e.length]=a.substr(c*b,a.length-c*b)),d=0;d255)switch(c){case 8364:c=128;break;case 8218:c=130;break;case 402:c=131;break;case 8222:c=132;break;case 8230:c=133;break;case 8224:c=134;break;case 8225:c=135;break;case 710:c=136;break;case 8240:c=137;break;case 352:c=138;break;case 8249:c=139;break;case 338:c=140;break;case 381:c=142;break;case 8216:c=145;break;case 8217:c=146;break;case 8220:c=147;break;case 8221:c=148;break;case 8226:c=149;break;case 8211:c=150;break;case 8212:c=151;break;case 732:c=152;break;case 8482:c=153;break;case 353:c=154;break;case 8250:c=155;break;case 339:c=156;break;case 382:c=158;break;case 376:c=159}return c},JXG.Util.utf8Decode=function(a){var b,c=[],d=0,e=0,f=0;if(!JXG.exists(a))return"";for(;de?(c.push(String.fromCharCode(e)),d++):e>191&&224>e?(f=a.charCodeAt(d+1),c.push(String.fromCharCode((31&e)<<6|63&f)),d+=2):(f=a.charCodeAt(d+1),b=a.charCodeAt(d+2),c.push(String.fromCharCode((15&e)<<12|(63&f)<<6|63&b)),d+=3);return c.join("")},JXG.Util.genUUID=function(){for(var a,b="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),c=new Array(36),d=0,e=0;36>e;e++)8==e||13==e||18==e||23==e?c[e]="-":14==e?c[e]="4":(2>=d&&(d=33554432+16777216*Math.random()|0),a=15&d,d>>=4,c[e]=b[19==e?3&a|8:a]);return c.join("")},b.exports=JXG},{}],3:[function(a,b){var c=a("../enums.js");b.exports={prefer_hash_algorithm:c.hash.sha256,encryption_cipher:c.symmetric.aes256,compression:c.compression.zip,show_version:!0,show_comment:!0,integrity_protect:!0,keyserver:"keyserver.linux.it",versionstring:"OpenPGP.js v0.0.1.20140102",commentstring:"http://openpgpjs.org",debug:!1}},{"../enums.js":27}],4:[function(a,b){var c=a("../util"),d=a("./cipher");b.exports={encrypt:function(a,b,e,f,g){b=new d[b](f);var h=b.blockSize,i=new Array(h),j=new Array(h);a=a+a.charAt(h-2)+a.charAt(h-1),c.print_debug("prefixrandom:"+c.hexstrdump(a));for(var k="",l=0;h>l;l++)i[l]=0;j=b.encrypt(i);for(var l=0;h>l;l++)k+=String.fromCharCode(j[l]^a.charCodeAt(l));for(var l=0;h>l;l++)i[l]=k.charCodeAt(l);if(j=b.encrypt(i),k+=String.fromCharCode(j[0]^a.charCodeAt(h)),k+=String.fromCharCode(j[1]^a.charCodeAt(h+1)),g)for(var l=0;h>l;l++)i[l]=k.charCodeAt(l+2);else for(var l=0;h>l;l++)i[l]=k.charCodeAt(l);if(j=b.encrypt(i,f),g){for(var l=0;h>l;l++)k+=String.fromCharCode(j[l]^e.charCodeAt(l));for(n=h+2;nl;l++)i[l]=k.charCodeAt(n+l);j=b.encrypt(i);for(var l=0;h>l;l++)k+=String.fromCharCode(j[l]^e.charCodeAt(n-2+l))}}else{e=" "+e;for(var l=2;h>l;l++)k+=String.fromCharCode(j[l]^e.charCodeAt(l));var m=k.substring(0,2*h).split(""),o=k.substring(h);for(n=h;nl;l++)i[l]=o.charCodeAt(l);o="",j=b.encrypt(i);for(var l=0;h>l;l++)m.push(String.fromCharCode(j[l]^e.charCodeAt(n+l))),o+=String.fromCharCode(j[l]^e.charCodeAt(n+l))}k=m.join("")}return k=k.substring(0,e.length+2+h)},mdc:function(a,b,e){a=new d[a](b);var f,g=a.blockSize,h=new Array(g),i=new Array(g);for(f=0;g>f;f++)h[f]=0;for(h=a.encrypt(h),f=0;g>f;f++)i[f]=e.charCodeAt(f),h[f]^=i[f];return i=a.encrypt(i),c.bin2str(h)+String.fromCharCode(i[0]^e.charCodeAt(g))+String.fromCharCode(i[1]^e.charCodeAt(g+1))},decrypt:function(a,b,c,e){a=new d[a](b);var f,g=a.blockSize,h=new Array(g),i=new Array(g),j="",k=[];for(f=0;g>f;f++)h[f]=0;for(h=a.encrypt(h,b),f=0;g>f;f++)i[f]=c.charCodeAt(f),h[f]^=i[f];if(i=a.encrypt(i,b),h[g-2]!=(i[0]^c.charCodeAt(g))||h[g-1]!=(i[1]^c.charCodeAt(g+1)))throw new Error("Invalid data.");if(e){for(f=0;g>f;f++)h[f]=c.charCodeAt(f+2);for(j=g+2;jf&&f+jf;f++)h[f]=c.charCodeAt(f);for(j=g;jf&&f+jg*j;){var m=a.encrypt(c.str2bin(i));h=e.substring(j*g,j*g+g);for(var n=0;nl;l++)h+=String.fromCharCode(0);else h=f.substring(0,g);for(;e.length>g*i;){var m=a.encrypt(c.str2bin(h));h=e.substring(i*g+k,i*g+g+k);for(var l=0;l>8&255}function e(a){return a>>16&255}function f(a){return a>>24&255}function g(a,b,c,e){return d(o[255&a])|d(o[b>>8&255])<<8|d(o[c>>16&255])<<16|d(o[e>>>24])<<24}function h(a){var b,c,d=a.length,e=new Array(d/4);if(a&&!(d%4)){for(b=0,c=0;d>c;c+=4)e[b++]=a[c]|a[c+1]<<8|a[c+2]<<16|a[c+3]<<24;return e}}function i(a){var b,g=0,h=a.length,i=new Array(4*h);for(b=0;h>b;b++)i[g++]=c(a[b]),i[g++]=d(a[b]),i[g++]=e(a[b]),i[g++]=f(a[b]);return i}function j(a){var b,g,h,i,j,k,l=new Array(t+1),o=a.length,p=new Array(s),q=new Array(s),r=0;if(16==o)k=10,b=4;else if(24==o)k=12,b=6;else{if(32!=o)throw new Error("Invalid key-length for AES key:"+o);k=14,b=8}for(g=0;t+1>g;g++)l[g]=new Array(4);for(g=0,h=0;o>h;h++,g+=4)p[h]=a.charCodeAt(g)|a.charCodeAt(g+1)<<8|a.charCodeAt(g+2)<<16|a.charCodeAt(g+3)<<24;for(h=b-1;h>=0;h--)q[h]=p[h];for(i=0,j=0,h=0;b>h&&k+1>i;){for(;b>h&&4>j;h++,j++)l[i][j]=q[h];4==j&&(i++,j=0)}for(;k+1>i;){var u=q[b-1];if(q[0]^=n[d(u)]|n[e(u)]<<8|n[f(u)]<<16|n[c(u)]<<24,q[0]^=m[r++],8!=b)for(h=1;b>h;h++)q[h]^=q[h-1];else{for(h=1;b/2>h;h++)q[h]^=q[h-1];for(u=q[b/2-1],q[b/2]^=n[c(u)]|n[d(u)]<<8|n[e(u)]<<16|n[f(u)]<<24,h=b/2+1;b>h;h++)q[h]^=q[h-1]}for(h=0;b>h&&k+1>i;){for(;b>h&&4>j;h++,j++)l[i][j]=q[h];4==j&&(i++,j=0)}}return this.rounds=k,this.rk=l,this}function k(a,b){var c,d,e,f,j,k=h(a),l=b.rounds,m=k[0],n=k[1],s=k[2],t=k[3];for(c=0;l-1>c;c++)d=m^b.rk[c][0],e=n^b.rk[c][1],f=s^b.rk[c][2],j=t^b.rk[c][3],m=o[255&d]^p[e>>8&255]^q[f>>16&255]^r[j>>>24],n=o[255&e]^p[f>>8&255]^q[j>>16&255]^r[d>>>24],s=o[255&f]^p[j>>8&255]^q[d>>16&255]^r[e>>>24],t=o[255&j]^p[d>>8&255]^q[e>>16&255]^r[f>>>24];return c=l-1,d=m^b.rk[c][0],e=n^b.rk[c][1],f=s^b.rk[c][2],j=t^b.rk[c][3],k[0]=g(d,e,f,j)^b.rk[l][0],k[1]=g(e,f,j,d)^b.rk[l][1],k[2]=g(f,j,d,e)^b.rk[l][2],k[3]=g(j,d,e,f)^b.rk[l][3],i(k)}function l(a){var b=function(a){this.key=j(a),this.encrypt=function(a){return k(a,this.key)}};return b.blockSize=b.prototype.blockSize=16,b.keySize=b.prototype.keySize=a/8,b}var m=(a("../../util"),[1,2,4,8,16,32,64,128,27,54,108,216,171,77,154,47,94,188,99,198,151,53,106,212,179,125,250,239,197,145]),n=[99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22],o=[2774754246,2222750968,2574743534,2373680118,234025727,3177933782,2976870366,1422247313,1345335392,50397442,2842126286,2099981142,436141799,1658312629,3870010189,2591454956,1170918031,2642575903,1086966153,2273148410,368769775,3948501426,3376891790,200339707,3970805057,1742001331,4255294047,3937382213,3214711843,4154762323,2524082916,1539358875,3266819957,486407649,2928907069,1780885068,1513502316,1094664062,49805301,1338821763,1546925160,4104496465,887481809,150073849,2473685474,1943591083,1395732834,1058346282,201589768,1388824469,1696801606,1589887901,672667696,2711000631,251987210,3046808111,151455502,907153956,2608889883,1038279391,652995533,1764173646,3451040383,2675275242,453576978,2659418909,1949051992,773462580,756751158,2993581788,3998898868,4221608027,4132590244,1295727478,1641469623,3467883389,2066295122,1055122397,1898917726,2542044179,4115878822,1758581177,0,753790401,1612718144,536673507,3367088505,3982187446,3194645204,1187761037,3653156455,1262041458,3729410708,3561770136,3898103984,1255133061,1808847035,720367557,3853167183,385612781,3309519750,3612167578,1429418854,2491778321,3477423498,284817897,100794884,2172616702,4031795360,1144798328,3131023141,3819481163,4082192802,4272137053,3225436288,2324664069,2912064063,3164445985,1211644016,83228145,3753688163,3249976951,1977277103,1663115586,806359072,452984805,250868733,1842533055,1288555905,336333848,890442534,804056259,3781124030,2727843637,3427026056,957814574,1472513171,4071073621,2189328124,1195195770,2892260552,3881655738,723065138,2507371494,2690670784,2558624025,3511635870,2145180835,1713513028,2116692564,2878378043,2206763019,3393603212,703524551,3552098411,1007948840,2044649127,3797835452,487262998,1994120109,1004593371,1446130276,1312438900,503974420,3679013266,168166924,1814307912,3831258296,1573044895,1859376061,4021070915,2791465668,2828112185,2761266481,937747667,2339994098,854058965,1137232011,1496790894,3077402074,2358086913,1691735473,3528347292,3769215305,3027004632,4199962284,133494003,636152527,2942657994,2390391540,3920539207,403179536,3585784431,2289596656,1864705354,1915629148,605822008,4054230615,3350508659,1371981463,602466507,2094914977,2624877800,555687742,3712699286,3703422305,2257292045,2240449039,2423288032,1111375484,3300242801,2858837708,3628615824,84083462,32962295,302911004,2741068226,1597322602,4183250862,3501832553,2441512471,1489093017,656219450,3114180135,954327513,335083755,3013122091,856756514,3144247762,1893325225,2307821063,2811532339,3063651117,572399164,2458355477,552200649,1238290055,4283782570,2015897680,2061492133,2408352771,4171342169,2156497161,386731290,3669999461,837215959,3326231172,3093850320,3275833730,2962856233,1999449434,286199582,3417354363,4233385128,3602627437,974525996],p=[1667483301,2088564868,2004348569,2071721613,4076011277,1802229437,1869602481,3318059348,808476752,16843267,1734856361,724260477,4278118169,3621238114,2880130534,1987505306,3402272581,2189565853,3385428288,2105408135,4210749205,1499050731,1195871945,4042324747,2913812972,3570709351,2728550397,2947499498,2627478463,2762232823,1920132246,3233848155,3082253762,4261273884,2475900334,640044138,909536346,1061125697,4160222466,3435955023,875849820,2779075060,3857043764,4059166984,1903288979,3638078323,825320019,353708607,67373068,3351745874,589514341,3284376926,404238376,2526427041,84216335,2593796021,117902857,303178806,2155879323,3806519101,3958099238,656887401,2998042573,1970662047,151589403,2206408094,741103732,437924910,454768173,1852759218,1515893998,2694863867,1381147894,993752653,3604395873,3014884814,690573947,3823361342,791633521,2223248279,1397991157,3520182632,0,3991781676,538984544,4244431647,2981198280,1532737261,1785386174,3419114822,3200149465,960066123,1246401758,1280088276,1482207464,3486483786,3503340395,4025468202,2863288293,4227591446,1128498885,1296931543,859006549,2240090516,1162185423,4193904912,33686534,2139094657,1347461360,1010595908,2678007226,2829601763,1364304627,2745392638,1077969088,2408514954,2459058093,2644320700,943222856,4126535940,3166462943,3065411521,3671764853,555827811,269492272,4294960410,4092853518,3537026925,3452797260,202119188,320022069,3974939439,1600110305,2543269282,1145342156,387395129,3301217111,2812761586,2122251394,1027439175,1684326572,1566423783,421081643,1936975509,1616953504,2172721560,1330618065,3705447295,572671078,707417214,2425371563,2290617219,1179028682,4008625961,3099093971,336865340,3739133817,1583267042,185275933,3688607094,3772832571,842163286,976909390,168432670,1229558491,101059594,606357612,1549580516,3267534685,3553869166,2896970735,1650640038,2442213800,2509582756,3840201527,2038035083,3890730290,3368586051,926379609,1835915959,2374828428,3587551588,1313774802,2846444e3,1819072692,1448520954,4109693703,3941256997,1701169839,2054878350,2930657257,134746136,3132780501,2021191816,623200879,774790258,471611428,2795919345,3031724999,3334903633,3907570467,3722289532,1953818780,522141217,1263245021,3183305180,2341145990,2324303749,1886445712,1044282434,3048567236,1718013098,1212715224,50529797,4143380225,235805714,1633796771,892693087,1465364217,3115936208,2256934801,3250690392,488454695,2661164985,3789674808,4177062675,2560109491,286335539,1768542907,3654920560,2391672713,2492740519,2610638262,505297954,2273777042,3924412704,3469641545,1431677695,673730680,3755976058,2357986191,2711706104,2307459456,218962455,3216991706,3873888049,1111655622,1751699640,1094812355,2576951728,757946999,252648977,2964356043,1414834428,3149622742,370551866],q=[1673962851,2096661628,2012125559,2079755643,4076801522,1809235307,1876865391,3314635973,811618352,16909057,1741597031,727088427,4276558334,3618988759,2874009259,1995217526,3398387146,2183110018,3381215433,2113570685,4209972730,1504897881,1200539975,4042984432,2906778797,3568527316,2724199842,2940594863,2619588508,2756966308,1927583346,3231407040,3077948087,4259388669,2470293139,642542118,913070646,1065238847,4160029431,3431157708,879254580,2773611685,3855693029,4059629809,1910674289,3635114968,828527409,355090197,67636228,3348452039,591815971,3281870531,405809176,2520228246,84545285,2586817946,118360327,304363026,2149292928,3806281186,3956090603,659450151,2994720178,1978310517,152181513,2199756419,743994412,439627290,456535323,1859957358,1521806938,2690382752,1386542674,997608763,3602342358,3011366579,693271337,3822927587,794718511,2215876484,1403450707,3518589137,0,3988860141,541089824,4242743292,2977548465,1538714971,1792327274,3415033547,3194476990,963791673,1251270218,1285084236,1487988824,3481619151,3501943760,4022676207,2857362858,4226619131,1132905795,1301993293,862344499,2232521861,1166724933,4192801017,33818114,2147385727,1352724560,1014514748,2670049951,2823545768,1369633617,2740846243,1082179648,2399505039,2453646738,2636233885,946882616,4126213365,3160661948,3061301686,3668932058,557998881,270544912,4293204735,4093447923,3535760850,3447803085,202904588,321271059,3972214764,1606345055,2536874647,1149815876,388905239,3297990596,2807427751,2130477694,1031423805,1690872932,1572530013,422718233,1944491379,1623236704,2165938305,1335808335,3701702620,574907938,710180394,2419829648,2282455944,1183631942,4006029806,3094074296,338181140,3735517662,1589437022,185998603,3685578459,3772464096,845436466,980700730,169090570,1234361161,101452294,608726052,1555620956,3265224130,3552407251,2890133420,1657054818,2436475025,2503058581,3839047652,2045938553,3889509095,3364570056,929978679,1843050349,2365688973,3585172693,1318900302,2840191145,1826141292,1454176854,4109567988,3939444202,1707781989,2062847610,2923948462,135272456,3127891386,2029029496,625635109,777810478,473441308,2790781350,3027486644,3331805638,3905627112,3718347997,1961401460,524165407,1268178251,3177307325,2332919435,2316273034,1893765232,1048330814,3044132021,1724688998,1217452104,50726147,4143383030,236720654,1640145761,896163637,1471084887,3110719673,2249691526,3248052417,490350365,2653403550,3789109473,4176155640,2553000856,287453969,1775418217,3651760345,2382858638,2486413204,2603464347,507257374,2266337927,3922272489,3464972750,1437269845,676362280,3752164063,2349043596,2707028129,2299101321,219813645,3211123391,3872862694,1115997762,1758509160,1099088705,2569646233,760903469,253628687,2960903088,1420360788,3144537787,371997206],r=[3332727651,4169432188,4003034999,4136467323,4279104242,3602738027,3736170351,2438251973,1615867952,33751297,3467208551,1451043627,3877240574,3043153879,1306962859,3969545846,2403715786,530416258,2302724553,4203183485,4011195130,3001768281,2395555655,4211863792,1106029997,3009926356,1610457762,1173008303,599760028,1408738468,3835064946,2606481600,1975695287,3776773629,1034851219,1282024998,1817851446,2118205247,4110612471,2203045068,1750873140,1374987685,3509904869,4178113009,3801313649,2876496088,1649619249,708777237,135005188,2505230279,1181033251,2640233411,807933976,933336726,168756485,800430746,235472647,607523346,463175808,3745374946,3441880043,1315514151,2144187058,3936318837,303761673,496927619,1484008492,875436570,908925723,3702681198,3035519578,1543217312,2767606354,1984772923,3076642518,2110698419,1383803177,3711886307,1584475951,328696964,2801095507,3110654417,0,3240947181,1080041504,3810524412,2043195825,3069008731,3569248874,2370227147,1742323390,1917532473,2497595978,2564049996,2968016984,2236272591,3144405200,3307925487,1340451498,3977706491,2261074755,2597801293,1716859699,294946181,2328839493,3910203897,67502594,4269899647,2700103760,2017737788,632987551,1273211048,2733855057,1576969123,2160083008,92966799,1068339858,566009245,1883781176,4043634165,1675607228,2009183926,2943736538,1113792801,540020752,3843751935,4245615603,3211645650,2169294285,403966988,641012499,3274697964,3202441055,899848087,2295088196,775493399,2472002756,1441965991,4236410494,2051489085,3366741092,3135724893,841685273,3868554099,3231735904,429425025,2664517455,2743065820,1147544098,1417554474,1001099408,193169544,2362066502,3341414126,1809037496,675025940,2809781982,3168951902,371002123,2910247899,3678134496,1683370546,1951283770,337512970,2463844681,201983494,1215046692,3101973596,2673722050,3178157011,1139780780,3299238498,967348625,832869781,3543655652,4069226873,3576883175,2336475336,1851340599,3669454189,25988493,2976175573,2631028302,1239460265,3635702892,2902087254,4077384948,3475368682,3400492389,4102978170,1206496942,270010376,1876277946,4035475576,1248797989,1550986798,941890588,1475454630,1942467764,2538718918,3408128232,2709315037,3902567540,1042358047,2531085131,1641856445,226921355,260409994,3767562352,2084716094,1908716981,3433719398,2430093384,100991747,4144101110,470945294,3265487201,1784624437,2935576407,1775286713,395413126,2572730817,975641885,666476190,3644383713,3943954680,733190296,573772049,3535497577,2842745305,126455438,866620564,766942107,1008868894,361924487,3374377449,2269761230,2868860245,1350051880,2776293343,59739276,1509466529,159418761,437718285,1708834751,3610371814,2227585602,3501746280,2193834305,699439513,1517759789,504434447,2076946608,2835108948,1842789307,742004246],s=8,t=14;b.exports={};var u=[128,192,256];for(var v in u)b.exports[u[v]]=l(u[v])},{"../../util":56}],6:[function(a,b){function c(){}function d(a){this.bf=new c,this.bf.init(e.str2bin(a)),this.encrypt=function(a){return this.bf.encrypt_block(a)}}c.prototype.BLOCKSIZE=8,c.prototype.SBOXES=[[3509652390,2564797868,805139163,3491422135,3101798381,1780907670,3128725573,4046225305,614570311,3012652279,134345442,2240740374,1667834072,1901547113,2757295779,4103290238,227898511,1921955416,1904987480,2182433518,2069144605,3260701109,2620446009,720527379,3318853667,677414384,3393288472,3101374703,2390351024,1614419982,1822297739,2954791486,3608508353,3174124327,2024746970,1432378464,3864339955,2857741204,1464375394,1676153920,1439316330,715854006,3033291828,289532110,2706671279,2087905683,3018724369,1668267050,732546397,1947742710,3462151702,2609353502,2950085171,1814351708,2050118529,680887927,999245976,1800124847,3300911131,1713906067,1641548236,4213287313,1216130144,1575780402,4018429277,3917837745,3693486850,3949271944,596196993,3549867205,258830323,2213823033,772490370,2760122372,1774776394,2652871518,566650946,4142492826,1728879713,2882767088,1783734482,3629395816,2517608232,2874225571,1861159788,326777828,3124490320,2130389656,2716951837,967770486,1724537150,2185432712,2364442137,1164943284,2105845187,998989502,3765401048,2244026483,1075463327,1455516326,1322494562,910128902,469688178,1117454909,936433444,3490320968,3675253459,1240580251,122909385,2157517691,634681816,4142456567,3825094682,3061402683,2540495037,79693498,3249098678,1084186820,1583128258,426386531,1761308591,1047286709,322548459,995290223,1845252383,2603652396,3431023940,2942221577,3202600964,3727903485,1712269319,422464435,3234572375,1170764815,3523960633,3117677531,1434042557,442511882,3600875718,1076654713,1738483198,4213154764,2393238008,3677496056,1014306527,4251020053,793779912,2902807211,842905082,4246964064,1395751752,1040244610,2656851899,3396308128,445077038,3742853595,3577915638,679411651,2892444358,2354009459,1767581616,3150600392,3791627101,3102740896,284835224,4246832056,1258075500,768725851,2589189241,3069724005,3532540348,1274779536,3789419226,2764799539,1660621633,3471099624,4011903706,913787905,3497959166,737222580,2514213453,2928710040,3937242737,1804850592,3499020752,2949064160,2386320175,2390070455,2415321851,4061277028,2290661394,2416832540,1336762016,1754252060,3520065937,3014181293,791618072,3188594551,3933548030,2332172193,3852520463,3043980520,413987798,3465142937,3030929376,4245938359,2093235073,3534596313,375366246,2157278981,2479649556,555357303,3870105701,2008414854,3344188149,4221384143,3956125452,2067696032,3594591187,2921233993,2428461,544322398,577241275,1471733935,610547355,4027169054,1432588573,1507829418,2025931657,3646575487,545086370,48609733,2200306550,1653985193,298326376,1316178497,3007786442,2064951626,458293330,2589141269,3591329599,3164325604,727753846,2179363840,146436021,1461446943,4069977195,705550613,3059967265,3887724982,4281599278,3313849956,1404054877,2845806497,146425753,1854211946],[1266315497,3048417604,3681880366,3289982499,290971e4,1235738493,2632868024,2414719590,3970600049,1771706367,1449415276,3266420449,422970021,1963543593,2690192192,3826793022,1062508698,1531092325,1804592342,2583117782,2714934279,4024971509,1294809318,4028980673,1289560198,2221992742,1669523910,35572830,157838143,1052438473,1016535060,1802137761,1753167236,1386275462,3080475397,2857371447,1040679964,2145300060,2390574316,1461121720,2956646967,4031777805,4028374788,33600511,2920084762,1018524850,629373528,3691585981,3515945977,2091462646,2486323059,586499841,988145025,935516892,3367335476,2599673255,2839830854,265290510,3972581182,2759138881,3795373465,1005194799,847297441,406762289,1314163512,1332590856,1866599683,4127851711,750260880,613907577,1450815602,3165620655,3734664991,3650291728,3012275730,3704569646,1427272223,778793252,1343938022,2676280711,2052605720,1946737175,3164576444,3914038668,3967478842,3682934266,1661551462,3294938066,4011595847,840292616,3712170807,616741398,312560963,711312465,1351876610,322626781,1910503582,271666773,2175563734,1594956187,70604529,3617834859,1007753275,1495573769,4069517037,2549218298,2663038764,504708206,2263041392,3941167025,2249088522,1514023603,1998579484,1312622330,694541497,2582060303,2151582166,1382467621,776784248,2618340202,3323268794,2497899128,2784771155,503983604,4076293799,907881277,423175695,432175456,1378068232,4145222326,3954048622,3938656102,3820766613,2793130115,2977904593,26017576,3274890735,3194772133,1700274565,1756076034,4006520079,3677328699,720338349,1533947780,354530856,688349552,3973924725,1637815568,332179504,3949051286,53804574,2852348879,3044236432,1282449977,3583942155,3416972820,4006381244,1617046695,2628476075,3002303598,1686838959,431878346,2686675385,1700445008,1080580658,1009431731,832498133,3223435511,2605976345,2271191193,2516031870,1648197032,4164389018,2548247927,300782431,375919233,238389289,3353747414,2531188641,2019080857,1475708069,455242339,2609103871,448939670,3451063019,1395535956,2413381860,1841049896,1491858159,885456874,4264095073,4001119347,1565136089,3898914787,1108368660,540939232,1173283510,2745871338,3681308437,4207628240,3343053890,4016749493,1699691293,1103962373,3625875870,2256883143,3830138730,1031889488,3479347698,1535977030,4236805024,3251091107,2132092099,1774941330,1199868427,1452454533,157007616,2904115357,342012276,595725824,1480756522,206960106,497939518,591360097,863170706,2375253569,3596610801,1814182875,2094937945,3421402208,1082520231,3463918190,2785509508,435703966,3908032597,1641649973,2842273706,3305899714,1510255612,2148256476,2655287854,3276092548,4258621189,236887753,3681803219,274041037,1734335097,3815195456,3317970021,1899903192,1026095262,4050517792,356393447,2410691914,3873677099,3682840055],[3913112168,2491498743,4132185628,2489919796,1091903735,1979897079,3170134830,3567386728,3557303409,857797738,1136121015,1342202287,507115054,2535736646,337727348,3213592640,1301675037,2528481711,1895095763,1721773893,3216771564,62756741,2142006736,835421444,2531993523,1442658625,3659876326,2882144922,676362277,1392781812,170690266,3921047035,1759253602,3611846912,1745797284,664899054,1329594018,3901205900,3045908486,2062866102,2865634940,3543621612,3464012697,1080764994,553557557,3656615353,3996768171,991055499,499776247,1265440854,648242737,3940784050,980351604,3713745714,1749149687,3396870395,4211799374,3640570775,1161844396,3125318951,1431517754,545492359,4268468663,3499529547,1437099964,2702547544,3433638243,2581715763,2787789398,1060185593,1593081372,2418618748,4260947970,69676912,2159744348,86519011,2512459080,3838209314,1220612927,3339683548,133810670,1090789135,1078426020,1569222167,845107691,3583754449,4072456591,1091646820,628848692,1613405280,3757631651,526609435,236106946,48312990,2942717905,3402727701,1797494240,859738849,992217954,4005476642,2243076622,3870952857,3732016268,765654824,3490871365,2511836413,1685915746,3888969200,1414112111,2273134842,3281911079,4080962846,172450625,2569994100,980381355,4109958455,2819808352,2716589560,2568741196,3681446669,3329971472,1835478071,660984891,3704678404,4045999559,3422617507,3040415634,1762651403,1719377915,3470491036,2693910283,3642056355,3138596744,1364962596,2073328063,1983633131,926494387,3423689081,2150032023,4096667949,1749200295,3328846651,309677260,2016342300,1779581495,3079819751,111262694,1274766160,443224088,298511866,1025883608,3806446537,1145181785,168956806,3641502830,3584813610,1689216846,3666258015,3200248200,1692713982,2646376535,4042768518,1618508792,1610833997,3523052358,4130873264,2001055236,3610705100,2202168115,4028541809,2961195399,1006657119,2006996926,3186142756,1430667929,3210227297,1314452623,4074634658,4101304120,2273951170,1399257539,3367210612,3027628629,1190975929,2062231137,2333990788,2221543033,2438960610,1181637006,548689776,2362791313,3372408396,3104550113,3145860560,296247880,1970579870,3078560182,3769228297,1714227617,3291629107,3898220290,166772364,1251581989,493813264,448347421,195405023,2709975567,677966185,3703036547,1463355134,2715995803,1338867538,1343315457,2802222074,2684532164,233230375,2599980071,2000651841,3277868038,1638401717,4028070440,3237316320,6314154,819756386,300326615,590932579,1405279636,3267499572,3150704214,2428286686,3959192993,3461946742,1862657033,1266418056,963775037,2089974820,2263052895,1917689273,448879540,3550394620,3981727096,150775221,3627908307,1303187396,508620638,2975983352,2726630617,1817252668,1876281319,1457606340,908771278,3720792119,3617206836,2455994898,1729034894,1080033504],[976866871,3556439503,2881648439,1522871579,1555064734,1336096578,3548522304,2579274686,3574697629,3205460757,3593280638,3338716283,3079412587,564236357,2993598910,1781952180,1464380207,3163844217,3332601554,1699332808,1393555694,1183702653,3581086237,1288719814,691649499,2847557200,2895455976,3193889540,2717570544,1781354906,1676643554,2592534050,3230253752,1126444790,2770207658,2633158820,2210423226,2615765581,2414155088,3127139286,673620729,2805611233,1269405062,4015350505,3341807571,4149409754,1057255273,2012875353,2162469141,2276492801,2601117357,993977747,3918593370,2654263191,753973209,36408145,2530585658,25011837,3520020182,2088578344,530523599,2918365339,1524020338,1518925132,3760827505,3759777254,1202760957,3985898139,3906192525,674977740,4174734889,2031300136,2019492241,3983892565,4153806404,3822280332,352677332,2297720250,60907813,90501309,3286998549,1016092578,2535922412,2839152426,457141659,509813237,4120667899,652014361,1966332200,2975202805,55981186,2327461051,676427537,3255491064,2882294119,3433927263,1307055953,942726286,933058658,2468411793,3933900994,4215176142,1361170020,2001714738,2830558078,3274259782,1222529897,1679025792,2729314320,3714953764,1770335741,151462246,3013232138,1682292957,1483529935,471910574,1539241949,458788160,3436315007,1807016891,3718408830,978976581,1043663428,3165965781,1927990952,4200891579,2372276910,3208408903,3533431907,1412390302,2931980059,4132332400,1947078029,3881505623,4168226417,2941484381,1077988104,1320477388,886195818,18198404,3786409e3,2509781533,112762804,3463356488,1866414978,891333506,18488651,661792760,1628790961,3885187036,3141171499,876946877,2693282273,1372485963,791857591,2686433993,3759982718,3167212022,3472953795,2716379847,445679433,3561995674,3504004811,3574258232,54117162,3331405415,2381918588,3769707343,4154350007,1140177722,4074052095,668550556,3214352940,367459370,261225585,2610173221,4209349473,3468074219,3265815641,314222801,3066103646,3808782860,282218597,3406013506,3773591054,379116347,1285071038,846784868,2669647154,3771962079,3550491691,2305946142,453669953,1268987020,3317592352,3279303384,3744833421,2610507566,3859509063,266596637,3847019092,517658769,3462560207,3443424879,370717030,4247526661,2224018117,4143653529,4112773975,2788324899,2477274417,1456262402,2901442914,1517677493,1846949527,2295493580,3734397586,2176403920,1280348187,1908823572,3871786941,846861322,1172426758,3287448474,3383383037,1655181056,3139813346,901632758,1897031941,2986607138,3066810236,3447102507,1393639104,373351379,950779232,625454576,3124240540,4148612726,2007998917,544563296,2244738638,2330496472,2058025392,1291430526,424198748,50039436,29584100,3605783033,2429876329,2791104160,1057563949,3255363231,3075367218,3463963227,1469046755,985887462]],c.prototype.PARRAY=[608135816,2242054355,320440878,57701188,2752067618,698298832,137296536,3964562569,1160258022,953160567,3193202383,887688300,3232508343,3380367581,1065670069,3041331479,2450970073,2306472731],c.prototype.NN=16,c.prototype._clean=function(a){if(0>a){var b=2147483647&a; +a=b+2147483648}return a},c.prototype._F=function(a){var b,c,d,e,f;return e=255&a,a>>>=8,d=255&a,a>>>=8,c=255&a,a>>>=8,b=255&a,f=this.sboxes[0][b]+this.sboxes[1][c],f^=this.sboxes[2][d],f+=this.sboxes[3][e]},c.prototype._encrypt_block=function(a){var b,c=a[0],d=a[1];for(b=0;b>>24-8*b&255,e[b+d]=c[1]>>>24-8*b&255;return e},c.prototype._decrypt_block=function(a){var b,c=a[0],d=a[1];for(b=this.NN+1;b>1;--b){c^=this.parray[b],d=this._F(c)^d;var e=c;c=d,d=e}c^=this.parray[1],d^=this.parray[0],a[0]=this._clean(d),a[1]=this._clean(c)},c.prototype.init=function(a){var b,c=0;for(this.parray=[],b=0;bd;++d)e=e<<8|255&a[c],++c>=a.length&&(c=0);this.parray[b]=this.PARRAY[b]^e}for(this.sboxes=[],b=0;4>b;++b)for(this.sboxes[b]=[],c=0;256>c;++c)this.sboxes[b][c]=this.SBOXES[b][c];var f=[0,0];for(b=0;bb;++b)for(c=0;256>c;c+=2)this._encrypt_block(f),this.sboxes[b][c+0]=f[0],this.sboxes[b][c+1]=f[1]};var e=a("../../util");b.exports=d,b.exports.keySize=d.prototype.keySize=16,b.exports.blockSize=d.prototype.blockSize=16},{"../../util":56}],7:[function(a,b){function c(){function a(a,b,c){var d=b+a,e=d<>>32-c;return(f[0][e>>>24]^f[1][e>>>16&255])-f[2][e>>>8&255]+f[3][255&e]}function b(a,b,c){var d=b^a,e=d<>>32-c;return f[0][e>>>24]-f[1][e>>>16&255]+f[2][e>>>8&255]^f[3][255&e]}function c(a,b,c){var d=b-a,e=d<>>32-c;return(f[0][e>>>24]+f[1][e>>>16&255]^f[2][e>>>8&255])-f[3][255&e]}this.BlockSize=8,this.KeySize=16,this.setKey=function(a){if(this.masking=new Array(16),this.rotate=new Array(16),this.reset(),a.length!=this.KeySize)throw new Error("CAST-128: keys must be 16 bytes");return this.keySchedule(a),!0},this.reset=function(){for(var a=0;16>a;a++)this.masking[a]=0,this.rotate[a]=0},this.getBlockSize=function(){return BlockSize},this.encrypt=function(d){for(var e=new Array(d.length),f=0;f>>24&255,e[f+1]=i>>>16&255,e[f+2]=i>>>8&255,e[f+3]=255&i,e[f+4]=h>>>24&255,e[f+5]=h>>>16&255,e[f+6]=h>>>8&255,e[f+7]=255&h}return e},this.decrypt=function(d){for(var e=new Array(d.length),f=0;f>>24&255,e[f+1]=i>>>16&255,e[f+2]=i>>>8&255,e[f+3]=255&i,e[f+4]=h>>>24&255,e[f+5]=h>>16&255,e[f+6]=h>>8&255,e[f+7]=255&h}return e};var d=new Array(4);d[0]=new Array(4),d[0][0]=new Array(4,0,13,15,12,14,8),d[0][1]=new Array(5,2,16,18,17,19,10),d[0][2]=new Array(6,3,23,22,21,20,9),d[0][3]=new Array(7,1,26,25,27,24,11),d[1]=new Array(4),d[1][0]=new Array(0,6,21,23,20,22,16),d[1][1]=new Array(1,4,0,2,1,3,18),d[1][2]=new Array(2,5,7,6,5,4,17),d[1][3]=new Array(3,7,10,9,11,8,19),d[2]=new Array(4),d[2][0]=new Array(4,0,13,15,12,14,8),d[2][1]=new Array(5,2,16,18,17,19,10),d[2][2]=new Array(6,3,23,22,21,20,9),d[2][3]=new Array(7,1,26,25,27,24,11),d[3]=new Array(4),d[3][0]=new Array(0,6,21,23,20,22,16),d[3][1]=new Array(1,4,0,2,1,3,18),d[3][2]=new Array(2,5,7,6,5,4,17),d[3][3]=new Array(3,7,10,9,11,8,19);var e=new Array(4);e[0]=new Array(4),e[0][0]=new Array(24,25,23,22,18),e[0][1]=new Array(26,27,21,20,22),e[0][2]=new Array(28,29,19,18,25),e[0][3]=new Array(30,31,17,16,28),e[1]=new Array(4),e[1][0]=new Array(3,2,12,13,8),e[1][1]=new Array(1,0,14,15,13),e[1][2]=new Array(7,6,8,9,3),e[1][3]=new Array(5,4,10,11,7),e[2]=new Array(4),e[2][0]=new Array(19,18,28,29,25),e[2][1]=new Array(17,16,30,31,28),e[2][2]=new Array(23,22,24,25,18),e[2][3]=new Array(21,20,26,27,22),e[3]=new Array(4),e[3][0]=new Array(8,9,7,6,3),e[3][1]=new Array(10,11,5,4,7),e[3][2]=new Array(12,13,3,2,8),e[3][3]=new Array(14,15,1,0,13),this.keySchedule=function(a){for(var b=new Array(8),c=new Array(32),g=0;4>g;g++){var h=4*g;b[g]=a[h]<<24|a[h+1]<<16|a[h+2]<<8|a[h+3]}for(var i=[6,7,4,5],j=0,k=0;2>k;k++)for(var l=0;4>l;l++){for(var h=0;4>h;h++){var m=d[l][h],n=b[m[1]];n^=f[4][b[m[2]>>>2]>>>24-8*(3&m[2])&255],n^=f[5][b[m[3]>>>2]>>>24-8*(3&m[3])&255],n^=f[6][b[m[4]>>>2]>>>24-8*(3&m[4])&255],n^=f[7][b[m[5]>>>2]>>>24-8*(3&m[5])&255],n^=f[i[h]][b[m[6]>>>2]>>>24-8*(3&m[6])&255],b[m[0]]=n}for(var h=0;4>h;h++){var o=e[l][h],n=f[4][b[o[0]>>>2]>>>24-8*(3&o[0])&255];n^=f[5][b[o[1]>>>2]>>>24-8*(3&o[1])&255],n^=f[6][b[o[2]>>>2]>>>24-8*(3&o[2])&255],n^=f[7][b[o[3]>>>2]>>>24-8*(3&o[3])&255],n^=f[4+h][b[o[4]>>>2]>>>24-8*(3&o[4])&255],c[j]=n,j++}}for(var g=0;16>g;g++)this.masking[g]=c[g],this.rotate[g]=31&c[16+g]};var f=new Array(8);f[0]=new Array(821772500,2678128395,1810681135,1059425402,505495343,2617265619,1610868032,3483355465,3218386727,2294005173,3791863952,2563806837,1852023008,365126098,3269944861,584384398,677919599,3229601881,4280515016,2002735330,1136869587,3744433750,2289869850,2731719981,2714362070,879511577,1639411079,575934255,717107937,2857637483,576097850,2731753936,1725645e3,2810460463,5111599,767152862,2543075244,1251459544,1383482551,3052681127,3089939183,3612463449,1878520045,1510570527,2189125840,2431448366,582008916,3163445557,1265446783,1354458274,3529918736,3202711853,3073581712,3912963487,3029263377,1275016285,4249207360,2905708351,3304509486,1442611557,3585198765,2712415662,2731849581,3248163920,2283946226,208555832,2766454743,1331405426,1447828783,3315356441,3108627284,2957404670,2981538698,3339933917,1669711173,286233437,1465092821,1782121619,3862771680,710211251,980974943,1651941557,430374111,2051154026,704238805,4128970897,3144820574,2857402727,948965521,3333752299,2227686284,718756367,2269778983,2731643755,718440111,2857816721,3616097120,1113355533,2478022182,410092745,1811985197,1944238868,2696854588,1415722873,1682284203,1060277122,1998114690,1503841958,82706478,2315155686,1068173648,845149890,2167947013,1768146376,1993038550,3566826697,3390574031,940016341,3355073782,2328040721,904371731,1205506512,4094660742,2816623006,825647681,85914773,2857843460,1249926541,1417871568,3287612,3211054559,3126306446,1975924523,1353700161,2814456437,2438597621,1800716203,722146342,2873936343,1151126914,4160483941,2877670899,458611604,2866078500,3483680063,770352098,2652916994,3367839148,3940505011,3585973912,3809620402,718646636,2504206814,2914927912,3631288169,2857486607,2860018678,575749918,2857478043,718488780,2069512688,3548183469,453416197,1106044049,3032691430,52586708,3378514636,3459808877,3211506028,1785789304,218356169,3571399134,3759170522,1194783844,1523787992,3007827094,1975193539,2555452411,1341901877,3045838698,3776907964,3217423946,2802510864,2889438986,1057244207,1636348243,3761863214,1462225785,2632663439,481089165,718503062,24497053,3332243209,3344655856,3655024856,3960371065,1195698900,2971415156,3710176158,2115785917,4027663609,3525578417,2524296189,2745972565,3564906415,1372086093,1452307862,2780501478,1476592880,3389271281,18495466,2378148571,901398090,891748256,3279637769,3157290713,2560960102,1447622437,4284372637,216884176,2086908623,1879786977,3588903153,2242455666,2938092967,3559082096,2810645491,758861177,1121993112,215018983,642190776,4169236812,1196255959,2081185372,3508738393,941322904,4124243163,2877523539,1848581667,2205260958,3180453958,2589345134,3694731276,550028657,2519456284,3789985535,2973870856,2093648313,443148163,46942275,2734146937,1117713533,1115362972,1523183689,3717140224,1551984063),f[1]=new Array(522195092,4010518363,1776537470,960447360,4267822970,4005896314,1435016340,1929119313,2913464185,1310552629,3579470798,3724818106,2579771631,1594623892,417127293,2715217907,2696228731,1508390405,3994398868,3925858569,3695444102,4019471449,3129199795,3770928635,3520741761,990456497,4187484609,2783367035,21106139,3840405339,631373633,3783325702,532942976,396095098,3548038825,4267192484,2564721535,2011709262,2039648873,620404603,3776170075,2898526339,3612357925,4159332703,1645490516,223693667,1567101217,3362177881,1029951347,3470931136,3570957959,1550265121,119497089,972513919,907948164,3840628539,1613718692,3594177948,465323573,2659255085,654439692,2575596212,2699288441,3127702412,277098644,624404830,4100943870,2717858591,546110314,2403699828,3655377447,1321679412,4236791657,1045293279,4010672264,895050893,2319792268,494945126,1914543101,2777056443,3894764339,2219737618,311263384,4275257268,3458730721,669096869,3584475730,3835122877,3319158237,3949359204,2005142349,2713102337,2228954793,3769984788,569394103,3855636576,1425027204,108000370,2736431443,3671869269,3043122623,1750473702,2211081108,762237499,3972989403,2798899386,3061857628,2943854345,867476300,964413654,1591880597,1594774276,2179821409,552026980,3026064248,3726140315,2283577634,3110545105,2152310760,582474363,1582640421,1383256631,2043843868,3322775884,1217180674,463797851,2763038571,480777679,2718707717,2289164131,3118346187,214354409,200212307,3810608407,3025414197,2674075964,3997296425,1847405948,1342460550,510035443,4080271814,815934613,833030224,1620250387,1945732119,2703661145,3966000196,1388869545,3456054182,2687178561,2092620194,562037615,1356438536,3409922145,3261847397,1688467115,2150901366,631725691,3840332284,549916902,3455104640,394546491,837744717,2114462948,751520235,2221554606,2415360136,3999097078,2063029875,803036379,2702586305,821456707,3019566164,360699898,4018502092,3511869016,3677355358,2402471449,812317050,49299192,2570164949,3259169295,2816732080,3331213574,3101303564,2156015656,3705598920,3546263921,143268808,3200304480,1638124008,3165189453,3341807610,578956953,2193977524,3638120073,2333881532,807278310,658237817,2969561766,1641658566,11683945,3086995007,148645947,1138423386,4158756760,1981396783,2401016740,3699783584,380097457,2680394679,2803068651,3334260286,441530178,4016580796,1375954390,761952171,891809099,2183123478,157052462,3683840763,1592404427,341349109,2438483839,1417898363,644327628,2233032776,2353769706,2201510100,220455161,1815641738,182899273,2995019788,3627381533,3702638151,2890684138,1052606899,588164016,1681439879,4038439418,2405343923,4229449282,167996282,1336969661,1688053129,2739224926,1543734051,1046297529,1138201970,2121126012,115334942,1819067631,1902159161,1941945968,2206692869,1159982321),f[2]=new Array(2381300288,637164959,3952098751,3893414151,1197506559,916448331,2350892612,2932787856,3199334847,4009478890,3905886544,1373570990,2450425862,4037870920,3778841987,2456817877,286293407,124026297,3001279700,1028597854,3115296800,4208886496,2691114635,2188540206,1430237888,1218109995,3572471700,308166588,570424558,2187009021,2455094765,307733056,1310360322,3135275007,1384269543,2388071438,863238079,2359263624,2801553128,3380786597,2831162807,1470087780,1728663345,4072488799,1090516929,532123132,2389430977,1132193179,2578464191,3051079243,1670234342,1434557849,2711078940,1241591150,3314043432,3435360113,3091448339,1812415473,2198440252,267246943,796911696,3619716990,38830015,1526438404,2806502096,374413614,2943401790,1489179520,1603809326,1920779204,168801282,260042626,2358705581,1563175598,2397674057,1356499128,2217211040,514611088,2037363785,2186468373,4022173083,2792511869,2913485016,1173701892,4200428547,3896427269,1334932762,2455136706,602925377,2835607854,1613172210,41346230,2499634548,2457437618,2188827595,41386358,4172255629,1313404830,2405527007,3801973774,2217704835,873260488,2528884354,2478092616,4012915883,2555359016,2006953883,2463913485,575479328,2218240648,2099895446,660001756,2341502190,3038761536,3888151779,3848713377,3286851934,1022894237,1620365795,3449594689,1551255054,15374395,3570825345,4249311020,4151111129,3181912732,310226346,1133119310,530038928,136043402,2476768958,3107506709,2544909567,1036173560,2367337196,1681395281,1758231547,3641649032,306774401,1575354324,3716085866,1990386196,3114533736,2455606671,1262092282,3124342505,2768229131,4210529083,1833535011,423410938,660763973,2187129978,1639812e3,3508421329,3467445492,310289298,272797111,2188552562,2456863912,310240523,677093832,1013118031,901835429,3892695601,1116285435,3036471170,1337354835,243122523,520626091,277223598,4244441197,4194248841,1766575121,594173102,316590669,742362309,3536858622,4176435350,3838792410,2501204839,1229605004,3115755532,1552908988,2312334149,979407927,3959474601,1148277331,176638793,3614686272,2083809052,40992502,1340822838,2731552767,3535757508,3560899520,1354035053,122129617,7215240,2732932949,3118912700,2718203926,2539075635,3609230695,3725561661,1928887091,2882293555,1988674909,2063640240,2491088897,1459647954,4189817080,2302804382,1113892351,2237858528,1927010603,4002880361,1856122846,1594404395,2944033133,3855189863,3474975698,1643104450,4054590833,3431086530,1730235576,2984608721,3084664418,2131803598,4178205752,267404349,1617849798,1616132681,1462223176,736725533,2327058232,551665188,2945899023,1749386277,2575514597,1611482493,674206544,2201269090,3642560800,728599968,1680547377,2620414464,1388111496,453204106,4156223445,1094905244,2754698257,2201108165,3757000246,2704524545,3922940700,3996465027),f[3]=new Array(2645754912,532081118,2814278639,3530793624,1246723035,1689095255,2236679235,4194438865,2116582143,3859789411,157234593,2045505824,4245003587,1687664561,4083425123,605965023,672431967,1336064205,3376611392,214114848,4258466608,3232053071,489488601,605322005,3998028058,264917351,1912574028,756637694,436560991,202637054,135989450,85393697,2152923392,3896401662,2895836408,2145855233,3535335007,115294817,3147733898,1922296357,3464822751,4117858305,1037454084,2725193275,2127856640,1417604070,1148013728,1827919605,642362335,2929772533,909348033,1346338451,3547799649,297154785,1917849091,4161712827,2883604526,3968694238,1469521537,3780077382,3375584256,1763717519,136166297,4290970789,1295325189,2134727907,2798151366,1566297257,3672928234,2677174161,2672173615,965822077,2780786062,289653839,1133871874,3491843819,35685304,1068898316,418943774,672553190,642281022,2346158704,1954014401,3037126780,4079815205,2030668546,3840588673,672283427,1776201016,359975446,3750173538,555499703,2769985273,1324923,69110472,152125443,3176785106,3822147285,1340634837,798073664,1434183902,15393959,216384236,1303690150,3881221631,3711134124,3960975413,106373927,2578434224,1455997841,1801814300,1578393881,1854262133,3188178946,3258078583,2302670060,1539295533,3505142565,3078625975,2372746020,549938159,3278284284,2620926080,181285381,2865321098,3970029511,68876850,488006234,1728155692,2608167508,836007927,2435231793,919367643,3339422534,3655756360,1457871481,40520939,1380155135,797931188,234455205,2255801827,3990488299,397000196,739833055,3077865373,2871719860,4022553888,772369276,390177364,3853951029,557662966,740064294,1640166671,1699928825,3535942136,622006121,3625353122,68743880,1742502,219489963,1664179233,1577743084,1236991741,410585305,2366487942,823226535,1050371084,3426619607,3586839478,212779912,4147118561,1819446015,1911218849,530248558,3486241071,3252585495,2886188651,3410272728,2342195030,20547779,2982490058,3032363469,3631753222,312714466,1870521650,1493008054,3491686656,615382978,4103671749,2534517445,1932181,2196105170,278426614,6369430,3274544417,2913018367,697336853,2143000447,2946413531,701099306,1558357093,2805003052,3500818408,2321334417,3567135975,216290473,3591032198,23009561,1996984579,3735042806,2024298078,3739440863,569400510,2339758983,3016033873,3097871343,3639523026,3844324983,3256173865,795471839,2951117563,4101031090,4091603803,3603732598,971261452,534414648,428311343,3389027175,2844869880,694888862,1227866773,2456207019,3043454569,2614353370,3749578031,3676663836,459166190,4132644070,1794958188,51825668,2252611902,3084671440,2036672799,3436641603,1099053433,2469121526,3059204941,1323291266,2061838604,1018778475,2233344254,2553501054,334295216,3556750194,1065731521,183467730),f[4]=new Array(2127105028,745436345,2601412319,2788391185,3093987327,500390133,1155374404,389092991,150729210,3891597772,3523549952,1935325696,716645080,946045387,2901812282,1774124410,3869435775,4039581901,3293136918,3438657920,948246080,363898952,3867875531,1286266623,1598556673,68334250,630723836,1104211938,1312863373,613332731,2377784574,1101634306,441780740,3129959883,1917973735,2510624549,3238456535,2544211978,3308894634,1299840618,4076074851,1756332096,3977027158,297047435,3790297736,2265573040,3621810518,1311375015,1667687725,47300608,3299642885,2474112369,201668394,1468347890,576830978,3594690761,3742605952,1958042578,1747032512,3558991340,1408974056,3366841779,682131401,1033214337,1545599232,4265137049,206503691,103024618,2855227313,1337551222,2428998917,2963842932,4015366655,3852247746,2796956967,3865723491,3747938335,247794022,3755824572,702416469,2434691994,397379957,851939612,2314769512,218229120,1380406772,62274761,214451378,3170103466,2276210409,3845813286,28563499,446592073,1693330814,3453727194,29968656,3093872512,220656637,2470637031,77972100,1667708854,1358280214,4064765667,2395616961,325977563,4277240721,4220025399,3605526484,3355147721,811859167,3069544926,3962126810,652502677,3075892249,4132761541,3498924215,1217549313,3250244479,3858715919,3053989961,1538642152,2279026266,2875879137,574252750,3324769229,2651358713,1758150215,141295887,2719868960,3515574750,4093007735,4194485238,1082055363,3417560400,395511885,2966884026,179534037,3646028556,3738688086,1092926436,2496269142,257381841,3772900718,1636087230,1477059743,2499234752,3811018894,2675660129,3285975680,90732309,1684827095,1150307763,1723134115,3237045386,1769919919,1240018934,815675215,750138730,2239792499,1234303040,1995484674,138143821,675421338,1145607174,1936608440,3238603024,2345230278,2105974004,323969391,779555213,3004902369,2861610098,1017501463,2098600890,2628620304,2940611490,2682542546,1171473753,3656571411,3687208071,4091869518,393037935,159126506,1662887367,1147106178,391545844,3452332695,1891500680,3016609650,1851642611,546529401,1167818917,3194020571,2848076033,3953471836,575554290,475796850,4134673196,450035699,2351251534,844027695,1080539133,86184846,1554234488,3692025454,1972511363,2018339607,1491841390,1141460869,1061690759,4244549243,2008416118,2351104703,2868147542,1598468138,722020353,1027143159,212344630,1387219594,1725294528,3745187956,2500153616,458938280,4129215917,1828119673,544571780,3503225445,2297937496,1241802790,267843827,2694610800,1397140384,1558801448,3782667683,1806446719,929573330,2234912681,400817706,616011623,4121520928,3603768725,1761550015,1968522284,4053731006,4192232858,4005120285,872482584,3140537016,3894607381,2287405443,1963876937,3663887957,1584857e3,2975024454,1833426440,4025083860),f[5]=new Array(4143615901,749497569,1285769319,3795025788,2514159847,23610292,3974978748,844452780,3214870880,3751928557,2213566365,1676510905,448177848,3730751033,4086298418,2307502392,871450977,3222878141,4110862042,3831651966,2735270553,1310974780,2043402188,1218528103,2736035353,4274605013,2702448458,3936360550,2693061421,162023535,2827510090,687910808,23484817,3784910947,3371371616,779677500,3503626546,3473927188,4157212626,3500679282,4248902014,2466621104,3899384794,1958663117,925738300,1283408968,3669349440,1840910019,137959847,2679828185,1239142320,1315376211,1547541505,1690155329,739140458,3128809933,3933172616,3876308834,905091803,1548541325,4040461708,3095483362,144808038,451078856,676114313,2861728291,2469707347,993665471,373509091,2599041286,4025009006,4170239449,2149739950,3275793571,3749616649,2794760199,1534877388,572371878,2590613551,1753320020,3467782511,1405125690,4270405205,633333386,3026356924,3475123903,632057672,2846462855,1404951397,3882875879,3915906424,195638627,2385783745,3902872553,1233155085,3355999740,2380578713,2702246304,2144565621,3663341248,3894384975,2502479241,4248018925,3094885567,1594115437,572884632,3385116731,767645374,1331858858,1475698373,3793881790,3532746431,1321687957,619889600,1121017241,3440213920,2070816767,2833025776,1933951238,4095615791,890643334,3874130214,859025556,360630002,925594799,1764062180,3920222280,4078305929,979562269,2810700344,4087740022,1949714515,546639971,1165388173,3069891591,1495988560,922170659,1291546247,2107952832,1813327274,3406010024,3306028637,4241950635,153207855,2313154747,1608695416,1150242611,1967526857,721801357,1220138373,3691287617,3356069787,2112743302,3281662835,1111556101,1778980689,250857638,2298507990,673216130,2846488510,3207751581,3562756981,3008625920,3417367384,2198807050,529510932,3547516680,3426503187,2364944742,102533054,2294910856,1617093527,1204784762,3066581635,1019391227,1069574518,1317995090,1691889997,3661132003,510022745,3238594800,1362108837,1817929911,2184153760,805817662,1953603311,3699844737,120799444,2118332377,207536705,2282301548,4120041617,145305846,2508124933,3086745533,3261524335,1877257368,2977164480,3160454186,2503252186,4221677074,759945014,254147243,2767453419,3801518371,629083197,2471014217,907280572,3900796746,940896768,2751021123,2625262786,3161476951,3661752313,3260732218,1425318020,2977912069,1496677566,3988592072,2140652971,3126511541,3069632175,977771578,1392695845,1698528874,1411812681,1369733098,1343739227,3620887944,1142123638,67414216,3102056737,3088749194,1626167401,2546293654,3941374235,697522451,33404913,143560186,2595682037,994885535,1247667115,3859094837,2699155541,3547024625,4114935275,2968073508,3199963069,2732024527,1237921620,951448369,1898488916,1211705605,2790989240,2233243581,3598044975),f[6]=new Array(2246066201,858518887,1714274303,3485882003,713916271,2879113490,3730835617,539548191,36158695,1298409750,419087104,1358007170,749914897,2989680476,1261868530,2995193822,2690628854,3443622377,3780124940,3796824509,2976433025,4259637129,1551479e3,512490819,1296650241,951993153,2436689437,2460458047,144139966,3136204276,310820559,3068840729,643875328,1969602020,1680088954,2185813161,3283332454,672358534,198762408,896343282,276269502,3014846926,84060815,197145886,376173866,3943890818,3813173521,3545068822,1316698879,1598252827,2633424951,1233235075,859989710,2358460855,3503838400,3409603720,1203513385,1193654839,2792018475,2060853022,207403770,1144516871,3068631394,1121114134,177607304,3785736302,326409831,1929119770,2983279095,4183308101,3474579288,3200513878,3228482096,119610148,1170376745,3378393471,3163473169,951863017,3337026068,3135789130,2907618374,1183797387,2015970143,4045674555,2182986399,2952138740,3928772205,384012900,2454997643,10178499,2879818989,2596892536,111523738,2995089006,451689641,3196290696,235406569,1441906262,3890558523,3013735005,4158569349,1644036924,376726067,1006849064,3664579700,2041234796,1021632941,1374734338,2566452058,371631263,4007144233,490221539,206551450,3140638584,1053219195,1853335209,3412429660,3562156231,735133835,1623211703,3104214392,2738312436,4096837757,3366392578,3110964274,3956598718,3196820781,2038037254,3877786376,2339753847,300912036,3766732888,2372630639,1516443558,4200396704,1574567987,4069441456,4122592016,2699739776,146372218,2748961456,2043888151,35287437,2596680554,655490400,1132482787,110692520,1031794116,2188192751,1324057718,1217253157,919197030,686247489,3261139658,1028237775,3135486431,3059715558,2460921700,986174950,2661811465,4062904701,2752986992,3709736643,367056889,1353824391,731860949,1650113154,1778481506,784341916,357075625,3608602432,1074092588,2480052770,3811426202,92751289,877911070,3600361838,1231880047,480201094,3756190983,3094495953,434011822,87971354,363687820,1717726236,1901380172,3926403882,2481662265,400339184,1490350766,2661455099,1389319756,2558787174,784598401,1983468483,30828846,3550527752,2716276238,3841122214,1765724805,1955612312,1277890269,1333098070,1564029816,2704417615,1026694237,3287671188,1260819201,3349086767,1016692350,1582273796,1073413053,1995943182,694588404,1025494639,3323872702,3551898420,4146854327,453260480,1316140391,1435673405,3038941953,3486689407,1622062951,403978347,817677117,950059133,4246079218,3278066075,1486738320,1417279718,481875527,2549965225,3933690356,760697757,1452955855,3897451437,1177426808,1702951038,4085348628,2447005172,1084371187,3516436277,3068336338,1073369276,1027665953,3284188590,1230553676,1368340146,2226246512,267243139,2274220762,4070734279,2497715176,2423353163,2504755875),f[7]=new Array(3793104909,3151888380,2817252029,895778965,2005530807,3871412763,237245952,86829237,296341424,3851759377,3974600970,2475086196,709006108,1994621201,2972577594,937287164,3734691505,168608556,3189338153,2225080640,3139713551,3033610191,3025041904,77524477,185966941,1208824168,2344345178,1721625922,3354191921,1066374631,1927223579,1971335949,2483503697,1551748602,2881383779,2856329572,3003241482,48746954,1398218158,2050065058,313056748,4255789917,393167848,1912293076,940740642,3465845460,3091687853,2522601570,2197016661,1727764327,364383054,492521376,1291706479,3264136376,1474851438,1685747964,2575719748,1619776915,1814040067,970743798,1561002147,2925768690,2123093554,1880132620,3151188041,697884420,2550985770,2607674513,2659114323,110200136,1489731079,997519150,1378877361,3527870668,478029773,2766872923,1022481122,431258168,1112503832,897933369,2635587303,669726182,3383752315,918222264,163866573,3246985393,3776823163,114105080,1903216136,761148244,3571337562,1690750982,3166750252,1037045171,1888456500,2010454850,642736655,616092351,365016990,1185228132,4174898510,1043824992,2023083429,2241598885,3863320456,3279669087,3674716684,108438443,2132974366,830746235,606445527,4173263986,2204105912,1844756978,2532684181,4245352700,2969441100,3796921661,1335562986,4061524517,2720232303,2679424040,634407289,885462008,3294724487,3933892248,2094100220,339117932,4048830727,3202280980,1458155303,2689246273,1022871705,2464987878,3714515309,353796843,2822958815,4256850100,4052777845,551748367,618185374,3778635579,4020649912,1904685140,3069366075,2670879810,3407193292,2954511620,4058283405,2219449317,3135758300,1120655984,3447565834,1474845562,3577699062,550456716,3466908712,2043752612,881257467,869518812,2005220179,938474677,3305539448,3850417126,1315485940,3318264702,226533026,965733244,321539988,1136104718,804158748,573969341,3708209826,937399083,3290727049,2901666755,1461057207,4013193437,4066861423,3242773476,2421326174,1581322155,3028952165,786071460,3900391652,3918438532,1485433313,4023619836,3708277595,3678951060,953673138,1467089153,1930354364,1533292819,2492563023,1346121658,1685000834,1965281866,3765933717,4190206607,2052792609,3515332758,690371149,3125873887,2180283551,2903598061,3933952357,436236910,289419410,14314871,1242357089,2904507907,1616633776,2666382180,585885352,3471299210,2699507360,1432659641,277164553,3354103607,770115018,2303809295,3741942315,3177781868,2853364978,2269453327,3774259834,987383833,1290892879,225909803,1741533526,890078084,1496906255,1111072499,916028167,243534141,1252605537,2204162171,531204876,290011180,3916834213,102027703,237315147,209093447,1486785922,220223953,2758195998,4175039106,82940208,3127791296,2569425252,518464269,1353887104,3941492737,2377294467,3935040926)}function d(a){this.cast5=new c,this.cast5.setKey(e.str2bin(a)),this.encrypt=function(a){return this.cast5.encrypt(a)}}var e=a("../../util");b.exports=d,b.exports.blockSize=d.prototype.blockSize=8,b.exports.keySize=d.prototype.keySize=16},{"../../util":56}],8:[function(a,b){function c(a,b,c,d,g,h){var i,j,k,l,m,n,o,p,q,r,s,t,u,v,w=new Array(16843776,0,65536,16843780,16842756,66564,4,65536,1024,16843776,16843780,1024,16778244,16842756,16777216,4,1028,16778240,16778240,66560,66560,16842752,16842752,16778244,65540,16777220,16777220,65540,0,1028,66564,16777216,65536,16843780,4,16842752,16843776,16777216,16777216,1024,16842756,65536,66560,16777220,1024,4,16778244,66564,16843780,65540,16842752,16778244,16777220,1028,66564,16843776,1028,16778240,16778240,0,65540,66560,0,16842756),x=new Array(-2146402272,-2147450880,32768,1081376,1048576,32,-2146435040,-2147450848,-2147483616,-2146402272,-2146402304,-2147483648,-2147450880,1048576,32,-2146435040,1081344,1048608,-2147450848,0,-2147483648,32768,1081376,-2146435072,1048608,-2147483616,0,1081344,32800,-2146402304,-2146435072,32800,0,1081376,-2146435040,1048576,-2147450848,-2146435072,-2146402304,32768,-2146435072,-2147450880,32,-2146402272,1081376,32,32768,-2147483648,32800,-2146402304,1048576,-2147483616,1048608,-2147450848,-2147483616,1048608,1081344,0,-2147450880,32800,-2147483648,-2146435040,-2146402272,1081344),y=new Array(520,134349312,0,134348808,134218240,0,131592,134218240,131080,134217736,134217736,131072,134349320,131080,134348800,520,134217728,8,134349312,512,131584,134348800,134348808,131592,134218248,131584,131072,134218248,8,134349320,512,134217728,134349312,134217728,131080,520,131072,134349312,134218240,0,512,131080,134349320,134218240,134217736,512,0,134348808,134218248,131072,134217728,134349320,8,131592,131584,134217736,134348800,134218248,520,134348800,131592,8,134348808,131584),z=new Array(8396801,8321,8321,128,8396928,8388737,8388609,8193,0,8396800,8396800,8396929,129,0,8388736,8388609,1,8192,8388608,8396801,128,8388608,8193,8320,8388737,1,8320,8388736,8192,8396928,8396929,129,8388736,8388609,8396800,8396929,129,0,0,8396800,8320,8388736,8388737,1,8396801,8321,8321,128,8396929,129,1,8192,8388609,8193,8396928,8388737,8193,8320,8388608,8396801,128,8388608,8192,8396928),A=new Array(256,34078976,34078720,1107296512,524288,256,1073741824,34078720,1074266368,524288,33554688,1074266368,1107296512,1107820544,524544,1073741824,33554432,1074266112,1074266112,0,1073742080,1107820800,1107820800,33554688,1107820544,1073742080,0,1107296256,34078976,33554432,1107296256,524544,524288,1107296512,256,33554432,1073741824,34078720,1107296512,1074266368,33554688,1073741824,1107820544,34078976,1074266368,256,33554432,1107820544,1107820800,524544,1107296256,1107820800,34078720,0,1074266112,1107296256,524544,33554688,1073742080,524288,0,1074266112,34078976,1073742080),B=new Array(536870928,541065216,16384,541081616,541065216,16,541081616,4194304,536887296,4210704,4194304,536870928,4194320,536887296,536870912,16400,0,4194320,536887312,16384,4210688,536887312,16,541065232,541065232,0,4210704,541081600,16400,4210688,541081600,536870912,536887296,16,541065232,4210688,541081616,4194304,16400,536870928,4194304,536887296,536870912,16400,536870928,541081616,4210688,541065216,4210704,541081600,0,541065232,16,16384,541065216,4210704,16384,4194320,536887312,0,541081600,536870912,4194320,536887312),C=new Array(2097152,69206018,67110914,0,2048,67110914,2099202,69208064,69208066,2097152,0,67108866,2,67108864,69206018,2050,67110912,2099202,2097154,67110912,67108866,69206016,69208064,2097154,69206016,2048,2050,69208066,2099200,2,67108864,2099200,67108864,2099200,2097152,67110914,67110914,69206018,69206018,2,2097154,67108864,67110912,2097152,69208064,2050,2099202,69208064,2050,67108866,69208066,69206016,2099200,0,2,69208066,0,2099202,69206016,2048,67108866,67110912,2048,2097154),D=new Array(268439616,4096,262144,268701760,268435456,268439616,64,268435456,262208,268697600,268701760,266240,268701696,266304,4096,64,268697600,268435520,268439552,4160,266240,262208,268697664,268701696,4160,0,0,268697664,268435520,268439552,266304,262144,266304,262144,268701696,4096,64,268697664,4096,266304,268439552,64,268435520,268697600,268697664,268435456,262144,268439616,0,268701760,262208,268435520,268697600,268439552,268439616,0,268701760,266240,266240,4160,4160,262208,268435456,268701696),E=0,F=b.length,G=0,H=32==a.length?3:9; +for(p=3==H?c?new Array(0,32,2):new Array(30,-2,-2):c?new Array(0,32,2,62,30,-2,64,96,2):new Array(94,62,-2,32,64,2,30,-2,-2),c&&(b=e(b,h),F=b.length),result="",tempresult="",1==d&&(q=g.charCodeAt(E++)<<24|g.charCodeAt(E++)<<16|g.charCodeAt(E++)<<8|g.charCodeAt(E++),s=g.charCodeAt(E++)<<24|g.charCodeAt(E++)<<16|g.charCodeAt(E++)<<8|g.charCodeAt(E++),E=0);F>E;){for(n=b.charCodeAt(E++)<<24|b.charCodeAt(E++)<<16|b.charCodeAt(E++)<<8|b.charCodeAt(E++),o=b.charCodeAt(E++)<<24|b.charCodeAt(E++)<<16|b.charCodeAt(E++)<<8|b.charCodeAt(E++),1==d&&(c?(n^=q,o^=s):(r=q,t=s,q=n,s=o)),k=252645135&(n>>>4^o),o^=k,n^=k<<4,k=65535&(n>>>16^o),o^=k,n^=k<<16,k=858993459&(o>>>2^n),n^=k,o^=k<<2,k=16711935&(o>>>8^n),n^=k,o^=k<<8,k=1431655765&(n>>>1^o),o^=k,n^=k<<1,n=n<<1|n>>>31,o=o<<1|o>>>31,j=0;H>j;j+=3){for(u=p[j+1],v=p[j+2],i=p[j];i!=u;i+=v)l=o^a[i],m=(o>>>4|o<<28)^a[i+1],k=n,n=o,o=k^(x[l>>>24&63]|z[l>>>16&63]|B[l>>>8&63]|D[63&l]|w[m>>>24&63]|y[m>>>16&63]|A[m>>>8&63]|C[63&m]);k=n,n=o,o=k}n=n>>>1|n<<31,o=o>>>1|o<<31,k=1431655765&(n>>>1^o),o^=k,n^=k<<1,k=16711935&(o>>>8^n),n^=k,o^=k<<8,k=858993459&(o>>>2^n),n^=k,o^=k<<2,k=65535&(n>>>16^o),o^=k,n^=k<<16,k=252645135&(n>>>4^o),o^=k,n^=k<<4,1==d&&(c?(q=n,s=o):(n^=r,o^=t)),tempresult+=String.fromCharCode(n>>>24,n>>>16&255,n>>>8&255,255&n,o>>>24,o>>>16&255,o>>>8&255,255&o),G+=8,512==G&&(result+=tempresult,tempresult="",G=0)}return result+=tempresult,c||(result=f(result,h)),result}function d(a){pc2bytes0=new Array(0,4,536870912,536870916,65536,65540,536936448,536936452,512,516,536871424,536871428,66048,66052,536936960,536936964),pc2bytes1=new Array(0,1,1048576,1048577,67108864,67108865,68157440,68157441,256,257,1048832,1048833,67109120,67109121,68157696,68157697),pc2bytes2=new Array(0,8,2048,2056,16777216,16777224,16779264,16779272,0,8,2048,2056,16777216,16777224,16779264,16779272),pc2bytes3=new Array(0,2097152,134217728,136314880,8192,2105344,134225920,136323072,131072,2228224,134348800,136445952,139264,2236416,134356992,136454144),pc2bytes4=new Array(0,262144,16,262160,0,262144,16,262160,4096,266240,4112,266256,4096,266240,4112,266256),pc2bytes5=new Array(0,1024,32,1056,0,1024,32,1056,33554432,33555456,33554464,33555488,33554432,33555456,33554464,33555488),pc2bytes6=new Array(0,268435456,524288,268959744,2,268435458,524290,268959746,0,268435456,524288,268959744,2,268435458,524290,268959746),pc2bytes7=new Array(0,65536,2048,67584,536870912,536936448,536872960,536938496,131072,196608,133120,198656,537001984,537067520,537004032,537069568),pc2bytes8=new Array(0,262144,0,262144,2,262146,2,262146,33554432,33816576,33554432,33816576,33554434,33816578,33554434,33816578),pc2bytes9=new Array(0,268435456,8,268435464,0,268435456,8,268435464,1024,268436480,1032,268436488,1024,268436480,1032,268436488),pc2bytes10=new Array(0,32,0,32,1048576,1048608,1048576,1048608,8192,8224,8192,8224,1056768,1056800,1056768,1056800),pc2bytes11=new Array(0,16777216,512,16777728,2097152,18874368,2097664,18874880,67108864,83886080,67109376,83886592,69206016,85983232,69206528,85983744),pc2bytes12=new Array(0,4096,134217728,134221824,524288,528384,134742016,134746112,16,4112,134217744,134221840,524304,528400,134742032,134746128),pc2bytes13=new Array(0,4,256,260,0,4,256,260,1,5,257,261,1,5,257,261);for(var b,c,d,e=a.length>8?3:1,f=new Array(32*e),g=new Array(0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0),h=0,j=0,k=0;e>k;k++)for(left=a.charCodeAt(h++)<<24|a.charCodeAt(h++)<<16|a.charCodeAt(h++)<<8|a.charCodeAt(h++),right=a.charCodeAt(h++)<<24|a.charCodeAt(h++)<<16|a.charCodeAt(h++)<<8|a.charCodeAt(h++),d=252645135&(left>>>4^right),right^=d,left^=d<<4,d=65535&(right>>>-16^left),left^=d,right^=d<<-16,d=858993459&(left>>>2^right),right^=d,left^=d<<2,d=65535&(right>>>-16^left),left^=d,right^=d<<-16,d=1431655765&(left>>>1^right),right^=d,left^=d<<1,d=16711935&(right>>>8^left),left^=d,right^=d<<8,d=1431655765&(left>>>1^right),right^=d,left^=d<<1,d=left<<8|right>>>20&240,left=right<<24|right<<8&16711680|right>>>8&65280|right>>>24&240,right=d,i=0;i>>26,right=right<<2|right>>>26):(left=left<<1|left>>>27,right=right<<1|right>>>27),left&=-15,right&=-15,b=pc2bytes0[left>>>28]|pc2bytes1[left>>>24&15]|pc2bytes2[left>>>20&15]|pc2bytes3[left>>>16&15]|pc2bytes4[left>>>12&15]|pc2bytes5[left>>>8&15]|pc2bytes6[left>>>4&15],c=pc2bytes7[right>>>28]|pc2bytes8[right>>>24&15]|pc2bytes9[right>>>20&15]|pc2bytes10[right>>>16&15]|pc2bytes11[right>>>12&15]|pc2bytes12[right>>>8&15]|pc2bytes13[right>>>4&15],d=65535&(c>>>16^b),f[j++]=b^d,f[j++]=c^d<<16;return f}function e(a,b){var c=8-a.length%8;return 2==b&&8>c?a+=" ".substr(0,c):1==b?a+=String.fromCharCode(c,c,c,c,c,c,c,c).substr(0,c):!b&&8>c&&(a+="\x00\x00\x00\x00\x00\x00\x00\x00".substr(0,c)),a}function f(a,b){if(2==b)a=a.replace(/ *$/g,"");else if(1==b){var c=a.charCodeAt(a.length-1);a=a.substr(0,a.length-c)}else b||(a=a.replace(/\0*$/g,""));return a}function g(a){this.key=[];for(var b=0;3>b;b++)this.key.push(a.substr(8*b,8));this.encrypt=function(a){return j.str2bin(c(d(this.key[2]),c(d(this.key[1]),c(d(this.key[0]),j.bin2str(a),!0,0,null,null),!1,0,null,null),!0,0,null,null))}}function h(a){this.key=a,this.encrypt=function(a,b){var e=d(this.key);return j.str2bin(c(e,j.bin2str(a),!0,0,null,b))},this.decrypt=function(a,b){var e=d(this.key);return j.str2bin(c(e,j.bin2str(a),!1,0,null,b))}}var j=a("../../util");g.keySize=g.prototype.keySize=24,g.blockSize=g.prototype.blockSize=8,b.exports={des:g,originalDes:h}},{"../../util":56}],9:[function(a,b){var c=a("./des.js");b.exports={des:c.des,originalDes:c.originalDes,cast5:a("./cast5.js"),twofish:a("./twofish.js"),blowfish:a("./blowfish.js")};var d=a("./aes.js");for(var e in d)b.exports["aes"+e]=d[e]},{"./aes.js":5,"./blowfish.js":6,"./cast5.js":7,"./des.js":8,"./twofish.js":10}],10:[function(a,b){function c(a,b){return(a<>>32-b)&i}function d(a,b){return a[b]|a[b+1]<<8|a[b+2]<<16|a[b+3]<<24}function e(a,b,c){a.splice(b,4,255&c,c>>>8&255,c>>>16&255,c>>>24&255)}function f(a,b){return a>>>8*b&255}function g(){function a(a){function b(a){return a^a>>2^[0,90,180,238][3&a]}function e(a){return a^a>>1^a>>2^[0,238,180,90][3&a]}function g(a,b){var c,d,e;for(c=0;8>c;c++)d=b>>>24,b=b<<8&i|a>>>24,a=a<<8&i,e=d<<1,128&d&&(e^=333),b^=d^e<<16,e^=d>>>1,1&d&&(e^=166),b^=e<<24|e<<8;return b}function h(a,b){var c,d,e,f;return c=b>>4,d=15&b,e=A[a][c^d],f=B[a][E[d]^F[c]],D[a][E[f]^F[e]]<<4|C[a][e^f]}function j(a,b){var c=f(a,0),d=f(a,1),e=f(a,2),g=f(a,3);switch(q){case 4:c=G[1][c]^f(b[3],0),d=G[0][d]^f(b[3],1),e=G[0][e]^f(b[3],2),g=G[1][g]^f(b[3],3);case 3:c=G[1][c]^f(b[2],0),d=G[1][d]^f(b[2],1),e=G[0][e]^f(b[2],2),g=G[0][g]^f(b[2],3);case 2:c=G[0][G[0][c]^f(b[1],0)]^f(b[0],0),d=G[0][G[1][d]^f(b[1],1)]^f(b[0],1),e=G[1][G[0][e]^f(b[1],2)]^f(b[0],2),g=G[1][G[1][g]^f(b[1],3)]^f(b[0],3)}return H[0][c]^H[1][d]^H[2][e]^H[3][g]}o=a;var k,l,m,n,p,q,r,u,v,w=[],x=[],y=[],z=[],A=[[8,1,7,13,6,15,3,2,0,11,5,9,14,12,10,4],[2,8,11,13,15,7,6,14,3,1,9,4,0,10,12,5]],B=[[14,12,11,8,1,2,3,5,15,4,10,6,7,0,9,13],[1,14,2,11,4,12,3,7,6,13,10,5,15,9,0,8]],C=[[11,10,5,14,6,13,9,0,12,8,15,3,2,4,7,1],[4,12,7,5,1,6,9,10,0,14,13,8,2,11,3,15]],D=[[13,7,15,4,1,2,6,14,9,11,3,0,8,5,12,10],[11,9,5,1,12,3,13,14,6,4,7,15,2,0,8,10]],E=[0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15],F=[0,9,2,11,4,13,6,15,8,1,10,3,12,5,14,7],G=[[],[]],H=[[],[],[],[]];for(o=o.slice(0,32),k=o.length;16!=k&&24!=k&&32!=k;)o[k++]=0;for(k=0;k>2]=d(o,k);for(k=0;256>k;k++)G[0][k]=h(0,k),G[1][k]=h(1,k);for(k=0;256>k;k++)r=G[1][k],u=b(r),v=e(r),H[0][k]=r+(u<<8)+(v<<16)+(v<<24),H[2][k]=u+(v<<8)+(r<<16)+(v<<24),r=G[0][k],u=b(r),v=e(r),H[1][k]=v+(v<<8)+(u<<16)+(r<<24),H[3][k]=u+(r<<8)+(v<<16)+(u<<24);for(q=y.length/2,k=0;q>k;k++)l=y[k+k],w[k]=l,m=y[k+k+1],x[k]=m,z[q-k-1]=g(l,m);for(k=0;40>k;k+=2)l=16843009*k,m=l+16843009,l=j(l,w),m=c(j(m,x),8),s[k]=l+m&i,s[k+1]=c(l+2*m,9);for(k=0;256>k;k++)switch(l=m=n=p=k,q){case 4:l=G[1][l]^f(z[3],0),m=G[0][m]^f(z[3],1),n=G[0][n]^f(z[3],2),p=G[1][p]^f(z[3],3);case 3:l=G[1][l]^f(z[2],0),m=G[1][m]^f(z[2],1),n=G[0][n]^f(z[2],2),p=G[0][p]^f(z[2],3);case 2:t[0][k]=H[0][G[0][G[0][l]^f(z[1],0)]^f(z[0],0)],t[1][k]=H[1][G[0][G[1][m]^f(z[1],1)]^f(z[0],1)],t[2][k]=H[2][G[1][G[0][n]^f(z[1],2)]^f(z[0],2)],t[3][k]=H[3][G[1][G[1][p]^f(z[1],3)]^f(z[0],3)]}}function b(a){return t[0][f(a,0)]^t[1][f(a,1)]^t[2][f(a,2)]^t[3][f(a,3)]}function g(a){return t[0][f(a,3)]^t[1][f(a,0)]^t[2][f(a,1)]^t[3][f(a,2)]}function h(a,d){var e=b(d[0]),f=g(d[1]);d[2]=c(d[2]^e+f+s[4*a+8]&i,31),d[3]=c(d[3],1)^e+2*f+s[4*a+9]&i,e=b(d[2]),f=g(d[3]),d[0]=c(d[0]^e+f+s[4*a+10]&i,31),d[1]=c(d[1],1)^e+2*f+s[4*a+11]&i}function j(a,d){var e=b(d[0]),f=g(d[1]);d[2]=c(d[2],1)^e+f+s[4*a+10]&i,d[3]=c(d[3]^e+2*f+s[4*a+11]&i,31),e=b(d[2]),f=g(d[3]),d[0]=c(d[0],1)^e+f+s[4*a+8]&i,d[1]=c(d[1]^e+2*f+s[4*a+9]&i,31)}function k(){s=[],t=[[],[],[],[]]}function l(a,b){p=a,q=b;for(var c=[d(p,q)^s[0],d(p,q+4)^s[1],d(p,q+8)^s[2],d(p,q+12)^s[3]],f=0;8>f;f++)h(f,c);return e(p,q,c[2]^s[4]),e(p,q+4,c[3]^s[5]),e(p,q+8,c[0]^s[6]),e(p,q+12,c[1]^s[7]),q+=16,p}function m(a,b){p=a,q=b;for(var c=[d(p,q)^s[4],d(p,q+4)^s[5],d(p,q+8)^s[6],d(p,q+12)^s[7]],f=7;f>=0;f--)j(f,c);e(p,q,c[2]^s[0]),e(p,q+4,c[3]^s[1]),e(p,q+8,c[0]^s[2]),e(p,q+12,c[1]^s[3]),q+=16}function n(){return p}var o=null,p=null,q=-1,r=null;r="twofish";var s=[],t=[[],[],[],[]];return{name:"twofish",blocksize:16,open:a,close:k,encrypt:l,decrypt:m,finalize:n}}function h(a){this.tf=g(),this.tf.open(j.str2bin(a),0),this.encrypt=function(a){return this.tf.encrypt([].concat(a),0)}}var i=4294967295,j=a("../../util");b.exports=h,b.exports.keySize=h.prototype.keySize=32,b.exports.blockSize=h.prototype.blockSize=16},{"../../util":56}],11:[function(a,b){var c=a("./random.js"),d=a("./cipher"),e=a("./public_key"),f=a("../type/mpi.js");b.exports={publicKeyEncrypt:function(a,b,c){var d=function(){switch(a){case"rsa_encrypt":case"rsa_encrypt_sign":var d=new e.rsa,f=b[0].toBigInteger(),g=b[1].toBigInteger(),h=c.toBigInteger();return[d.encrypt(h,g,f)];case"elgamal":var i=new e.elgamal,j=b[0].toBigInteger(),k=b[1].toBigInteger(),l=b[2].toBigInteger(),h=c.toBigInteger();return i.encrypt(h,k,j,l);default:return[]}}();return d.map(function(a){var b=new f;return b.fromBigInteger(a),b})},publicKeyDecrypt:function(a,b,c){var d=function(){switch(a){case"rsa_encrypt_sign":case"rsa_encrypt":var d=new e.rsa,f=b[2].toBigInteger(),g=b[3].toBigInteger(),h=b[4].toBigInteger(),i=b[5].toBigInteger(),j=c[0].toBigInteger();return d.decrypt(j,f,g,h,i);case"elgamal":var k=new e.elgamal,l=b[3].toBigInteger(),m=c[0].toBigInteger(),n=c[1].toBigInteger(),g=b[0].toBigInteger();return k.decrypt(m,n,g,l);default:return null}}(),g=new f;return g.fromBigInteger(d),g},getPrivateMpiCount:function(a){switch(a){case"rsa_encrypt":case"rsa_encrypt_sign":case"rsa_sign":return 4;case"elgamal":return 1;case"dsa":return 1;default:throw new Error("Unknown algorithm")}},getPublicMpiCount:function(a){switch(a){case"rsa_encrypt":case"rsa_encrypt_sign":case"rsa_sign":return 2;case"elgamal":return 3;case"dsa":return 4;default:throw new Error("Unknown algorithm.")}},generateMpi:function(a,b){var c=function(){switch(a){case"rsa_encrypt":case"rsa_encrypt_sign":case"rsa_sign":var c=new e.rsa,d=c.generate(b,"10001"),f=[];return f.push(d.n),f.push(d.ee),f.push(d.d),f.push(d.p),f.push(d.q),f.push(d.u),f;default:throw new Error("Unsupported algorithm for key generation.")}}();return c.map(function(a){var b=new f;return b.fromBigInteger(a),b})},getPrefixRandom:function(a){return c.getRandomBytes(d[a].blockSize)},generateSessionKey:function(a){return c.getRandomBytes(d[a].keySize)}}},{"../type/mpi.js":54,"./cipher":9,"./public_key":20,"./random.js":23}],12:[function(a,b){var c=a("./sha.js");b.exports={md5:a("./md5.js"),sha1:c.sha1,sha224:c.sha224,sha256:c.sha256,sha384:c.sha384,sha512:c.sha512,ripemd:a("./ripe-md.js"),digest:function(a,b){switch(a){case 1:return this.md5(b);case 2:return this.sha1(b);case 3:return this.ripemd(b);case 8:return this.sha256(b);case 9:return this.sha384(b);case 10:return this.sha512(b);case 11:return this.sha224(b);default:throw new Error("Invalid hash function.")}},getHashByteLength:function(a){switch(a){case 1:return 16;case 2:case 3:return 20;case 8:return 32;case 9:return 48;case 10:return 64;case 11:return 28;default:throw new Error("Invalid hash algorithm.")}}}},{"./md5.js":13,"./ripe-md.js":14,"./sha.js":15}],13:[function(a,b){function c(a,b){var c=a[0],d=a[1],i=a[2],j=a[3];c=e(c,d,i,j,b[0],7,-680876936),j=e(j,c,d,i,b[1],12,-389564586),i=e(i,j,c,d,b[2],17,606105819),d=e(d,i,j,c,b[3],22,-1044525330),c=e(c,d,i,j,b[4],7,-176418897),j=e(j,c,d,i,b[5],12,1200080426),i=e(i,j,c,d,b[6],17,-1473231341),d=e(d,i,j,c,b[7],22,-45705983),c=e(c,d,i,j,b[8],7,1770035416),j=e(j,c,d,i,b[9],12,-1958414417),i=e(i,j,c,d,b[10],17,-42063),d=e(d,i,j,c,b[11],22,-1990404162),c=e(c,d,i,j,b[12],7,1804603682),j=e(j,c,d,i,b[13],12,-40341101),i=e(i,j,c,d,b[14],17,-1502002290),d=e(d,i,j,c,b[15],22,1236535329),c=f(c,d,i,j,b[1],5,-165796510),j=f(j,c,d,i,b[6],9,-1069501632),i=f(i,j,c,d,b[11],14,643717713),d=f(d,i,j,c,b[0],20,-373897302),c=f(c,d,i,j,b[5],5,-701558691),j=f(j,c,d,i,b[10],9,38016083),i=f(i,j,c,d,b[15],14,-660478335),d=f(d,i,j,c,b[4],20,-405537848),c=f(c,d,i,j,b[9],5,568446438),j=f(j,c,d,i,b[14],9,-1019803690),i=f(i,j,c,d,b[3],14,-187363961),d=f(d,i,j,c,b[8],20,1163531501),c=f(c,d,i,j,b[13],5,-1444681467),j=f(j,c,d,i,b[2],9,-51403784),i=f(i,j,c,d,b[7],14,1735328473),d=f(d,i,j,c,b[12],20,-1926607734),c=g(c,d,i,j,b[5],4,-378558),j=g(j,c,d,i,b[8],11,-2022574463),i=g(i,j,c,d,b[11],16,1839030562),d=g(d,i,j,c,b[14],23,-35309556),c=g(c,d,i,j,b[1],4,-1530992060),j=g(j,c,d,i,b[4],11,1272893353),i=g(i,j,c,d,b[7],16,-155497632),d=g(d,i,j,c,b[10],23,-1094730640),c=g(c,d,i,j,b[13],4,681279174),j=g(j,c,d,i,b[0],11,-358537222),i=g(i,j,c,d,b[3],16,-722521979),d=g(d,i,j,c,b[6],23,76029189),c=g(c,d,i,j,b[9],4,-640364487),j=g(j,c,d,i,b[12],11,-421815835),i=g(i,j,c,d,b[15],16,530742520),d=g(d,i,j,c,b[2],23,-995338651),c=h(c,d,i,j,b[0],6,-198630844),j=h(j,c,d,i,b[7],10,1126891415),i=h(i,j,c,d,b[14],15,-1416354905),d=h(d,i,j,c,b[5],21,-57434055),c=h(c,d,i,j,b[12],6,1700485571),j=h(j,c,d,i,b[3],10,-1894986606),i=h(i,j,c,d,b[10],15,-1051523),d=h(d,i,j,c,b[1],21,-2054922799),c=h(c,d,i,j,b[8],6,1873313359),j=h(j,c,d,i,b[15],10,-30611744),i=h(i,j,c,d,b[6],15,-1560198380),d=h(d,i,j,c,b[13],21,1309151649),c=h(c,d,i,j,b[4],6,-145523070),j=h(j,c,d,i,b[11],10,-1120210379),i=h(i,j,c,d,b[2],15,718787259),d=h(d,i,j,c,b[9],21,-343485551),a[0]=n(c,a[0]),a[1]=n(d,a[1]),a[2]=n(i,a[2]),a[3]=n(j,a[3])}function d(a,b,c,d,e,f){return b=n(n(b,a),n(d,f)),n(b<>>32-e,c)}function e(a,b,c,e,f,g,h){return d(b&c|~b&e,a,b,f,g,h)}function f(a,b,c,e,f,g,h){return d(b&e|c&~e,a,b,f,g,h)}function g(a,b,c,e,f,g,h){return d(b^c^e,a,b,f,g,h)}function h(a,b,c,e,f,g,h){return d(c^(b|~e),a,b,f,g,h)}function i(a){txt="";var b,d=a.length,e=[1732584193,-271733879,-1732584194,271733878];for(b=64;b<=a.length;b+=64)c(e,j(a.substring(b-64,b)));a=a.substring(b-64);var f=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(b=0;b>2]|=a.charCodeAt(b)<<(b%4<<3);if(f[b>>2]|=128<<(b%4<<3),b>55)for(c(e,f),b=0;16>b;b++)f[b]=0;return f[14]=8*d,c(e,f),e}function j(a){var b,c=[];for(b=0;64>b;b+=4)c[b>>2]=a.charCodeAt(b)+(a.charCodeAt(b+1)<<8)+(a.charCodeAt(b+2)<<16)+(a.charCodeAt(b+3)<<24);return c}function k(a){for(var b="",c=0;4>c;c++)b+=p[a>>8*c+4&15]+p[a>>8*c&15];return b}function l(a){for(var b=0;b>16)+(b>>16)+(c>>16);return d<<16|65535&c}var o=a("../../util");b.exports=function(a){var b=m(a),c=o.hex2bin(b);return c};var p="0123456789abcdef".split("");"5d41402abc4b2a76b9719d911017c592"!=m("hello")},{"../../util":56}],14:[function(a,b){function c(a,b){return new Number(a<>>32-b)}function d(a,b,c){return new Number(a^b^c)}function e(a,b,c){return new Number(a&b|~a&c)}function f(a,b,c){return new Number((a|~b)^c)}function g(a,b,c){return new Number(a&c|b&~c)}function h(a,b,c){return new Number(a^(b|~c))}function i(a,b,i,j,k,l,m,n){switch(n){case 0:a+=d(b,i,j)+l+0;break;case 1:a+=e(b,i,j)+l+1518500249;break;case 2:a+=f(b,i,j)+l+1859775393;break;case 3:a+=g(b,i,j)+l+2400959708;break;case 4:a+=h(b,i,j)+l+2840853838;break;case 5:a+=h(b,i,j)+l+1352829926;break;case 6:a+=g(b,i,j)+l+1548603684;break;case 7:a+=f(b,i,j)+l+1836072691;break;case 8:a+=e(b,i,j)+l+2053994217;break;case 9:a+=d(b,i,j)+l+0;break;default:document.write("Bogus round number")}a=c(a,m)+k,i=c(i,10),a&=4294967295,b&=4294967295,i&=4294967295,j&=4294967295,k&=4294967295;var o=new Array;return o[0]=a,o[1]=b,o[2]=i,o[3]=j,o[4]=k,o[5]=l,o[6]=m,o}function j(a){a[0]=1732584193,a[1]=4023233417,a[2]=2562383102,a[3]=271733878,a[4]=3285377520}function k(a,b){blockA=new Array,blockB=new Array;for(var c,d=0;5>d;d++)blockA[d]=new Number(a[d]),blockB[d]=new Number(a[d]);for(var e=0,f=0;5>f;f++)for(var d=0;16>d;d++)c=i(blockA[(e+0)%5],blockA[(e+1)%5],blockA[(e+2)%5],blockA[(e+3)%5],blockA[(e+4)%5],b[s[f][d]],r[f][d],f),blockA[(e+0)%5]=c[0],blockA[(e+1)%5]=c[1],blockA[(e+2)%5]=c[2],blockA[(e+3)%5]=c[3],blockA[(e+4)%5]=c[4],e+=4;e=0;for(var f=5;10>f;f++)for(var d=0;16>d;d++)c=i(blockB[(e+0)%5],blockB[(e+1)%5],blockB[(e+2)%5],blockB[(e+3)%5],blockB[(e+4)%5],b[s[f][d]],r[f][d],f),blockB[(e+0)%5]=c[0],blockB[(e+1)%5]=c[1],blockB[(e+2)%5]=c[2],blockB[(e+3)%5]=c[3],blockB[(e+4)%5]=c[4],e+=4;blockB[3]+=blockA[2]+a[1],a[1]=a[2]+blockA[3]+blockB[4],a[2]=a[3]+blockA[4]+blockB[0],a[3]=a[4]+blockA[0]+blockB[1],a[4]=a[0]+blockA[1]+blockB[2],a[0]=blockB[3]}function l(a){for(var b=0;16>b;b++)a[b]=0}function m(a,b,c,d){var e=new Array(16);l(e);for(var f=0,g=0;(63&c)>g;g++)e[g>>>2]^=(255&b.charCodeAt(f++))<<8*(3&g);if(e[c>>>2&15]^=1<<8*(3&c)+7,(63&c)>55){k(a,e);var e=new Array(16);l(e)}e[14]=c<<3,e[15]=c>>>29|d<<3,k(a,e)}function n(a){var b=(255&a.charCodeAt(3))<<24;return b|=(255&a.charCodeAt(2))<<16,b|=(255&a.charCodeAt(1))<<8,b|=255&a.charCodeAt(0)}function o(a){var b,c,d=new Array(q/32),e=new Array(q/8);j(d),b=a.length;var f=new Array(16);l(f);for(var g=0,c=b;c>63;c-=64){for(var h=0;16>h;h++)f[h]=n(a.substr(g,4)),g+=4;k(d,f)}m(d,a.substr(g),b,0);for(var h=0;q/8>h;h+=4)e[h]=255&d[h>>>2],e[h+1]=d[h>>>2]>>>8&255,e[h+2]=d[h>>>2]>>>16&255,e[h+3]=d[h>>>2]>>>24&255;return e}function p(a){for(var b=o(a),c="",d=0;q/8>d;d++)c+=String.fromCharCode(b[d]);return c}var q=160,r=(new Array,[[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8],[7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12],[11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5],[11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12],[9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6],[9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11],[9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5],[15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8],[8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]]),s=[[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],[7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8],[3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12],[1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2],[4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12],[6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2],[15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13],[8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14],[12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]];b.exports=p},{}],15:[function(a,b){var c=function(){var a=8,b="",c=0,d=function(a,b){this.highOrder=a,this.lowOrder=b},e=function(b){var c,d=[],e=(1<c;c+=a)d[c>>5]|=(b.charCodeAt(c/a)&e)<<32-a-c%32;return d},f=function(a){var b,c,d=[],e=a.length;for(b=0;e>b;b+=2){if(c=parseInt(a.substr(b,2),16),isNaN(c))return"INVALID HEX STRING";d[b>>3]|=c<<24-4*(b%8)}return d},g=function(a){var b,d,e=c?"0123456789ABCDEF":"0123456789abcdef",f="",g=4*a.length;for(b=0;g>b;b+=1)d=a[b>>2]>>8*(3-b%4),f+=e.charAt(d>>4&15)+e.charAt(15&d);return f},h=function(a){var c,d,e,f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",g="",h=4*a.length;for(c=0;h>c;c+=3)for(e=(a[c>>2]>>8*(3-c%4)&255)<<16|(a[c+1>>2]>>8*(3-(c+1)%4)&255)<<8|a[c+2>>2]>>8*(3-(c+2)%4)&255,d=0;4>d;d+=1)g+=8*c+6*d<=32*a.length?f.charAt(e>>6*(3-d)&63):b;return g},i=function(a){for(var b="",c=255,d=0;d<32*a.length;d+=8)b+=String.fromCharCode(a[d>>5]>>>24-d%32&c);return b},j=function(a,b){return a<>>32-b},k=function(a,b){return a>>>b|a<<32-b},l=function(a,b){return 32>=b?new d(a.highOrder>>>b|a.lowOrder<<32-b,a.lowOrder>>>b|a.highOrder<<32-b):new d(a.lowOrder>>>b|a.highOrder<<32-b,a.highOrder>>>b|a.lowOrder<<32-b)},m=function(a,b){return a>>>b},n=function(a,b){return 32>=b?new d(a.highOrder>>>b,a.lowOrder>>>b|a.highOrder<<32-b):new d(0,a.highOrder<<32-b)},o=function(a,b,c){return a^b^c},p=function(a,b,c){return a&b^~a&c},q=function(a,b,c){return new d(a.highOrder&b.highOrder^~a.highOrder&c.highOrder,a.lowOrder&b.lowOrder^~a.lowOrder&c.lowOrder)},r=function(a,b,c){return a&b^a&c^b&c},s=function(a,b,c){return new d(a.highOrder&b.highOrder^a.highOrder&c.highOrder^b.highOrder&c.highOrder,a.lowOrder&b.lowOrder^a.lowOrder&c.lowOrder^b.lowOrder&c.lowOrder)},t=function(a){return k(a,2)^k(a,13)^k(a,22)},u=function(a){var b=l(a,28),c=l(a,34),e=l(a,39);return new d(b.highOrder^c.highOrder^e.highOrder,b.lowOrder^c.lowOrder^e.lowOrder)},v=function(a){return k(a,6)^k(a,11)^k(a,25)},w=function(a){var b=l(a,14),c=l(a,18),e=l(a,41);return new d(b.highOrder^c.highOrder^e.highOrder,b.lowOrder^c.lowOrder^e.lowOrder)},x=function(a){return k(a,7)^k(a,18)^m(a,3)},y=function(a){var b=l(a,1),c=l(a,8),e=n(a,7);return new d(b.highOrder^c.highOrder^e.highOrder,b.lowOrder^c.lowOrder^e.lowOrder)},z=function(a){return k(a,17)^k(a,19)^m(a,10)},A=function(a){var b=l(a,19),c=l(a,61),e=n(a,6);return new d(b.highOrder^c.highOrder^e.highOrder,b.lowOrder^c.lowOrder^e.lowOrder)},B=function(a,b){var c=(65535&a)+(65535&b),d=(a>>>16)+(b>>>16)+(c>>>16);return(65535&d)<<16|65535&c},C=function(a,b,c,d){var e=(65535&a)+(65535&b)+(65535&c)+(65535&d),f=(a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(e>>>16);return(65535&f)<<16|65535&e},D=function(a,b,c,d,e){var f=(65535&a)+(65535&b)+(65535&c)+(65535&d)+(65535&e),g=(a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(e>>>16)+(f>>>16);return(65535&g)<<16|65535&f},E=function(a,b){var c,e,f,g;return c=(65535&a.lowOrder)+(65535&b.lowOrder),e=(a.lowOrder>>>16)+(b.lowOrder>>>16)+(c>>>16),f=(65535&e)<<16|65535&c,c=(65535&a.highOrder)+(65535&b.highOrder)+(e>>>16),e=(a.highOrder>>>16)+(b.highOrder>>>16)+(c>>>16),g=(65535&e)<<16|65535&c,new d(g,f)},F=function(a,b,c,e){var f,g,h,i;return f=(65535&a.lowOrder)+(65535&b.lowOrder)+(65535&c.lowOrder)+(65535&e.lowOrder),g=(a.lowOrder>>>16)+(b.lowOrder>>>16)+(c.lowOrder>>>16)+(e.lowOrder>>>16)+(f>>>16),h=(65535&g)<<16|65535&f,f=(65535&a.highOrder)+(65535&b.highOrder)+(65535&c.highOrder)+(65535&e.highOrder)+(g>>>16),g=(a.highOrder>>>16)+(b.highOrder>>>16)+(c.highOrder>>>16)+(e.highOrder>>>16)+(f>>>16),i=(65535&g)<<16|65535&f,new d(i,h)},G=function(a,b,c,e,f){var g,h,i,j;return g=(65535&a.lowOrder)+(65535&b.lowOrder)+(65535&c.lowOrder)+(65535&e.lowOrder)+(65535&f.lowOrder),h=(a.lowOrder>>>16)+(b.lowOrder>>>16)+(c.lowOrder>>>16)+(e.lowOrder>>>16)+(f.lowOrder>>>16)+(g>>>16),i=(65535&h)<<16|65535&g,g=(65535&a.highOrder)+(65535&b.highOrder)+(65535&c.highOrder)+(65535&e.highOrder)+(65535&f.highOrder)+(h>>>16),h=(a.highOrder>>>16)+(b.highOrder>>>16)+(c.highOrder>>>16)+(e.highOrder>>>16)+(f.highOrder>>>16)+(g>>>16),j=(65535&h)<<16|65535&g,new d(j,i)},H=function(a,b){var c,d,e,f,g,h,i,k,l,m=[],n=p,q=o,s=r,t=j,u=B,v=D,w=[1732584193,4023233417,2562383102,271733878,3285377520],x=[1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782];for(a[b>>5]|=128<<24-b%32,a[(b+65>>9<<4)+15]=b,l=a.length,i=0;l>i;i+=16){for(c=w[0],d=w[1],e=w[2],f=w[3],g=w[4],k=0;80>k;k+=1)m[k]=16>k?a[k+i]:t(m[k-3]^m[k-8]^m[k-14]^m[k-16],1),h=20>k?v(t(c,5),n(d,e,f),g,x[k],m[k]):40>k?v(t(c,5),q(d,e,f),g,x[k],m[k]):60>k?v(t(c,5),s(d,e,f),g,x[k],m[k]):v(t(c,5),q(d,e,f),g,x[k],m[k]),g=f,f=e,e=t(d,30),d=c,c=h;w[0]=u(c,w[0]),w[1]=u(d,w[1]),w[2]=u(e,w[2]),w[3]=u(f,w[3]),w[4]=u(g,w[4])}return w},I=function(a,b,c){var e,f,g,h,i,j,k,l,m,n,o,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z=[];for("SHA-224"===c||"SHA-256"===c?(H=64,I=(b+65>>9<<4)+15,L=16,M=1,W=Number,N=B,O=C,P=D,Q=x,R=z,S=t,T=v,V=r,U=p,X=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],o="SHA-224"===c?[3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428]:[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]):("SHA-384"===c||"SHA-512"===c)&&(H=80,I=(b+128>>10<<5)+31,L=32,M=2,W=d,N=E,O=F,P=G,Q=y,R=A,S=u,T=w,V=s,U=q,X=[new W(1116352408,3609767458),new W(1899447441,602891725),new W(3049323471,3964484399),new W(3921009573,2173295548),new W(961987163,4081628472),new W(1508970993,3053834265),new W(2453635748,2937671579),new W(2870763221,3664609560),new W(3624381080,2734883394),new W(310598401,1164996542),new W(607225278,1323610764),new W(1426881987,3590304994),new W(1925078388,4068182383),new W(2162078206,991336113),new W(2614888103,633803317),new W(3248222580,3479774868),new W(3835390401,2666613458),new W(4022224774,944711139),new W(264347078,2341262773),new W(604807628,2007800933),new W(770255983,1495990901),new W(1249150122,1856431235),new W(1555081692,3175218132),new W(1996064986,2198950837),new W(2554220882,3999719339),new W(2821834349,766784016),new W(2952996808,2566594879),new W(3210313671,3203337956),new W(3336571891,1034457026),new W(3584528711,2466948901),new W(113926993,3758326383),new W(338241895,168717936),new W(666307205,1188179964),new W(773529912,1546045734),new W(1294757372,1522805485),new W(1396182291,2643833823),new W(1695183700,2343527390),new W(1986661051,1014477480),new W(2177026350,1206759142),new W(2456956037,344077627),new W(2730485921,1290863460),new W(2820302411,3158454273),new W(3259730800,3505952657),new W(3345764771,106217008),new W(3516065817,3606008344),new W(3600352804,1432725776),new W(4094571909,1467031594),new W(275423344,851169720),new W(430227734,3100823752),new W(506948616,1363258195),new W(659060556,3750685593),new W(883997877,3785050280),new W(958139571,3318307427),new W(1322822218,3812723403),new W(1537002063,2003034995),new W(1747873779,3602036899),new W(1955562222,1575990012),new W(2024104815,1125592928),new W(2227730452,2716904306),new W(2361852424,442776044),new W(2428436474,593698344),new W(2756734187,3733110249),new W(3204031479,2999351573),new W(3329325298,3815920427),new W(3391569614,3928383900),new W(3515267271,566280711),new W(3940187606,3454069534),new W(4118630271,4000239992),new W(116418474,1914138554),new W(174292421,2731055270),new W(289380356,3203993006),new W(460393269,320620315),new W(685471733,587496836),new W(852142971,1086792851),new W(1017036298,365543100),new W(1126000580,2618297676),new W(1288033470,3409855158),new W(1501505948,4234509866),new W(1607167915,987167468),new W(1816402316,1246189591)],o="SHA-384"===c?[new W(3418070365,3238371032),new W(1654270250,914150663),new W(2438529370,812702999),new W(355462360,4144912697),new W(1731405415,4290775857),new W(41048885895,1750603025),new W(3675008525,1694076839),new W(1203062813,3204075428)]:[new W(1779033703,4089235720),new W(3144134277,2227873595),new W(1013904242,4271175723),new W(2773480762,1595750129),new W(1359893119,2917565137),new W(2600822924,725511199),new W(528734635,4215389547),new W(1541459225,327033209)]),a[b>>5]|=128<<24-b%32,a[I]=b,Y=a.length,J=0;Y>J;J+=L){for(e=o[0],f=o[1],g=o[2],h=o[3],i=o[4],j=o[5],k=o[6],l=o[7],K=0;H>K;K+=1)Z[K]=16>K?new W(a[K*M+J],a[K*M+J+1]):O(R(Z[K-2]),Z[K-7],Q(Z[K-15]),Z[K-16]),m=P(l,T(i),U(i,j,k),X[K],Z[K]),n=N(S(e),V(e,f,g)),l=k,k=j,j=i,i=N(h,m),h=g,g=f,f=e,e=N(m,n);o[0]=N(e,o[0]),o[1]=N(f,o[1]),o[2]=N(g,o[2]),o[3]=N(h,o[3]),o[4]=N(i,o[4]),o[5]=N(j,o[5]),o[6]=N(k,o[6]),o[7]=N(l,o[7])}switch(c){case"SHA-224":return[o[0],o[1],o[2],o[3],o[4],o[5],o[6]];case"SHA-256":return o;case"SHA-384":return[o[0].highOrder,o[0].lowOrder,o[1].highOrder,o[1].lowOrder,o[2].highOrder,o[2].lowOrder,o[3].highOrder,o[3].lowOrder,o[4].highOrder,o[4].lowOrder,o[5].highOrder,o[5].lowOrder];case"SHA-512":return[o[0].highOrder,o[0].lowOrder,o[1].highOrder,o[1].lowOrder,o[2].highOrder,o[2].lowOrder,o[3].highOrder,o[3].lowOrder,o[4].highOrder,o[4].lowOrder,o[5].highOrder,o[5].lowOrder,o[6].highOrder,o[6].lowOrder,o[7].highOrder,o[7].lowOrder];default:return[]}},J=function(b,c){if(this.sha1=null,this.sha224=null,this.sha256=null,this.sha384=null,this.sha512=null,this.strBinLen=null,this.strToHash=null,"HEX"===c){if(0!==b.length%2)return"TEXT MUST BE IN BYTE INCREMENTS";this.strBinLen=4*b.length,this.strToHash=f(b)}else{if("ASCII"!==c&&"undefined"!=typeof c)return"UNKNOWN TEXT INPUT TYPE";this.strBinLen=b.length*a,this.strToHash=e(b)}};return J.prototype={getHash:function(a,b){var c=null,d=this.strToHash.slice();switch(b){case"HEX":c=g;break;case"B64":c=h;break;case"ASCII":c=i;break;default:return"FORMAT NOT RECOGNIZED"}switch(a){case"SHA-1":return null===this.sha1&&(this.sha1=H(d,this.strBinLen)),c(this.sha1);case"SHA-224":return null===this.sha224&&(this.sha224=I(d,this.strBinLen,a)),c(this.sha224);case"SHA-256":return null===this.sha256&&(this.sha256=I(d,this.strBinLen,a)),c(this.sha256);case"SHA-384":return null===this.sha384&&(this.sha384=I(d,this.strBinLen,a)),c(this.sha384);case"SHA-512":return null===this.sha512&&(this.sha512=I(d,this.strBinLen,a)),c(this.sha512);default:return"HASH NOT RECOGNIZED"}},getHMAC:function(b,c,d,j){var k,l,m,n,o,p,q,r,s,t=[],u=[];switch(j){case"HEX":k=g;break;case"B64":k=h;break;case"ASCII":k=i;break;default:return"FORMAT NOT RECOGNIZED"}switch(d){case"SHA-1":m=64,s=160;break;case"SHA-224":m=64,s=224;break;case"SHA-256":m=64,s=256;break;case"SHA-384":m=128,s=384;break;case"SHA-512":m=128,s=512;break;default:return"HASH NOT RECOGNIZED"}if("HEX"===c){if(0!==b.length%2)return"KEY MUST BE IN BYTE INCREMENTS";l=f(b),r=4*b.length}else{if("ASCII"!==c)return"UNKNOWN KEY INPUT TYPE";l=e(b),r=b.length*a}for(n=8*m,q=m/4-1,r/8>m?(l="SHA-1"===d?H(l,r):I(l,r,d),l[q]&=4294967040):m>r/8&&(l[q]&=4294967040),o=0;q>=o;o+=1)t[o]=909522486^l[o],u[o]=1549556828^l[o];return"SHA-1"===d?(p=H(t.concat(this.strToHash),n+this.strBinLen),p=H(u.concat(p),n+s)):(p=I(t.concat(this.strToHash),n+this.strBinLen,d),p=I(u.concat(p),n+s,d)),k(p)}},J}();b.exports={sha1:function(a){var b=new c(a,"ASCII");return b.getHash("SHA-1","ASCII")},sha224:function(a){var b=new c(a,"ASCII");return b.getHash("SHA-224","ASCII")},sha256:function(a){var b=new c(a,"ASCII");return b.getHash("SHA-256","ASCII")},sha384:function(a){var b=new c(a,"ASCII");return b.getHash("SHA-384","ASCII")},sha512:function(a){var b=new c(a,"ASCII"); +return b.getHash("SHA-512","ASCII")}}},{}],16:[function(a,b){b.exports={cipher:a("./cipher"),hash:a("./hash"),cfb:a("./cfb.js"),publicKey:a("./public_key"),signature:a("./signature.js"),random:a("./random.js"),pkcs1:a("./pkcs1.js")};var c=a("./crypto.js");for(var d in c)b.exports[d]=c[d]},{"./cfb.js":4,"./cipher":9,"./crypto.js":11,"./hash":12,"./pkcs1.js":17,"./public_key":20,"./random.js":23,"./signature.js":24}],17:[function(a,b){hash_headers=new Array,hash_headers[1]=[48,32,48,12,6,8,42,134,72,134,247,13,2,5,5,0,4,16],hash_headers[2]=[48,33,48,9,6,5,43,14,3,2,26,5,0,4,20],hash_headers[3]=[48,33,48,9,6,5,43,36,3,2,1,5,0,4,20],hash_headers[8]=[48,49,48,13,6,9,96,134,72,1,101,3,4,2,1,5,0,4,32],hash_headers[9]=[48,65,48,13,6,9,96,134,72,1,101,3,4,2,2,5,0,4,48],hash_headers[10]=[48,81,48,13,6,9,96,134,72,1,101,3,4,2,3,5,0,4,64],hash_headers[11]=[48,49,48,13,6,9,96,134,72,1,101,3,4,2,4,5,0,4,28];var c=(a("./crypto.js"),a("./random.js")),d=a("../util"),e=a("./public_key/jsbn.js"),f=a("./hash");b.exports={eme:{encode:function(a,b){if(a.length>b-11)return-1;var d="";d+=String.fromCharCode(0),d+=String.fromCharCode(2);for(var e=0;ec;)c++;return a.substring(c+1,a.length)}},emsa:{encode:function(a,b,c){var g="";g+=String.fromCharCode(0),g+=String.fromCharCode(1);for(var h=0;h11&&10!=b&&8>b?2:b;case 28:return b>11&&8>b?11:b;case 32:return b>10&&8>b?8:b;default:return g.print_debug("DSA select hash algorithm: returning null for an unknown length of q"),null}}function c(a,b,c,e,h,i,j,k){var l=g.getLeftNBits(f.digest(a,e),i.bitLength()),m=new d(g.hexstrdump(l),16);if(d.ZERO.compareTo(b)>0||b.compareTo(i)>0||d.ZERO.compareTo(c)>0||c.compareTo(i)>0)return g.print_debug("invalid DSA Signature"),null;var n=c.modInverse(i),o=m.multiply(n).mod(i),p=b.multiply(n).mod(i);return j.modPow(o,h).multiply(k.modPow(p,h)).mod(h).mod(i)}this.select_hash_algorithm=b,this.sign=a,this.verify=c}var d=a("./jsbn.js"),e=a("../random.js"),f=a("../hash"),g=a("../../util"),h=a("../../config");b.exports=c},{"../../config":3,"../../util":56,"../hash":12,"../random.js":23,"./jsbn.js":21}],19:[function(a,b){function c(){function a(a,b,c,f){var g=d.ONE.add(d.ONE),h=c.subtract(g),i=e.getRandomBigIntegerInRange(g,h);i=i.mod(h).add(d.ONE);var j=[];return j[0]=b.modPow(i,c),j[1]=f.modPow(i,c).multiply(a).mod(c),j}function b(a,b,c,d){return f.print_debug("Elgamal Decrypt:\nc1:"+f.hexstrdump(a.toMPI())+"\nc2:"+f.hexstrdump(b.toMPI())+"\np:"+f.hexstrdump(c.toMPI())+"\nx:"+f.hexstrdump(d.toMPI())),a.modPow(d,c).modInverse(c).multiply(b).mod(c)}this.encrypt=a,this.decrypt=b}var d=a("./jsbn.js"),e=a("../random.js"),f=a("../../util");b.exports=c},{"../../util":56,"../random.js":23,"./jsbn.js":21}],20:[function(a,b){b.exports={rsa:a("./rsa.js"),elgamal:a("./elgamal.js"),dsa:a("./dsa.js")}},{"./dsa.js":18,"./elgamal.js":19,"./rsa.js":22}],21:[function(a,b){function c(a,b,c){null!=a&&("number"==typeof a?this.fromNumber(a,b,c):null==b&&"string"!=typeof a?this.fromString(a,256):this.fromString(a,b))}function d(){return new c(null)}function e(a,b,c,d,e,f){for(;--f>=0;){var g=b*this[a++]+c[d]+e;e=Math.floor(g/67108864),c[d++]=67108863&g}return e}function f(a){return ec.charAt(a)}function g(a,b){var c=fc[a.charCodeAt(b)];return null==c?-1:c}function h(a){for(var b=this.t-1;b>=0;--b)a[b]=this[b];a.t=this.t,a.s=this.s}function i(a){this.t=1,this.s=0>a?-1:0,a>0?this[0]=a:-1>a?this[0]=a+DV:this.t=0}function j(a){var b=d();return b.fromInt(a),b}function k(a,b){var d;if(16==b)d=4;else if(8==b)d=3;else if(256==b)d=8;else if(2==b)d=1;else if(32==b)d=5;else{if(4!=b)return this.fromRadix(a,b),void 0;d=2}this.t=0,this.s=0;for(var e=a.length,f=!1,h=0;--e>=0;){var i=8==d?255&a[e]:g(a,e);0>i?"-"==a.charAt(e)&&(f=!0):(f=!1,0==h?this[this.t++]=i:h+d>this.DB?(this[this.t-1]|=(i&(1<>this.DB-h):this[this.t-1]|=i<=this.DB&&(h-=this.DB))}8==d&&0!=(128&a[0])&&(this.s=-1,h>0&&(this[this.t-1]|=(1<0&&this[this.t-1]==a;)--this.t}function m(a){if(this.s<0)return"-"+this.negate().toString(a);var b;if(16==a)b=4;else if(8==a)b=3;else if(2==a)b=1;else if(32==a)b=5;else{if(4!=a)return this.toRadix(a);b=2}var c,d=(1<0)for(i>i)>0&&(e=!0,g=f(c));h>=0;)b>i?(c=(this[h]&(1<>(i+=this.DB-b)):(c=this[h]>>(i-=b)&d,0>=i&&(i+=this.DB,--h)),c>0&&(e=!0),e&&(g+=f(c));return e?g:"0"}function n(){var a=d();return c.ZERO.subTo(this,a),a}function o(){return this.s<0?this.negate():this}function p(a){var b=this.s-a.s;if(0!=b)return b;var c=this.t;if(b=c-a.t,0!=b)return b;for(;--c>=0;)if(0!=(b=this[c]-a[c]))return b;return 0}function q(a){var b,c=1;return 0!=(b=a>>>16)&&(a=b,c+=16),0!=(b=a>>8)&&(a=b,c+=8),0!=(b=a>>4)&&(a=b,c+=4),0!=(b=a>>2)&&(a=b,c+=2),0!=(b=a>>1)&&(a=b,c+=1),c}function r(){return this.t<=0?0:this.DB*(this.t-1)+q(this[this.t-1]^this.s&this.DM)}function s(a,b){var c;for(c=this.t-1;c>=0;--c)b[c+a]=this[c];for(c=a-1;c>=0;--c)b[c]=0;b.t=this.t+a,b.s=this.s}function t(a,b){for(var c=a;c=0;--c)b[c+g+1]=this[c]>>e|h,h=(this[c]&f)<=0;--c)b[c]=0;b[g]=h,b.t=this.t+g+1,b.s=this.s,b.clamp()}function v(a,b){b.s=this.s;var c=Math.floor(a/this.DB);if(c>=this.t)return b.t=0,void 0;var d=a%this.DB,e=this.DB-d,f=(1<>d;for(var g=c+1;g>d;d>0&&(b[this.t-c-1]|=(this.s&f)<c;)d+=this[c]-a[c],b[c++]=d&this.DM,d>>=this.DB;if(a.t>=this.DB;d+=this.s}else{for(d+=this.s;c>=this.DB;d-=a.s}b.s=0>d?-1:0,-1>d?b[c++]=this.DV+d:d>0&&(b[c++]=d),b.t=c,b.clamp()}function x(a,b){var d=this.abs(),e=a.abs(),f=d.t;for(b.t=f+e.t;--f>=0;)b[f]=0;for(f=0;f=0;)a[c]=0;for(c=0;c=b.DV&&(a[c+b.t]-=b.DV,a[c+b.t+1]=1)}a.t>0&&(a[a.t-1]+=b.am(c,b[c],a,2*c,0,1)),a.s=0,a.clamp()}function z(a,b,e){var f=a.abs();if(!(f.t<=0)){var g=this.abs();if(g.t0?(f.lShiftTo(k,h),g.lShiftTo(k,e)):(f.copyTo(h),g.copyTo(e));var l=h.t,m=h[l-1];if(0!=m){var n=m*(1<1?h[l-2]>>this.F2:0),o=this.FV/n,p=(1<=0&&(e[e.t++]=1,e.subTo(u,e)),c.ONE.dlShiftTo(l,u),u.subTo(h,h);h.t=0;){var v=e[--s]==m?this.DM:Math.floor(e[s]*o+(e[s-1]+r)*p);if((e[s]+=h.am(0,v,e,t,0,l))0&&e.rShiftTo(k,e),0>i&&c.ZERO.subTo(e,e)}}}function A(a){var b=d();return this.abs().divRemTo(a,null,b),this.s<0&&b.compareTo(c.ZERO)>0&&a.subTo(b,b),b}function B(a){this.m=a}function C(a){return a.s<0||a.compareTo(this.m)>=0?a.mod(this.m):a}function D(a){return a}function E(a){a.divRemTo(this.m,null,a)}function F(a,b,c){a.multiplyTo(b,c),this.reduce(c)}function G(a,b){a.squareTo(b),this.reduce(b)}function H(){if(this.t<1)return 0;var a=this[0];if(0==(1&a))return 0;var b=3&a;return b=b*(2-(15&a)*b)&15,b=b*(2-(255&a)*b)&255,b=b*(2-((65535&a)*b&65535))&65535,b=b*(2-a*b%this.DV)%this.DV,b>0?this.DV-b:-b}function I(a){this.m=a,this.mp=a.invDigit(),this.mpl=32767&this.mp,this.mph=this.mp>>15,this.um=(1<0&&this.m.subTo(b,b),b}function K(a){var b=d();return a.copyTo(b),this.reduce(b),b}function L(a){for(;a.t<=this.mt2;)a[a.t++]=0;for(var b=0;b>15)*this.mpl&this.um)<<15)&a.DM;for(c=b+this.m.t,a[c]+=this.m.am(0,d,a,b,0,this.m.t);a[c]>=a.DV;)a[c]-=a.DV,a[++c]++}a.clamp(),a.drShiftTo(this.m.t,a),a.compareTo(this.m)>=0&&a.subTo(this.m,a)}function M(a,b){a.squareTo(b),this.reduce(b)}function N(a,b,c){a.multiplyTo(b,c),this.reduce(c)}function O(){return 0==(this.t>0?1&this[0]:this.s)}function P(a,b){if(a>4294967295||1>a)return c.ONE;var e=d(),f=d(),g=b.convert(this),h=q(a)-1;for(g.copyTo(e);--h>=0;)if(b.sqrTo(e,f),(a&1<0)b.mulTo(f,g,e);else{var i=e;e=f,f=i}return b.revert(e)}function Q(a,b){var c;return c=256>a||b.isEven()?new B(b):new I(b),this.exp(a,c)}function R(){var a=d();return this.copyTo(a),a}function S(){if(this.s<0){if(1==this.t)return this[0]-this.DV;if(0==this.t)return-1}else{if(1==this.t)return this[0];if(0==this.t)return 0}return(this[1]&(1<<32-this.DB)-1)<>24}function U(){return 0==this.t?this.s:this[0]<<16>>16}function V(a){return Math.floor(Math.LN2*this.DB/Math.log(a))}function W(){return this.s<0?-1:this.t<=0||1==this.t&&this[0]<=0?0:1}function X(a){if(null==a&&(a=10),0==this.signum()||2>a||a>36)return"0";var b=this.chunkSize(a),c=Math.pow(a,b),e=j(c),f=d(),g=d(),h="";for(this.divRemTo(e,f,g);f.signum()>0;)h=(c+g.intValue()).toString(a).substr(1)+h,f.divRemTo(e,f,g);return g.intValue().toString(a)+h}function Y(a,b){this.fromInt(0),null==b&&(b=10);for(var d=this.chunkSize(b),e=Math.pow(b,d),f=!1,h=0,i=0,j=0;jk?"-"==a.charAt(j)&&0==this.signum()&&(f=!0):(i=b*i+k,++h>=d&&(this.dMultiply(e),this.dAddOffset(i,0),h=0,i=0))}h>0&&(this.dMultiply(Math.pow(b,h)),this.dAddOffset(i,0)),f&&c.ZERO.subTo(this,this)}function Z(a,b,d){if("number"==typeof b)if(2>a)this.fromInt(1);else for(this.fromNumber(a,d),this.testBit(a-1)||this.bitwiseTo(c.ONE.shiftLeft(a-1),fb,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(b);)this.dAddOffset(2,0),this.bitLength()>a&&this.subTo(c.ONE.shiftLeft(a-1),this);else{var e=new Array,f=7&a;e.length=(a>>3)+1,b.nextBytes(e),f>0?e[0]&=(1<0)for(d>d)!=(this.s&this.DM)>>d&&(b[e++]=c|this.s<=0;)8>d?(c=(this[a]&(1<>(d+=this.DB-8)):(c=this[a]>>(d-=8)&255,0>=d&&(d+=this.DB,--a)),(e>0||c!=this.s)&&(b[e++]=c);return b}function _(a){return 0==this.compareTo(a)}function ab(a){return this.compareTo(a)<0?this:a}function bb(a){return this.compareTo(a)>0?this:a}function cb(a,b,c){var d,e,f=Math.min(a.t,this.t);for(d=0;f>d;++d)c[d]=b(this[d],a[d]);if(a.ta?this.rShiftTo(-a,b):this.lShiftTo(a,b),b}function nb(a){var b=d();return 0>a?this.lShiftTo(-a,b):this.rShiftTo(a,b),b}function ob(a){if(0==a)return-1;var b=0;return 0==(65535&a)&&(a>>=16,b+=16),0==(255&a)&&(a>>=8,b+=8),0==(15&a)&&(a>>=4,b+=4),0==(3&a)&&(a>>=2,b+=2),0==(1&a)&&++b,b}function pb(){for(var a=0;a=this.t?0!=this.s:0!=(this[b]&1<c;)d+=this[c]+a[c],b[c++]=d&this.DM,d>>=this.DB;if(a.t>=this.DB;d+=this.s}else{for(d+=this.s;c>=this.DB;d+=a.s}b.s=0>d?-1:0,d>0?b[c++]=d:-1>d&&(b[c++]=this.DV+d),b.t=c,b.clamp()}function yb(a){var b=d();return this.addTo(a,b),b}function zb(a){var b=d();return this.subTo(a,b),b}function Ab(a){var b=d();return this.multiplyTo(a,b),b}function Bb(){var a=d();return this.squareTo(a),a}function Cb(a){var b=d();return this.divRemTo(a,b,null),b}function Db(a){var b=d();return this.divRemTo(a,null,b),b}function Eb(a){var b=d(),c=d();return this.divRemTo(a,b,c),new Array(b,c)}function Fb(a){this[this.t]=this.am(0,a-1,this,0,0,this.t),++this.t,this.clamp()}function Gb(a,b){if(0!=a){for(;this.t<=b;)this[this.t++]=0;for(this[b]+=a;this[b]>=this.DV;)this[b]-=this.DV,++b>=this.t&&(this[this.t++]=0),++this[b]}}function Hb(){}function Ib(a){return a}function Jb(a,b,c){a.multiplyTo(b,c)}function Kb(a,b){a.squareTo(b)}function Lb(a){return this.exp(a,new Hb)}function Mb(a,b,c){var d=Math.min(this.t+a.t,b);for(c.s=0,c.t=d;d>0;)c[--d]=0;var e;for(e=c.t-this.t;e>d;++d)c[d+this.t]=this.am(0,a[d],c,d,0,this.t);for(e=Math.min(a.t,b);e>d;++d)this.am(0,a[d],c,d,0,b-d);c.clamp()}function Nb(a,b,c){--b;var d=c.t=this.t+a.t-b;for(c.s=0;--d>=0;)c[d]=0;for(d=Math.max(b-this.t,0);d2*this.m.t)return a.mod(this.m);if(a.compareTo(this.m)<0)return a;var b=d();return a.copyTo(b),this.reduce(b),b}function Qb(a){return a}function Rb(a){for(a.drShiftTo(this.m.t-1,this.r2),a.t>this.m.t+1&&(a.t=this.m.t+1,a.clamp()),this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3),this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);a.compareTo(this.r2)<0;)a.dAddOffset(1,this.m.t+1);for(a.subTo(this.r2,a);a.compareTo(this.m)>=0;)a.subTo(this.m,a)}function Sb(a,b){a.squareTo(b),this.reduce(b)}function Tb(a,b,c){a.multiplyTo(b,c),this.reduce(c)}function Ub(a,b){var c,e,f=a.bitLength(),g=j(1);if(0>=f)return g;c=18>f?1:48>f?3:144>f?4:768>f?5:6,e=8>f?new B(b):b.isEven()?new Ob(b):new I(b);var h=new Array,i=3,k=c-1,l=(1<1){var m=d();for(e.sqrTo(h[1],m);l>=i;)h[i]=d(),e.mulTo(m,h[i-2],h[i]),i+=2}var n,o,p=a.t-1,r=!0,s=d();for(f=q(a[p])-1;p>=0;){for(f>=k?n=a[p]>>f-k&l:(n=(a[p]&(1<0&&(n|=a[p-1]>>this.DB+f-k)),i=c;0==(1&n);)n>>=1,--i;if((f-=i)<0&&(f+=this.DB,--p),r)h[n].copyTo(g),r=!1;else{for(;i>1;)e.sqrTo(g,s),e.sqrTo(s,g),i-=2;i>0?e.sqrTo(g,s):(o=g,g=s,s=o),e.mulTo(s,h[n],g)}for(;p>=0&&0==(a[p]&1<f)return b;for(f>e&&(f=e),f>0&&(b.rShiftTo(f,b),c.rShiftTo(f,c));b.signum()>0;)(e=b.getLowestSetBit())>0&&b.rShiftTo(e,b),(e=c.getLowestSetBit())>0&&c.rShiftTo(e,c),b.compareTo(c)>=0?(b.subTo(c,b),b.rShiftTo(1,b)):(c.subTo(b,c),c.rShiftTo(1,c));return f>0&&c.lShiftTo(f,c),c}function Wb(a){if(0>=a)return 0;var b=this.DV%a,c=this.s<0?a-1:0;if(this.t>0)if(0==b)c=this[0]%a;else for(var d=this.t-1;d>=0;--d)c=(b*c+this[d])%a;return c}function Xb(a){var b=a.isEven();if(this.isEven()&&b||0==a.signum())return c.ZERO;for(var d=a.clone(),e=this.clone(),f=j(1),g=j(0),h=j(0),i=j(1);0!=d.signum();){for(;d.isEven();)d.rShiftTo(1,d),b?(f.isEven()&&g.isEven()||(f.addTo(this,f),g.subTo(a,g)),f.rShiftTo(1,f)):g.isEven()||g.subTo(a,g),g.rShiftTo(1,g);for(;e.isEven();)e.rShiftTo(1,e),b?(h.isEven()&&i.isEven()||(h.addTo(this,h),i.subTo(a,i)),h.rShiftTo(1,h)):i.isEven()||i.subTo(a,i),i.rShiftTo(1,i);d.compareTo(e)>=0?(d.subTo(e,d),b&&f.subTo(h,f),g.subTo(i,g)):(e.subTo(d,e),b&&h.subTo(f,h),i.subTo(g,i))}return 0!=e.compareTo(c.ONE)?c.ZERO:i.compareTo(a)>=0?i.subtract(a):i.signum()<0?(i.addTo(a,i),i.signum()<0?i.add(a):i):i}function Yb(a){var b,c=this.abs();if(1==c.t&&c[0]<=gc[gc.length-1]){for(b=0;bd;)d*=gc[e++];for(d=c.modInt(d);e>b;)if(d%gc[b++]==0)return!1}return c.millerRabin(a)}function q(a){var b,c=1;return 0!=(b=a>>>16)&&(a=b,c+=16),0!=(b=a>>8)&&(a=b,c+=8),0!=(b=a>>4)&&(a=b,c+=4),0!=(b=a>>2)&&(a=b,c+=2),0!=(b=a>>1)&&(a=b,c+=1),c}function Zb(){var a=this.toByteArray(),b=8*(a.length-1)+q(a[0]),c="";return c+=String.fromCharCode((65280&b)>>8),c+=String.fromCharCode(255&b),c+=ac.bin2str(a)}function $b(a){var b=this.subtract(c.ONE),e=b.getLowestSetBit();if(0>=e)return!1;var f=b.shiftRight(e);a=a+1>>1,a>gc.length&&(a=gc.length);for(var g,h=d(),i=[],j=0;a>j;++j){for(;g=gc[Math.floor(Math.random()*gc.length)],-1!=i.indexOf(g););i.push(g),h.fromInt(g);var k=h.modPow(f,this);if(0!=k.compareTo(c.ONE)&&0!=k.compareTo(b)){for(var g=1;g++=dc;++dc)fc[cc++]=dc;for(cc="a".charCodeAt(0),dc=10;36>dc;++dc)fc[cc++]=dc;for(cc="A".charCodeAt(0),dc=10;36>dc;++dc)fc[cc++]=dc;B.prototype.convert=C,B.prototype.revert=D,B.prototype.reduce=E,B.prototype.mulTo=F,B.prototype.sqrTo=G,I.prototype.convert=J,I.prototype.revert=K,I.prototype.reduce=L,I.prototype.mulTo=N,I.prototype.sqrTo=M,c.prototype.copyTo=h,c.prototype.fromInt=i,c.prototype.fromString=k,c.prototype.clamp=l,c.prototype.dlShiftTo=s,c.prototype.drShiftTo=t,c.prototype.lShiftTo=u,c.prototype.rShiftTo=v,c.prototype.subTo=w,c.prototype.multiplyTo=x,c.prototype.squareTo=y,c.prototype.divRemTo=z,c.prototype.invDigit=H,c.prototype.isEven=O,c.prototype.exp=P,c.prototype.toString=m,c.prototype.negate=n,c.prototype.abs=o,c.prototype.compareTo=p,c.prototype.bitLength=r,c.prototype.mod=A,c.prototype.modPowInt=Q,c.ZERO=j(0),c.ONE=j(1),b.exports=c,Hb.prototype.convert=Ib,Hb.prototype.revert=Ib,Hb.prototype.mulTo=Jb,Hb.prototype.sqrTo=Kb,Ob.prototype.convert=Pb,Ob.prototype.revert=Qb,Ob.prototype.reduce=Rb,Ob.prototype.mulTo=Tb,Ob.prototype.sqrTo=Sb;var gc=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],hc=(1<<26)/gc[gc.length-1],c=a("./jsbn.js");c.prototype.chunkSize=V,c.prototype.toRadix=X,c.prototype.fromRadix=Y,c.prototype.fromNumber=Z,c.prototype.bitwiseTo=cb,c.prototype.changeBit=tb,c.prototype.addTo=xb,c.prototype.dMultiply=Fb,c.prototype.dAddOffset=Gb,c.prototype.multiplyLowerTo=Mb,c.prototype.multiplyUpperTo=Nb,c.prototype.modInt=Wb,c.prototype.millerRabin=$b,c.prototype.clone=R,c.prototype.intValue=S,c.prototype.byteValue=T,c.prototype.shortValue=U,c.prototype.signum=W,c.prototype.toByteArray=$,c.prototype.equals=_,c.prototype.min=ab,c.prototype.max=bb,c.prototype.and=eb,c.prototype.or=gb,c.prototype.xor=ib,c.prototype.andNot=kb,c.prototype.not=lb,c.prototype.shiftLeft=mb,c.prototype.shiftRight=nb,c.prototype.getLowestSetBit=pb,c.prototype.bitCount=rb,c.prototype.testBit=sb,c.prototype.setBit=ub,c.prototype.clearBit=vb,c.prototype.flipBit=wb,c.prototype.add=yb,c.prototype.subtract=zb,c.prototype.multiply=Ab,c.prototype.divide=Cb,c.prototype.remainder=Db,c.prototype.divideAndRemainder=Eb,c.prototype.modPow=Ub,c.prototype.modInverse=Xb,c.prototype.pow=Lb,c.prototype.gcd=Vb,c.prototype.isProbablePrime=Yb,c.prototype.toMPI=Zb,c.prototype.square=Bb},{"../../util":56,"./jsbn.js":21}],22:[function(a,b){function c(){function a(a){for(var b=0;b>1;for(d.e=parseInt(b,16),d.ee=new e(b,16);;){for(;d.p=new e(a-g,1,f),0!=d.p.subtract(e.ONE).gcd(d.ee).compareTo(e.ONE)||!d.p.isProbablePrime(10););for(;d.q=new e(g,1,f),0!=d.q.subtract(e.ONE).gcd(d.ee).compareTo(e.ONE)||!d.q.isProbablePrime(10););if(d.p.compareTo(d.q)<=0){var i=d.p;d.p=d.q,d.q=i}var j=d.p.subtract(e.ONE),k=d.q.subtract(e.ONE),l=j.multiply(k);if(0==l.gcd(d.ee).compareTo(e.ONE)){d.n=d.p.multiply(d.q),d.d=d.ee.modInverse(l),d.dmp1=d.d.mod(j),d.dmq1=d.d.mod(k),d.u=d.p.modInverse(d.q);break}}return d}this.encrypt=b,this.decrypt=a,this.verify=g,this.sign=d,this.generate=i,this.keyObject=h}var e=a("./jsbn.js"),f=a("../../util"),g=a("../random.js");b.exports=d},{"../../util":56,"../random.js":23,"./jsbn.js":21}],23:[function(a,b){var c=a("../type/mpi.js");b.exports={getRandomBytes:function(a){for(var b="",c=0;a>c;c++)b+=String.fromCharCode(this.getSecureRandomOctet());return b},getPseudoRandom:function(a,b){return Math.round(Math.random()*(b-a))+a},getSecureRandom:function(a,b){var c=new Uint32Array(1);window.crypto.getRandomValues(c);for(var d=(b-a).toString(2).length;(c[0]&Math.pow(2,d)-1)>b-a;)window.crypto.getRandomValues(c);return a+Math.abs(c[0]&Math.pow(2,d)-1)},getSecureRandomOctet:function(){var a=new Uint32Array(1);return window.crypto.getRandomValues(a),255&a[0]},getRandomBigInteger:function(a){if(0>a)return null;var b=Math.floor((a+7)/8),d=this.getRandomBytes(b);a%8>0&&(d=String.fromCharCode(Math.pow(2,a%8)-1&d.charCodeAt(0))+d.substring(1));var e=new c;return e.fromBytes(d),e.toBigInteger()},getRandomBigIntegerInRange:function(a,b){if(!(b.compareTo(a)<=0)){for(var c=b.subtract(a),d=this.getRandomBigInteger(c.bitLength());d>c;)d=this.getRandomBigInteger(c.bitLength());return a.add(d)}}}},{"../type/mpi.js":54}],24:[function(a,b){var c=a("./public_key"),d=a("./pkcs1.js"),e=a("./hash");b.exports={verify:function(a,b,f,g,h){var i=e.digest(b,h);switch(a){case 1:case 2:case 3:var j=new c.rsa,k=g[0].toBigInteger(),l=g[1].toBigInteger(),m=f[0].toBigInteger(),n=j.verify(m,l,k),o=d.emsa.decode(b,n.toMPI().substring(2));if(-1==o)throw new Error("PKCS1 padding in message or key incorrect. Aborting...");return o==i;case 16:throw new Error("signing with Elgamal is not defined in the OpenPGP standard.");case 17:var p=new c.dsa,q=f[0].toBigInteger(),r=f[1].toBigInteger(),s=g[0].toBigInteger(),t=g[1].toBigInteger(),u=g[2].toBigInteger(),v=g[3].toBigInteger(),w=h,n=p.verify(b,q,r,w,s,t,u,v);return 0==n.compareTo(q);default:throw new Error("Invalid signature algorithm.")}},sign:function(a,b,e,f){switch(b){case 1:case 2:case 3:var g=new c.rsa,h=e[2].toBigInteger(),i=e[0].toBigInteger(),j=d.emsa.encode(a,f,e[0].byteLength());return g.sign(j,h,i).toMPI();case 17:var k=new c.dsa,l=e[0].toBigInteger(),m=e[1].toBigInteger(),n=e[2].toBigInteger(),o=(e[3].toBigInteger(),e[4].toBigInteger()),j=f,p=k.sign(a,j,n,l,m,o);return p[0].toString()+p[1].toString();case 16:throw new Error("Signing with Elgamal is not defined in the OpenPGP standard.");default:throw new Error("Invalid signature algorithm.")}}}},{"./hash":12,"./pkcs1.js":17,"./public_key":20}],25:[function(a,b){function c(a){var b=/^-----([^-]+)-----$\n/m,c=a.match(b);return c[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)?m.armor.multipart_section:c[1].match(/BEGIN PGP MESSAGE, PART \d+/)?m.armor.multipart_last:c[1].match(/BEGIN PGP SIGNED MESSAGE/)?m.armor.signed:c[1].match(/BEGIN PGP MESSAGE/)?m.armor.message:c[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)?m.armor.public_key:c[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)?m.armor.private_key:void 0}function d(){var a="";return n.show_version&&(a+="Version: "+n.versionstring+"\r\n"),n.show_comment&&(a+="Comment: "+n.commentstring+"\r\n"),a+="\r\n"}function e(a){var b=g(a),c=""+String.fromCharCode(b>>16)+String.fromCharCode(b>>8&255)+String.fromCharCode(255&b);return l.encode(c)}function f(a,b){var c=e(a),d=b;return c[0]==d[0]&&c[1]==d[1]&&c[2]==d[2]}function g(a){for(var b=11994318,c=0;a.length-c>16;)b=b<<8^o[255&(b>>16^a.charCodeAt(c))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+1))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+2))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+3))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+4))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+5))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+6))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+7))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+8))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+9))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+10))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+11))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+12))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+13))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+14))],b=b<<8^o[255&(b>>16^a.charCodeAt(c+15))],c+=16;for(var d=c;d>16^a.charCodeAt(c++))];return 16777215&b}function h(a){var b=/^[\t ]*\n/m,c="",d=a,e=b.exec(a);return null!=e&&(c=a.slice(0,e.index),d=a.slice(e.index+e[0].length)),{headers:c,body:d}}function i(a){var b=/^=/m,c=a,d="",e=b.exec(a);return null!=e&&(c=a.slice(0,e.index),d=a.slice(e.index+1)),{body:c,checksum:d}}function j(a){var b=/^-----[^-]+-----$\n/m;a=a.replace(/\r/g,"");var d=c(a);if(!d)throw new Error("Unknow ASCII armor type");var g,j,k=a.split(b),m=1;if(a.search(b)!=k[0].length&&(m=0),2!=d){var n=h(k[m]),o=i(n.body);g={data:l.decode(o.body),type:d},j=o.checksum}else{var n=h(k[m].replace(/^- /gm,"").replace(/[\t ]+\n/g,"\n")),p=h(k[m+1].replace(/^- /gm,"")),q=i(p.body);g={text:n.body.replace(/\n$/,"").replace(/\n/g,"\r\n"),data:l.decode(q.body),type:d},j=q.checksum}if(f(g.data,j))return g;throw new Error("Ascii armor integrity check on message failed: '"+j+"' should be '"+e(g)+"'")}function k(a,b,c,f){var g="";switch(a){case m.armor.multipart_section:g+="-----BEGIN PGP MESSAGE, PART "+c+"/"+f+"-----\r\n",g+=d(),g+=l.encode(b),g+="\r\n="+e(b)+"\r\n",g+="-----END PGP MESSAGE, PART "+c+"/"+f+"-----\r\n";break;case m.armor.mutlipart_last:g+="-----BEGIN PGP MESSAGE, PART "+c+"-----\r\n",g+=d(),g+=l.encode(b),g+="\r\n="+e(b)+"\r\n",g+="-----END PGP MESSAGE, PART "+c+"-----\r\n";break;case m.armor.signed:g+="\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\n",g+="Hash: "+b.hash+"\r\n\r\n",g+=b.text.replace(/\n-/g,"\n- -"),g+="\r\n-----BEGIN PGP SIGNATURE-----\r\n",g+=d(),g+=l.encode(b.data),g+="\r\n="+e(b.data)+"\r\n",g+="-----END PGP SIGNATURE-----\r\n";break;case m.armor.message:g+="-----BEGIN PGP MESSAGE-----\r\n",g+=d(),g+=l.encode(b),g+="\r\n="+e(b)+"\r\n",g+="-----END PGP MESSAGE-----\r\n";break;case m.armor.public_key:g+="-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n",g+=d(),g+=l.encode(b),g+="\r\n="+e(b)+"\r\n",g+="-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";break;case m.armor.private_key:g+="-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n",g+=d(),g+=l.encode(b),g+="\r\n="+e(b)+"\r\n",g+="-----END PGP PRIVATE KEY BLOCK-----\r\n"}return g}var l=a("./base64.js"),m=a("../enums.js"),n=a("../config"),o=[0,8801531,25875725,17603062,60024545,51751450,35206124,44007191,128024889,120049090,103502900,112007375,70412248,78916387,95990485,88014382,264588937,256049778,240098180,248108927,207005800,215016595,232553829,224014750,140824496,149062475,166599357,157832774,200747345,191980970,176028764,184266919,520933865,529177874,512099556,503334943,480196360,471432179,487973381,496217854,414011600,405478443,422020573,430033190,457094705,465107658,448029500,439496647,281648992,273666971,289622637,298124950,324696449,333198714,315665548,307683447,392699481,401494690,383961940,375687087,352057528,343782467,359738805,368533838,1041867730,1050668841,1066628831,1058355748,1032471859,1024199112,1006669886,1015471301,968368875,960392720,942864358,951368477,975946762,984451313,1000411399,992435708,836562267,828023200,810956886,818967725,844041146,852051777,868605623,860066380,914189410,922427545,938981743,930215316,904825475,896059e3,878993294,887231349,555053627,563297984,547333942,538569677,579245274,570480673,588005847,596249900,649392898,640860153,658384399,666397428,623318499,631331096,615366894,606833685,785398962,777416777,794487231,802989380,759421523,767923880,751374174,743392165,695319947,704115056,687564934,679289981,719477610,711202705,728272487,737067676,2083735460,2092239711,2109313705,2101337682,2141233477,2133257662,2116711496,2125215923,2073216669,2064943718,2048398224,2057199467,2013339772,2022141063,2039215473,2030942602,1945504045,1936737750,1920785440,1929023707,1885728716,1893966647,1911503553,1902736954,1951893524,1959904495,1977441561,1968902626,2009362165,2000822798,1984871416,1992881923,1665111629,1673124534,1656046400,1647513531,1621913772,1613380695,1629922721,1637935450,1688082292,1679317903,1695859321,1704103554,1728967061,1737211246,1720132760,1711368291,1828378820,1820103743,1836060105,1844855090,1869168165,1877963486,1860430632,1852155859,1801148925,1809650950,1792118e3,1784135691,1757986588,1750004711,1765960209,1774462698,1110107254,1118611597,1134571899,1126595968,1102643863,1094667884,1077139354,1085643617,1166763343,1158490548,1140961346,1149762745,1176011694,1184812885,1200772771,1192499800,1307552511,1298785796,1281720306,1289958153,1316768798,1325007077,1341561107,1332794856,1246636998,1254647613,1271201483,1262662192,1239272743,1230733788,1213667370,1221678289,1562785183,1570797924,1554833554,1546300521,1588974462,1580441477,1597965939,1605978760,1518843046,1510078557,1527603627,1535847760,1494504007,1502748348,1486784330,1478020017,1390639894,1382365165,1399434779,1408230112,1366334967,1375129868,1358579962,1350304769,1430452783,1438955220,1422405410,1414423513,1456544974,1448562741,1465633219,1474135352]; +b.exports={encode:k,decode:j}},{"../config":3,"../enums.js":27,"./base64.js":26}],26:[function(a,b){function c(a){var b,c,d,f="",g=0,h=0,i=a.length;for(d=0;i>d;d++)c=a.charCodeAt(d),0==h?(f+=e.charAt(c>>2&63),b=(3&c)<<4):1==h?(f+=e.charAt(b|c>>4&15),b=(15&c)<<2):2==h&&(f+=e.charAt(b|c>>6&3),g+=1,g%60==0&&(f+="\n"),f+=e.charAt(63&c)),g+=1,g%60==0&&(f+="\n"),h+=1,3==h&&(h=0);return h>0&&(f+=e.charAt(b),g+=1,g%60==0&&(f+="\n"),f+="=",g+=1),1==h&&(g%60==0&&(f+="\n"),f+="="),f}function d(a){var b,c,d="",f=0,g=0,h=a.length;for(c=0;h>c;c++)b=e.indexOf(a.charAt(c)),b>=0&&(f&&(d+=String.fromCharCode(g|b>>6-f&255)),f=f+2&7,g=b<this.primaryKey.created.getTime()+24*this.primaryKey.expirationTimeV3*3600*1e3)return m.keyStatus.expired;for(var a=!1,b=0;bc.selfCertificate.created.getTime()+1e3*c.selfCertificate.keyExpirationTime?m.keyStatus.expired:m.keyStatus.valid:m.keyStatus.invalid},d.prototype.getPrimaryUser=function(){for(var a,b=null,c=0;cb?-1:b>a?1:0}),b[0]},h.prototype.verify=function(a){if(!this.selfCertifications)return m.keyStatus.no_self_cert;for(var b,c=0;cthis.subKey.created.getTime()+24*this.subKey.expirationTimeV3*3600*1e3?m.keyStatus.expired:this.bindingSignature?this.bindingSignature.isExpired()?m.keyStatus.expired:this.bindingSignature.verified||this.bindingSignature.verify(a,{key:a,bind:this.subKey})?4==this.subKey.version&&this.bindingSignature.keyNeverExpires===!1&&Date.now()>this.subKey.created.getTime()+1e3*this.bindingSignature.keyExpirationTime?m.keyStatus.expired:m.keyStatus.valid:m.keyStatus.invalid:m.keyStatus.invalid},c.Key=d,c.readArmored=j,c.generate=k},{"./config":3,"./encoding/armor.js":25,"./enums.js":27,"./packet":35}],31:[function(a,b,c){function d(a){return this instanceof d?(this.packets=a||new h.list,void 0):new d(a)}function e(a){var b=j.decode(a).data,c=new h.list;c.read(b);var e=new d(c);return e}function f(a){var b=new h.literal;b.setText(a);var c=new h.list;c.push(b);var e=new d(c);return e}function g(a){var b=new h.literal;b.setBytes(a,i.read(i.literal,i.literal.binary));var c=new h.list;c.push(b);var e=new d(c);return e}var h=a("./packet"),i=a("./enums.js"),j=a("./encoding/armor.js"),k=a("./config"),l=a("./crypto");d.prototype.getEncryptionKeyIds=function(){var a=[],b=this.packets.filterByTag(i.packet.public_key_encrypted_session_key);return b.forEach(function(b){a.push(b.publicKeyId)}),a},d.prototype.getSigningKeyIds=function(){var a=[],b=this.unwrapCompressed(),c=b.packets.filterByTag(i.packet.one_pass_signature);if(c.forEach(function(b){a.push(b.signingKeyId)}),!a.length){var d=b.packets.filterByTag(i.packet.signature);d.forEach(function(b){a.push(b.issuerKeyId)})}return a},d.prototype.decrypt=function(a){var b=this.getEncryptionKeyIds();if(!b.length)return this;var c=a.getPrivateKeyPacket(b);if(!c.isDecrypted)throw new Error("Private key is not decrypted.");for(var e,f=this.packets.filterByTag(i.packet.public_key_encrypted_session_key),g=0;g=0;g--){var m=new h.signature;if(m.signatureType=f,m.hashAlgorithm=k.prefer_hash_algorithm,m.publicKeyAlgorithm=l.algorithm,!l.isDecrypted)throw new Error("Private key is not decrypted.");m.sign(l,c),b.push(m)}return new d(b)},d.prototype.verify=function(a){var b=[],c=this.unwrapCompressed(),d=c.packets.filterByTag(i.packet.literal);if(1!==d.length)throw new Error("Can only verify message with one literal data packet.");var e=c.packets.filterByTag(i.packet.signature);return a.forEach(function(a){for(var c=0;ce?(d=a.charCodeAt(0),b=1):255>e?(d=(a.charCodeAt(0)-192<<8)+a.charCodeAt(1)+192,b=2):255==e&&(d=c.readNumber(a.substr(1,4)),b=5),{len:d,offset:b}},writeSimpleLength:function(a){var b="";return 192>a?b+=String.fromCharCode(a):a>191&&8384>a?(b+=String.fromCharCode((a-192>>8)+192),b+=String.fromCharCode(a-192&255)):(b+=String.fromCharCode(255),b+=c.writeNumber(a,4)),b},writeHeader:function(a,b){var c="";return c+=String.fromCharCode(192|a),c+=this.writeSimpleLength(b)},writeOldHeader:function(a,b){var d="";return 256>b?(d+=String.fromCharCode(128|a<<2),d+=String.fromCharCode(b)):65536>b?(d+=String.fromCharCode(128|a<<2|1),d+=c.writeNumber(b,2)):(d+=String.fromCharCode(128|a<<2|2),d+=c.writeNumber(b,4)),d},read:function(a,b,d){if(null==a||a.length<=b||a.substring(b).length<2||0==(128&a.charCodeAt(b)))throw new Error("Error during parsing. This message / key is probably not containing a valid OpenPGP format.");var e,f=b,g=-1,h=-1;h=0,0!=(64&a.charCodeAt(f))&&(h=1);var i;h?g=63&a.charCodeAt(f):(g=(63&a.charCodeAt(f))>>2,i=3&a.charCodeAt(f)),f++;var j=null,k=-1;if(h)if(a.charCodeAt(f)<192)e=a.charCodeAt(f++),c.print_debug("1 byte length:"+e);else if(a.charCodeAt(f)>=192&&a.charCodeAt(f)<224)e=(a.charCodeAt(f++)-192<<8)+a.charCodeAt(f++)+192,c.print_debug("2 byte length:"+e);else if(a.charCodeAt(f)>223&&a.charCodeAt(f)<255){e=1<<(31&a.charCodeAt(f++)),c.print_debug("4 byte length:"+e);var l=f+e;for(j=a.substring(f,f+e);;){if(a.charCodeAt(l)<192){var m=a.charCodeAt(l++);e+=m,j+=a.substring(l,l+m),l+=m;break}if(a.charCodeAt(l)>=192&&a.charCodeAt(l)<224){var m=(a.charCodeAt(l++)-192<<8)+a.charCodeAt(l++)+192;e+=m,j+=a.substring(l,l+m),l+=m;break}if(!(a.charCodeAt(l)>223&&a.charCodeAt(l)<255)){l++;var m=a.charCodeAt(l++)<<24|a.charCodeAt(l++)<<16|a[l++].charCodeAt()<<8|a.charCodeAt(l++);j+=a.substring(l,l+m),e+=m,l+=m;break}var m=1<<(31&a.charCodeAt(l++));e+=m,j+=a.substring(l,l+m),l+=m}k=l}else f++,e=a.charCodeAt(f++)<<24|a.charCodeAt(f++)<<16|a.charCodeAt(f++)<<8|a.charCodeAt(f++);else switch(i){case 0:e=a.charCodeAt(f++);break;case 1:e=a.charCodeAt(f++)<<8|a.charCodeAt(f++);break;case 2:e=a.charCodeAt(f++)<<24|a.charCodeAt(f++)<<16|a.charCodeAt(f++)<<8|a.charCodeAt(f++);break;default:e=d}return-1==k&&(k=e),null==j&&(j=a.substring(f,f+k)),{tag:g,packet:j,offset:f+k}}}},{"../enums.js":27,"../util":56}],40:[function(a,b){var c=a("./packet.js"),d=a("./all_packets.js"),e=a("../enums.js");b.exports=function f(){this.length=0,this.read=function(a){for(var b=0;bd;d++)c.push(this[d]);return c},this.concat=function(a){if(a)for(var b=0;bj&&ih.length)throw new Error("Error reading MPI @:"+i);return i+6}throw new Error("Version "+version+" of the key packet is unsupported.")},this.readPublicKey=this.read,this.write=function(){var a=String.fromCharCode(this.version);a+=c.writeDate(this.created),3==this.version&&(a+=c.writeNumber(this.expirationTimeV3,2)),a+=String.fromCharCode(f.write(f.publicKey,this.algorithm));for(var b=g.getPublicMpiCount(this.algorithm),d=0;b>d;d++)a+=this.mpi[d].write();return a},this.writePublicKey=this.write,this.writeOld=function(){var a=this.writePublicKey();return String.fromCharCode(153)+c.writeNumber(a.length,2)+a},this.getKeyId=function(){var a=new e;return 4==this.version?a.read(this.getFingerprint().substr(12,8)):3==this.version&&a.read(this.mpi[0].write().substr(-8)),a},this.getFingerprint=function(){var a="";if(4==this.version)return a=this.writeOld(),g.hash.sha1(a);if(3==this.version){for(var b=g.getPublicMpiCount(this.algorithm),c=0;b>c;c++)a+=this.mpi[c].toBytes();return g.hash.md5(a)}}}},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56}],42:[function(a,b){var c=a("../type/keyid.js"),d=a("../util"),e=a("../type/mpi.js"),f=a("../enums.js"),g=a("../crypto");b.exports=function(){this.version=3,this.publicKeyId=new c,this.publicKeyAlgorithm="rsa_encrypt",this.sessionKey=null,this.sessionKeyAlgorithm="aes256",this.encrypted=[],this.read=function(a){this.version=a.charCodeAt(0),this.publicKeyId.read(a.substr(1)),this.publicKeyAlgorithm=f.read(f.publicKey,a.charCodeAt(9));var b=10,c=function(a){switch(a){case"rsa_encrypt":case"rsa_encrypt_sign":return 1;case"elgamal":return 2;default:throw new Error("Invalid algorithm.")}}(this.publicKeyAlgorithm);this.encrypted=[];for(var d=0;c>d;d++){var g=new e;b+=g.read(a.substr(b)),this.encrypted.push(g)}},this.write=function(){var a=String.fromCharCode(this.version);a+=this.publicKeyId.write(),a+=String.fromCharCode(f.write(f.publicKey,this.publicKeyAlgorithm));for(var b=0;bo&&me;){var f=d.readSimpleLength(a.substr(e));e+=f.offset,this.read_sub_packet(a.substr(e,f.len)),e+=f.len}return e}var e=0;switch(this.version=a.charCodeAt(e++),this.version){case 3:5!=a.charCodeAt(e++)&&c.print_debug("packet/signature.js\ninvalid One-octet length of following hashed material.MUST be 5. @:"+(e-1));var f=e;this.signatureType=a.charCodeAt(e++),this.created=c.readDate(a.substr(e,4)),e+=4,this.signatureData=a.substring(f,e),this.issuerKeyId.read(a.substring(e,e+8)),e+=8,this.publicKeyAlgorithm=a.charCodeAt(e++),this.hashAlgorithm=a.charCodeAt(e++);break;case 4:this.signatureType=a.charCodeAt(e++),this.publicKeyAlgorithm=a.charCodeAt(e++),this.hashAlgorithm=a.charCodeAt(e++),e+=b.call(this,a.substr(e),!0),this.signatureData=a.substr(0,e),e+=b.call(this,a.substr(e),!1);break;default:throw new Error("Version "+version+" of the signature is unsupported.")}this.signedHashValue=a.substr(e,2),e+=2,this.signature=a.substr(e)},this.write=function(){return this.signatureData+c.writeNumber(0,2)+this.signedHashValue+this.signature},this.sign=function(a,b){var c=e.write(e.signature,this.signatureType),d=e.write(e.publicKey,this.publicKeyAlgorithm),g=e.write(e.hash,this.hashAlgorithm),h=String.fromCharCode(4);h+=String.fromCharCode(c),h+=String.fromCharCode(d),h+=String.fromCharCode(g),this.issuerKeyId=a.getKeyId(),h+=this.write_all_sub_packets(),this.signatureData=h;var i=this.calculateTrailer(),j=this.toSign(c,b)+this.signatureData+i,k=f.hash.digest(g,j);this.signedHashValue=k.substr(0,2),this.signature=f.signature.sign(g,d,a.mpi,j)},this.write_all_sub_packets=function(){var b=e.signatureSubpacket,d="",f="";if(null!==this.created&&(d+=a(b.signature_creation_time,c.writeDate(this.created))),null!==this.signatureExpirationTime&&(d+=a(b.signature_expiration_time,c.writeNumber(this.signatureExpirationTime,4))),null!==this.exportable&&(d+=a(b.exportable_certification,String.fromCharCode(this.exportable?1:0))),null!==this.trustLevel&&(f=String.fromCharCode(this.trustLevel)+String.fromCharCode(this.trustAmount),d+=a(b.trust_signature,f)),null!==this.regularExpression&&(d+=a(b.regular_expression,this.regularExpression)),null!==this.revocable&&(d+=a(b.revocable,String.fromCharCode(this.revocable?1:0))),null!==this.keyExpirationTime&&(d+=a(b.key_expiration_time,c.writeNumber(this.keyExpirationTime,4))),null!==this.preferredSymmetricAlgorithms&&(f=c.bin2str(this.preferredSymmetricAlgorithms),d+=a(b.preferred_symmetric_algorithms,f)),null!==this.revocationKeyClass&&(f=String.fromCharCode(this.revocationKeyClass),f+=String.fromCharCode(this.revocationKeyAlgorithm),f+=this.revocationKeyFingerprint,d+=a(b.revocation_key,f)),this.issuerKeyId.isNull()||(d+=a(b.issuer,this.issuerKeyId.write())),null!==this.notation)for(var g in this.notation)if(this.notation.hasOwnProperty(g)){var h=this.notation[g];f=String.fromCharCode(128),f+=String.fromCharCode(0),f+=String.fromCharCode(0),f+=String.fromCharCode(0),f+=c.writeNumber(g.length,2),f+=c.writeNumber(h.length,2),f+=g+h,d+=a(b.notation_data,f)}return null!==this.preferredHashAlgorithms&&(f=c.bin2str(this.preferredHashAlgorithms),d+=a(b.preferred_hash_algorithms,f)),null!==this.preferredCompressionAlgorithms&&(f=c.bin2str(this.preferredCompressionAlgorithms),d+=a(b.preferred_hash_algorithms,f)),null!==this.keyServerPreferences&&(f=c.bin2str(this.keyServerPreferences),d+=a(b.key_server_preferences,f)),null!==this.preferredKeyServer&&(d+=a(b.preferred_key_server,this.preferredKeyServer)),null!==this.isPrimaryUserID&&(d+=a(b.primary_user_id,String.fromCharCode(this.isPrimaryUserID?1:0))),null!==this.policyURI&&(d+=a(b.policy_uri,this.policyURI)),null!==this.keyFlags&&(f=c.bin2str(this.keyFlags),d+=a(b.key_flags,f)),null!==this.signersUserId&&(d+=a(b.signers_user_id,this.signersUserId)),null!==this.reasonForRevocationFlag&&(f=String.fromCharCode(this.reasonForRevocationFlag),f+=this.reasonForRevocationString,d+=a(b.reason_for_revocation,f)),null!==this.features&&(f=c.bin2str(this.features),d+=a(b.features,f)),null!==this.signatureTargetPublicKeyAlgorithm&&(f=String.fromCharCode(this.signatureTargetPublicKeyAlgorithm),f+=String.fromCharCode(this.signatureTargetHashAlgorithm),f+=this.signatureTargetHash,d+=a(b.signature_target,f)),null!==this.embeddedSignature&&(d+=a(b.embedded_signature,this.embeddedSignature.write())),d=c.writeNumber(d.length,2)+d},this.read_sub_packet=function(a){function b(a,b){this[a]=[];for(var c=0;c0&&4>d?k=1:17==d&&(k=2);for(var l=[],m=0,n=0;k>n;n++)l[n]=new g,m+=l[n].read(this.signature.substr(m));return this.verified=f.signature.verify(d,h,l,a.mpi,i+this.signatureData+j),this.verified},this.isExpired=function(){return this.signatureNeverExpires?!1:Date.now()>this.created.getTime()+1e3*this.signatureExpirationTime}}},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56,"./packet.js":39}],47:[function(a,b){var c=(a("../util"),a("../crypto"));b.exports=function(){this.encrypted=null,this.modification=!1,this.packets=null,this.read=function(a){var b=a.charCodeAt(0);if(1!=b)throw new Error("Invalid packet version.");this.encrypted=a.substr(1)},this.write=function(){return String.fromCharCode(1)+this.encrypted},this.encrypt=function(a,b){var d=this.packets.write(),e=c.getPrefixRandom(a),f=e+e.charAt(e.length-2)+e.charAt(e.length-1),g=d;g+=String.fromCharCode(211),g+=String.fromCharCode(20),g+=c.hash.sha1(f+g),this.encrypted=c.cfb.encrypt(e,a,g,b,!1).substring(0,f.length+g.length)},this.decrypt=function(a,b){var d=c.cfb.decrypt(a,b,this.encrypted,!1);this.hash=c.hash.sha1(c.cfb.mdc(a,b,this.encrypted)+d.substring(0,d.length-20));var e=d.substr(d.length-20,20);if(this.hash!=e)throw new Error("Modification detected.");this.packets.read(d.substr(0,d.length-22))}}},{"../crypto":16,"../util":56}],48:[function(a,b){var c=a("../type/s2k.js"),d=a("../enums.js"),e=a("../crypto");b.exports=function(){this.tag=3,this.sessionKeyEncryptionAlgorithm=null,this.sessionKeyAlgorithm="aes256",this.encrypted=null,this.s2k=new c,this.read=function(a){this.version=a.charCodeAt(0);var b=d.read(d.symmetric,a.charCodeAt(1)),c=this.s2k.read(a.substr(2)),e=c+2;e>4)+a},this.read=function(a){var b=0;switch(this.type=c.read(c.s2k,a.charCodeAt(b++)),this.algorithm=c.read(c.hash,a.charCodeAt(b++)),this.type){case"simple":break;case"salted":this.salt=a.substr(b,8),b+=8;break;case"iterated":this.salt=a.substr(b,8),b+=8,this.c=a.charCodeAt(b++);break;case"gnu":if("GNU"!=a.substr(b,3))throw new Error("Unknown s2k type.");b+=3;var d=1e3+a.charCodeAt(b++);if(1001!=d)throw new Error("Unknown s2k gnu protection mode.");this.type=d;break;default:throw new Error("Unknown s2k type.")}return b},this.write=function(){var a=String.fromCharCode(c.write(c.s2k,this.type));switch(a+=String.fromCharCode(c.write(c.hash,this.algorithm)),this.type){case"simple":break;case"salted":a+=this.salt;break;case"iterated":a+=this.salt,a+=String.fromCharCode(this.c)}return a},this.produce_key=function(a,b){function f(b,d){var f=c.write(c.hash,d.algorithm);switch(d.type){case"simple":return e.hash.digest(f,b+a);case"salted":return e.hash.digest(f,b+d.salt+a);case"iterated":var g=[],h=d.get_count();for(data=d.salt+a;g.length*data.lengthh&&(g=g.substr(0,h)),e.hash.digest(f,b+g)}}a=d.encode_utf8(a);for(var g="",h="";g.length<=b;)g+=f(h,this),h+=String.fromCharCode(0);return g.substr(0,b)}}},{"../crypto":16,"../enums.js":27,"../util":56}],56:[function(a,b){var c=a("../config");b.exports={readNumber:function(a){for(var b=0,c=0;cd;d++)c+=String.fromCharCode(a>>8*(b-d-1)&255);return c},readDate:function(a){var b=this.readNumber(a),c=new Date;return c.setTime(1e3*b),c},writeDate:function(a){var b=Math.round(a.getTime()/1e3);return this.writeNumber(b,4)},emailRegEx:/^[+a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,6}$/,hexdump:function(a){for(var b,c=[],d=a.length,e=0,f=0;d>e;){for(b=a.charCodeAt(e++).toString(16);b.length<2;)b="0"+b;c.push(" "+b),f++,f%32==0&&c.push("\n ")}return c.join("")},hexstrdump:function(a){if(null==a)return"";for(var b,c=[],d=a.length,e=0;d>e;){for(b=a.charCodeAt(e++).toString(16);b.length<2;)b="0"+b;c.push(""+b)}return c.join("")},hex2bin:function(a){for(var b="",c=0;ce;){for(b=a[e++].toString(16);b.length<2;)b="0"+b;c.push(""+b)}return c.join("")},encode_utf8:function(a){return unescape(encodeURIComponent(a))},decode_utf8:function(a){try{return decodeURIComponent(escape(a))}catch(b){return a}},bin2str:function(a){for(var b=[],c=0;c=0;d--)c[d]>>=b%8,d>0&&(c[d]|=c[d-1]<<8-b%8&255);return util.bin2str(c)},get_hashAlgorithmString:function(a){switch(a){case 1:return"MD5";case 2:return"SHA1";case 3:return"RIPEMD160";case 8:return"SHA256";case 9:return"SHA384";case 10:return"SHA512";case 11:return"SHA224"}return"unknown"}}},{"../config":3}]},{},[]); \ No newline at end of file diff --git a/src/ciphers/asymmetric/dsa.js b/src/ciphers/asymmetric/dsa.js deleted file mode 100644 index ca477706..00000000 --- a/src/ciphers/asymmetric/dsa.js +++ /dev/null @@ -1,151 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// -// A Digital signature algorithm implementation - -function DSA() { - // s1 = ((g**s) mod p) mod q - // s1 = ((s**-1)*(sha-1(m)+(s1*x) mod q) - function sign(hashalgo, m, g, p, q, x) { - // If the output size of the chosen hash is larger than the number of - // bits of q, the hash result is truncated to fit by taking the number - // of leftmost bits equal to the number of bits of q. This (possibly - // truncated) hash function result is treated as a number and used - // directly in the DSA signature algorithm. - var hashed_data = util.getLeftNBits(openpgp_crypto_hashData(hashalgo,m),q.bitLength()); - var hash = new BigInteger(util.hexstrdump(hashed_data), 16); - var k = openpgp_crypto_getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE)); - var s1 = (g.modPow(k,p)).mod(q); - var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q); - var result = new Array(); - result[0] = s1.toMPI(); - result[1] = s2.toMPI(); - return result; - } - function select_hash_algorithm(q) { - var usersetting = openpgp.config.config.prefer_hash_algorithm; - /* - * 1024-bit key, 160-bit q, SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512 hash - * 2048-bit key, 224-bit q, SHA-224, SHA-256, SHA-384, or SHA-512 hash - * 2048-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash - * 3072-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash - */ - switch (Math.round(q.bitLength() / 8)) { - case 20: // 1024 bit - if (usersetting != 2 && - usersetting > 11 && - usersetting != 10 && - usersetting < 8) - return 2; // prefer sha1 - return usersetting; - case 28: // 2048 bit - if (usersetting > 11 && - usersetting < 8) - return 11; - return usersetting; - case 32: // 4096 bit // prefer sha224 - if (usersetting > 10 && - usersetting < 8) - return 8; // prefer sha256 - return usersetting; - default: - util.print_debug("DSA select hash algorithm: returning null for an unknown length of q"); - return null; - - } - } - this.select_hash_algorithm = select_hash_algorithm; - - function verify(hashalgo, s1,s2,m,p,q,g,y) { - var hashed_data = util.getLeftNBits(openpgp_crypto_hashData(hashalgo,m),q.bitLength()); - var hash = new BigInteger(util.hexstrdump(hashed_data), 16); - if (BigInteger.ZERO.compareTo(s1) > 0 || - s1.compareTo(q) > 0 || - BigInteger.ZERO.compareTo(s2) > 0 || - s2.compareTo(q) > 0) { - util.print_error("invalid DSA Signature"); - return null; - } - var w = s2.modInverse(q); - var u1 = hash.multiply(w).mod(q); - var u2 = s1.multiply(w).mod(q); - return g.modPow(u1,p).multiply(y.modPow(u2,p)).mod(p).mod(q); - } - - /* - * unused code. This can be used as a start to write a key generator - * function. - - function generateKey(bitcount) { - var qi = new BigInteger(bitcount, primeCenterie); - var pi = generateP(q, 512); - var gi = generateG(p, q, bitcount); - var xi; - do { - xi = new BigInteger(q.bitCount(), rand); - } while (x.compareTo(BigInteger.ZERO) != 1 && x.compareTo(q) != -1); - var yi = g.modPow(x, p); - return {x: xi, q: qi, p: pi, g: gi, y: yi}; - } - - function generateP(q, bitlength, randomfn) { - if (bitlength % 64 != 0) { - return false; - } - var pTemp; - var pTemp2; - do { - pTemp = randomfn(bitcount, true); - pTemp2 = pTemp.subtract(BigInteger.ONE); - pTemp = pTemp.subtract(pTemp2.remainder(q)); - } while (!pTemp.isProbablePrime(primeCenterie) || pTemp.bitLength() != l); - return pTemp; - } - - function generateG(p, q, bitlength, randomfn) { - var aux = p.subtract(BigInteger.ONE); - var pow = aux.divide(q); - var gTemp; - do { - gTemp = randomfn(bitlength); - } while (gTemp.compareTo(aux) != -1 && gTemp.compareTo(BigInteger.ONE) != 1); - return gTemp.modPow(pow, p); - } - - function generateK(q, bitlength, randomfn) { - var tempK; - do { - tempK = randomfn(bitlength, false); - } while (tempK.compareTo(q) != -1 && tempK.compareTo(BigInteger.ZERO) != 1); - return tempK; - } - - function generateR(q,p) { - k = generateK(q); - var r = g.modPow(k, p).mod(q); - return r; - } - - function generateS(hashfn,k,r,m,q,x) { - var hash = hashfn(m); - s = (k.modInverse(q).multiply(hash.add(x.multiply(r)))).mod(q); - return s; - } */ - this.sign = sign; - this.verify = verify; - // this.generate = generateKey; -} diff --git a/src/ciphers/asymmetric/elgamal.js b/src/ciphers/asymmetric/elgamal.js deleted file mode 100644 index 820f0851..00000000 --- a/src/ciphers/asymmetric/elgamal.js +++ /dev/null @@ -1,48 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// -// ElGamal implementation - -function Elgamal() { - - function encrypt(m,g,p,y) { - // choose k in {2,...,p-2} - var two = BigInteger.ONE.add(BigInteger.ONE); - var pMinus2 = p.subtract(two); - var k = openpgp_crypto_getRandomBigIntegerInRange(two, pMinus2); - var k = k.mod(pMinus2).add(BigInteger.ONE); - var c = new Array(); - c[0] = g.modPow(k, p); - c[1] = y.modPow(k, p).multiply(m).mod(p).toMPI(); - c[0] = c[0].toMPI(); - return c; - } - - function decrypt(c1,c2,p,x) { - util.print_debug("Elgamal Decrypt:\nc1:"+util.hexstrdump(c1.toMPI())+"\n"+ - "c2:"+util.hexstrdump(c2.toMPI())+"\n"+ - "p:"+util.hexstrdump(p.toMPI())+"\n"+ - "x:"+util.hexstrdump(x.toMPI())); - return (c1.modPow(x, p).modInverse(p)).multiply(c2).mod(p); - //var c = c1.pow(x).modInverse(p); // c0^-a mod p - //return c.multiply(c2).mod(p); - } - - // signing and signature verification using Elgamal is not required by OpenPGP. - this.encrypt = encrypt; - this.decrypt = decrypt; -} \ No newline at end of file diff --git a/src/ciphers/asymmetric/jsbn.js b/src/ciphers/asymmetric/jsbn.js deleted file mode 100644 index 7b402783..00000000 --- a/src/ciphers/asymmetric/jsbn.js +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU) - * All Rights Reserved. - * - * Modified by Recurity Labs GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - -// Basic JavaScript BN library - subset useful for RSA encryption. - -// Bits per digit -var dbits; - -// JavaScript engine analysis -var canary = 0xdeadbeefcafe; -var j_lm = ((canary&0xffffff)==0xefcafe); - -// (public) Constructor -function BigInteger(a,b,c) { - if(a != null) - if("number" == typeof a) this.fromNumber(a,b,c); - else if(b == null && "string" != typeof a) this.fromString(a,256); - else this.fromString(a,b); -} - -// return new, unset BigInteger -function nbi() { return new BigInteger(null); } - -// am: Compute w_j += (x*this_i), propagate carries, -// c is initial carry, returns final carry. -// c < 3*dvalue, x < 2*dvalue, this_i < dvalue -// We need to select the fastest one that works in this environment. - -// am1: use a single mult and divide to get the high bits, -// max digit bits should be 26 because -// max internal value = 2*dvalue^2-2*dvalue (< 2^53) -function am1(i,x,w,j,c,n) { - while(--n >= 0) { - var v = x*this[i++]+w[j]+c; - c = Math.floor(v/0x4000000); - w[j++] = v&0x3ffffff; - } - return c; -} -// am2 avoids a big mult-and-extract completely. -// Max digit bits should be <= 30 because we do bitwise ops -// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) -function am2(i,x,w,j,c,n) { - var xl = x&0x7fff, xh = x>>15; - while(--n >= 0) { - var l = this[i]&0x7fff; - var h = this[i++]>>15; - var m = xh*l+h*xl; - l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); - c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); - w[j++] = l&0x3fffffff; - } - return c; -} -// Alternately, set max digit bits to 28 since some -// browsers slow down when dealing with 32-bit numbers. -function am3(i,x,w,j,c,n) { - var xl = x&0x3fff, xh = x>>14; - while(--n >= 0) { - var l = this[i]&0x3fff; - var h = this[i++]>>14; - var m = xh*l+h*xl; - l = xl*l+((m&0x3fff)<<14)+w[j]+c; - c = (l>>28)+(m>>14)+xh*h; - w[j++] = l&0xfffffff; - } - return c; -} -if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { - BigInteger.prototype.am = am2; - dbits = 30; -} -else if(j_lm && (navigator.appName != "Netscape")) { - BigInteger.prototype.am = am1; - dbits = 26; -} -else { // Mozilla/Netscape seems to prefer am3 - BigInteger.prototype.am = am3; - dbits = 28; -} - -BigInteger.prototype.DB = dbits; -BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i]; - r.t = this.t; - r.s = this.s; -} - -// (protected) set from integer value x, -DV <= x < DV -function bnpFromInt(x) { - this.t = 1; - this.s = (x<0)?-1:0; - if(x > 0) this[0] = x; - else if(x < -1) this[0] = x+DV; - else this.t = 0; -} - -// return bigint initialized to value -function nbv(i) { var r = nbi(); r.fromInt(i); return r; } - -// (protected) set from string and radix -function bnpFromString(s,b) { - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 256) k = 8; // byte array - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else { this.fromRadix(s,b); return; } - this.t = 0; - this.s = 0; - var i = s.length, mi = false, sh = 0; - while(--i >= 0) { - var x = (k==8)?s[i]&0xff:intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-") mi = true; - continue; - } - mi = false; - if(sh == 0) - this[this.t++] = x; - else if(sh+k > this.DB) { - this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); - } - else - this[this.t-1] |= x<= this.DB) sh -= this.DB; - } - if(k == 8 && (s[0]&0x80) != 0) { - this.s = -1; - if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t; -} - -// (public) return string representation in given radix -function bnToString(b) { - if(this.s < 0) return "-"+this.negate().toString(b); - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else return this.toRadix(b); - var km = (1< 0) { - if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } - while(i >= 0) { - if(p < k) { - d = (this[i]&((1<>(p+=this.DB-k); - } - else { - d = (this[i]>>(p-=k))&km; - if(p <= 0) { p += this.DB; --i; } - } - if(d > 0) m = true; - if(m) r += int2char(d); - } - } - return m?r:"0"; -} - -// (public) -this -function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } - -// (public) |this| -function bnAbs() { return (this.s<0)?this.negate():this; } - -// (public) return + if this > a, - if this < a, 0 if equal -function bnCompareTo(a) { - var r = this.s-a.s; - if(r != 0) return r; - var i = this.t; - r = i-a.t; - if(r != 0) return r; - while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; - return 0; -} - -// returns bit length of the integer x -function nbits(x) { - var r = 1, t; - if((t=x>>>16) != 0) { x = t; r += 16; } - if((t=x>>8) != 0) { x = t; r += 8; } - if((t=x>>4) != 0) { x = t; r += 4; } - if((t=x>>2) != 0) { x = t; r += 2; } - if((t=x>>1) != 0) { x = t; r += 1; } - return r; -} - -// (public) return the number of bits in "this" -function bnBitLength() { - if(this.t <= 0) return 0; - return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); -} - -// (protected) r = this << n*DB -function bnpDLShiftTo(n,r) { - var i; - for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; - for(i = n-1; i >= 0; --i) r[i] = 0; - r.t = this.t+n; - r.s = this.s; -} - -// (protected) r = this >> n*DB -function bnpDRShiftTo(n,r) { - for(var i = n; i < this.t; ++i) r[i-n] = this[i]; - r.t = Math.max(this.t-n,0); - r.s = this.s; -} - -// (protected) r = this << n -function bnpLShiftTo(n,r) { - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<= 0; --i) { - r[i+ds+1] = (this[i]>>cbs)|c; - c = (this[i]&bm)<= 0; --i) r[i] = 0; - r[ds] = c; - r.t = this.t+ds+1; - r.s = this.s; - r.clamp(); -} - -// (protected) r = this >> n -function bnpRShiftTo(n,r) { - r.s = this.s; - var ds = Math.floor(n/this.DB); - if(ds >= this.t) { r.t = 0; return; } - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<>bs; - for(var i = ds+1; i < this.t; ++i) { - r[i-ds-1] |= (this[i]&bm)<>bs; - } - if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB; - } - if(a.t < this.t) { - c -= a.s; - while(i < this.t) { - c += this[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c += this.s; - } - else { - c += this.s; - while(i < a.t) { - c -= a[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c -= a.s; - } - r.s = (c<0)?-1:0; - if(c < -1) r[i++] = this.DV+c; - else if(c > 0) r[i++] = c; - r.t = i; - r.clamp(); -} - -// (protected) r = this * a, r != this,a (HAC 14.12) -// "this" should be the larger one if appropriate. -function bnpMultiplyTo(a,r) { - var x = this.abs(), y = a.abs(); - var i = x.t; - r.t = i+y.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); - r.s = 0; - r.clamp(); - if(this.s != a.s) BigInteger.ZERO.subTo(r,r); -} - -// (protected) r = this^2, r != this (HAC 14.16) -function bnpSquareTo(r) { - var x = this.abs(); - var i = r.t = 2*x.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < x.t-1; ++i) { - var c = x.am(i,x[i],r,2*i,0,1); - if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { - r[i+x.t] -= x.DV; - r[i+x.t+1] = 1; - } - } - if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); - r.s = 0; - r.clamp(); -} - -// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) -// r != q, this != m. q or r may be null. -function bnpDivRemTo(m,q,r) { - var pm = m.abs(); - if(pm.t <= 0) return; - var pt = this.abs(); - if(pt.t < pm.t) { - if(q != null) q.fromInt(0); - if(r != null) this.copyTo(r); - return; - } - if(r == null) r = nbi(); - var y = nbi(), ts = this.s, ms = m.s; - var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus - if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } - else { pm.copyTo(y); pt.copyTo(r); } - var ys = y.t; - var y0 = y[ys-1]; - if(y0 == 0) return; - var yt = y0*(1<1)?y[ys-2]>>this.F2:0); - var d1 = this.FV/yt, d2 = (1<= 0) { - r[r.t++] = 1; - r.subTo(t,r); - } - BigInteger.ONE.dlShiftTo(ys,t); - t.subTo(y,y); // "negative" y so we can replace sub with am later - while(y.t < ys) y[y.t++] = 0; - while(--j >= 0) { - // Estimate quotient digit - var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); - if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out - y.dlShiftTo(j,t); - r.subTo(t,r); - while(r[i] < --qd) r.subTo(t,r); - } - } - if(q != null) { - r.drShiftTo(ys,q); - if(ts != ms) BigInteger.ZERO.subTo(q,q); - } - r.t = ys; - r.clamp(); - if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder - if(ts < 0) BigInteger.ZERO.subTo(r,r); -} - -// (public) this mod a -function bnMod(a) { - var r = nbi(); - this.abs().divRemTo(a,null,r); - if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); - return r; -} - -// Modular reduction using "classic" algorithm -function Classic(m) { this.m = m; } -function cConvert(x) { - if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); - else return x; -} -function cRevert(x) { return x; } -function cReduce(x) { x.divRemTo(this.m,null,x); } -function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } -function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -Classic.prototype.convert = cConvert; -Classic.prototype.revert = cRevert; -Classic.prototype.reduce = cReduce; -Classic.prototype.mulTo = cMulTo; -Classic.prototype.sqrTo = cSqrTo; - -// (protected) return "-1/this % 2^DB"; useful for Mont. reduction -// justification: -// xy == 1 (mod m) -// xy = 1+km -// xy(2-xy) = (1+km)(1-km) -// x[y(2-xy)] = 1-k^2m^2 -// x[y(2-xy)] == 1 (mod m^2) -// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 -// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. -// JS multiply "overflows" differently from C/C++, so care is needed here. -function bnpInvDigit() { - if(this.t < 1) return 0; - var x = this[0]; - if((x&1) == 0) return 0; - var y = x&3; // y == 1/x mod 2^2 - y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 - y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 - y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 - // last step - calculate inverse mod DV directly; - // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints - y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits - // we really want the negative inverse, and -DV < y < DV - return (y>0)?this.DV-y:-y; -} - -// Montgomery reduction -function Montgomery(m) { - this.m = m; - this.mp = m.invDigit(); - this.mpl = this.mp&0x7fff; - this.mph = this.mp>>15; - this.um = (1<<(m.DB-15))-1; - this.mt2 = 2*m.t; -} - -// xR mod m -function montConvert(x) { - var r = nbi(); - x.abs().dlShiftTo(this.m.t,r); - r.divRemTo(this.m,null,r); - if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); - return r; -} - -// x/R mod m -function montRevert(x) { - var r = nbi(); - x.copyTo(r); - this.reduce(r); - return r; -} - -// x = x/R mod m (HAC 14.32) -function montReduce(x) { - while(x.t <= this.mt2) // pad x so am has enough room later - x[x.t++] = 0; - for(var i = 0; i < this.m.t; ++i) { - // faster way of calculating u0 = x[i]*mp mod DV - var j = x[i]&0x7fff; - var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; - // use am to combine the multiply-shift-add into one call - j = i+this.m.t; - x[j] += this.m.am(0,u0,x,i,0,this.m.t); - // propagate carry - while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } - } - x.clamp(); - x.drShiftTo(this.m.t,x); - if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); -} - -// r = "x^2/R mod m"; x != r -function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -// r = "xy/R mod m"; x,y != r -function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - -Montgomery.prototype.convert = montConvert; -Montgomery.prototype.revert = montRevert; -Montgomery.prototype.reduce = montReduce; -Montgomery.prototype.mulTo = montMulTo; -Montgomery.prototype.sqrTo = montSqrTo; - -// (protected) true iff this is even -function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } - -// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) -function bnpExp(e,z) { - if(e > 0xffffffff || e < 1) return BigInteger.ONE; - var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; - g.copyTo(r); - while(--i >= 0) { - z.sqrTo(r,r2); - if((e&(1< 0) z.mulTo(r2,g,r); - else { var t = r; r = r2; r2 = t; } - } - return z.revert(r); -} - -// (public) this^e % m, 0 <= e < 2^32 -function bnModPowInt(e,m) { - var z; - if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); - return this.exp(e,z); -} - -// protected -BigInteger.prototype.copyTo = bnpCopyTo; -BigInteger.prototype.fromInt = bnpFromInt; -BigInteger.prototype.fromString = bnpFromString; -BigInteger.prototype.clamp = bnpClamp; -BigInteger.prototype.dlShiftTo = bnpDLShiftTo; -BigInteger.prototype.drShiftTo = bnpDRShiftTo; -BigInteger.prototype.lShiftTo = bnpLShiftTo; -BigInteger.prototype.rShiftTo = bnpRShiftTo; -BigInteger.prototype.subTo = bnpSubTo; -BigInteger.prototype.multiplyTo = bnpMultiplyTo; -BigInteger.prototype.squareTo = bnpSquareTo; -BigInteger.prototype.divRemTo = bnpDivRemTo; -BigInteger.prototype.invDigit = bnpInvDigit; -BigInteger.prototype.isEven = bnpIsEven; -BigInteger.prototype.exp = bnpExp; - -// public -BigInteger.prototype.toString = bnToString; -BigInteger.prototype.negate = bnNegate; -BigInteger.prototype.abs = bnAbs; -BigInteger.prototype.compareTo = bnCompareTo; -BigInteger.prototype.bitLength = bnBitLength; -BigInteger.prototype.mod = bnMod; -BigInteger.prototype.modPowInt = bnModPowInt; - -// "constants" -BigInteger.ZERO = nbv(0); -BigInteger.ONE = nbv(1); - diff --git a/src/ciphers/asymmetric/rsa.js b/src/ciphers/asymmetric/rsa.js deleted file mode 100644 index d843121c..00000000 --- a/src/ciphers/asymmetric/rsa.js +++ /dev/null @@ -1,135 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// -// RSA implementation - -function SecureRandom(){ - function nextBytes(byteArray){ - for(var n = 0; n < byteArray.length;n++){ - byteArray[n] = openpgp_crypto_getSecureRandomOctet(); - } - } - this.nextBytes = nextBytes; -} - -function RSA() { - /** - * This function uses jsbn Big Num library to decrypt RSA - * @param m - * message - * @param d - * RSA d as BigInteger - * @param p - * RSA p as BigInteger - * @param q - * RSA q as BigInteger - * @param u - * RSA u as BigInteger - * @return {BigInteger} The decrypted value of the message - */ - function decrypt(m, d, p, q, u) { - var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); - var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); - util.print_debug("rsa.js decrypt\nxpn:"+util.hexstrdump(xp.toMPI())+"\nxqn:"+util.hexstrdump(xq.toMPI())); - - var t = xq.subtract(xp); - if (t[0] == 0) { - t = xp.subtract(xq); - t = t.multiply(u).mod(q); - t = q.subtract(t); - } else { - t = t.multiply(u).mod(q); - } - return t.multiply(p).add(xp); - } - - /** - * encrypt message - * @param m message as BigInteger - * @param e public MPI part as BigInteger - * @param n public MPI part as BigInteger - * @return BigInteger - */ - function encrypt(m,e,n) { - return m.modPowInt(e, n); - } - - /* Sign and Verify */ - function sign(m,d,n) { - return m.modPow(d, n); - } - - function verify(x,e,n) { - return x.modPowInt(e, n); - } - - // "empty" RSA key constructor - function keyObject() { - this.n = null; - this.e = 0; - this.ee = null; - this.d = null; - this.p = null; - this.q = null; - this.dmp1 = null; - this.dmq1 = null; - this.u = null; - } - - // Generate a new random private key B bits long, using public expt E - function generate(B,E) { - var key = new keyObject(); - var rng = new SecureRandom(); - var qs = B>>1; - key.e = parseInt(E,16); - key.ee = new BigInteger(E,16); - for(;;) { - for(;;) { - key.p = new BigInteger(B-qs,1,rng); - if(key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) break; - } - for(;;) { - key.q = new BigInteger(qs,1,rng); - if(key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) break; - } - if(key.p.compareTo(key.q) <= 0) { - var t = key.p; - key.p = key.q; - key.q = t; - } - var p1 = key.p.subtract(BigInteger.ONE); - var q1 = key.q.subtract(BigInteger.ONE); - var phi = p1.multiply(q1); - if(phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) { - key.n = key.p.multiply(key.q); - key.d = key.ee.modInverse(phi); - key.dmp1 = key.d.mod(p1); - key.dmq1 = key.d.mod(q1); - key.u = key.p.modInverse(key.q); - break; - } - } - return key; - } - - this.encrypt = encrypt; - this.decrypt = decrypt; - this.verify = verify; - this.sign = sign; - this.generate = generate; - this.keyObject = keyObject; -} diff --git a/src/ciphers/hash/md5.js b/src/ciphers/hash/md5.js deleted file mode 100644 index 3c0adfbb..00000000 --- a/src/ciphers/hash/md5.js +++ /dev/null @@ -1,204 +0,0 @@ -/** - * A fast MD5 JavaScript implementation - * Copyright (c) 2012 Joseph Myers - * http://www.myersdaily.org/joseph/javascript/md5-text.html - * - * Permission to use, copy, modify, and distribute this software - * and its documentation for any purposes and without - * fee is hereby granted provided that this copyright notice - * appears in all copies. - * - * Of course, this soft is provided "as is" without express or implied - * warranty of any kind. - */ - -function MD5(entree) { - var hex = md5(entree); - var bin = util.hex2bin(hex); - return bin; -} - -function md5cycle(x, k) { -var a = x[0], b = x[1], c = x[2], d = x[3]; - -a = ff(a, b, c, d, k[0], 7, -680876936); -d = ff(d, a, b, c, k[1], 12, -389564586); -c = ff(c, d, a, b, k[2], 17, 606105819); -b = ff(b, c, d, a, k[3], 22, -1044525330); -a = ff(a, b, c, d, k[4], 7, -176418897); -d = ff(d, a, b, c, k[5], 12, 1200080426); -c = ff(c, d, a, b, k[6], 17, -1473231341); -b = ff(b, c, d, a, k[7], 22, -45705983); -a = ff(a, b, c, d, k[8], 7, 1770035416); -d = ff(d, a, b, c, k[9], 12, -1958414417); -c = ff(c, d, a, b, k[10], 17, -42063); -b = ff(b, c, d, a, k[11], 22, -1990404162); -a = ff(a, b, c, d, k[12], 7, 1804603682); -d = ff(d, a, b, c, k[13], 12, -40341101); -c = ff(c, d, a, b, k[14], 17, -1502002290); -b = ff(b, c, d, a, k[15], 22, 1236535329); - -a = gg(a, b, c, d, k[1], 5, -165796510); -d = gg(d, a, b, c, k[6], 9, -1069501632); -c = gg(c, d, a, b, k[11], 14, 643717713); -b = gg(b, c, d, a, k[0], 20, -373897302); -a = gg(a, b, c, d, k[5], 5, -701558691); -d = gg(d, a, b, c, k[10], 9, 38016083); -c = gg(c, d, a, b, k[15], 14, -660478335); -b = gg(b, c, d, a, k[4], 20, -405537848); -a = gg(a, b, c, d, k[9], 5, 568446438); -d = gg(d, a, b, c, k[14], 9, -1019803690); -c = gg(c, d, a, b, k[3], 14, -187363961); -b = gg(b, c, d, a, k[8], 20, 1163531501); -a = gg(a, b, c, d, k[13], 5, -1444681467); -d = gg(d, a, b, c, k[2], 9, -51403784); -c = gg(c, d, a, b, k[7], 14, 1735328473); -b = gg(b, c, d, a, k[12], 20, -1926607734); - -a = hh(a, b, c, d, k[5], 4, -378558); -d = hh(d, a, b, c, k[8], 11, -2022574463); -c = hh(c, d, a, b, k[11], 16, 1839030562); -b = hh(b, c, d, a, k[14], 23, -35309556); -a = hh(a, b, c, d, k[1], 4, -1530992060); -d = hh(d, a, b, c, k[4], 11, 1272893353); -c = hh(c, d, a, b, k[7], 16, -155497632); -b = hh(b, c, d, a, k[10], 23, -1094730640); -a = hh(a, b, c, d, k[13], 4, 681279174); -d = hh(d, a, b, c, k[0], 11, -358537222); -c = hh(c, d, a, b, k[3], 16, -722521979); -b = hh(b, c, d, a, k[6], 23, 76029189); -a = hh(a, b, c, d, k[9], 4, -640364487); -d = hh(d, a, b, c, k[12], 11, -421815835); -c = hh(c, d, a, b, k[15], 16, 530742520); -b = hh(b, c, d, a, k[2], 23, -995338651); - -a = ii(a, b, c, d, k[0], 6, -198630844); -d = ii(d, a, b, c, k[7], 10, 1126891415); -c = ii(c, d, a, b, k[14], 15, -1416354905); -b = ii(b, c, d, a, k[5], 21, -57434055); -a = ii(a, b, c, d, k[12], 6, 1700485571); -d = ii(d, a, b, c, k[3], 10, -1894986606); -c = ii(c, d, a, b, k[10], 15, -1051523); -b = ii(b, c, d, a, k[1], 21, -2054922799); -a = ii(a, b, c, d, k[8], 6, 1873313359); -d = ii(d, a, b, c, k[15], 10, -30611744); -c = ii(c, d, a, b, k[6], 15, -1560198380); -b = ii(b, c, d, a, k[13], 21, 1309151649); -a = ii(a, b, c, d, k[4], 6, -145523070); -d = ii(d, a, b, c, k[11], 10, -1120210379); -c = ii(c, d, a, b, k[2], 15, 718787259); -b = ii(b, c, d, a, k[9], 21, -343485551); - -x[0] = add32(a, x[0]); -x[1] = add32(b, x[1]); -x[2] = add32(c, x[2]); -x[3] = add32(d, x[3]); - -} - -function cmn(q, a, b, x, s, t) { -a = add32(add32(a, q), add32(x, t)); -return add32((a << s) | (a >>> (32 - s)), b); -} - -function ff(a, b, c, d, x, s, t) { -return cmn((b & c) | ((~b) & d), a, b, x, s, t); -} - -function gg(a, b, c, d, x, s, t) { -return cmn((b & d) | (c & (~d)), a, b, x, s, t); -} - -function hh(a, b, c, d, x, s, t) { -return cmn(b ^ c ^ d, a, b, x, s, t); -} - -function ii(a, b, c, d, x, s, t) { -return cmn(c ^ (b | (~d)), a, b, x, s, t); -} - -function md51(s) { -txt = ''; -var n = s.length, -state = [1732584193, -271733879, -1732584194, 271733878], i; -for (i=64; i<=s.length; i+=64) { -md5cycle(state, md5blk(s.substring(i-64, i))); -} -s = s.substring(i-64); -var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; -for (i=0; i>2] |= s.charCodeAt(i) << ((i%4) << 3); -tail[i>>2] |= 0x80 << ((i%4) << 3); -if (i > 55) { -md5cycle(state, tail); -for (i=0; i<16; i++) tail[i] = 0; -} -tail[14] = n*8; -md5cycle(state, tail); -return state; -} - -/* there needs to be support for Unicode here, - * unless we pretend that we can redefine the MD-5 - * algorithm for multi-byte characters (perhaps - * by adding every four 16-bit characters and - * shortening the sum to 32 bits). Otherwise - * I suggest performing MD-5 as if every character - * was two bytes--e.g., 0040 0025 = @%--but then - * how will an ordinary MD-5 sum be matched? - * There is no way to standardize text to something - * like UTF-8 before transformation; speed cost is - * utterly prohibitive. The JavaScript standard - * itself needs to look at this: it should start - * providing access to strings as preformed UTF-8 - * 8-bit unsigned value arrays. - */ -function md5blk(s) { /* I figured global was faster. */ -var md5blks = [], i; /* Andy King said do it this way. */ -for (i=0; i<64; i+=4) { -md5blks[i>>2] = s.charCodeAt(i) -+ (s.charCodeAt(i+1) << 8) -+ (s.charCodeAt(i+2) << 16) -+ (s.charCodeAt(i+3) << 24); -} -return md5blks; -} - -var hex_chr = '0123456789abcdef'.split(''); - -function rhex(n) -{ -var s='', j=0; -for(; j<4; j++) -s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] -+ hex_chr[(n >> (j * 8)) & 0x0F]; -return s; -} - -function hex(x) { -for (var i=0; i> 16) + (y >> 16) + (lsw >> 16); -return (msw << 16) | (lsw & 0xFFFF); -} -} diff --git a/src/ciphers/hash/ripe-md.js b/src/ciphers/hash/ripe-md.js deleted file mode 100644 index aedd71bc..00000000 --- a/src/ciphers/hash/ripe-md.js +++ /dev/null @@ -1,293 +0,0 @@ -/* - * CryptoMX Tools - * Copyright (C) 2004 - 2006 Derek Buitenhuis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Modified by Recurity Labs GmbH - */ - -var RMDsize = 160; -var X = new Array(); - -function ROL(x, n) -{ - return new Number ((x << n) | ( x >>> (32 - n))); -} - -function F(x, y, z) -{ - return new Number(x ^ y ^ z); -} - -function G(x, y, z) -{ - return new Number((x & y) | (~x & z)); -} - -function H(x, y, z) -{ - return new Number((x | ~y) ^ z); -} - -function I(x, y, z) -{ - return new Number((x & z) | (y & ~z)); -} - -function J(x, y, z) -{ - return new Number(x ^ (y | ~z)); -} - -function mixOneRound(a, b, c, d, e, x, s, roundNumber) -{ - switch (roundNumber) - { - case 0 : a += F(b, c, d) + x + 0x00000000; break; - case 1 : a += G(b, c, d) + x + 0x5a827999; break; - case 2 : a += H(b, c, d) + x + 0x6ed9eba1; break; - case 3 : a += I(b, c, d) + x + 0x8f1bbcdc; break; - case 4 : a += J(b, c, d) + x + 0xa953fd4e; break; - case 5 : a += J(b, c, d) + x + 0x50a28be6; break; - case 6 : a += I(b, c, d) + x + 0x5c4dd124; break; - case 7 : a += H(b, c, d) + x + 0x6d703ef3; break; - case 8 : a += G(b, c, d) + x + 0x7a6d76e9; break; - case 9 : a += F(b, c, d) + x + 0x00000000; break; - - default : document.write("Bogus round number"); break; - } - - a = ROL(a, s) + e; - c = ROL(c, 10); - - a &= 0xffffffff; - b &= 0xffffffff; - c &= 0xffffffff; - d &= 0xffffffff; - e &= 0xffffffff; - - var retBlock = new Array(); - retBlock[0] = a; - retBlock[1] = b; - retBlock[2] = c; - retBlock[3] = d; - retBlock[4] = e; - retBlock[5] = x; - retBlock[6] = s; - - return retBlock; -} - -function MDinit (MDbuf) -{ - MDbuf[0] = 0x67452301; - MDbuf[1] = 0xefcdab89; - MDbuf[2] = 0x98badcfe; - MDbuf[3] = 0x10325476; - MDbuf[4] = 0xc3d2e1f0; -} - -var ROLs = [ - [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8], - [ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12], - [11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5], - [11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12], - [ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6], - [ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6], - [ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11], - [ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5], - [15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8], - [ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11] -]; - -var indexes = [ - [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - [ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8], - [ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12], - [ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2], - [ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], - [ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12], - [ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2], - [15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13], - [ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14], - [12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11] -]; - -function compress (MDbuf, X) -{ - blockA = new Array(); - blockB = new Array(); - - var retBlock; - - for (var i=0; i < 5; i++) - { - blockA[i] = new Number(MDbuf[i]); - blockB[i] = new Number(MDbuf[i]); - } - - var step = 0; - for (var j = 0; j < 5; j++) - { - for (var i = 0; i < 16; i++) - { - retBlock = mixOneRound( - blockA[(step+0) % 5], - blockA[(step+1) % 5], - blockA[(step+2) % 5], - blockA[(step+3) % 5], - blockA[(step+4) % 5], - X[indexes[j][i]], - ROLs[j][i], - j - ); - - blockA[(step+0) % 5] = retBlock[0]; - blockA[(step+1) % 5] = retBlock[1]; - blockA[(step+2) % 5] = retBlock[2]; - blockA[(step+3) % 5] = retBlock[3]; - blockA[(step+4) % 5] = retBlock[4]; - - step += 4; - } - } - - step = 0; - for (var j = 5; j < 10; j++) - { - for (var i = 0; i < 16; i++) - { - retBlock = mixOneRound( - blockB[(step+0) % 5], - blockB[(step+1) % 5], - blockB[(step+2) % 5], - blockB[(step+3) % 5], - blockB[(step+4) % 5], - X[indexes[j][i]], - ROLs[j][i], - j - ); - - blockB[(step+0) % 5] = retBlock[0]; - blockB[(step+1) % 5] = retBlock[1]; - blockB[(step+2) % 5] = retBlock[2]; - blockB[(step+3) % 5] = retBlock[3]; - blockB[(step+4) % 5] = retBlock[4]; - - step += 4; - } - } - - blockB[3] += blockA[2] + MDbuf[1]; - MDbuf[1] = MDbuf[2] + blockA[3] + blockB[4]; - MDbuf[2] = MDbuf[3] + blockA[4] + blockB[0]; - MDbuf[3] = MDbuf[4] + blockA[0] + blockB[1]; - MDbuf[4] = MDbuf[0] + blockA[1] + blockB[2]; - MDbuf[0] = blockB[3]; -} - -function zeroX(X) -{ - for (var i = 0; i < 16; i++) { X[i] = 0; } -} - -function MDfinish (MDbuf, strptr, lswlen, mswlen) -{ - var X = new Array(16); - zeroX(X); - - var j = 0; - for (var i=0; i < (lswlen & 63); i++) - { - X[i >>> 2] ^= (strptr.charCodeAt(j++) & 255) << (8 * (i & 3)); - } - - X[(lswlen >>> 2) & 15] ^= 1 << (8 * (lswlen & 3) + 7); - - if ((lswlen & 63) > 55) - { - compress(MDbuf, X); - var X = new Array(16); - zeroX(X); - } - - X[14] = lswlen << 3; - X[15] = (lswlen >>> 29) | (mswlen << 3); - - compress(MDbuf, X); -} - -function BYTES_TO_DWORD(fourChars) -{ - var tmp = (fourChars.charCodeAt(3) & 255) << 24; - tmp |= (fourChars.charCodeAt(2) & 255) << 16; - tmp |= (fourChars.charCodeAt(1) & 255) << 8; - tmp |= (fourChars.charCodeAt(0) & 255); - - return tmp; -} - -function RMD(message) -{ - var MDbuf = new Array(RMDsize / 32); - var hashcode = new Array(RMDsize / 8); - var length; - var nbytes; - - MDinit(MDbuf); - length = message.length; - - var X = new Array(16); - zeroX(X); - - var j=0; - for (var nbytes=length; nbytes > 63; nbytes -= 64) - { - for (var i=0; i < 16; i++) - { - X[i] = BYTES_TO_DWORD(message.substr(j, 4)); - j += 4; - } - compress(MDbuf, X); - } - - MDfinish(MDbuf, message.substr(j), length, 0); - - for (var i=0; i < RMDsize / 8; i += 4) - { - hashcode[i] = MDbuf[i >>> 2] & 255; - hashcode[i+1] = (MDbuf[i >>> 2] >>> 8) & 255; - hashcode[i+2] = (MDbuf[i >>> 2] >>> 16) & 255; - hashcode[i+3] = (MDbuf[i >>> 2] >>> 24) & 255; - } - - return hashcode; -} - - -function RMDstring(message) -{ - var hashcode = RMD(message); - var retString = ""; - - for (var i=0; i < RMDsize/8; i++) - { - retString += String.fromCharCode(hashcode[i]); - } - - return retString; -} \ No newline at end of file diff --git a/src/ciphers/hash/sha.js b/src/ciphers/hash/sha.js deleted file mode 100644 index 8945fbcf..00000000 --- a/src/ciphers/hash/sha.js +++ /dev/null @@ -1,1221 +0,0 @@ -/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS - * PUB 180-2 as well as the corresponding HMAC implementation as defined in - * FIPS PUB 198a - * - * Version 1.3 Copyright Brian Turek 2008-2010 - * Distributed under the BSD License - * See http://jssha.sourceforge.net/ for more information - * - * Several functions taken from Paul Johnson - */ - -/* Modified by Recurity Labs GmbH - * - * This code has been slightly modified direct string output: - * - bin2bstr has been added - * - following wrappers of this library have been added: - * - str_sha1 - * - str_sha256 - * - str_sha224 - * - str_sha384 - * - str_sha512 - */ - -var jsSHA = (function () { - - /* - * Configurable variables. Defaults typically work - */ - /* Number of Bits Per character (8 for ASCII, 16 for Unicode) */ - var charSize = 8, - /* base-64 pad character. "=" for strict RFC compliance */ - b64pad = "", - /* hex output format. 0 - lowercase; 1 - uppercase */ - hexCase = 0, - - /* - * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number - * - * @constructor - * @param {Number} msint_32 The most significant 32-bits of a 64-bit number - * @param {Number} lsint_32 The least significant 32-bits of a 64-bit number - */ - Int_64 = function (msint_32, lsint_32) - { - this.highOrder = msint_32; - this.lowOrder = lsint_32; - }, - - /* - * Convert a string to an array of big-endian words - * If charSize is ASCII, characters >255 have their hi-byte silently - * ignored. - * - * @param {String} str String to be converted to binary representation - * @return Integer array representation of the parameter - */ - str2binb = function (str) - { - var bin = [], mask = (1 << charSize) - 1, - length = str.length * charSize, i; - - for (i = 0; i < length; i += charSize) - { - bin[i >> 5] |= (str.charCodeAt(i / charSize) & mask) << - (32 - charSize - (i % 32)); - } - - return bin; - }, - - /* - * Convert a hex string to an array of big-endian words - * - * @param {String} str String to be converted to binary representation - * @return Integer array representation of the parameter - */ - hex2binb = function (str) - { - var bin = [], length = str.length, i, num; - - for (i = 0; i < length; i += 2) - { - num = parseInt(str.substr(i, 2), 16); - if (!isNaN(num)) - { - bin[i >> 3] |= num << (24 - (4 * (i % 8))); - } - else - { - return "INVALID HEX STRING"; - } - } - - return bin; - }, - - /* - * Convert an array of big-endian words to a hex string. - * - * @private - * @param {Array} binarray Array of integers to be converted to hexidecimal - * representation - * @return Hexidecimal representation of the parameter in String form - */ - binb2hex = function (binarray) - { - var hex_tab = (hexCase) ? "0123456789ABCDEF" : "0123456789abcdef", - str = "", length = binarray.length * 4, i, srcByte; - - for (i = 0; i < length; i += 1) - { - srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); - str += hex_tab.charAt((srcByte >> 4) & 0xF) + - hex_tab.charAt(srcByte & 0xF); - } - - return str; - }, - - /* - * Convert an array of big-endian words to a base-64 string - * - * @private - * @param {Array} binarray Array of integers to be converted to base-64 - * representation - * @return Base-64 encoded representation of the parameter in String form - */ - binb2b64 = function (binarray) - { - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + - "0123456789+/", str = "", length = binarray.length * 4, i, j, - triplet; - - for (i = 0; i < length; i += 3) - { - triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | - (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | - ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); - for (j = 0; j < 4; j += 1) - { - if (i * 8 + j * 6 <= binarray.length * 32) - { - str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); - } - else - { - str += b64pad; - } - } - } - return str; - }, - - /* - * Convert an array of big-endian words to a string - */ - binb2str = function (bin) - { - var str = ""; - var mask = (1 << 8) - 1; - for(var i = 0; i < bin.length * 32; i += 8) - str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask); - return str; - }, - /* - * The 32-bit implementation of circular rotate left - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotl_32 = function (x, n) - { - return (x << n) | (x >>> (32 - n)); - }, - - /* - * The 32-bit implementation of circular rotate right - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotr_32 = function (x, n) - { - return (x >>> n) | (x << (32 - n)); - }, - - /* - * The 64-bit implementation of circular rotate right - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotr_64 = function (x, n) - { - if (n <= 32) - { - return new Int_64( - (x.highOrder >>> n) | (x.lowOrder << (32 - n)), - (x.lowOrder >>> n) | (x.highOrder << (32 - n)) - ); - } - else - { - return new Int_64( - (x.lowOrder >>> n) | (x.highOrder << (32 - n)), - (x.highOrder >>> n) | (x.lowOrder << (32 - n)) - ); - } - }, - - /* - * The 32-bit implementation of shift right - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted by n bits - */ - shr_32 = function (x, n) - { - return x >>> n; - }, - - /* - * The 64-bit implementation of shift right - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted by n bits - */ - shr_64 = function (x, n) - { - if (n <= 32) - { - return new Int_64( - x.highOrder >>> n, - x.lowOrder >>> n | (x.highOrder << (32 - n)) - ); - } - else - { - return new Int_64( - 0, - x.highOrder << (32 - n) - ); - } - }, - - /* - * The 32-bit implementation of the NIST specified Parity function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - parity_32 = function (x, y, z) - { - return x ^ y ^ z; - }, - - /* - * The 32-bit implementation of the NIST specified Ch function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - ch_32 = function (x, y, z) - { - return (x & y) ^ (~x & z); - }, - - /* - * The 64-bit implementation of the NIST specified Ch function - * - * @private - * @param {Int_64} x The first 64-bit integer argument - * @param {Int_64} y The second 64-bit integer argument - * @param {Int_64} z The third 64-bit integer argument - * @return The NIST specified output of the function - */ - ch_64 = function (x, y, z) - { - return new Int_64( - (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), - (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder) - ); - }, - - /* - * The 32-bit implementation of the NIST specified Maj function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - maj_32 = function (x, y, z) - { - return (x & y) ^ (x & z) ^ (y & z); - }, - - /* - * The 64-bit implementation of the NIST specified Maj function - * - * @private - * @param {Int_64} x The first 64-bit integer argument - * @param {Int_64} y The second 64-bit integer argument - * @param {Int_64} z The third 64-bit integer argument - * @return The NIST specified output of the function - */ - maj_64 = function (x, y, z) - { - return new Int_64( - (x.highOrder & y.highOrder) ^ - (x.highOrder & z.highOrder) ^ - (y.highOrder & z.highOrder), - (x.lowOrder & y.lowOrder) ^ - (x.lowOrder & z.lowOrder) ^ - (y.lowOrder & z.lowOrder) - ); - }, - - /* - * The 32-bit implementation of the NIST specified Sigma0 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - sigma0_32 = function (x) - { - return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22); - }, - - /* - * The 64-bit implementation of the NIST specified Sigma0 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - sigma0_64 = function (x) - { - var rotr28 = rotr_64(x, 28), rotr34 = rotr_64(x, 34), - rotr39 = rotr_64(x, 39); - - return new Int_64( - rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, - rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder); - }, - - /* - * The 32-bit implementation of the NIST specified Sigma1 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - sigma1_32 = function (x) - { - return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25); - }, - - /* - * The 64-bit implementation of the NIST specified Sigma1 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - sigma1_64 = function (x) - { - var rotr14 = rotr_64(x, 14), rotr18 = rotr_64(x, 18), - rotr41 = rotr_64(x, 41); - - return new Int_64( - rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, - rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder); - }, - - /* - * The 32-bit implementation of the NIST specified Gamma0 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - gamma0_32 = function (x) - { - return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3); - }, - - /* - * The 64-bit implementation of the NIST specified Gamma0 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - gamma0_64 = function (x) - { - var rotr1 = rotr_64(x, 1), rotr8 = rotr_64(x, 8), shr7 = shr_64(x, 7); - - return new Int_64( - rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, - rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder - ); - }, - - /* - * The 32-bit implementation of the NIST specified Gamma1 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - gamma1_32 = function (x) - { - return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10); - }, - - /* - * The 64-bit implementation of the NIST specified Gamma1 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - gamma1_64 = function (x) - { - var rotr19 = rotr_64(x, 19), rotr61 = rotr_64(x, 61), - shr6 = shr_64(x, 6); - - return new Int_64( - rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, - rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder - ); - }, - - /* - * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} x The first 32-bit integer argument to be added - * @param {Number} y The second 32-bit integer argument to be added - * @return The sum of x + y - */ - safeAdd_32_2 = function (x, y) - { - var lsw = (x & 0xFFFF) + (y & 0xFFFF), - msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16); - - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, - - /* - * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} a The first 32-bit integer argument to be added - * @param {Number} b The second 32-bit integer argument to be added - * @param {Number} c The third 32-bit integer argument to be added - * @param {Number} d The fourth 32-bit integer argument to be added - * @return The sum of a + b + c + d - */ - safeAdd_32_4 = function (a, b, c, d) - { - var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF), - msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + - (lsw >>> 16); - - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, - - /* - * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} a The first 32-bit integer argument to be added - * @param {Number} b The second 32-bit integer argument to be added - * @param {Number} c The third 32-bit integer argument to be added - * @param {Number} d The fourth 32-bit integer argument to be added - * @param {Number} e The fifth 32-bit integer argument to be added - * @return The sum of a + b + c + d + e - */ - safeAdd_32_5 = function (a, b, c, d, e) - { - var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) + - (e & 0xFFFF), - msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + - (e >>> 16) + (lsw >>> 16); - - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, - - /* - * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} x The first 64-bit integer argument to be added - * @param {Int_64} y The second 64-bit integer argument to be added - * @return The sum of x + y - */ - safeAdd_64_2 = function (x, y) - { - var lsw, msw, lowOrder, highOrder; - - lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF); - msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16); - msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - return new Int_64(highOrder, lowOrder); - }, - - /* - * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} a The first 64-bit integer argument to be added - * @param {Int_64} b The second 64-bit integer argument to be added - * @param {Int_64} c The third 64-bit integer argument to be added - * @param {Int_64} d The fouth 64-bit integer argument to be added - * @return The sum of a + b + c + d - */ - safeAdd_64_4 = function (a, b, c, d) - { - var lsw, msw, lowOrder, highOrder; - - lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + - (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF); - msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + - (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16); - msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + - (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - return new Int_64(highOrder, lowOrder); - }, - - /* - * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} a The first 64-bit integer argument to be added - * @param {Int_64} b The second 64-bit integer argument to be added - * @param {Int_64} c The third 64-bit integer argument to be added - * @param {Int_64} d The fouth 64-bit integer argument to be added - * @param {Int_64} e The fouth 64-bit integer argument to be added - * @return The sum of a + b + c + d + e - */ - safeAdd_64_5 = function (a, b, c, d, e) - { - var lsw, msw, lowOrder, highOrder; - - lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + - (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + - (e.lowOrder & 0xFFFF); - msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + - (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + - (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + - (e.highOrder & 0xFFFF) + (msw >>> 16); - msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + - (c.highOrder >>> 16) + (d.highOrder >>> 16) + - (e.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - - return new Int_64(highOrder, lowOrder); - }, - - /* - * Calculates the SHA-1 hash of the string set at instantiation - * - * @private - * @param {Array} message The binary array representation of the string to - * hash - * @param {Number} messageLen The number of bits in the message - * @return The array of integers representing the SHA-1 hash of message - */ - coreSHA1 = function (message, messageLen) - { - var W = [], a, b, c, d, e, T, ch = ch_32, parity = parity_32, - maj = maj_32, rotl = rotl_32, safeAdd_2 = safeAdd_32_2, i, t, - safeAdd_5 = safeAdd_32_5, appendedMessageLength, - H = [ - 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 - ], - K = [ - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 - ]; - - /* Append '1' at the end of the binary string */ - message[messageLen >> 5] |= 0x80 << (24 - (messageLen % 32)); - /* Append length of binary string in the position such that the new - length is a multiple of 512. Logic does not work for even multiples - of 512 but there can never be even multiples of 512 */ - message[(((messageLen + 65) >> 9) << 4) + 15] = messageLen; - - appendedMessageLength = message.length; - - for (i = 0; i < appendedMessageLength; i += 16) - { - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - - for (t = 0; t < 80; t += 1) - { - if (t < 16) - { - W[t] = message[t + i]; - } - else - { - W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); - } - - if (t < 20) - { - T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, K[t], W[t]); - } - else if (t < 40) - { - T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); - } - else if (t < 60) - { - T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, K[t], W[t]); - } else { - T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); - } - - e = d; - d = c; - c = rotl(b, 30); - b = a; - a = T; - } - - H[0] = safeAdd_2(a, H[0]); - H[1] = safeAdd_2(b, H[1]); - H[2] = safeAdd_2(c, H[2]); - H[3] = safeAdd_2(d, H[3]); - H[4] = safeAdd_2(e, H[4]); - } - - return H; - }, - - /* - * Calculates the desired SHA-2 hash of the string set at instantiation - * - * @private - * @param {Array} The binary array representation of the string to hash - * @param {Number} The number of bits in message - * @param {String} variant The desired SHA-2 variant - * @return The array of integers representing the SHA-2 hash of message - */ - coreSHA2 = function (message, messageLen, variant) - { - var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t, - binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5, - gamma0, gamma1, sigma0, sigma1, ch, maj, Int, K, W = [], - appendedMessageLength; - - /* Set up the various function handles and variable for the specific - * variant */ - if (variant === "SHA-224" || variant === "SHA-256") - { - /* 32-bit variant */ - numRounds = 64; - lengthPosition = (((messageLen + 65) >> 9) << 4) + 15; - binaryStringInc = 16; - binaryStringMult = 1; - Int = Number; - safeAdd_2 = safeAdd_32_2; - safeAdd_4 = safeAdd_32_4; - safeAdd_5 = safeAdd_32_5; - gamma0 = gamma0_32; - gamma1 = gamma1_32; - sigma0 = sigma0_32; - sigma1 = sigma1_32; - maj = maj_32; - ch = ch_32; - K = [ - 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, - 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, - 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, - 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, - 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, - 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, - 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, - 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, - 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, - 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, - 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, - 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, - 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, - 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, - 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, - 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 - ]; - - if (variant === "SHA-224") - { - H = [ - 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, - 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 - ]; - } - else - { - H = [ - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 - ]; - } - } - else if (variant === "SHA-384" || variant === "SHA-512") - { - /* 64-bit variant */ - numRounds = 80; - lengthPosition = (((messageLen + 128) >> 10) << 5) + 31; - binaryStringInc = 32; - binaryStringMult = 2; - Int = Int_64; - safeAdd_2 = safeAdd_64_2; - safeAdd_4 = safeAdd_64_4; - safeAdd_5 = safeAdd_64_5; - gamma0 = gamma0_64; - gamma1 = gamma1_64; - sigma0 = sigma0_64; - sigma1 = sigma1_64; - maj = maj_64; - ch = ch_64; - - K = [ - new Int(0x428a2f98, 0xd728ae22), new Int(0x71374491, 0x23ef65cd), - new Int(0xb5c0fbcf, 0xec4d3b2f), new Int(0xe9b5dba5, 0x8189dbbc), - new Int(0x3956c25b, 0xf348b538), new Int(0x59f111f1, 0xb605d019), - new Int(0x923f82a4, 0xaf194f9b), new Int(0xab1c5ed5, 0xda6d8118), - new Int(0xd807aa98, 0xa3030242), new Int(0x12835b01, 0x45706fbe), - new Int(0x243185be, 0x4ee4b28c), new Int(0x550c7dc3, 0xd5ffb4e2), - new Int(0x72be5d74, 0xf27b896f), new Int(0x80deb1fe, 0x3b1696b1), - new Int(0x9bdc06a7, 0x25c71235), new Int(0xc19bf174, 0xcf692694), - new Int(0xe49b69c1, 0x9ef14ad2), new Int(0xefbe4786, 0x384f25e3), - new Int(0x0fc19dc6, 0x8b8cd5b5), new Int(0x240ca1cc, 0x77ac9c65), - new Int(0x2de92c6f, 0x592b0275), new Int(0x4a7484aa, 0x6ea6e483), - new Int(0x5cb0a9dc, 0xbd41fbd4), new Int(0x76f988da, 0x831153b5), - new Int(0x983e5152, 0xee66dfab), new Int(0xa831c66d, 0x2db43210), - new Int(0xb00327c8, 0x98fb213f), new Int(0xbf597fc7, 0xbeef0ee4), - new Int(0xc6e00bf3, 0x3da88fc2), new Int(0xd5a79147, 0x930aa725), - new Int(0x06ca6351, 0xe003826f), new Int(0x14292967, 0x0a0e6e70), - new Int(0x27b70a85, 0x46d22ffc), new Int(0x2e1b2138, 0x5c26c926), - new Int(0x4d2c6dfc, 0x5ac42aed), new Int(0x53380d13, 0x9d95b3df), - new Int(0x650a7354, 0x8baf63de), new Int(0x766a0abb, 0x3c77b2a8), - new Int(0x81c2c92e, 0x47edaee6), new Int(0x92722c85, 0x1482353b), - new Int(0xa2bfe8a1, 0x4cf10364), new Int(0xa81a664b, 0xbc423001), - new Int(0xc24b8b70, 0xd0f89791), new Int(0xc76c51a3, 0x0654be30), - new Int(0xd192e819, 0xd6ef5218), new Int(0xd6990624, 0x5565a910), - new Int(0xf40e3585, 0x5771202a), new Int(0x106aa070, 0x32bbd1b8), - new Int(0x19a4c116, 0xb8d2d0c8), new Int(0x1e376c08, 0x5141ab53), - new Int(0x2748774c, 0xdf8eeb99), new Int(0x34b0bcb5, 0xe19b48a8), - new Int(0x391c0cb3, 0xc5c95a63), new Int(0x4ed8aa4a, 0xe3418acb), - new Int(0x5b9cca4f, 0x7763e373), new Int(0x682e6ff3, 0xd6b2b8a3), - new Int(0x748f82ee, 0x5defb2fc), new Int(0x78a5636f, 0x43172f60), - new Int(0x84c87814, 0xa1f0ab72), new Int(0x8cc70208, 0x1a6439ec), - new Int(0x90befffa, 0x23631e28), new Int(0xa4506ceb, 0xde82bde9), - new Int(0xbef9a3f7, 0xb2c67915), new Int(0xc67178f2, 0xe372532b), - new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207), - new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178), - new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6), - new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b), - new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493), - new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c), - new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a), - new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817) - ]; - - if (variant === "SHA-384") - { - H = [ - new Int(0xcbbb9d5d, 0xc1059ed8), new Int(0x0629a292a, 0x367cd507), - new Int(0x9159015a, 0x3070dd17), new Int(0x0152fecd8, 0xf70e5939), - new Int(0x67332667, 0xffc00b31), new Int(0x98eb44a87, 0x68581511), - new Int(0xdb0c2e0d, 0x64f98fa7), new Int(0x047b5481d, 0xbefa4fa4) - ]; - } - else - { - H = [ - new Int(0x6a09e667, 0xf3bcc908), new Int(0xbb67ae85, 0x84caa73b), - new Int(0x3c6ef372, 0xfe94f82b), new Int(0xa54ff53a, 0x5f1d36f1), - new Int(0x510e527f, 0xade682d1), new Int(0x9b05688c, 0x2b3e6c1f), - new Int(0x1f83d9ab, 0xfb41bd6b), new Int(0x5be0cd19, 0x137e2179) - ]; - } - } - - /* Append '1' at the end of the binary string */ - message[messageLen >> 5] |= 0x80 << (24 - messageLen % 32); - /* Append length of binary string in the position such that the new - * length is correct */ - message[lengthPosition] = messageLen; - - appendedMessageLength = message.length; - - for (i = 0; i < appendedMessageLength; i += binaryStringInc) - { - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - f = H[5]; - g = H[6]; - h = H[7]; - - for (t = 0; t < numRounds; t += 1) - { - if (t < 16) - { - /* Bit of a hack - for 32-bit, the second term is ignored */ - W[t] = new Int(message[t * binaryStringMult + i], - message[t * binaryStringMult + i + 1]); - } - else - { - W[t] = safeAdd_4( - gamma1(W[t - 2]), W[t - 7], - gamma0(W[t - 15]), W[t - 16] - ); - } - - T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]); - T2 = safeAdd_2(sigma0(a), maj(a, b, c)); - h = g; - g = f; - f = e; - e = safeAdd_2(d, T1); - d = c; - c = b; - b = a; - a = safeAdd_2(T1, T2); - } - - H[0] = safeAdd_2(a, H[0]); - H[1] = safeAdd_2(b, H[1]); - H[2] = safeAdd_2(c, H[2]); - H[3] = safeAdd_2(d, H[3]); - H[4] = safeAdd_2(e, H[4]); - H[5] = safeAdd_2(f, H[5]); - H[6] = safeAdd_2(g, H[6]); - H[7] = safeAdd_2(h, H[7]); - } - - switch (variant) - { - case "SHA-224": - return [ - H[0], H[1], H[2], H[3], - H[4], H[5], H[6] - ]; - case "SHA-256": - return H; - case "SHA-384": - return [ - H[0].highOrder, H[0].lowOrder, - H[1].highOrder, H[1].lowOrder, - H[2].highOrder, H[2].lowOrder, - H[3].highOrder, H[3].lowOrder, - H[4].highOrder, H[4].lowOrder, - H[5].highOrder, H[5].lowOrder - ]; - case "SHA-512": - return [ - H[0].highOrder, H[0].lowOrder, - H[1].highOrder, H[1].lowOrder, - H[2].highOrder, H[2].lowOrder, - H[3].highOrder, H[3].lowOrder, - H[4].highOrder, H[4].lowOrder, - H[5].highOrder, H[5].lowOrder, - H[6].highOrder, H[6].lowOrder, - H[7].highOrder, H[7].lowOrder - ]; - default: - /* This should never be reached */ - return []; - } - }, - - /* - * jsSHA is the workhorse of the library. Instantiate it with the string to - * be hashed as the parameter - * - * @constructor - * @param {String} srcString The string to be hashed - * @param {String} inputFormat The format of srcString, ASCII or HEX - */ - jsSHA = function (srcString, inputFormat) - { - - this.sha1 = null; - this.sha224 = null; - this.sha256 = null; - this.sha384 = null; - this.sha512 = null; - - this.strBinLen = null; - this.strToHash = null; - - /* Convert the input string into the correct type */ - if ("HEX" === inputFormat) - { - if (0 !== (srcString.length % 2)) - { - return "TEXT MUST BE IN BYTE INCREMENTS"; - } - this.strBinLen = srcString.length * 4; - this.strToHash = hex2binb(srcString); - } - else if (("ASCII" === inputFormat) || - ('undefined' === typeof(inputFormat))) - { - this.strBinLen = srcString.length * charSize; - this.strToHash = str2binb(srcString); - } - else - { - return "UNKNOWN TEXT INPUT TYPE"; - } - }; - - jsSHA.prototype = { - /* - * Returns the desired SHA hash of the string specified at instantiation - * using the specified parameters - * - * @param {String} variant The desired SHA variant (SHA-1, SHA-224, - * SHA-256, SHA-384, or SHA-512) - * @param {String} format The desired output formatting (B64 or HEX) - * @return The string representation of the hash in the format specified - */ - getHash : function (variant, format) - { - var formatFunc = null, message = this.strToHash.slice(); - - switch (format) - { - case "HEX": - formatFunc = binb2hex; - break; - case "B64": - formatFunc = binb2b64; - break; - case "ASCII": - formatFunc = binb2str; - break; - default: - return "FORMAT NOT RECOGNIZED"; - } - - switch (variant) - { - case "SHA-1": - if (null === this.sha1) - { - this.sha1 = coreSHA1(message, this.strBinLen); - } - return formatFunc(this.sha1); - case "SHA-224": - if (null === this.sha224) - { - this.sha224 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha224); - case "SHA-256": - if (null === this.sha256) - { - this.sha256 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha256); - case "SHA-384": - if (null === this.sha384) - { - this.sha384 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha384); - case "SHA-512": - if (null === this.sha512) - { - this.sha512 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha512); - default: - return "HASH NOT RECOGNIZED"; - } - }, - - /* - * Returns the desired HMAC of the string specified at instantiation - * using the key and variant param. - * - * @param {String} key The key used to calculate the HMAC - * @param {String} inputFormat The format of key, ASCII or HEX - * @param {String} variant The desired SHA variant (SHA-1, SHA-224, - * SHA-256, SHA-384, or SHA-512) - * @param {String} outputFormat The desired output formatting - * (B64 or HEX) - * @return The string representation of the hash in the format specified - */ - getHMAC : function (key, inputFormat, variant, outputFormat) - { - var formatFunc, keyToUse, blockByteSize, blockBitSize, i, - retVal, lastArrayIndex, keyBinLen, hashBitSize, - keyWithIPad = [], keyWithOPad = []; - - /* Validate the output format selection */ - switch (outputFormat) - { - case "HEX": - formatFunc = binb2hex; - break; - case "B64": - formatFunc = binb2b64; - break; - case "ASCII": - formatFunc = binb2str; - break; - default: - return "FORMAT NOT RECOGNIZED"; - } - - /* Validate the hash variant selection and set needed variables */ - switch (variant) - { - case "SHA-1": - blockByteSize = 64; - hashBitSize = 160; - break; - case "SHA-224": - blockByteSize = 64; - hashBitSize = 224; - break; - case "SHA-256": - blockByteSize = 64; - hashBitSize = 256; - break; - case "SHA-384": - blockByteSize = 128; - hashBitSize = 384; - break; - case "SHA-512": - blockByteSize = 128; - hashBitSize = 512; - break; - default: - return "HASH NOT RECOGNIZED"; - } - - /* Validate input format selection */ - if ("HEX" === inputFormat) - { - /* Nibbles must come in pairs */ - if (0 !== (key.length % 2)) - { - return "KEY MUST BE IN BYTE INCREMENTS"; - } - keyToUse = hex2binb(key); - keyBinLen = key.length * 4; - } - else if ("ASCII" === inputFormat) - { - keyToUse = str2binb(key); - keyBinLen = key.length * charSize; - } - else - { - return "UNKNOWN KEY INPUT TYPE"; - } - - /* These are used multiple times, calculate and store them */ - blockBitSize = blockByteSize * 8; - lastArrayIndex = (blockByteSize / 4) - 1; - - /* Figure out what to do with the key based on its size relative to - * the hash's block size */ - if (blockByteSize < (keyBinLen / 8)) - { - if ("SHA-1" === variant) - { - keyToUse = coreSHA1(keyToUse, keyBinLen); - } - else - { - keyToUse = coreSHA2(keyToUse, keyBinLen, variant); - } - /* For all variants, the block size is bigger than the output - * size so there will never be a useful byte at the end of the - * string */ - keyToUse[lastArrayIndex] &= 0xFFFFFF00; - } - else if (blockByteSize > (keyBinLen / 8)) - { - /* If the blockByteSize is greater than the key length, there - * will always be at LEAST one "useless" byte at the end of the - * string */ - keyToUse[lastArrayIndex] &= 0xFFFFFF00; - } - - /* Create ipad and opad */ - for (i = 0; i <= lastArrayIndex; i += 1) - { - keyWithIPad[i] = keyToUse[i] ^ 0x36363636; - keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C; - } - - /* Calculate the HMAC */ - if ("SHA-1" === variant) - { - retVal = coreSHA1( - keyWithIPad.concat(this.strToHash), - blockBitSize + this.strBinLen); - retVal = coreSHA1( - keyWithOPad.concat(retVal), - blockBitSize + hashBitSize); - } - else - { - retVal = coreSHA2( - keyWithIPad.concat(this.strToHash), - blockBitSize + this.strBinLen, variant); - retVal = coreSHA2( - keyWithOPad.concat(retVal), - blockBitSize + hashBitSize, variant); - } - - return (formatFunc(retVal)); - } - }; - - return jsSHA; -}()); - -function str_sha1(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-1", "ASCII"); -} - -function str_sha224(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-224", "ASCII"); -} - -function str_sha256(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-256", "ASCII"); -} - - -function str_sha384(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-384", "ASCII"); - -} - -function str_sha512(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-512", "ASCII"); -} diff --git a/src/ciphers/openpgp.cfb.js b/src/ciphers/openpgp.cfb.js deleted file mode 100644 index a53ab499..00000000 --- a/src/ciphers/openpgp.cfb.js +++ /dev/null @@ -1,290 +0,0 @@ -// Modified by Recurity Labs GmbH - -// modified version of http://www.hanewin.net/encrypt/PGdecode.js: - -/* OpenPGP encryption using RSA/AES - * Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de - * version 2.0, check www.haneWIN.de for the latest version - - * This software is provided as-is, without express or implied warranty. - * Permission to use, copy, modify, distribute or sell this software, with or - * without fee, for any purpose and by any individual or organization, is hereby - * granted, provided that the above copyright notice and this paragraph appear - * in all copies. Distribution as a part of an application or binary must - * include the above copyright notice in the documentation and/or other - * materials provided with the application or distribution. - */ - -/** - * An array of bytes, that is integers with values from 0 to 255 - * @typedef {(Array|Uint8Array)} openpgp_byte_array - */ - -/** - * Block cipher function - * @callback openpgp_cipher_block_fn - * @param {openpgp_byte_array} block A block to perform operations on - * @param {openpgp_byte_array} key to use in encryption/decryption - * @return {openpgp_byte_array} Encrypted/decrypted block - */ - - -// -------------------------------------- -/** - * This function encrypts a given with the specified prefixrandom - * using the specified blockcipher to encrypt a message - * @param {String} prefixrandom random bytes of block_size length provided - * as a string to be used in prefixing the data - * @param {openpgp_cipher_block_fn} blockcipherfn the algorithm encrypt function to encrypt - * data in one block_size encryption. - * @param {Integer} block_size the block size in bytes of the algorithm used - * @param {String} plaintext data to be encrypted provided as a string - * @param {openpgp_byte_array} key key to be used to encrypt the data. This will be passed to the - * blockcipherfn - * @param {Boolean} resync a boolean value specifying if a resync of the - * IV should be used or not. The encrypteddatapacket uses the - * "old" style with a resync. Encryption within an - * encryptedintegrityprotecteddata packet is not resyncing the IV. - * @return {String} a string with the encrypted data - */ -function openpgp_cfb_encrypt(prefixrandom, blockcipherencryptfn, plaintext, block_size, key, resync) { - var FR = new Array(block_size); - var FRE = new Array(block_size); - - prefixrandom = prefixrandom + prefixrandom.charAt(block_size-2) +prefixrandom.charAt(block_size-1); - util.print_debug("prefixrandom:"+util.hexstrdump(prefixrandom)); - var ciphertext = ""; - // 1. The feedback register (FR) is set to the IV, which is all zeros. - for (var i = 0; i < block_size; i++) FR[i] = 0; - - // 2. FR is encrypted to produce FRE (FR Encrypted). This is the - // encryption of an all-zero value. - FRE = blockcipherencryptfn(FR, key); - // 3. FRE is xored with the first BS octets of random data prefixed to - // the plaintext to produce C[1] through C[BS], the first BS octets - // of ciphertext. - for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i)); - - // 4. FR is loaded with C[1] through C[BS]. - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); - - // 5. FR is encrypted to produce FRE, the encryption of the first BS - // octets of ciphertext. - FRE = blockcipherencryptfn(FR, key); - - // 6. The left two octets of FRE get xored with the next two octets of - // data that were prefixed to the plaintext. This produces C[BS+1] - // and C[BS+2], the next two octets of ciphertext. - ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size)); - ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size+1)); - - if (resync) { - // 7. (The resync step) FR is loaded with C3-C10. - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i+2); - } else { - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); - } - // 8. FR is encrypted to produce FRE. - FRE = blockcipherencryptfn(FR, key); - - if (resync) { - // 9. FRE is xored with the first 8 octets of the given plaintext, now - // that we have finished encrypting the 10 octets of prefixed data. - // This produces C11-C18, the next 8 octets of ciphertext. - for (var i = 0; i < block_size; i++) - ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); - for(n=block_size+2; n < plaintext.length; n+=block_size) { - // 10. FR is loaded with C11-C18 - for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n+i); - - // 11. FR is encrypted to produce FRE. - FRE = blockcipherencryptfn(FR, key); - - // 12. FRE is xored with the next 8 octets of plaintext, to produce the - // next 8 octets of ciphertext. These are loaded into FR and the - // process is repeated until the plaintext is used up. - for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n-2)+i)); - } - } - else { - plaintext = " "+plaintext; - // 9. FRE is xored with the first 8 octets of the given plaintext, now - // that we have finished encrypting the 10 octets of prefixed data. - // This produces C11-C18, the next 8 octets of ciphertext. - for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); - var tempCiphertext = ciphertext.substring(0,2*block_size).split(''); - var tempCiphertextString = ciphertext.substring(block_size); - for(n=block_size; n block_size*pos) { - var encblock = blockcipherencryptfn(blockc, key); - blocki = plaintext.substring((pos*block_size),(pos*block_size)+block_size); - for (var i=0; i < blocki.length; i++) - tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i])); - blockc = tempBlock.join(''); - tempBlock = []; - cyphertext.push(blockc); - pos++; - } - return cyphertext.join(''); -} - -function normal_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, iv) { - var blockp =""; - var pos = 0; - var plaintext = []; - var offset = 0; - if (iv == null) - for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0); - else - blockp = iv.substring(0,block_size); - while (ciphertext.length > (block_size*pos)) { - var decblock = blockcipherencryptfn(blockp, key); - blockp = ciphertext.substring((pos*(block_size))+offset,(pos*(block_size))+(block_size)+offset); - for (var i=0; i < blockp.length; i++) { - plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i])); - } - pos++; - } - - return plaintext.join(''); -} diff --git a/src/ciphers/openpgp.crypto.sym.js b/src/ciphers/openpgp.crypto.sym.js deleted file mode 100644 index 30879a7d..00000000 --- a/src/ciphers/openpgp.crypto.sym.js +++ /dev/null @@ -1,94 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -// The GPG4Browsers symmetric crypto interface - -/** - * Symmetrically encrypts data using prefixedrandom, a key with length - * depending on the algorithm in openpgp_cfb mode with or without resync - * (MDC style) - * @param {String} prefixrandom Secure random bytes as string in - * length equal to the block size of the algorithm used (use - * openpgp_crypto_getPrefixRandom(algo) to retrieve that string - * @param {Integer} algo Algorithm to use (see RFC4880 9.2) - * @param {String} key Key as string. length is depending on the algorithm used - * @param {String} data Data to encrypt - * @param {Boolean} openpgp_cfb - * @return {String} Encrypted data - */ -function openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_cfb) { - switch(algo) { - case 0: // Plaintext or unencrypted data - return data; // blockcipherencryptfn, plaintext, block_size, key - case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - return openpgp_cfb_encrypt(prefixrandom, desede, data,8,key, openpgp_cfb).substring(0, data.length + 10); - case 3: // CAST5 (128 bit key, as per [RFC2144]) - return openpgp_cfb_encrypt(prefixrandom, cast5_encrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10); - case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH] - return openpgp_cfb_encrypt(prefixrandom, BFencrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10); - case 7: // AES with 128-bit key [AES] - case 8: // AES with 192-bit key - case 9: // AES with 256-bit key - return openpgp_cfb_encrypt(prefixrandom, AESencrypt, data, 16, keyExpansion(key), openpgp_cfb).substring(0, data.length + 18); - case 10: // Twofish with 256-bit key [TWOFISH] - return openpgp_cfb_encrypt(prefixrandom, TFencrypt, data,16, key, openpgp_cfb).substring(0, data.length + 18); - case 1: // IDEA [IDEA] - util.print_error("IDEA Algorithm not implemented"); - return null; - default: - return null; - } -} - -/** - * Symmetrically decrypts data using a key with length depending on the - * algorithm in openpgp_cfb mode with or without resync (MDC style) - * @param {Integer} algo Algorithm to use (see RFC4880 9.2) - * @param {String} key Key as string. length is depending on the algorithm used - * @param {String} data Data to be decrypted - * @param {Boolean} openpgp_cfb If true use the resync (for encrypteddata); - * otherwise use without the resync (for MDC encrypted data) - * @return {String} Plaintext data - */ -function openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) { - util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nalgo:"+algo+"\nencrypteddata:",data); - var n = 0; - if (!openpgp_cfb) - n = 2; - switch(algo) { - case 0: // Plaintext or unencrypted data - return data; - case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192) - return openpgp_cfb_decrypt(desede, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10); - case 3: // CAST5 (128 bit key, as per [RFC2144]) - return openpgp_cfb_decrypt(cast5_encrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10); - case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH] - return openpgp_cfb_decrypt(BFencrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10); - case 7: // AES with 128-bit key [AES] - case 8: // AES with 192-bit key - case 9: // AES with 256-bit key - return openpgp_cfb_decrypt(AESencrypt, 16, keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18); - case 10: // Twofish with 256-bit key [TWOFISH] - var result = openpgp_cfb_decrypt(TFencrypt, 16, key, data, openpgp_cfb).substring(n, (data.length+n)-18); - return result; - case 1: // IDEA [IDEA] - util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented")); - return null; - default: - } - return null; -} diff --git a/src/ciphers/symmetric/aes.js b/src/ciphers/symmetric/aes.js deleted file mode 100644 index bbbc0bea..00000000 --- a/src/ciphers/symmetric/aes.js +++ /dev/null @@ -1,484 +0,0 @@ - -/* Rijndael (AES) Encryption - * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de - * version 1.1, check www.haneWIN.de for the latest version - - * This software is provided as-is, without express or implied warranty. - * Permission to use, copy, modify, distribute or sell this software, with or - * without fee, for any purpose and by any individual or organization, is hereby - * granted, provided that the above copyright notice and this paragraph appear - * in all copies. Distribution as a part of an application or binary must - * include the above copyright notice in the documentation and/or other - * materials provided with the application or distribution. - */ - -// The round constants used in subkey expansion -var Rcon = [ -0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, -0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, -0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]; - -// Precomputed lookup table for the SBox -var S = [ - 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, -118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, -114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, -216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, -235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, -179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, -190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, -249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, -188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, -23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, -144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, - 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, -141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, - 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, -181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, -248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, -140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, - 22 ]; - -var T1 = [ -0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, -0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, -0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, -0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, -0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, -0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, -0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, -0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, -0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, -0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, -0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, -0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, -0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, -0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, -0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, -0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, -0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, -0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, -0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, -0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, -0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, -0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, -0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, -0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, -0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, -0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, -0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, -0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, -0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, -0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, -0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, -0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, -0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, -0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, -0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, -0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, -0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, -0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, -0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, -0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, -0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, -0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, -0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, -0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, -0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, -0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, -0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, -0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, -0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, -0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, -0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, -0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, -0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, -0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, -0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, -0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, -0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, -0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, -0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, -0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, -0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, -0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, -0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, -0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c ]; - -var T2 = [ -0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, -0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, -0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, -0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, -0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, -0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, -0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, -0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, -0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, -0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, -0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, -0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, -0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, -0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, -0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, -0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, -0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, -0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, -0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, -0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, -0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, -0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, -0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, -0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, -0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, -0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, -0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, -0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, -0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, -0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, -0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, -0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, -0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, -0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, -0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, -0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, -0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, -0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, -0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, -0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, -0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, -0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, -0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, -0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, -0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, -0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, -0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, -0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, -0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, -0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, -0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, -0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, -0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, -0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, -0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, -0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, -0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, -0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, -0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, -0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, -0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, -0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, -0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, -0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a ]; - -var T3 = [ -0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, -0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, -0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, -0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, -0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, -0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, -0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, -0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, -0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, -0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, -0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, -0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, -0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, -0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, -0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, -0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, -0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, -0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, -0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, -0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, -0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, -0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, -0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, -0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, -0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, -0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, -0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, -0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, -0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, -0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, -0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, -0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, -0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, -0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, -0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, -0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, -0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, -0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, -0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, -0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, -0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, -0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, -0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, -0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, -0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, -0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, -0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, -0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, -0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, -0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, -0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, -0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, -0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, -0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, -0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, -0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, -0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, -0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, -0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, -0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, -0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, -0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, -0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, -0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16 ]; - -var T4 = [ -0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, -0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, -0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, -0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, -0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, -0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, -0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, -0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, -0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, -0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, -0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, -0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, -0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, -0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, -0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, -0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, -0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, -0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, -0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, -0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, -0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, -0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, -0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, -0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, -0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, -0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, -0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, -0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, -0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, -0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, -0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, -0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, -0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, -0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, -0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, -0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, -0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, -0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, -0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, -0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, -0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, -0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, -0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, -0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, -0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, -0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, -0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, -0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, -0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, -0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, -0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, -0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, -0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, -0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, -0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, -0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, -0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, -0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, -0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, -0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, -0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, -0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, -0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, -0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 ]; - -function B0(x) { return (x&255); } -function B1(x) { return ((x>>8)&255); } -function B2(x) { return ((x>>16)&255); } -function B3(x) { return ((x>>24)&255); } - -function F1(x0, x1, x2, x3) -{ - return B1(T1[x0&255]) | (B1(T1[(x1>>8)&255])<<8) - | (B1(T1[(x2>>16)&255])<<16) | (B1(T1[x3>>>24])<<24); -} - -function packBytes(octets) -{ - var i, j; - var len=octets.length; - var b=new Array(len/4); - - if (!octets || len % 4) return; - - for (i=0, j=0; j=0; j--) tk[j] = k[j]; - - r=0; - t=0; - for(j=0; (j>8)&255] ^ T3[(t2>>16)&255] ^ T4[t3>>>24]; - b1 = T1[t1&255] ^ T2[(t2>>8)&255] ^ T3[(t3>>16)&255] ^ T4[t0>>>24]; - b2 = T1[t2&255] ^ T2[(t3>>8)&255] ^ T3[(t0>>16)&255] ^ T4[t1>>>24]; - b3 = T1[t3&255] ^ T2[(t0>>8)&255] ^ T3[(t1>>16)&255] ^ T4[t2>>>24]; - } - - // last round is special - r = rounds-1; - - t0 = b0 ^ ctx.rk[r][0]; - t1 = b1 ^ ctx.rk[r][1]; - t2 = b2 ^ ctx.rk[r][2]; - t3 = b3 ^ ctx.rk[r][3]; - - b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0]; - b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1]; - b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2]; - b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3]; - - return unpackBytes(b); -} diff --git a/src/ciphers/symmetric/blowfish.js b/src/ciphers/symmetric/blowfish.js deleted file mode 100644 index 13b384ac..00000000 --- a/src/ciphers/symmetric/blowfish.js +++ /dev/null @@ -1,393 +0,0 @@ -/* Modified by Recurity Labs GmbH - * - * Originally written by nklein software (nklein.com) - */ - -/* - * Javascript implementation based on Bruce Schneier's reference implementation. - * - * - * The constructor doesn't do much of anything. It's just here - * so we can start defining properties and methods and such. - */ -function Blowfish() { -}; - -/* - * Declare the block size so that protocols know what size - * Initialization Vector (IV) they will need. - */ -Blowfish.prototype.BLOCKSIZE = 8; - -/* - * These are the default SBOXES. - */ -Blowfish.prototype.SBOXES = [ - [ - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, - 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, - 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, - 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, - 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, - 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, - 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, - 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, - 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, - 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, - 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, - 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, - 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, - 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, - 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, - 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, - 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, - 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, - 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, - 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, - 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, - 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a - ], [ - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, - 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, - 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, - 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, - 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, - 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, - 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, - 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, - 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, - 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, - 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, - 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, - 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, - 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, - 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, - 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, - 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, - 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, - 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, - 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, - 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, - 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 - ], [ - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, - 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, - 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, - 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, - 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, - 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, - 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, - 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, - 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, - 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, - 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, - 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, - 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, - 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, - 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, - 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, - 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, - 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, - 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, - 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, - 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, - 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 - ], [ - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, - 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, - 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, - 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, - 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, - 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, - 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, - 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, - 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, - 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, - 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, - 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, - 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, - 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, - 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, - 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, - 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, - 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, - 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, - 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, - 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, - 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 - ] -]; - -//* -//* This is the default PARRAY -//* -Blowfish.prototype.PARRAY = [ - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, - 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b -]; - -//* -//* This is the number of rounds the cipher will go -//* -Blowfish.prototype.NN = 16; - -//* -//* This function is needed to get rid of problems -//* with the high-bit getting set. If we don't do -//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not -//* equal to ( bb & 0x00FFFFFFFF ) even when they -//* agree bit-for-bit for the first 32 bits. -//* -Blowfish.prototype._clean = function( xx ) { - if ( xx < 0 ) { - var yy = xx & 0x7FFFFFFF; - xx = yy + 0x80000000; - } - return xx; -}; - -//* -//* This is the mixing function that uses the sboxes -//* -Blowfish.prototype._F = function ( xx ) { - var aa; - var bb; - var cc; - var dd; - var yy; - - dd = xx & 0x00FF; - xx >>>= 8; - cc = xx & 0x00FF; - xx >>>= 8; - bb = xx & 0x00FF; - xx >>>= 8; - aa = xx & 0x00FF; - - yy = this.sboxes[ 0 ][ aa ] + this.sboxes[ 1 ][ bb ]; - yy = yy ^ this.sboxes[ 2 ][ cc ]; - yy = yy + this.sboxes[ 3 ][ dd ]; - - return yy; -}; - -//* -//* This method takes an array with two values, left and right -//* and does NN rounds of Blowfish on them. -//* -Blowfish.prototype._encrypt_block = function ( vals ) { - var dataL = vals[ 0 ]; - var dataR = vals[ 1 ]; - - var ii; - - for ( ii=0; ii < this.NN; ++ii ) { - dataL = dataL ^ this.parray[ ii ]; - dataR = this._F( dataL ) ^ dataR; - - var tmp = dataL; - dataL = dataR; - dataR = tmp; - } - - dataL = dataL ^ this.parray[ this.NN + 0 ]; - dataR = dataR ^ this.parray[ this.NN + 1 ]; - - vals[ 0 ] = this._clean( dataR ); - vals[ 1 ] = this._clean( dataL ); -}; - -//* -//* This method takes a vector of numbers and turns them -//* into long words so that they can be processed by the -//* real algorithm. -//* -//* Maybe I should make the real algorithm above take a vector -//* instead. That will involve more looping, but it won't require -//* the F() method to deconstruct the vector. -//* -Blowfish.prototype.encrypt_block = function ( vector ) { - var ii; - var vals = [ 0, 0 ]; - var off = this.BLOCKSIZE/2; - for ( ii = 0; ii < this.BLOCKSIZE/2; ++ii ) { - vals[0] = ( vals[0] << 8 ) | ( vector[ ii + 0 ] & 0x00FF ); - vals[1] = ( vals[1] << 8 ) | ( vector[ ii + off ] & 0x00FF ); - } - - this._encrypt_block( vals ); - - var ret = [ ]; - for ( ii = 0; ii < this.BLOCKSIZE/2; ++ii ) { - ret[ ii + 0 ] = ( vals[ 0 ] >>> (24 - 8*(ii)) & 0x00FF ); - ret[ ii + off ] = ( vals[ 1 ] >>> (24 - 8*(ii)) & 0x00FF ); - // vals[ 0 ] = ( vals[ 0 ] >>> 8 ); - // vals[ 1 ] = ( vals[ 1 ] >>> 8 ); - } - - return ret; -}; - -//* -//* This method takes an array with two values, left and right -//* and undoes NN rounds of Blowfish on them. -//* -Blowfish.prototype._decrypt_block = function ( vals ) { - var dataL = vals[ 0 ]; - var dataR = vals[ 1 ]; - - var ii; - - for ( ii=this.NN+1; ii > 1; --ii ) { - dataL = dataL ^ this.parray[ ii ]; - dataR = this._F( dataL ) ^ dataR; - - var tmp = dataL; - dataL = dataR; - dataR = tmp; - } - - dataL = dataL ^ this.parray[ 1 ]; - dataR = dataR ^ this.parray[ 0 ]; - - vals[ 0 ] = this._clean( dataR ); - vals[ 1 ] = this._clean( dataL ); -}; - -//* -//* This method takes a key array and initializes the -//* sboxes and parray for this encryption. -//* -Blowfish.prototype.init = function ( key ) { - var ii; - var jj = 0; - - this.parray = []; - for ( ii=0; ii < this.NN + 2; ++ii ) { - var data = 0x00000000; - var kk; - for ( kk=0; kk < 4; ++kk ) { - data = ( data << 8 ) | ( key[ jj ] & 0x00FF ); - if ( ++jj >= key.length ) { - jj = 0; - } - } - this.parray[ ii ] = this.PARRAY[ ii ] ^ data; - } - - this.sboxes = []; - for ( ii=0; ii < 4; ++ii ) { - this.sboxes[ ii ] = []; - for ( jj=0; jj < 256; ++jj ) { - this.sboxes[ ii ][ jj ] = this.SBOXES[ ii ][ jj ]; - } - } - - var vals = [ 0x00000000, 0x00000000 ]; - - for ( ii=0; ii < this.NN+2; ii += 2 ) { - this._encrypt_block( vals ); - this.parray[ ii + 0 ] = vals[ 0 ]; - this.parray[ ii + 1 ] = vals[ 1 ]; - } - - for ( ii=0; ii < 4; ++ii ) { - for ( jj=0; jj < 256; jj += 2 ) { - this._encrypt_block( vals ); - this.sboxes[ ii ][ jj + 0 ] = vals[ 0 ]; - this.sboxes[ ii ][ jj + 1 ] = vals[ 1 ]; - } - } -}; - -// added by Recurity Labs -function BFencrypt(block,key) { - var bf = new Blowfish(); - bf.init(util.str2bin(key)); - return bf.encrypt_block(block); -} diff --git a/src/ciphers/symmetric/cast5.js b/src/ciphers/symmetric/cast5.js deleted file mode 100644 index a429fa4a..00000000 --- a/src/ciphers/symmetric/cast5.js +++ /dev/null @@ -1,547 +0,0 @@ - -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Copyright 2010 pjacobs@xeekr.com . All rights reserved. - -// Modified by Recurity Labs GmbH - -// fixed/modified by Herbert Hanewinkel, www.haneWIN.de -// check www.haneWIN.de for the latest version - -// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144. -// CAST-128 is a common OpenPGP cipher. - - -// CAST5 constructor - -function cast5_encrypt(block, key) { - var cast5 = new openpgp_symenc_cast5(); - cast5.setKey(util.str2bin(key)); - return cast5.encrypt(block); -} - -function openpgp_symenc_cast5() { - this.BlockSize= 8; - this.KeySize = 16; - - this.setKey = function (key) { - this.masking = new Array(16); - this.rotate = new Array(16); - - this.reset(); - - if (key.length == this.KeySize) - { - this.keySchedule(key); - } - else - { - util.print_error('cast5.js: CAST-128: keys must be 16 bytes'); - return false; - } - return true; - }; - - this.reset = function() { - for (var i = 0; i < 16; i++) - { - this.masking[i] = 0; - this.rotate[i] = 0; - } - }; - - this.getBlockSize = function() { - return BlockSize; - }; - - this.encrypt = function(src) { - var dst = new Array(src.length); - - for(var i = 0; i < src.length; i+=8) - { - var l = src[i]<<24 | src[i+1]<<16 | src[i+2]<<8 | src[i+3]; - var r = src[i+4]<<24 | src[i+5]<<16 | src[i+6]<<8 | src[i+7]; - var t; - - t = r; r = l^f1(r, this.masking[0], this.rotate[0]); l = t; - t = r; r = l^f2(r, this.masking[1], this.rotate[1]); l = t; - t = r; r = l^f3(r, this.masking[2], this.rotate[2]); l = t; - t = r; r = l^f1(r, this.masking[3], this.rotate[3]); l = t; - - t = r; r = l^f2(r, this.masking[4], this.rotate[4]); l = t; - t = r; r = l^f3(r, this.masking[5], this.rotate[5]); l = t; - t = r; r = l^f1(r, this.masking[6], this.rotate[6]); l = t; - t = r; r = l^f2(r, this.masking[7], this.rotate[7]); l = t; - - t = r; r = l^f3(r, this.masking[8], this.rotate[8]); l = t; - t = r; r = l^f1(r, this.masking[9], this.rotate[9]); l = t; - t = r; r = l^f2(r, this.masking[10], this.rotate[10]); l = t; - t = r; r = l^f3(r, this.masking[11], this.rotate[11]); l = t; - - t = r; r = l^f1(r, this.masking[12], this.rotate[12]); l = t; - t = r; r = l^f2(r, this.masking[13], this.rotate[13]); l = t; - t = r; r = l^f3(r, this.masking[14], this.rotate[14]); l = t; - t = r; r = l^f1(r, this.masking[15], this.rotate[15]); l = t; - - dst[i] = (r >>> 24)&255; - dst[i+1] = (r >>> 16)&255; - dst[i+2] = (r >>> 8)&255; - dst[i+3] = r&255; - dst[i+4] = (l >>> 24)&255; - dst[i+5] = (l >>> 16)&255; - dst[i+6] = (l >>> 8)&255; - dst[i+7] = l&255; - } - - return dst; - }; - - this.decrypt = function(src) { - var dst = new Array(src.length); - - for(var i = 0; i < src.length; i+=8) - { - var l = src[i]<<24 | src[i+1]<<16 | src[i+2]<<8 | src[i+3]; - var r = src[i+4]<<24 | src[i+5]<<16 | src[i+6]<<8 | src[i+7]; - var t; - - t = r; r = l^f1(r, this.masking[15], this.rotate[15]); l = t; - t = r; r = l^f3(r, this.masking[14], this.rotate[14]); l = t; - t = r; r = l^f2(r, this.masking[13], this.rotate[13]); l = t; - t = r; r = l^f1(r, this.masking[12], this.rotate[12]); l = t; - - t = r; r = l^f3(r, this.masking[11], this.rotate[11]); l = t; - t = r; r = l^f2(r, this.masking[10], this.rotate[10]); l = t; - t = r; r = l^f1(r, this.masking[9], this.rotate[9]); l = t; - t = r; r = l^f3(r, this.masking[8], this.rotate[8]); l = t; - - t = r; r = l^f2(r, this.masking[7], this.rotate[7]); l = t; - t = r; r = l^f1(r, this.masking[6], this.rotate[6]); l = t; - t = r; r = l^f3(r, this.masking[5], this.rotate[5]); l = t; - t = r; r = l^f2(r, this.masking[4], this.rotate[4]); l = t; - - t = r; r = l^f1(r, this.masking[3], this.rotate[3]); l = t; - t = r; r = l^f3(r, this.masking[2], this.rotate[2]); l = t; - t = r; r = l^f2(r, this.masking[1], this.rotate[1]); l = t; - t = r; r = l^f1(r, this.masking[0], this.rotate[0]); l = t; - - dst[i] = (r >>> 24)&255; - dst[i+1] = (r >>> 16)&255; - dst[i+2] = (r >>> 8)&255; - dst[i+3] = r&255; - dst[i+4] = (l >>> 24)&255; - dst[i+5] = (l >> 16)&255; - dst[i+6] = (l >> 8)&255; - dst[i+7] = l&255; - } - - return dst; - }; - var scheduleA = new Array(4); - - scheduleA[0] = new Array(4); - scheduleA[0][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 0x8); - scheduleA[0][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); - scheduleA[0][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); - scheduleA[0][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); - - scheduleA[1] = new Array(4); - scheduleA[1][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); - scheduleA[1][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); - scheduleA[1][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); - scheduleA[1][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); - - scheduleA[2] = new Array(4); - scheduleA[2][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 8); - scheduleA[2][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); - scheduleA[2][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); - scheduleA[2][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); - - - scheduleA[3] = new Array(4); - scheduleA[3][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); - scheduleA[3][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); - scheduleA[3][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); - scheduleA[3][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); - - var scheduleB = new Array(4); - - scheduleB[0] = new Array(4); - scheduleB[0][0] = new Array(16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2); - scheduleB[0][1] = new Array(16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6); - scheduleB[0][2] = new Array(16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9); - scheduleB[0][3] = new Array(16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc); - - scheduleB[1] = new Array(4); - scheduleB[1][0] = new Array(3, 2, 0xc, 0xd, 8); - scheduleB[1][1] = new Array(1, 0, 0xe, 0xf, 0xd); - scheduleB[1][2] = new Array(7, 6, 8, 9, 3); - scheduleB[1][3] = new Array(5, 4, 0xa, 0xb, 7); - - - scheduleB[2] = new Array(4); - scheduleB[2][0] = new Array(16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9); - scheduleB[2][1] = new Array(16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc); - scheduleB[2][2] = new Array(16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2); - scheduleB[2][3] = new Array(16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6); - - - scheduleB[3] = new Array(4); - scheduleB[3][0] = new Array(8, 9, 7, 6, 3); - scheduleB[3][1] = new Array(0xa, 0xb, 5, 4, 7); - scheduleB[3][2] = new Array(0xc, 0xd, 3, 2, 8); - scheduleB[3][3] = new Array(0xe, 0xf, 1, 0, 0xd); - - // changed 'in' to 'inn' (in javascript 'in' is a reserved word) - this.keySchedule = function(inn) - { - var t = new Array(8); - var k = new Array(32); - - for (var i = 0; i < 4; i++) - { - var j = i * 4; - t[i] = inn[j]<<24 | inn[j+1]<<16 | inn[j+2]<<8 | inn[j+3]; - } - - var x = [6, 7, 4, 5]; - var ki = 0; - - for (var half = 0; half < 2; half++) - { - for (var round = 0; round < 4; round++) - { - for (var j = 0; j < 4; j++) - { - var a = scheduleA[round][j]; - var w = t[a[1]]; - - w ^= sBox[4][(t[a[2]>>>2]>>>(24-8*(a[2]&3)))&0xff]; - w ^= sBox[5][(t[a[3]>>>2]>>>(24-8*(a[3]&3)))&0xff]; - w ^= sBox[6][(t[a[4]>>>2]>>>(24-8*(a[4]&3)))&0xff]; - w ^= sBox[7][(t[a[5]>>>2]>>>(24-8*(a[5]&3)))&0xff]; - w ^= sBox[x[j]][(t[a[6]>>>2]>>>(24-8*(a[6]&3)))&0xff]; - t[a[0]] = w; - } - - for (var j = 0; j < 4; j++) - { - var b = scheduleB[round][j]; - var w = sBox[4][(t[b[0]>>>2]>>>(24-8*(b[0]&3)))&0xff]; - - w ^= sBox[5][(t[b[1]>>>2]>>>(24-8*(b[1]&3)))&0xff]; - w ^= sBox[6][(t[b[2]>>>2]>>>(24-8*(b[2]&3)))&0xff]; - w ^= sBox[7][(t[b[3]>>>2]>>>(24-8*(b[3]&3)))&0xff]; - w ^= sBox[4+j][(t[b[4]>>>2]>>>(24-8*(b[4]&3)))&0xff]; - k[ki] = w; - ki++; - } - } - } - - for (var i = 0; i < 16; i++) - { - this.masking[i] = k[i]; - this.rotate[i] = k[16+i] & 0x1f; - } - }; - - // These are the three 'f' functions. See RFC 2144, section 2.2. - - function f1(d, m, r) - { - var t = m + d; - var I = (t << r) | (t >>> (32 - r)); - return ((sBox[0][I>>>24] ^ sBox[1][(I>>>16)&255]) - sBox[2][(I>>>8)&255]) + sBox[3][I&255]; - } - - function f2(d, m, r) - { - var t = m ^ d; - var I = (t << r) | (t >>> (32 - r)); - return ((sBox[0][I>>>24] - sBox[1][(I>>>16)&255]) + sBox[2][(I>>>8)&255]) ^ sBox[3][I&255]; - } - - function f3(d, m, r) - { - var t = m - d; - var I = (t << r) | (t >>> (32 - r)); - return ((sBox[0][I>>>24] + sBox[1][(I>>>16)&255]) ^ sBox[2][(I>>>8)&255]) - sBox[3][I&255]; - } - - var sBox = new Array(8); - sBox[0] = new Array( - 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, - 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, - 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, - 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, - 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, - 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, - 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, - 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, - 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, - 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, - 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, - 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, - 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, - 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, - 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, - 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, - 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, - 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, - 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, - 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, - 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, - 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, - 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, - 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, - 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, - 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, - 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, - 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, - 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, - 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, - 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, - 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf); - - sBox[1] = new Array( - 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, - 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, - 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, - 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, - 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, - 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, - 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, - 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, - 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, - 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, - 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, - 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, - 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, - 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, - 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, - 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, - 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, - 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, - 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, - 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, - 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, - 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, - 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, - 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, - 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, - 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, - 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, - 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, - 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, - 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, - 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, - 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1); - - sBox[2] = new Array( - 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, - 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, - 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, - 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, - 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, - 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, - 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, - 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, - 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, - 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, - 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, - 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, - 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, - 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, - 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, - 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, - 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, - 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, - 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, - 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, - 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, - 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, - 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, - 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, - 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, - 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, - 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, - 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, - 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, - 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, - 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, - 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783); - - sBox[3] = new Array( - 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, - 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, - 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, - 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, - 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, - 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, - 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, - 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, - 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, - 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, - 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, - 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, - 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, - 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, - 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, - 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, - 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, - 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, - 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, - 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, - 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, - 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, - 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, - 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, - 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, - 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, - 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, - 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, - 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, - 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, - 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, - 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2); - - sBox[4] = new Array( - 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, - 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, - 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, - 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, - 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, - 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, - 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, - 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, - 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, - 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, - 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, - 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, - 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, - 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, - 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, - 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, - 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, - 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, - 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, - 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, - 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, - 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, - 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, - 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, - 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, - 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, - 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, - 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, - 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, - 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, - 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, - 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4); - - sBox[5] = new Array( - 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, - 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, - 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, - 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, - 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, - 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, - 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, - 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, - 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, - 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, - 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, - 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, - 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, - 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, - 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, - 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, - 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, - 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, - 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, - 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, - 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, - 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, - 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, - 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, - 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, - 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, - 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, - 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, - 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, - 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, - 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, - 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f); - - sBox[6] = new Array( - 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, - 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, - 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, - 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, - 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, - 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, - 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, - 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, - 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, - 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, - 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, - 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, - 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, - 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, - 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, - 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, - 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, - 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, - 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, - 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, - 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, - 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, - 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, - 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, - 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, - 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, - 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, - 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, - 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, - 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, - 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, - 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3); - - sBox[7] = new Array( - 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, - 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, - 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, - 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, - 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, - 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, - 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, - 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, - 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, - 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, - 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, - 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, - 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, - 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, - 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, - 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, - 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, - 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, - 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, - 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, - 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, - 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, - 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, - 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, - 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, - 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, - 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, - 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, - 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, - 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, - 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, - 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e); - -}; - diff --git a/src/ciphers/symmetric/twofish.js b/src/ciphers/symmetric/twofish.js deleted file mode 100644 index ba0d6646..00000000 --- a/src/ciphers/symmetric/twofish.js +++ /dev/null @@ -1,302 +0,0 @@ -/* Modified by Recurity Labs GmbH - * - * Cipher.js - * A block-cipher algorithm implementation on JavaScript - * See Cipher.readme.txt for further information. - * - * Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ] - * This script file is distributed under the LGPL - * - * ACKNOWLEDGMENT - * - * The main subroutines are written by Michiel van Everdingen. - * - * Michiel van Everdingen - * http://home.versatel.nl/MAvanEverdingen/index.html - * - * All rights for these routines are reserved to Michiel van Everdingen. - * - */ - -// added by Recurity Labs -function TFencrypt(block, key) { - var block_copy = [].concat(block); - var tf = createTwofish(); - tf.open(util.str2bin(key),0); - var result = tf.encrypt(block_copy, 0); - tf.close(); - return result; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Math -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -var MAXINT = 0xFFFFFFFF; - -function rotb(b,n){ return ( b<>>( 8-n) ) & 0xFF; } -function rotw(w,n){ return ( w<>>(32-n) ) & MAXINT; } -function getW(a,i){ return a[i]|a[i+1]<<8|a[i+2]<<16|a[i+3]<<24; } -function setW(a,i,w){ a.splice(i,4,w&0xFF,(w>>>8)&0xFF,(w>>>16)&0xFF,(w>>>24)&0xFF); } -function setWInv(a,i,w){ a.splice(i,4,(w>>>24)&0xFF,(w>>>16)&0xFF,(w>>>8)&0xFF,w&0xFF); } -function getB(x,n){ return (x>>>(n*8))&0xFF; } - -function getNrBits(i){ var n=0; while (i>0){ n++; i>>>=1; } return n; } -function getMask(n){ return (1<> 2) ^ [ 0, 90, 180, 238 ][x & 3]; - } - function ffmEf(x) { - return x ^ (x >> 1) ^ (x >> 2) ^ [ 0, 238, 180, 90 ][x & 3]; - } - - function mdsRem(p, q) { - var i, t, u; - for (i = 0; i < 8; i++) { - t = q >>> 24; - q = ((q << 8) & MAXINT) | p >>> 24; - p = (p << 8) & MAXINT; - u = t << 1; - if (t & 128) { - u ^= 333; - } - q ^= t ^ (u << 16); - u ^= t >>> 1; - if (t & 1) { - u ^= 166; - } - q ^= u << 24 | u << 8; - } - return q; - } - - function qp(n, x) { - var a, b, c, d; - a = x >> 4; - b = x & 15; - c = q0[n][a ^ b]; - d = q1[n][ror4[b] ^ ashx[a]]; - return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d]; - } - - function hFun(x, key) { - var a = getB(x, 0), b = getB(x, 1), c = getB(x, 2), d = getB(x, 3); - switch (kLen) { - case 4: - a = q[1][a] ^ getB(key[3], 0); - b = q[0][b] ^ getB(key[3], 1); - c = q[0][c] ^ getB(key[3], 2); - d = q[1][d] ^ getB(key[3], 3); - case 3: - a = q[1][a] ^ getB(key[2], 0); - b = q[1][b] ^ getB(key[2], 1); - c = q[0][c] ^ getB(key[2], 2); - d = q[0][d] ^ getB(key[2], 3); - case 2: - a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0); - b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1); - c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2); - d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3); - } - return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d]; - } - - keyBytes = keyBytes.slice(0, 32); - i = keyBytes.length; - while (i != 16 && i != 24 && i != 32) - keyBytes[i++] = 0; - - for (i = 0; i < keyBytes.length; i += 4) { - inKey[i >> 2] = getW(keyBytes, i); - } - for (i = 0; i < 256; i++) { - q[0][i] = qp(0, i); - q[1][i] = qp(1, i); - } - for (i = 0; i < 256; i++) { - f01 = q[1][i]; - f5b = ffm5b(f01); - fef = ffmEf(f01); - m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24); - m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24); - f01 = q[0][i]; - f5b = ffm5b(f01); - fef = ffmEf(f01); - m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24); - m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24); - } - - kLen = inKey.length / 2; - for (i = 0; i < kLen; i++) { - a = inKey[i + i]; - meKey[i] = a; - b = inKey[i + i + 1]; - moKey[i] = b; - sKey[kLen - i - 1] = mdsRem(a, b); - } - for (i = 0; i < 40; i += 2) { - a = 0x1010101 * i; - b = a + 0x1010101; - a = hFun(a, meKey); - b = rotw(hFun(b, moKey), 8); - tfsKey[i] = (a + b) & MAXINT; - tfsKey[i + 1] = rotw(a + 2 * b, 9); - } - for (i = 0; i < 256; i++) { - a = b = c = d = i; - switch (kLen) { - case 4: - a = q[1][a] ^ getB(sKey[3], 0); - b = q[0][b] ^ getB(sKey[3], 1); - c = q[0][c] ^ getB(sKey[3], 2); - d = q[1][d] ^ getB(sKey[3], 3); - case 3: - a = q[1][a] ^ getB(sKey[2], 0); - b = q[1][b] ^ getB(sKey[2], 1); - c = q[0][c] ^ getB(sKey[2], 2); - d = q[0][d] ^ getB(sKey[2], 3); - case 2: - tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)] - ^ getB(sKey[0], 0)]; - tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)] - ^ getB(sKey[0], 1)]; - tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)] - ^ getB(sKey[0], 2)]; - tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)] - ^ getB(sKey[0], 3)]; - } - } - } - - function tfsG0(x) { - return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)] - ^ tfsM[3][getB(x, 3)]; - } - function tfsG1(x) { - return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)] - ^ tfsM[3][getB(x, 2)]; - } - - function tfsFrnd(r, blk) { - var a = tfsG0(blk[0]); - var b = tfsG1(blk[1]); - blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31); - blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT; - a = tfsG0(blk[2]); - b = tfsG1(blk[3]); - blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31); - blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT; - } - - function tfsIrnd(i, blk) { - var a = tfsG0(blk[0]); - var b = tfsG1(blk[1]); - blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT; - blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31); - a = tfsG0(blk[2]); - b = tfsG1(blk[3]); - blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT; - blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31); - } - - function tfsClose() { - tfsKey = []; - tfsM = [ [], [], [], [] ]; - } - - function tfsEncrypt(data, offset) { - dataBytes = data; - dataOffset = offset; - var blk = [ getW(dataBytes, dataOffset) ^ tfsKey[0], - getW(dataBytes, dataOffset + 4) ^ tfsKey[1], - getW(dataBytes, dataOffset + 8) ^ tfsKey[2], - getW(dataBytes, dataOffset + 12) ^ tfsKey[3] ]; - for ( var j = 0; j < 8; j++) { - tfsFrnd(j, blk); - } - setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]); - setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]); - setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]); - setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]); - dataOffset += 16; - return dataBytes; - } - - function tfsDecrypt(data, offset) { - dataBytes = data; - dataOffset = offset; - var blk = [ getW(dataBytes, dataOffset) ^ tfsKey[4], - getW(dataBytes, dataOffset + 4) ^ tfsKey[5], - getW(dataBytes, dataOffset + 8) ^ tfsKey[6], - getW(dataBytes, dataOffset + 12) ^ tfsKey[7] ]; - for ( var j = 7; j >= 0; j--) { - tfsIrnd(j, blk); - } - setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]); - setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]); - setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]); - setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]); - dataOffset += 16; - } - - // added by Recurity Labs - function tfsFinal() { - return dataBytes; - } - - return { - name : "twofish", - blocksize : 128 / 8, - open : tfsInit, - close : tfsClose, - encrypt : tfsEncrypt, - decrypt : tfsDecrypt, - // added by Recurity Labs - finalize: tfsFinal - }; -} - diff --git a/src/cleartext.js b/src/cleartext.js new file mode 100644 index 00000000..34924849 --- /dev/null +++ b/src/cleartext.js @@ -0,0 +1,150 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires config + * @requires encoding/armor + * @requires enums + * @requires packet + * @module cleartext + */ + +var config = require('./config'), + packet = require('./packet'), + enums = require('./enums.js'), + armor = require('./encoding/armor.js'); + +/** + * @class + * @classdesc Class that represents an OpenPGP cleartext signed message. + * See http://tools.ietf.org/html/rfc4880#section-7 + * @param {String} text The cleartext of the signed message + * @param {module:packet/packetlist} packetlist The packetlist with signature packets or undefined + * if message not yet signed + */ + +function CleartextMessage(text, packetlist) { + if (!(this instanceof CleartextMessage)) { + return new CleartextMessage(packetlist); + } + // normalize EOL to canonical form + this.text = text.replace(/\r/g, '').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n"); + this.packets = packetlist || new packet.list(); +} + +/** + * Returns the key IDs of the keys that signed the cleartext message + * @return {Array} array of keyid objects + */ +CleartextMessage.prototype.getSigningKeyIds = function() { + var keyIds = []; + var signatureList = this.packets.filterByTag(enums.packet.signature); + signatureList.forEach(function(packet) { + keyIds.push(packet.issuerKeyId); + }); + return keyIds; +}; + +/** + * Sign the cleartext message + * @param {Array} privateKeys private keys with decrypted secret key data for signing + */ +CleartextMessage.prototype.sign = function(privateKeys) { + var packetlist = new packet.list(); + var literalDataPacket = new packet.literal(); + literalDataPacket.setText(this.text); + for (var i = 0; i < privateKeys.length; i++) { + var signaturePacket = new packet.signature(); + signaturePacket.signatureType = enums.signature.text; + signaturePacket.hashAlgorithm = config.prefer_hash_algorithm; + var signingKeyPacket = privateKeys[i].getSigningKeyPacket(); + signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; + if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.'); + signaturePacket.sign(signingKeyPacket, literalDataPacket); + packetlist.push(signaturePacket); + } + this.packets = packetlist; +}; + +/** + * Verify signatures of cleartext signed message + * @param {Array} publicKeys public keys to verify signatures + * @return {Array<{keyid: module:type/keyid, valid: Boolean}>} list of signer's keyid and validity of signature + */ +CleartextMessage.prototype.verify = function(publicKeys) { + var result = []; + var signatureList = this.packets.filterByTag(enums.packet.signature); + var literalDataPacket = new packet.literal(); + // we assume that cleartext signature is generated based on UTF8 cleartext + literalDataPacket.setText(this.text); + publicKeys.forEach(function(pubKey) { + for (var i = 0; i < signatureList.length; i++) { + var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]); + if (publicKeyPacket) { + var verifiedSig = {}; + verifiedSig.keyid = signatureList[i].issuerKeyId; + verifiedSig.valid = signatureList[i].verify(publicKeyPacket, literalDataPacket); + result.push(verifiedSig); + break; + } + } + }); + return result; +}; + +/** + * Get cleartext + * @return {String} cleartext of message + */ +CleartextMessage.prototype.getText = function() { + // normalize end of line to \n + return this.text.replace(/\r\n/g,"\n"); +}; + +/** + * Returns ASCII armored text of cleartext signed message + * @return {String} ASCII armor + */ +CleartextMessage.prototype.armor = function() { + var body = { + hash: enums.read(enums.hash, config.prefer_hash_algorithm).toUpperCase(), + text: this.text, + data: this.packets.write() + } + return armor.encode(enums.armor.signed, body); +}; + + +/** + * reads an OpenPGP cleartext signed message and returns a CleartextMessage object + * @param {String} armoredText text to be parsed + * @return {module:cleartext~CleartextMessage} new cleartext message object + * @static + */ +function readArmored(armoredText) { + var input = armor.decode(armoredText); + if (input.type !== enums.armor.signed) { + throw new Error('No cleartext signed message.'); + } + var packetlist = new packet.list(); + packetlist.read(input.data); + var newMessage = new CleartextMessage(input.text, packetlist); + return newMessage; +} + +exports.CleartextMessage = CleartextMessage; +exports.readArmored = readArmored; diff --git a/src/compression/jxg.js b/src/compression/jxg.js new file mode 100644 index 00000000..814ceda2 --- /dev/null +++ b/src/compression/jxg.js @@ -0,0 +1,1267 @@ +JXG = { + exists: (function(undefined) { + return function(v) { + return !(v === undefined || v === null); + } + })() +}; +JXG.decompress = function(str) { + return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip()[0][0]); +}; +/* + Copyright 2008-2012 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses. + + You should have received a copy of the GNU Lesser General Public License + along with JSXCompressor. If not, see . + + You should have received a copy of the Apache License along with JSXCompressor. + If not, see . + +*/ + +/** + * @class Util class + * @classdesc Utilities for uncompressing and base64 decoding + * Class for gunzipping, unzipping and base64 decoding of files. + * It is used for reading GEONExT, Geogebra and Intergeo files. + * + * Only Huffman codes are decoded in gunzip. + * The code is based on the source code for gunzip.c by Pasi Ojala + * {@link http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c} + * {@link http://www.cs.tut.fi/~albert} + */ +JXG.Util = {}; + +/** + * Unzip zip files + */ +JXG.Util.Unzip = function(barray) { + var outputArr = [], + output = "", + debug = false, + gpflags, + files = 0, + unzipped = [], + crc, + buf32k = new Array(32768), + bIdx = 0, + modeZIP = false, + + CRC, SIZE, + + bitReverse = [ + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff + ], + + cplens = [ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + ], + + cplext = [ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 + ], + /* 99==invalid */ + + cpdist = [ + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, + 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, + 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01, + 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001 + ], + + cpdext = [ + 0, 0, 0, 0, 1, 1, 2, 2, + 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13 + ], + + border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], + + bA = barray, + + bytepos = 0, + bitpos = 0, + bb = 1, + bits = 0, + + NAMEMAX = 256, + + nameBuf = [], + + fileout; + + function readByte() { + bits += 8; + if (bytepos < bA.length) { + //if (debug) + // document.write(bytepos+": "+bA[bytepos]+"
      "); + return bA[bytepos++]; + } else + return -1; + }; + + function byteAlign() { + bb = 1; + }; + + function readBit() { + var carry; + bits++; + carry = (bb & 1); + bb >>= 1; + if (bb == 0) { + bb = readByte(); + carry = (bb & 1); + bb = (bb >> 1) | 0x80; + } + return carry; + }; + + function readBits(a) { + var res = 0, + i = a; + + while (i--) { + res = (res << 1) | readBit(); + } + if (a) { + res = bitReverse[res] >> (8 - a); + } + return res; + }; + + function flushBuffer() { + //document.write('FLUSHBUFFER:'+buf32k); + bIdx = 0; + }; + + function addBuffer(a) { + SIZE++; + //CRC=updcrc(a,crc); + buf32k[bIdx++] = a; + outputArr.push(String.fromCharCode(a)); + //output+=String.fromCharCode(a); + if (bIdx == 0x8000) { + //document.write('ADDBUFFER:'+buf32k); + bIdx = 0; + } + }; + + function HufNode() { + this.b0 = 0; + this.b1 = 0; + this.jump = null; + this.jumppos = -1; + }; + + var LITERALS = 288; + + var literalTree = new Array(LITERALS); + var distanceTree = new Array(32); + var treepos = 0; + var Places = null; + var Places2 = null; + + var impDistanceTree = new Array(64); + var impLengthTree = new Array(64); + + var len = 0; + var fpos = new Array(17); + fpos[0] = 0; + var flens; + var fmax; + + function IsPat() { + while (1) { + if (fpos[len] >= fmax) + return -1; + if (flens[fpos[len]] == len) + return fpos[len]++; + fpos[len]++; + } + }; + + function Rec() { + var curplace = Places[treepos]; + var tmp; + if (debug) + document.write("
      len:" + len + " treepos:" + treepos); + if (len == 17) { //war 17 + return -1; + } + treepos++; + len++; + + tmp = IsPat(); + if (debug) + document.write("
      IsPat " + tmp); + if (tmp >= 0) { + curplace.b0 = tmp; /* leaf cell for 0-bit */ + if (debug) + document.write("
      b0 " + curplace.b0); + } else { + /* Not a Leaf cell */ + curplace.b0 = 0x8000; + if (debug) + document.write("
      b0 " + curplace.b0); + if (Rec()) + return -1; + } + tmp = IsPat(); + if (tmp >= 0) { + curplace.b1 = tmp; /* leaf cell for 1-bit */ + if (debug) + document.write("
      b1 " + curplace.b1); + curplace.jump = null; /* Just for the display routine */ + } else { + /* Not a Leaf cell */ + curplace.b1 = 0x8000; + if (debug) + document.write("
      b1 " + curplace.b1); + curplace.jump = Places[treepos]; + curplace.jumppos = treepos; + if (Rec()) + return -1; + } + len--; + return 0; + }; + + function CreateTree(currentTree, numval, lengths, show) { + var i; + /* Create the Huffman decode tree/table */ + //document.write("
      createtree
      "); + if (debug) + document.write("currentTree " + currentTree + " numval " + numval + " lengths " + lengths + " show " + show); + Places = currentTree; + treepos = 0; + flens = lengths; + fmax = numval; + for (i = 0; i < 17; i++) + fpos[i] = 0; + len = 0; + if (Rec()) { + //fprintf(stderr, "invalid huffman tree\n"); + if (debug) + alert("invalid huffman tree\n"); + return -1; + } + if (debug) { + document.write('
      Tree: ' + Places.length); + for (var a = 0; a < 32; a++) { + document.write("Places[" + a + "].b0=" + Places[a].b0 + "
      "); + document.write("Places[" + a + "].b1=" + Places[a].b1 + "
      "); + } + } + + /*if(show) { + var tmp; + for(tmp=currentTree;tmpjump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0); + if(!(tmp.b0 & 0x8000)) { + //fprintf(stdout, " 0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�'); + } + if(!(tmp.b1 & 0x8000)) { + if((tmp.b0 & 0x8000)) + fprintf(stdout, " "); + fprintf(stdout, " 0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�'); + } + fprintf(stdout, "\n"); + } + }*/ + return 0; + }; + + function DecodeValue(currentTree) { + var len, i, + xtreepos = 0, + X = currentTree[xtreepos], + b; + + /* decode one symbol of the data */ + while (1) { + b = readBit(); + if (debug) + document.write("b=" + b); + if (b) { + if (!(X.b1 & 0x8000)) { + if (debug) + document.write("ret1"); + return X.b1; /* If leaf node, return data */ + } + X = X.jump; + len = currentTree.length; + for (i = 0; i < len; i++) { + if (currentTree[i] === X) { + xtreepos = i; + break; + } + } + //xtreepos++; + } else { + if (!(X.b0 & 0x8000)) { + if (debug) + document.write("ret2"); + return X.b0; /* If leaf node, return data */ + } + //X++; //?????????????????? + xtreepos++; + X = currentTree[xtreepos]; + } + } + }; + + function DeflateLoop() { + var last, c, type, i, len; + + do { + /*if((last = readBit())){ + fprintf(errfp, "Last Block: "); + } else { + fprintf(errfp, "Not Last Block: "); + }*/ + last = readBit(); + type = readBits(2); + switch (type) { + case 0: + if (debug) + alert("Stored\n"); + break; + case 1: + if (debug) + alert("Fixed Huffman codes\n"); + break; + case 2: + if (debug) + alert("Dynamic Huffman codes\n"); + break; + case 3: + if (debug) + alert("Reserved block type!!\n"); + break; + default: + if (debug) + alert("Unexpected value %d!\n", type); + break; + } + + if (type == 0) { + var blockLen, cSum; + + // Stored + byteAlign(); + blockLen = readByte(); + blockLen |= (readByte() << 8); + + cSum = readByte(); + cSum |= (readByte() << 8); + + if (((blockLen ^ ~cSum) & 0xffff)) { + document.write("BlockLen checksum mismatch\n"); + } + while (blockLen--) { + c = readByte(); + addBuffer(c); + } + } else if (type == 1) { + var j; + + /* Fixed Huffman tables -- fixed decode routine */ + while (1) { + /* + 256 0000000 0 + : : : + 279 0010111 23 + 0 00110000 48 + : : : + 143 10111111 191 + 280 11000000 192 + : : : + 287 11000111 199 + 144 110010000 400 + : : : + 255 111111111 511 + + Note the bit order! + */ + + j = (bitReverse[readBits(7)] >> 1); + if (j > 23) { + j = (j << 1) | readBit(); /* 48..255 */ + + if (j > 199) { /* 200..255 */ + j -= 128; /* 72..127 */ + j = (j << 1) | readBit(); /* 144..255 << */ + } else { /* 48..199 */ + j -= 48; /* 0..151 */ + if (j > 143) { + j = j + 136; /* 280..287 << */ + /* 0..143 << */ + } + } + } else { /* 0..23 */ + j += 256; /* 256..279 << */ + } + if (j < 256) { + addBuffer(j); + //document.write("out:"+String.fromCharCode(j)); + /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/ + } else if (j == 256) { + /* EOF */ + break; + } else { + var len, dist; + + j -= 256 + 1; /* bytes + EOF */ + len = readBits(cplext[j]) + cplens[j]; + + j = bitReverse[readBits(5)] >> 3; + if (cpdext[j] > 8) { + dist = readBits(8); + dist |= (readBits(cpdext[j] - 8) << 8); + } else { + dist = readBits(cpdext[j]); + } + dist += cpdist[j]; + + /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/ + for (j = 0; j < len; j++) { + var c = buf32k[(bIdx - dist) & 0x7fff]; + addBuffer(c); + } + } + } // while + } else if (type == 2) { + var j, n, literalCodes, distCodes, lenCodes; + var ll = new Array(288 + 32); // "static" just to preserve stack + + // Dynamic Huffman tables + + literalCodes = 257 + readBits(5); + distCodes = 1 + readBits(5); + lenCodes = 4 + readBits(4); + //document.write("
      param: "+literalCodes+" "+distCodes+" "+lenCodes+"
      "); + for (j = 0; j < 19; j++) { + ll[j] = 0; + } + + // Get the decode tree code lengths + + //document.write("
      "); + for (j = 0; j < lenCodes; j++) { + ll[border[j]] = readBits(3); + //document.write(ll[border[j]]+" "); + } + //fprintf(errfp, "\n"); + //document.write('
      ll:'+ll); + len = distanceTree.length; + for (i = 0; i < len; i++) + distanceTree[i] = new HufNode(); + if (CreateTree(distanceTree, 19, ll, 0)) { + flushBuffer(); + return 1; + } + if (debug) { + document.write("
      distanceTree"); + for (var a = 0; a < distanceTree.length; a++) { + document.write("
      " + distanceTree[a].b0 + " " + distanceTree[a].b1 + " " + distanceTree[a].jump + " " + + distanceTree[a].jumppos); + /*if (distanceTree[a].jumppos!=-1) + document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1); + */ + } + } + //document.write('
      tree created'); + + //read in literal and distance code lengths + n = literalCodes + distCodes; + i = 0; + var z = -1; + if (debug) + document.write("
      n=" + n + " bits: " + bits + "
      "); + while (i < n) { + z++; + j = DecodeValue(distanceTree); + if (debug) + document.write("
      " + z + " i:" + i + " decode: " + j + " bits " + bits + "
      "); + if (j < 16) { // length of code in bits (0..15) + ll[i++] = j; + } else if (j == 16) { // repeat last length 3 to 6 times + var l; + j = 3 + readBits(2); + if (i + j > n) { + flushBuffer(); + return 1; + } + l = i ? ll[i - 1] : 0; + while (j--) { + ll[i++] = l; + } + } else { + if (j == 17) { // 3 to 10 zero length codes + j = 3 + readBits(3); + } else { // j == 18: 11 to 138 zero length codes + j = 11 + readBits(7); + } + if (i + j > n) { + flushBuffer(); + return 1; + } + while (j--) { + ll[i++] = 0; + } + } + } + /*for(j=0; jliteralTree"); + outer: while (1) { + j = DecodeValue(literalTree); + if (j >= 256) { // In C64: if carry set + var len, dist; + j -= 256; + if (j == 0) { + // EOF + break; + } + j--; + len = readBits(cplext[j]) + cplens[j]; + + j = DecodeValue(distanceTree); + if (cpdext[j] > 8) { + dist = readBits(8); + dist |= (readBits(cpdext[j] - 8) << 8); + } else { + dist = readBits(cpdext[j]); + } + dist += cpdist[j]; + while (len--) { + if (bIdx - dist < 0) { + break outer; + } + var c = buf32k[(bIdx - dist) & 0x7fff]; + addBuffer(c); + } + } else { + addBuffer(j); + } + } + } + } while (!last); + flushBuffer(); + + byteAlign(); + return 0; + }; + + JXG.Util.Unzip.prototype.unzipFile = function(name) { + var i; + this.unzip(); + //alert(unzipped[0][1]); + for (i = 0; i < unzipped.length; i++) { + if (unzipped[i][1] == name) { + return unzipped[i][0]; + } + } + + }; + + JXG.Util.Unzip.prototype.deflate = function() { + outputArr = []; + var tmp = []; + modeZIP = false; + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "DEFLATE"; + files++; + return unzipped; + } + + JXG.Util.Unzip.prototype.unzip = function() { + //convertToByteArray(input); + if (debug) + alert(bA); + /*for (i=0;i"); + } + */ + //alert(bA); + nextFile(); + return unzipped; + }; + + function nextFile() { + if (debug) + alert("NEXTFILE"); + outputArr = []; + var tmp = []; + modeZIP = false; + tmp[0] = readByte(); + tmp[1] = readByte(); + if (debug) + alert("type: " + tmp[0] + " " + tmp[1]); + if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("da", 16)) { //GZIP + if (debug) + alert("GEONExT-GZIP"); + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "geonext.gxt"; + files++; + } + if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("9c", 16)) { //ZLIB + if (debug) + alert("ZLIB"); + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "ZLIB"; + files++; + } + if (tmp[0] == parseInt("1f", 16) && tmp[1] == parseInt("8b", 16)) { //GZIP + if (debug) + alert("GZIP"); + //DeflateLoop(); + skipdir(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = "file"; + files++; + } + if (tmp[0] == parseInt("50", 16) && tmp[1] == parseInt("4b", 16)) { //ZIP + modeZIP = true; + tmp[2] = readByte(); + tmp[3] = readByte(); + if (tmp[2] == parseInt("3", 16) && tmp[3] == parseInt("4", 16)) { + //MODE_ZIP + tmp[0] = readByte(); + tmp[1] = readByte(); + if (debug) + alert("ZIP-Version: " + tmp[1] + " " + tmp[0] / 10 + "." + tmp[0] % 10); + + gpflags = readByte(); + gpflags |= (readByte() << 8); + if (debug) + alert("gpflags: " + gpflags); + + var method = readByte(); + method |= (readByte() << 8); + if (debug) + alert("method: " + method); + + readByte(); + readByte(); + readByte(); + readByte(); + + var crc = readByte(); + crc |= (readByte() << 8); + crc |= (readByte() << 16); + crc |= (readByte() << 24); + + var compSize = readByte(); + compSize |= (readByte() << 8); + compSize |= (readByte() << 16); + compSize |= (readByte() << 24); + + var size = readByte(); + size |= (readByte() << 8); + size |= (readByte() << 16); + size |= (readByte() << 24); + + if (debug) + alert("local CRC: " + crc + "\nlocal Size: " + size + "\nlocal CompSize: " + compSize); + + var filelen = readByte(); + filelen |= (readByte() << 8); + + var extralen = readByte(); + extralen |= (readByte() << 8); + + if (debug) + alert("filelen " + filelen); + i = 0; + nameBuf = []; + while (filelen--) { + var c = readByte(); + if (c == "/" | c == ":") { + i = 0; + } else if (i < NAMEMAX - 1) + nameBuf[i++] = String.fromCharCode(c); + } + if (debug) + alert("nameBuf: " + nameBuf); + + //nameBuf[i] = "\0"; + if (!fileout) + fileout = nameBuf; + + var i = 0; + while (i < extralen) { + c = readByte(); + i++; + } + + CRC = 0xffffffff; + SIZE = 0; + + if (size == 0 && fileOut.charAt(fileout.length - 1) == "/") { + //skipdir + if (debug) + alert("skipdir"); + } + if (method == 8) { + DeflateLoop(); + if (debug) + alert(outputArr.join('')); + unzipped[files] = new Array(2); + unzipped[files][0] = outputArr.join(''); + unzipped[files][1] = nameBuf.join(''); + files++; + //return outputArr.join(''); + } + skipdir(); + } + } + }; + + function skipdir() { + var crc, + tmp = [], + compSize, size, os, i, c; + + if ((gpflags & 8)) { + tmp[0] = readByte(); + tmp[1] = readByte(); + tmp[2] = readByte(); + tmp[3] = readByte(); + + if (tmp[0] == parseInt("50", 16) && + tmp[1] == parseInt("4b", 16) && + tmp[2] == parseInt("07", 16) && + tmp[3] == parseInt("08", 16)) { + crc = readByte(); + crc |= (readByte() << 8); + crc |= (readByte() << 16); + crc |= (readByte() << 24); + } else { + crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24); + } + + compSize = readByte(); + compSize |= (readByte() << 8); + compSize |= (readByte() << 16); + compSize |= (readByte() << 24); + + size = readByte(); + size |= (readByte() << 8); + size |= (readByte() << 16); + size |= (readByte() << 24); + + if (debug) + alert("CRC:"); + } + + if (modeZIP) + nextFile(); + + tmp[0] = readByte(); + if (tmp[0] != 8) { + if (debug) + alert("Unknown compression method!"); + return 0; + } + + gpflags = readByte(); + if (debug) { + if ((gpflags & ~(parseInt("1f", 16)))) + alert("Unknown flags set!"); + } + + readByte(); + readByte(); + readByte(); + readByte(); + + readByte(); + os = readByte(); + + if ((gpflags & 4)) { + tmp[0] = readByte(); + tmp[2] = readByte(); + len = tmp[0] + 256 * tmp[1]; + if (debug) + alert("Extra field size: " + len); + for (i = 0; i < len; i++) + readByte(); + } + + if ((gpflags & 8)) { + i = 0; + nameBuf = []; + while (c = readByte()) { + if (c == "7" || c == ":") + i = 0; + if (i < NAMEMAX - 1) + nameBuf[i++] = c; + } + //nameBuf[i] = "\0"; + if (debug) + alert("original file name: " + nameBuf); + } + + if ((gpflags & 16)) { + while (c = readByte()) { + //FILE COMMENT + } + } + + if ((gpflags & 2)) { + readByte(); + readByte(); + } + + DeflateLoop(); + + crc = readByte(); + crc |= (readByte() << 8); + crc |= (readByte() << 16); + crc |= (readByte() << 24); + + size = readByte(); + size |= (readByte() << 8); + size |= (readByte() << 16); + size |= (readByte() << 24); + + if (modeZIP) + nextFile(); + + }; + +}; + +/** + * Base64 encoding / decoding + * {@link http://www.webtoolkit.info/} + */ +JXG.Util.Base64 = { + + // private property + _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + + // public method for encoding + encode: function(input) { + var output = [], + chr1, chr2, chr3, enc1, enc2, enc3, enc4, + i = 0; + + input = JXG.Util.Base64._utf8_encode(input); + + while (i < input.length) { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output.push([this._keyStr.charAt(enc1), + this._keyStr.charAt(enc2), + this._keyStr.charAt(enc3), + this._keyStr.charAt(enc4) + ].join('')); + } + + return output.join(''); + }, + + // public method for decoding + decode: function(input, utf8) { + var output = [], + chr1, chr2, chr3, + enc1, enc2, enc3, enc4, + i = 0; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + while (i < input.length) { + + enc1 = this._keyStr.indexOf(input.charAt(i++)); + enc2 = this._keyStr.indexOf(input.charAt(i++)); + enc3 = this._keyStr.indexOf(input.charAt(i++)); + enc4 = this._keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output.push(String.fromCharCode(chr1)); + + if (enc3 != 64) { + output.push(String.fromCharCode(chr2)); + } + if (enc4 != 64) { + output.push(String.fromCharCode(chr3)); + } + } + + output = output.join(''); + + if (utf8) { + output = JXG.Util.Base64._utf8_decode(output); + } + return output; + + }, + + // private method for UTF-8 encoding + _utf8_encode: function(string) { + string = string.replace(/\r\n/g, "\n"); + var utftext = ""; + + for (var n = 0; n < string.length; n++) { + + var c = string.charCodeAt(n); + + if (c < 128) { + utftext += String.fromCharCode(c); + } else if ((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + + return utftext; + }, + + // private method for UTF-8 decoding + _utf8_decode: function(utftext) { + var string = [], + i = 0, + c = 0, + c2 = 0, + c3 = 0; + + while (i < utftext.length) { + c = utftext.charCodeAt(i); + if (c < 128) { + string.push(String.fromCharCode(c)); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i + 1); + string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63))); + i += 2; + } else { + c2 = utftext.charCodeAt(i + 1); + c3 = utftext.charCodeAt(i + 2); + string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); + i += 3; + } + } + return string.join(''); + }, + + _destrip: function(stripped, wrap) { + var lines = [], + lineno, i, + destripped = []; + + if (wrap == null) + wrap = 76; + + stripped.replace(/ /g, ""); + lineno = stripped.length / wrap; + for (i = 0; i < lineno; i++) + lines[i] = stripped.substr(i * wrap, wrap); + if (lineno != stripped.length / wrap) + lines[lines.length] = stripped.substr(lineno * wrap, stripped.length - (lineno * wrap)); + + for (i = 0; i < lines.length; i++) + destripped.push(lines[i]); + return destripped.join('\n'); + }, + + decodeAsArray: function(input) { + var dec = this.decode(input), + ar = [], + i; + for (i = 0; i < dec.length; i++) { + ar[i] = dec.charCodeAt(i); + } + return ar; + }, + + decodeGEONExT: function(input) { + return decodeAsArray(destrip(input), false); + } +}; + +/** + * @private + */ +JXG.Util.asciiCharCodeAt = function(str, i) { + var c = str.charCodeAt(i); + if (c > 255) { + switch (c) { + case 8364: + c = 128; + break; + case 8218: + c = 130; + break; + case 402: + c = 131; + break; + case 8222: + c = 132; + break; + case 8230: + c = 133; + break; + case 8224: + c = 134; + break; + case 8225: + c = 135; + break; + case 710: + c = 136; + break; + case 8240: + c = 137; + break; + case 352: + c = 138; + break; + case 8249: + c = 139; + break; + case 338: + c = 140; + break; + case 381: + c = 142; + break; + case 8216: + c = 145; + break; + case 8217: + c = 146; + break; + case 8220: + c = 147; + break; + case 8221: + c = 148; + break; + case 8226: + c = 149; + break; + case 8211: + c = 150; + break; + case 8212: + c = 151; + break; + case 732: + c = 152; + break; + case 8482: + c = 153; + break; + case 353: + c = 154; + break; + case 8250: + c = 155; + break; + case 339: + c = 156; + break; + case 382: + c = 158; + break; + case 376: + c = 159; + break; + default: + break; + } + } + return c; +}; + +/** + * Decoding string into utf-8 + * @param {String} string to decode + * @return {String} utf8 decoded string + */ +JXG.Util.utf8Decode = function(utftext) { + var string = []; + var i = 0; + var c = 0, + c1 = 0, + c2 = 0, + c3; + if (!JXG.exists(utftext)) return ''; + + while (i < utftext.length) { + c = utftext.charCodeAt(i); + + if (c < 128) { + string.push(String.fromCharCode(c)); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i + 1); + string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63))); + i += 2; + } else { + c2 = utftext.charCodeAt(i + 1); + c3 = utftext.charCodeAt(i + 2); + string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); + i += 3; + } + }; + return string.join(''); +}; + +/** + * Generate a random uuid. + * http://www.broofa.com + * mailto:robert@broofa.com + * + * Copyright (c) 2010 Robert Kieffer + * Dual licensed under the MIT and GPL licenses. + * + * EXAMPLES: + * >>> Math.uuid() + * "92329D39-6F5C-4520-ABFC-AAB64544E172" + */ +JXG.Util.genUUID = function() { + // Private array of chars to use + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''), + uuid = new Array(36), + rnd = 0, + r; + + for (var i = 0; i < 36; i++) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + uuid[i] = '-'; + } else if (i == 14) { + uuid[i] = '4'; + } else { + if (rnd <= 0x02) rnd = 0x2000000 + (Math.random() * 0x1000000) | 0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + } + } + + return uuid.join(''); +}; + + +module.exports = JXG; diff --git a/src/config/config.js b/src/config/config.js new file mode 100644 index 00000000..8f38163e --- /dev/null +++ b/src/config/config.js @@ -0,0 +1,47 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * This object contains configuration values. + * @requires enums + * @property {Integer} prefer_hash_algorithm + * @property {Integer} encryption_cipher + * @property {Integer} compression + * @property {Boolean} show_version + * @property {Boolean} show_comment + * @property {Boolean} integrity_protect + * @property {String} keyserver + * @property {Boolean} debug If enabled, debug messages will be printed + * @module config/config + */ + +var enums = require('../enums.js'); + +module.exports = { + prefer_hash_algorithm: enums.hash.sha256, + encryption_cipher: enums.symmetric.aes256, + compression: enums.compression.zip, + show_version: true, + show_comment: true, + integrity_protect: true, + keyserver: "keyserver.linux.it", // "pgp.mit.edu:11371" + + versionstring: "OpenPGP.js VERSION", + commentstring: "http://openpgpjs.org", + + debug: false +}; diff --git a/src/config/localStorage.js b/src/config/localStorage.js new file mode 100644 index 00000000..b4ecb8b8 --- /dev/null +++ b/src/config/localStorage.js @@ -0,0 +1,31 @@ +/** + * This object storing and retrieving configuration from HTML5 local storage. + * @module config/localStorage + */ + +/** + * @constructor + */ +module.exports = function localStorage() { + + /** + * Reads the config out of the HTML5 local storage + * and initializes the object config. + * if config is null the default config will be used + */ + this.read = function () { + var cf = JSON.parse(window.localStorage.getItem("config")); + if (cf === null) { + this.config = this.default_config; + this.write(); + } else + this.config = cf; + } + + /** + * Writes the config to HTML5 local storage + */ + this.write = function () { + window.localStorage.setItem("config", JSON.stringify(this.config)); + } +} diff --git a/src/config/openpgp.config.js b/src/config/openpgp.config.js deleted file mode 100644 index 0da8dfdf..00000000 --- a/src/config/openpgp.config.js +++ /dev/null @@ -1,90 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * - * This object contains configuration values and implements - * storing and retrieving configuration them from HTML5 local storage. - * - * This object can be accessed after calling openpgp.init() - * using openpgp.config - * Stored config parameters can be accessed using - * openpgp.config.config - * @class - * @classdesc Implementation of the GPG4Browsers config object - */ -function openpgp_config() { - /** - * The variable with the actual configuration - * @property {Integer} prefer_hash_algorithm - * @property {Integer} encryption_cipher - * @property {Integer} compression - * @property {Boolean} show_version - * @property {Boolean} show_comment - * @property {Boolean} integrity_protect - * @property {Integer} composition_behavior - * @property {String} keyserver - */ - this.config = null; - - /** - * The default config object which is used if no - * configuration was in place - */ - this.default_config = { - prefer_hash_algorithm: 8, - encryption_cipher: 9, - compression: 1, - show_version: true, - show_comment: true, - integrity_protect: true, - composition_behavior: 0, - keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371" - }; - - this.versionstring ="OpenPGP.js VERSION"; - this.commentstring ="http://openpgpjs.org"; - /** - * Reads the config out of the HTML5 local storage - * and initializes the object config. - * if config is null the default config will be used - */ - function read() { - var cf = JSON.parse(window.localStorage.getItem("config")); - if (cf == null) { - this.config = this.default_config; - this.write(); - } - else - this.config = cf; - } - - /** - * If enabled, debug messages will be printed - */ - this.debug = false; - - /** - * Writes the config to HTML5 local storage - */ - function write() { - window.localStorage.setItem("config",JSON.stringify(this.config)); - } - - this.read = read; - this.write = write; -} diff --git a/src/config/package.json b/src/config/package.json new file mode 100644 index 00000000..6e46f15d --- /dev/null +++ b/src/config/package.json @@ -0,0 +1,5 @@ +{ + "name": "openpgp-config", + "version": "0.0.1", + "main": "./config.js" +} diff --git a/src/crypto/cfb.js b/src/crypto/cfb.js new file mode 100644 index 00000000..a2147782 --- /dev/null +++ b/src/crypto/cfb.js @@ -0,0 +1,299 @@ +// Modified by Recurity Labs GmbH + +// modified version of http://www.hanewin.net/encrypt/PGdecode.js: + +/* OpenPGP encryption using RSA/AES + * Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de + * version 2.0, check www.haneWIN.de for the latest version + + * This software is provided as-is, without express or implied warranty. + * Permission to use, copy, modify, distribute or sell this software, with or + * without fee, for any purpose and by any individual or organization, is hereby + * granted, provided that the above copyright notice and this paragraph appear + * in all copies. Distribution as a part of an application or binary must + * include the above copyright notice in the documentation and/or other + * materials provided with the application or distribution. + */ + +/** + * @requires crypto/cipher + * @requires util + * @module crypto/cfb + */ + +var util = require('../util'), + cipher = require('./cipher'); + +module.exports = { + + /** + * This function encrypts a given with the specified prefixrandom + * using the specified blockcipher to encrypt a message + * @param {String} prefixrandom random bytes of block_size length provided + * as a string to be used in prefixing the data + * @param {String} cipherfn the algorithm cipher class to encrypt + * data in one block_size encryption, @see module:crypto/cipher. + * @param {String} plaintext data to be encrypted provided as a string + * @param {String} key binary string representation of key to be used to encrypt the plaintext. + * This will be passed to the cipherfn + * @param {Boolean} resync a boolean value specifying if a resync of the + * IV should be used or not. The encrypteddatapacket uses the + * "old" style with a resync. Encryption within an + * encryptedintegrityprotecteddata packet is not resyncing the IV. + * @return {String} a string with the encrypted data + */ + encrypt: function(prefixrandom, cipherfn, plaintext, key, resync) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var FR = new Array(block_size); + var FRE = new Array(block_size); + + prefixrandom = prefixrandom + prefixrandom.charAt(block_size - 2) + prefixrandom.charAt(block_size - 1); + util.print_debug("prefixrandom:" + util.hexstrdump(prefixrandom)); + var ciphertext = ""; + // 1. The feedback register (FR) is set to the IV, which is all zeros. + for (var i = 0; i < block_size; i++) FR[i] = 0; + + // 2. FR is encrypted to produce FRE (FR Encrypted). This is the + // encryption of an all-zero value. + FRE = cipherfn.encrypt(FR); + // 3. FRE is xored with the first BS octets of random data prefixed to + // the plaintext to produce C[1] through C[BS], the first BS octets + // of ciphertext. + for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i)); + + // 4. FR is loaded with C[1] through C[BS]. + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); + + // 5. FR is encrypted to produce FRE, the encryption of the first BS + // octets of ciphertext. + FRE = cipherfn.encrypt(FR); + + // 6. The left two octets of FRE get xored with the next two octets of + // data that were prefixed to the plaintext. This produces C[BS+1] + // and C[BS+2], the next two octets of ciphertext. + ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size)); + ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size + 1)); + + if (resync) { + // 7. (The resync step) FR is loaded with C3-C10. + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i + 2); + } else { + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i); + } + // 8. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR, key); + + if (resync) { + // 9. FRE is xored with the first 8 octets of the given plaintext, now + // that we have finished encrypting the 10 octets of prefixed data. + // This produces C11-C18, the next 8 octets of ciphertext. + for (var i = 0; i < block_size; i++) + ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); + for (n = block_size + 2; n < plaintext.length; n += block_size) { + // 10. FR is loaded with C11-C18 + for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n + i); + + // 11. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR); + + // 12. FRE is xored with the next 8 octets of plaintext, to produce the + // next 8 octets of ciphertext. These are loaded into FR and the + // process is repeated until the plaintext is used up. + for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n - 2) + + i)); + } + } else { + plaintext = " " + plaintext; + // 9. FRE is xored with the first 8 octets of the given plaintext, now + // that we have finished encrypting the 10 octets of prefixed data. + // This produces C11-C18, the next 8 octets of ciphertext. + for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i)); + var tempCiphertext = ciphertext.substring(0, 2 * block_size).split(''); + var tempCiphertextString = ciphertext.substring(block_size); + for (n = block_size; n < plaintext.length; n += block_size) { + // 10. FR is loaded with C11-C18 + for (var i = 0; i < block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i); + tempCiphertextString = ''; + + // 11. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR); + + // 12. FRE is xored with the next 8 octets of plaintext, to produce the + // next 8 octets of ciphertext. These are loaded into FR and the + // process is repeated until the plaintext is used up. + for (var i = 0; i < block_size; i++) { + tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i))); + tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i)); + } + } + ciphertext = tempCiphertext.join(''); + + } + + ciphertext = ciphertext.substring(0, plaintext.length + 2 + block_size); + + return ciphertext; + }, + + /** + * Decrypts the prefixed data for the Modification Detection Code (MDC) computation + * @param {String} cipherfn.encrypt Cipher function to use, + * @see module:crypto/cipher. + * @param {String} key binary string representation of key to be used to check the mdc + * This will be passed to the cipherfn + * @param {String} ciphertext The encrypted data + * @return {String} plaintext Data of D(ciphertext) with blocksize length +2 + */ + mdc: function(cipherfn, key, ciphertext) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var iblock = new Array(block_size); + var ablock = new Array(block_size); + var i; + + + // initialisation vector + for (i = 0; i < block_size; i++) iblock[i] = 0; + + iblock = cipherfn.encrypt(iblock); + for (i = 0; i < block_size; i++) { + ablock[i] = ciphertext.charCodeAt(i); + iblock[i] ^= ablock[i]; + } + + ablock = cipherfn.encrypt(ablock); + + return util.bin2str(iblock) + + String.fromCharCode(ablock[0] ^ ciphertext.charCodeAt(block_size)) + + String.fromCharCode(ablock[1] ^ ciphertext.charCodeAt(block_size + 1)); + }, + /** + * This function decrypts a given plaintext using the specified + * blockcipher to decrypt a message + * @param {String} cipherfn the algorithm cipher class to decrypt + * data in one block_size encryption, @see module:crypto/cipher. + * @param {String} key binary string representation of key to be used to decrypt the ciphertext. + * This will be passed to the cipherfn + * @param {String} ciphertext to be decrypted provided as a string + * @param {Boolean} resync a boolean value specifying if a resync of the + * IV should be used or not. The encrypteddatapacket uses the + * "old" style with a resync. Decryption within an + * encryptedintegrityprotecteddata packet is not resyncing the IV. + * @return {String} a string with the plaintext data + */ + + decrypt: function(cipherfn, key, ciphertext, resync) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var iblock = new Array(block_size); + var ablock = new Array(block_size); + var i, n = ''; + var text = []; + + // initialisation vector + for (i = 0; i < block_size; i++) iblock[i] = 0; + + iblock = cipherfn.encrypt(iblock, key); + for (i = 0; i < block_size; i++) { + ablock[i] = ciphertext.charCodeAt(i); + iblock[i] ^= ablock[i]; + } + + ablock = cipherfn.encrypt(ablock, key); + + // test check octets + if (iblock[block_size - 2] != (ablock[0] ^ ciphertext.charCodeAt(block_size)) || iblock[block_size - 1] != (ablock[ + 1] ^ ciphertext.charCodeAt(block_size + 1))) { + throw new Error('Invalid data.'); + } + + /* RFC4880: Tag 18 and Resync: + * [...] Unlike the Symmetrically Encrypted Data Packet, no + * special CFB resynchronization is done after encrypting this prefix + * data. See "OpenPGP CFB Mode" below for more details. + + */ + + if (resync) { + for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i + 2); + for (n = block_size + 2; n < ciphertext.length; n += block_size) { + ablock = cipherfn.encrypt(iblock); + + for (i = 0; i < block_size && i + n < ciphertext.length; i++) { + iblock[i] = ciphertext.charCodeAt(n + i); + text.push(String.fromCharCode(ablock[i] ^ iblock[i])); + } + } + } else { + for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i); + for (n = block_size; n < ciphertext.length; n += block_size) { + ablock = cipherfn.encrypt(iblock); + for (i = 0; i < block_size && i + n < ciphertext.length; i++) { + iblock[i] = ciphertext.charCodeAt(n + i); + text.push(String.fromCharCode(ablock[i] ^ iblock[i])); + } + } + } + + var n = resync ? 0 : 2; + + text = text.join(''); + + text = text.substring(n, ciphertext.length - block_size - 2 + n); + + + return text; + }, + + + normalEncrypt: function(cipherfn, key, plaintext, iv) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var blocki = ""; + var blockc = ""; + var pos = 0; + var cyphertext = []; + var tempBlock = []; + blockc = iv.substring(0, block_size); + while (plaintext.length > block_size * pos) { + var encblock = cipherfn.encrypt(util.str2bin(blockc)); + blocki = plaintext.substring((pos * block_size), (pos * block_size) + block_size); + for (var i = 0; i < blocki.length; i++) + tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i])); + blockc = tempBlock.join(''); + tempBlock = []; + cyphertext.push(blockc); + pos++; + } + return cyphertext.join(''); + }, + + normalDecrypt: function(cipherfn, key, ciphertext, iv) { + cipherfn = new cipher[cipherfn](key); + var block_size = cipherfn.blockSize; + + var blockp = ""; + var pos = 0; + var plaintext = []; + var offset = 0; + if (iv == null) + for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0); + else + blockp = iv.substring(0, block_size); + while (ciphertext.length > (block_size * pos)) { + var decblock = cipherfn.encrypt(util.str2bin(blockp)); + blockp = ciphertext.substring((pos * (block_size)) + offset, (pos * (block_size)) + (block_size) + offset); + for (var i = 0; i < blockp.length; i++) { + plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i])); + } + pos++; + } + + return plaintext.join(''); + } +} diff --git a/src/crypto/cipher/aes.js b/src/crypto/cipher/aes.js new file mode 100644 index 00000000..a8f6e6cd --- /dev/null +++ b/src/crypto/cipher/aes.js @@ -0,0 +1,511 @@ +/* Rijndael (AES) Encryption + * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de + * version 1.1, check www.haneWIN.de for the latest version + + * This software is provided as-is, without express or implied warranty. + * Permission to use, copy, modify, distribute or sell this software, with or + * without fee, for any purpose and by any individual or organization, is hereby + * granted, provided that the above copyright notice and this paragraph appear + * in all copies. Distribution as a part of an application or binary must + * include the above copyright notice in the documentation and/or other + * materials provided with the application or distribution. + */ + +/** + * @requires util + * @module crypto/cipher/aes + */ + +var util = require('../../util'); + +// The round constants used in subkey expansion +var Rcon = [ + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, + 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 +]; + +// Precomputed lookup table for the SBox +var S = [ + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, + 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, + 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, + 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, + 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, + 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, + 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, + 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, + 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, + 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, + 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, + 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, + 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, + 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, + 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, + 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, + 22 +]; + +var T1 = [ + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, + 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, + 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, + 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, + 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, + 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, + 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, + 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, + 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, + 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, + 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, + 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, + 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, + 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, + 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, + 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, + 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, + 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, + 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, + 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, + 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, + 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, + 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, + 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, + 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, + 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, + 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, + 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, + 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, + 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, + 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, + 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, + 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, + 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, + 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, + 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, + 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, + 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, + 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, + 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, + 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, + 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, + 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, + 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, + 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, + 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, + 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, + 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, + 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, + 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, + 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, + 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, + 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, + 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, + 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, + 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, + 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, + 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c +]; + +var T2 = [ + 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, + 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, + 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, + 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, + 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, + 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, + 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, + 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, + 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, + 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, + 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, + 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, + 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, + 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, + 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, + 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, + 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, + 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, + 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, + 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, + 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, + 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, + 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, + 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, + 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, + 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, + 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, + 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, + 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, + 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, + 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, + 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, + 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, + 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, + 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, + 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, + 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, + 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, + 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, + 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, + 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, + 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, + 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, + 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, + 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, + 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, + 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, + 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, + 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, + 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, + 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, + 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, + 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, + 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, + 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, + 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, + 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, + 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, + 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, + 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, + 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, + 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, + 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, + 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a +]; + +var T3 = [ + 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, + 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, + 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, + 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, + 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, + 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, + 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, + 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, + 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, + 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, + 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, + 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, + 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, + 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, + 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, + 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, + 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, + 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, + 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, + 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, + 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, + 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, + 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, + 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, + 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, + 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, + 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, + 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, + 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, + 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, + 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, + 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, + 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, + 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, + 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, + 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, + 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, + 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, + 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, + 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, + 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, + 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, + 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, + 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, + 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, + 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, + 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, + 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, + 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, + 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, + 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, + 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, + 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, + 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, + 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, + 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, + 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, + 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, + 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, + 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, + 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, + 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, + 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, + 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16 +]; + +var T4 = [ + 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, + 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, + 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, + 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, + 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, + 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, + 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, + 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, + 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, + 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, + 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, + 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, + 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, + 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, + 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, + 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, + 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, + 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, + 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, + 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, + 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, + 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, + 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, + 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, + 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, + 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, + 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, + 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, + 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, + 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, + 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, + 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, + 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, + 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, + 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, + 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, + 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, + 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, + 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, + 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, + 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, + 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, + 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, + 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, + 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, + 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, + 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, + 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, + 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, + 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, + 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, + 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, + 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, + 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, + 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, + 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, + 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, + 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, + 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, + 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, + 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, + 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, + 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, + 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 +]; + +function B0(x) { + return (x & 255); +} + +function B1(x) { + return ((x >> 8) & 255); +} + +function B2(x) { + return ((x >> 16) & 255); +} + +function B3(x) { + return ((x >> 24) & 255); +} + +function F1(x0, x1, x2, x3) { + return B1(T1[x0 & 255]) | (B1(T1[(x1 >> 8) & 255]) << 8) | (B1(T1[(x2 >> 16) & 255]) << 16) | (B1(T1[x3 >>> 24]) << + 24); +} + +function packBytes(octets) { + var i, j; + var len = octets.length; + var b = new Array(len / 4); + + if (!octets || len % 4) return; + + for (i = 0, j = 0; j < len; j += 4) + b[i++] = octets[j] | (octets[j + 1] << 8) | (octets[j + 2] << 16) | (octets[j + 3] << 24); + + return b; +} + +function unpackBytes(packed) { + var j; + var i = 0, + l = packed.length; + var r = new Array(l * 4); + + for (j = 0; j < l; j++) { + r[i++] = B0(packed[j]); + r[i++] = B1(packed[j]); + r[i++] = B2(packed[j]); + r[i++] = B3(packed[j]); + } + return r; +} + +// ------------------------------------------------ + +var maxkc = 8; +var maxrk = 14; + +function keyExpansion(key) { + var kc, i, j, r, t; + var rounds; + var keySched = new Array(maxrk + 1); + var keylen = key.length; + var k = new Array(maxkc); + var tk = new Array(maxkc); + var rconpointer = 0; + + if (keylen == 16) { + rounds = 10; + kc = 4; + } else if (keylen == 24) { + rounds = 12; + kc = 6; + } else if (keylen == 32) { + rounds = 14; + kc = 8; + } else { + throw new Error('Invalid key-length for AES key:' + keylen); + } + + for (i = 0; i < maxrk + 1; i++) keySched[i] = new Array(4); + + for (i = 0, j = 0; j < keylen; j++, i += 4) + k[j] = key.charCodeAt(i) | (key.charCodeAt(i + 1) << 8) | (key.charCodeAt(i + 2) << 16) | (key.charCodeAt(i + 3) << + 24); + + for (j = kc - 1; j >= 0; j--) tk[j] = k[j]; + + r = 0; + t = 0; + for (j = 0; + (j < kc) && (r < rounds + 1);) { + for (; + (j < kc) && (t < 4); j++, t++) { + keySched[r][t] = tk[j]; + } + if (t == 4) { + r++; + t = 0; + } + } + + while (r < rounds + 1) { + var temp = tk[kc - 1]; + + tk[0] ^= S[B1(temp)] | (S[B2(temp)] << 8) | (S[B3(temp)] << 16) | (S[B0(temp)] << 24); + tk[0] ^= Rcon[rconpointer++]; + + if (kc != 8) { + for (j = 1; j < kc; j++) tk[j] ^= tk[j - 1]; + } else { + for (j = 1; j < kc / 2; j++) tk[j] ^= tk[j - 1]; + + temp = tk[kc / 2 - 1]; + tk[kc / 2] ^= S[B0(temp)] | (S[B1(temp)] << 8) | (S[B2(temp)] << 16) | (S[B3(temp)] << 24); + + for (j = kc / 2 + 1; j < kc; j++) tk[j] ^= tk[j - 1]; + } + + for (j = 0; + (j < kc) && (r < rounds + 1);) { + for (; + (j < kc) && (t < 4); j++, t++) { + keySched[r][t] = tk[j]; + } + if (t == 4) { + r++; + t = 0; + } + } + } + this.rounds = rounds; + this.rk = keySched; + return this; +} + +function AESencrypt(block, ctx) { + var r; + var t0, t1, t2, t3; + + var b = packBytes(block); + var rounds = ctx.rounds; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var b3 = b[3]; + + for (r = 0; r < rounds - 1; r++) { + t0 = b0 ^ ctx.rk[r][0]; + t1 = b1 ^ ctx.rk[r][1]; + t2 = b2 ^ ctx.rk[r][2]; + t3 = b3 ^ ctx.rk[r][3]; + + b0 = T1[t0 & 255] ^ T2[(t1 >> 8) & 255] ^ T3[(t2 >> 16) & 255] ^ T4[t3 >>> 24]; + b1 = T1[t1 & 255] ^ T2[(t2 >> 8) & 255] ^ T3[(t3 >> 16) & 255] ^ T4[t0 >>> 24]; + b2 = T1[t2 & 255] ^ T2[(t3 >> 8) & 255] ^ T3[(t0 >> 16) & 255] ^ T4[t1 >>> 24]; + b3 = T1[t3 & 255] ^ T2[(t0 >> 8) & 255] ^ T3[(t1 >> 16) & 255] ^ T4[t2 >>> 24]; + } + + // last round is special + r = rounds - 1; + + t0 = b0 ^ ctx.rk[r][0]; + t1 = b1 ^ ctx.rk[r][1]; + t2 = b2 ^ ctx.rk[r][2]; + t3 = b3 ^ ctx.rk[r][3]; + + b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0]; + b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1]; + b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2]; + b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3]; + + return unpackBytes(b); +} + +function makeClass(length) { + + var c = function(key) { + this.key = keyExpansion(key); + + this.encrypt = function(block) { + return AESencrypt(block, this.key); + } + } + + c.blockSize = c.prototype.blockSize = 16; + c.keySize = c.prototype.keySize = length / 8; + + return c; +} + +module.exports = {} + +var types = [128, 192, 256]; + +for (var i in types) { + module.exports[types[i]] = makeClass(types[i]); +} diff --git a/src/crypto/cipher/blowfish.js b/src/crypto/cipher/blowfish.js new file mode 100644 index 00000000..f6d2445d --- /dev/null +++ b/src/crypto/cipher/blowfish.js @@ -0,0 +1,416 @@ +/* Modified by Recurity Labs GmbH + * + * Originally written by nklein software (nklein.com) + */ + +/** + * @module crypto/cipher/blowfish + */ + +/* + * Javascript implementation based on Bruce Schneier's reference implementation. + * + * + * The constructor doesn't do much of anything. It's just here + * so we can start defining properties and methods and such. + */ +function Blowfish() {}; + +/* + * Declare the block size so that protocols know what size + * Initialization Vector (IV) they will need. + */ +Blowfish.prototype.BLOCKSIZE = 8; + +/* + * These are the default SBOXES. + */ +Blowfish.prototype.SBOXES = [ + [ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, + 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, + 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, + 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, + 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, + 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, + 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, + 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, + 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, + 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, + 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, + 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, + 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, + 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, + 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, + 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, + 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, + 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, + 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, + 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, + 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, + 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + ], + [ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, + 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, + 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, + 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, + 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, + 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, + 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, + 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, + 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, + 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, + 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, + 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, + 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, + 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, + 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, + 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, + 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, + 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, + 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, + 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, + 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, + 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + ], + [ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, + 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, + 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, + 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, + 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, + 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, + 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, + 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, + 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, + 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, + 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, + 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, + 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, + 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, + 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, + 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, + 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, + 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, + 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, + 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, + 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, + 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + ], + [ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, + 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, + 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, + 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, + 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, + 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, + 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, + 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, + 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, + 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, + 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, + 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, + 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, + 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, + 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, + 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, + 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, + 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, + 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, + 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, + 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, + 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + ] +]; + +//* +//* This is the default PARRAY +//* +Blowfish.prototype.PARRAY = [ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b +]; + +//* +//* This is the number of rounds the cipher will go +//* +Blowfish.prototype.NN = 16; + +//* +//* This function is needed to get rid of problems +//* with the high-bit getting set. If we don't do +//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not +//* equal to ( bb & 0x00FFFFFFFF ) even when they +//* agree bit-for-bit for the first 32 bits. +//* +Blowfish.prototype._clean = function(xx) { + if (xx < 0) { + var yy = xx & 0x7FFFFFFF; + xx = yy + 0x80000000; + } + return xx; +}; + +//* +//* This is the mixing function that uses the sboxes +//* +Blowfish.prototype._F = function(xx) { + var aa; + var bb; + var cc; + var dd; + var yy; + + dd = xx & 0x00FF; + xx >>>= 8; + cc = xx & 0x00FF; + xx >>>= 8; + bb = xx & 0x00FF; + xx >>>= 8; + aa = xx & 0x00FF; + + yy = this.sboxes[0][aa] + this.sboxes[1][bb]; + yy = yy ^ this.sboxes[2][cc]; + yy = yy + this.sboxes[3][dd]; + + return yy; +}; + +//* +//* This method takes an array with two values, left and right +//* and does NN rounds of Blowfish on them. +//* +Blowfish.prototype._encrypt_block = function(vals) { + var dataL = vals[0]; + var dataR = vals[1]; + + var ii; + + for (ii = 0; ii < this.NN; ++ii) { + dataL = dataL ^ this.parray[ii]; + dataR = this._F(dataL) ^ dataR; + + var tmp = dataL; + dataL = dataR; + dataR = tmp; + } + + dataL = dataL ^ this.parray[this.NN + 0]; + dataR = dataR ^ this.parray[this.NN + 1]; + + vals[0] = this._clean(dataR); + vals[1] = this._clean(dataL); +}; + +//* +//* This method takes a vector of numbers and turns them +//* into long words so that they can be processed by the +//* real algorithm. +//* +//* Maybe I should make the real algorithm above take a vector +//* instead. That will involve more looping, but it won't require +//* the F() method to deconstruct the vector. +//* +Blowfish.prototype.encrypt_block = function(vector) { + var ii; + var vals = [0, 0]; + var off = this.BLOCKSIZE / 2; + for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) { + vals[0] = (vals[0] << 8) | (vector[ii + 0] & 0x00FF); + vals[1] = (vals[1] << 8) | (vector[ii + off] & 0x00FF); + } + + this._encrypt_block(vals); + + var ret = []; + for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) { + ret[ii + 0] = (vals[0] >>> (24 - 8 * (ii)) & 0x00FF); + ret[ii + off] = (vals[1] >>> (24 - 8 * (ii)) & 0x00FF); + // vals[ 0 ] = ( vals[ 0 ] >>> 8 ); + // vals[ 1 ] = ( vals[ 1 ] >>> 8 ); + } + + return ret; +}; + +//* +//* This method takes an array with two values, left and right +//* and undoes NN rounds of Blowfish on them. +//* +Blowfish.prototype._decrypt_block = function(vals) { + var dataL = vals[0]; + var dataR = vals[1]; + + var ii; + + for (ii = this.NN + 1; ii > 1; --ii) { + dataL = dataL ^ this.parray[ii]; + dataR = this._F(dataL) ^ dataR; + + var tmp = dataL; + dataL = dataR; + dataR = tmp; + } + + dataL = dataL ^ this.parray[1]; + dataR = dataR ^ this.parray[0]; + + vals[0] = this._clean(dataR); + vals[1] = this._clean(dataL); +}; + +//* +//* This method takes a key array and initializes the +//* sboxes and parray for this encryption. +//* +Blowfish.prototype.init = function(key) { + var ii; + var jj = 0; + + this.parray = []; + for (ii = 0; ii < this.NN + 2; ++ii) { + var data = 0x00000000; + var kk; + for (kk = 0; kk < 4; ++kk) { + data = (data << 8) | (key[jj] & 0x00FF); + if (++jj >= key.length) { + jj = 0; + } + } + this.parray[ii] = this.PARRAY[ii] ^ data; + } + + this.sboxes = []; + for (ii = 0; ii < 4; ++ii) { + this.sboxes[ii] = []; + for (jj = 0; jj < 256; ++jj) { + this.sboxes[ii][jj] = this.SBOXES[ii][jj]; + } + } + + var vals = [0x00000000, 0x00000000]; + + for (ii = 0; ii < this.NN + 2; ii += 2) { + this._encrypt_block(vals); + this.parray[ii + 0] = vals[0]; + this.parray[ii + 1] = vals[1]; + } + + for (ii = 0; ii < 4; ++ii) { + for (jj = 0; jj < 256; jj += 2) { + this._encrypt_block(vals); + this.sboxes[ii][jj + 0] = vals[0]; + this.sboxes[ii][jj + 1] = vals[1]; + } + } +}; + +var util = require('../../util'); + +// added by Recurity Labs + +function BFencrypt(block, key) { + var bf = new Blowfish(); + bf.init(util.str2bin(key)); + return bf.encrypt_block(block); +} + +function BF(key) { + this.bf = new Blowfish(); + this.bf.init(util.str2bin(key)); + + this.encrypt = function(block) { + return this.bf.encrypt_block(block); + } +} + + +module.exports = BF; +module.exports.keySize = BF.prototype.keySize = 16; +module.exports.blockSize = BF.prototype.blockSize = 16; diff --git a/src/crypto/cipher/cast5.js b/src/crypto/cipher/cast5.js new file mode 100644 index 00000000..782083d6 --- /dev/null +++ b/src/crypto/cipher/cast5.js @@ -0,0 +1,605 @@ +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Copyright 2010 pjacobs@xeekr.com . All rights reserved. + +// Modified by Recurity Labs GmbH + +// fixed/modified by Herbert Hanewinkel, www.haneWIN.de +// check www.haneWIN.de for the latest version + +// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144. +// CAST-128 is a common OpenPGP cipher. + + +// CAST5 constructor + +/** @module crypto/cipher/cast5 */ + + + +function openpgp_symenc_cast5() { + this.BlockSize = 8; + this.KeySize = 16; + + this.setKey = function(key) { + this.masking = new Array(16); + this.rotate = new Array(16); + + this.reset(); + + if (key.length == this.KeySize) { + this.keySchedule(key); + } else { + throw new Error('CAST-128: keys must be 16 bytes'); + } + return true; + }; + + this.reset = function() { + for (var i = 0; i < 16; i++) { + this.masking[i] = 0; + this.rotate[i] = 0; + } + }; + + this.getBlockSize = function() { + return BlockSize; + }; + + this.encrypt = function(src) { + var dst = new Array(src.length); + + for (var i = 0; i < src.length; i += 8) { + var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3]; + var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7]; + var t; + + t = r; + r = l ^ f1(r, this.masking[0], this.rotate[0]); + l = t; + t = r; + r = l ^ f2(r, this.masking[1], this.rotate[1]); + l = t; + t = r; + r = l ^ f3(r, this.masking[2], this.rotate[2]); + l = t; + t = r; + r = l ^ f1(r, this.masking[3], this.rotate[3]); + l = t; + + t = r; + r = l ^ f2(r, this.masking[4], this.rotate[4]); + l = t; + t = r; + r = l ^ f3(r, this.masking[5], this.rotate[5]); + l = t; + t = r; + r = l ^ f1(r, this.masking[6], this.rotate[6]); + l = t; + t = r; + r = l ^ f2(r, this.masking[7], this.rotate[7]); + l = t; + + t = r; + r = l ^ f3(r, this.masking[8], this.rotate[8]); + l = t; + t = r; + r = l ^ f1(r, this.masking[9], this.rotate[9]); + l = t; + t = r; + r = l ^ f2(r, this.masking[10], this.rotate[10]); + l = t; + t = r; + r = l ^ f3(r, this.masking[11], this.rotate[11]); + l = t; + + t = r; + r = l ^ f1(r, this.masking[12], this.rotate[12]); + l = t; + t = r; + r = l ^ f2(r, this.masking[13], this.rotate[13]); + l = t; + t = r; + r = l ^ f3(r, this.masking[14], this.rotate[14]); + l = t; + t = r; + r = l ^ f1(r, this.masking[15], this.rotate[15]); + l = t; + + dst[i] = (r >>> 24) & 255; + dst[i + 1] = (r >>> 16) & 255; + dst[i + 2] = (r >>> 8) & 255; + dst[i + 3] = r & 255; + dst[i + 4] = (l >>> 24) & 255; + dst[i + 5] = (l >>> 16) & 255; + dst[i + 6] = (l >>> 8) & 255; + dst[i + 7] = l & 255; + } + + return dst; + }; + + this.decrypt = function(src) { + var dst = new Array(src.length); + + for (var i = 0; i < src.length; i += 8) { + var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3]; + var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7]; + var t; + + t = r; + r = l ^ f1(r, this.masking[15], this.rotate[15]); + l = t; + t = r; + r = l ^ f3(r, this.masking[14], this.rotate[14]); + l = t; + t = r; + r = l ^ f2(r, this.masking[13], this.rotate[13]); + l = t; + t = r; + r = l ^ f1(r, this.masking[12], this.rotate[12]); + l = t; + + t = r; + r = l ^ f3(r, this.masking[11], this.rotate[11]); + l = t; + t = r; + r = l ^ f2(r, this.masking[10], this.rotate[10]); + l = t; + t = r; + r = l ^ f1(r, this.masking[9], this.rotate[9]); + l = t; + t = r; + r = l ^ f3(r, this.masking[8], this.rotate[8]); + l = t; + + t = r; + r = l ^ f2(r, this.masking[7], this.rotate[7]); + l = t; + t = r; + r = l ^ f1(r, this.masking[6], this.rotate[6]); + l = t; + t = r; + r = l ^ f3(r, this.masking[5], this.rotate[5]); + l = t; + t = r; + r = l ^ f2(r, this.masking[4], this.rotate[4]); + l = t; + + t = r; + r = l ^ f1(r, this.masking[3], this.rotate[3]); + l = t; + t = r; + r = l ^ f3(r, this.masking[2], this.rotate[2]); + l = t; + t = r; + r = l ^ f2(r, this.masking[1], this.rotate[1]); + l = t; + t = r; + r = l ^ f1(r, this.masking[0], this.rotate[0]); + l = t; + + dst[i] = (r >>> 24) & 255; + dst[i + 1] = (r >>> 16) & 255; + dst[i + 2] = (r >>> 8) & 255; + dst[i + 3] = r & 255; + dst[i + 4] = (l >>> 24) & 255; + dst[i + 5] = (l >> 16) & 255; + dst[i + 6] = (l >> 8) & 255; + dst[i + 7] = l & 255; + } + + return dst; + }; + var scheduleA = new Array(4); + + scheduleA[0] = new Array(4); + scheduleA[0][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 0x8); + scheduleA[0][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); + scheduleA[0][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); + scheduleA[0][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); + + scheduleA[1] = new Array(4); + scheduleA[1][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); + scheduleA[1][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); + scheduleA[1][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); + scheduleA[1][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); + + scheduleA[2] = new Array(4); + scheduleA[2][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 8); + scheduleA[2][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa); + scheduleA[2][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9); + scheduleA[2][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb); + + + scheduleA[3] = new Array(4); + scheduleA[3][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0); + scheduleA[3][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2); + scheduleA[3][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1); + scheduleA[3][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3); + + var scheduleB = new Array(4); + + scheduleB[0] = new Array(4); + scheduleB[0][0] = new Array(16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2); + scheduleB[0][1] = new Array(16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6); + scheduleB[0][2] = new Array(16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9); + scheduleB[0][3] = new Array(16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc); + + scheduleB[1] = new Array(4); + scheduleB[1][0] = new Array(3, 2, 0xc, 0xd, 8); + scheduleB[1][1] = new Array(1, 0, 0xe, 0xf, 0xd); + scheduleB[1][2] = new Array(7, 6, 8, 9, 3); + scheduleB[1][3] = new Array(5, 4, 0xa, 0xb, 7); + + + scheduleB[2] = new Array(4); + scheduleB[2][0] = new Array(16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9); + scheduleB[2][1] = new Array(16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc); + scheduleB[2][2] = new Array(16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2); + scheduleB[2][3] = new Array(16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6); + + + scheduleB[3] = new Array(4); + scheduleB[3][0] = new Array(8, 9, 7, 6, 3); + scheduleB[3][1] = new Array(0xa, 0xb, 5, 4, 7); + scheduleB[3][2] = new Array(0xc, 0xd, 3, 2, 8); + scheduleB[3][3] = new Array(0xe, 0xf, 1, 0, 0xd); + + // changed 'in' to 'inn' (in javascript 'in' is a reserved word) + this.keySchedule = function(inn) { + var t = new Array(8); + var k = new Array(32); + + for (var i = 0; i < 4; i++) { + var j = i * 4; + t[i] = inn[j] << 24 | inn[j + 1] << 16 | inn[j + 2] << 8 | inn[j + 3]; + } + + var x = [6, 7, 4, 5]; + var ki = 0; + + for (var half = 0; half < 2; half++) { + for (var round = 0; round < 4; round++) { + for (var j = 0; j < 4; j++) { + var a = scheduleA[round][j]; + var w = t[a[1]]; + + w ^= sBox[4][(t[a[2] >>> 2] >>> (24 - 8 * (a[2] & 3))) & 0xff]; + w ^= sBox[5][(t[a[3] >>> 2] >>> (24 - 8 * (a[3] & 3))) & 0xff]; + w ^= sBox[6][(t[a[4] >>> 2] >>> (24 - 8 * (a[4] & 3))) & 0xff]; + w ^= sBox[7][(t[a[5] >>> 2] >>> (24 - 8 * (a[5] & 3))) & 0xff]; + w ^= sBox[x[j]][(t[a[6] >>> 2] >>> (24 - 8 * (a[6] & 3))) & 0xff]; + t[a[0]] = w; + } + + for (var j = 0; j < 4; j++) { + var b = scheduleB[round][j]; + var w = sBox[4][(t[b[0] >>> 2] >>> (24 - 8 * (b[0] & 3))) & 0xff]; + + w ^= sBox[5][(t[b[1] >>> 2] >>> (24 - 8 * (b[1] & 3))) & 0xff]; + w ^= sBox[6][(t[b[2] >>> 2] >>> (24 - 8 * (b[2] & 3))) & 0xff]; + w ^= sBox[7][(t[b[3] >>> 2] >>> (24 - 8 * (b[3] & 3))) & 0xff]; + w ^= sBox[4 + j][(t[b[4] >>> 2] >>> (24 - 8 * (b[4] & 3))) & 0xff]; + k[ki] = w; + ki++; + } + } + } + + for (var i = 0; i < 16; i++) { + this.masking[i] = k[i]; + this.rotate[i] = k[16 + i] & 0x1f; + } + }; + + // These are the three 'f' functions. See RFC 2144, section 2.2. + + function f1(d, m, r) { + var t = m + d; + var I = (t << r) | (t >>> (32 - r)); + return ((sBox[0][I >>> 24] ^ sBox[1][(I >>> 16) & 255]) - sBox[2][(I >>> 8) & 255]) + sBox[3][I & 255]; + } + + function f2(d, m, r) { + var t = m ^ d; + var I = (t << r) | (t >>> (32 - r)); + return ((sBox[0][I >>> 24] - sBox[1][(I >>> 16) & 255]) + sBox[2][(I >>> 8) & 255]) ^ sBox[3][I & 255]; + } + + function f3(d, m, r) { + var t = m - d; + var I = (t << r) | (t >>> (32 - r)); + return ((sBox[0][I >>> 24] + sBox[1][(I >>> 16) & 255]) ^ sBox[2][(I >>> 8) & 255]) - sBox[3][I & 255]; + } + + var sBox = new Array(8); + sBox[0] = new Array( + 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, + 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, + 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, + 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, + 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, + 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, + 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, + 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, + 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, + 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, + 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, + 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, + 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, + 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, + 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, + 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, + 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, + 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, + 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, + 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, + 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, + 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, + 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, + 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, + 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, + 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, + 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, + 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, + 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, + 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, + 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, + 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf); + + sBox[1] = new Array( + 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, + 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, + 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, + 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, + 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, + 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, + 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, + 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, + 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, + 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, + 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, + 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, + 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, + 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, + 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, + 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, + 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, + 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, + 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, + 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, + 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, + 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, + 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, + 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, + 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, + 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, + 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, + 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, + 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, + 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, + 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, + 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1); + + sBox[2] = new Array( + 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, + 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, + 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, + 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, + 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, + 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, + 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, + 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, + 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, + 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, + 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, + 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, + 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, + 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, + 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, + 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, + 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, + 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, + 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, + 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, + 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, + 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, + 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, + 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, + 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, + 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, + 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, + 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, + 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, + 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, + 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, + 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783); + + sBox[3] = new Array( + 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, + 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, + 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, + 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, + 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, + 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, + 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, + 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, + 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, + 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, + 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, + 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, + 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, + 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, + 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, + 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, + 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, + 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, + 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, + 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, + 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, + 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, + 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, + 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, + 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, + 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, + 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, + 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, + 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, + 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, + 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, + 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2); + + sBox[4] = new Array( + 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, + 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, + 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, + 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, + 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, + 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, + 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, + 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, + 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, + 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, + 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, + 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, + 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, + 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, + 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, + 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, + 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, + 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, + 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, + 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, + 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, + 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, + 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, + 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, + 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, + 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, + 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, + 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, + 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, + 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, + 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, + 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4); + + sBox[5] = new Array( + 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, + 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, + 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, + 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, + 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, + 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, + 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, + 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, + 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, + 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, + 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, + 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, + 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, + 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, + 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, + 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, + 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, + 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, + 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, + 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, + 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, + 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, + 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, + 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, + 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, + 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, + 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, + 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, + 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, + 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, + 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, + 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f); + + sBox[6] = new Array( + 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, + 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, + 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, + 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, + 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, + 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, + 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, + 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, + 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, + 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, + 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, + 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, + 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, + 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, + 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, + 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, + 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, + 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, + 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, + 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, + 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, + 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, + 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, + 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, + 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, + 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, + 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, + 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, + 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, + 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, + 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, + 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3); + + sBox[7] = new Array( + 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, + 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, + 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, + 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, + 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, + 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, + 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, + 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, + 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, + 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, + 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, + 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, + 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, + 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, + 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, + 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, + 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, + 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, + 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, + 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, + 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, + 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, + 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, + 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, + 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, + 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, + 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, + 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, + 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, + 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, + 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, + 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e); + +}; + +var util = require('../../util'); + +function cast5(key) { + this.cast5 = new openpgp_symenc_cast5(); + this.cast5.setKey(util.str2bin(key)); + + this.encrypt = function(block) { + return this.cast5.encrypt(block); + } +} + +module.exports = cast5; +module.exports.blockSize = cast5.prototype.blockSize = 8; +module.exports.keySize = cast5.prototype.keySize = 16; diff --git a/src/crypto/cipher/des.js b/src/crypto/cipher/des.js new file mode 100644 index 00000000..5cb2bf03 --- /dev/null +++ b/src/crypto/cipher/des.js @@ -0,0 +1,409 @@ +//Paul Tero, July 2001 +//http://www.tero.co.uk/des/ +// +//Optimised for performance with large blocks by Michael Hayworth, November 2001 +//http://www.netdealing.com +// +// Modified by Recurity Labs GmbH + +//THIS SOFTWARE IS PROVIDED "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +//SUCH DAMAGE. + +//des +//this takes the key, the message, and whether to encrypt or decrypt + +/** + * @module crypto/cipher/des + */ + + +function des(keys, message, encrypt, mode, iv, padding) { + //declaring this locally speeds things up a bit + var spfunction1 = new Array(0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400, + 0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000, + 0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4, + 0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404, + 0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400, + 0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004); + var spfunction2 = new Array(-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, - + 0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020, - + 0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, - + 0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, - + 0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0, + 0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0, - + 0x7fef7fe0, 0x108000); + var spfunction3 = new Array(0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008, + 0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000, + 0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000, + 0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0, + 0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208, + 0x8020000, 0x20208, 0x8, 0x8020008, 0x20200); + var spfunction4 = new Array(0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000, + 0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080, + 0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0, + 0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001, + 0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080); + var spfunction5 = new Array(0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000, + 0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000, + 0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100, + 0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100, + 0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100, + 0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0, + 0x40080000, 0x2080100, 0x40000100); + var spfunction6 = new Array(0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000, + 0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010, + 0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000, + 0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000, + 0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000, + 0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010); + var spfunction7 = new Array(0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802, + 0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002, + 0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000, + 0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000, + 0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0, + 0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002); + var spfunction8 = new Array(0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000, + 0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000, + 0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040, + 0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040, + 0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000); + + //create the 16 or 48 subkeys we will need + var m = 0, + i, j, temp, temp2, right1, right2, left, right, looping; + var cbcleft, cbcleft2, cbcright, cbcright2 + var endloop, loopinc; + var len = message.length; + var chunk = 0; + //set up the loops for single and triple des + var iterations = keys.length == 32 ? 3 : 9; //single or triple des + if (iterations == 3) { + looping = encrypt ? new Array(0, 32, 2) : new Array(30, -2, -2); + } else { + looping = encrypt ? new Array(0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array(94, 62, -2, 32, 64, 2, 30, -2, -2); + } + + //pad the message depending on the padding parameter + //only add padding if encrypting - note that you need to use the same padding option for both encrypt and decrypt + if (encrypt) { + message = des_addPadding(message, padding); + len = message.length; + } + + //store the result here + result = ""; + tempresult = ""; + + if (mode == 1) { //CBC mode + cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); + cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); + m = 0; + } + + //loop through each 64 bit chunk of the message + while (m < len) { + left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message + .charCodeAt(m++); + right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | + message.charCodeAt(m++); + + //for Cipher Block Chaining mode, xor the message with the previous result + if (mode == 1) { + if (encrypt) { + left ^= cbcleft; + right ^= cbcright; + } else { + cbcleft2 = cbcleft; + cbcright2 = cbcright; + cbcleft = left; + cbcright = right; + } + } + + //first each 64 but chunk of the message must be permuted according to IP + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= (temp << 4); + temp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= temp; + left ^= (temp << 16); + temp = ((right >>> 2) ^ left) & 0x33333333; + left ^= temp; + right ^= (temp << 2); + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= (temp << 8); + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + + left = ((left << 1) | (left >>> 31)); + right = ((right << 1) | (right >>> 31)); + + //do this either 1 or 3 times for each chunk of the message + for (j = 0; j < iterations; j += 3) { + endloop = looping[j + 1]; + loopinc = looping[j + 2]; + //now go through and perform the encryption or decryption + for (i = looping[j]; i != endloop; i += loopinc) { //for efficiency + right1 = right ^ keys[i]; + right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1]; + //the result is attained by passing these bytes through the S selection functions + temp = left; + left = right; + right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f] | spfunction6[(right1 >>> + 8) & 0x3f] | spfunction8[right1 & 0x3f] | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & + 0x3f] | spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]); + } + temp = left; + left = right; + right = temp; //unreverse left and right + } //for either 1 or 3 iterations + + //move then each one bit to the right + left = ((left >>> 1) | (left << 31)); + right = ((right >>> 1) | (right << 31)); + + //now perform IP-1, which is IP in the opposite direction + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= (temp << 8); + temp = ((right >>> 2) ^ left) & 0x33333333; + left ^= temp; + right ^= (temp << 2); + temp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= temp; + left ^= (temp << 16); + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= (temp << 4); + + //for Cipher Block Chaining mode, xor the message with the previous result + if (mode == 1) { + if (encrypt) { + cbcleft = left; + cbcright = right; + } else { + left ^= cbcleft2; + right ^= cbcright2; + } + } + tempresult += String.fromCharCode((left >>> 24), ((left >>> 16) & 0xff), ((left >>> 8) & 0xff), (left & 0xff), ( + right >>> 24), ((right >>> 16) & 0xff), ((right >>> 8) & 0xff), (right & 0xff)); + + chunk += 8; + if (chunk == 512) { + result += tempresult; + tempresult = ""; + chunk = 0; + } + } //for every 8 characters, or 64 bits in the message + + //return the result as an array + result += tempresult; + + //only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt + if (!encrypt) { + result = des_removePadding(result, padding); + } + + return result; +} //end of des + + + +//des_createKeys +//this takes as input a 64 bit key (even though only 56 bits are used) +//as an array of 2 integers, and returns 16 48 bit keys + +function des_createKeys(key) { + //declaring this locally speeds things up a bit + pc2bytes0 = new Array(0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204, + 0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204); + pc2bytes1 = new Array(0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100, + 0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101); + pc2bytes2 = new Array(0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808, + 0x1000000, 0x1000008, 0x1000800, 0x1000808); + pc2bytes3 = new Array(0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000, + 0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000); + pc2bytes4 = new Array(0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000, + 0x41000, 0x1010, 0x41010); + pc2bytes5 = new Array(0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420, + 0x2000000, 0x2000400, 0x2000020, 0x2000420); + pc2bytes6 = new Array(0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000, + 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002); + pc2bytes7 = new Array(0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000, + 0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800); + pc2bytes8 = new Array(0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000, + 0x2000002, 0x2040002, 0x2000002, 0x2040002); + pc2bytes9 = new Array(0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408, + 0x10000408, 0x400, 0x10000400, 0x408, 0x10000408); + pc2bytes10 = new Array(0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020, + 0x102000, 0x102020, 0x102000, 0x102020); + pc2bytes11 = new Array(0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000, + 0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200); + pc2bytes12 = new Array(0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010, + 0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010); + pc2bytes13 = new Array(0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105); + + //how many iterations (1 for des, 3 for triple des) + var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys + //stores the return keys + var keys = new Array(32 * iterations); + //now define the left shifts which need to be done + var shifts = new Array(0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0); + //other variables + var lefttemp, righttemp, m = 0, + n = 0, + temp; + + for (var j = 0; j < iterations; j++) { //either 1 or 3 iterations + left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++); + right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++); + + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= (temp << 4); + temp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= temp; + right ^= (temp << -16); + temp = ((left >>> 2) ^ right) & 0x33333333; + right ^= temp; + left ^= (temp << 2); + temp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= temp; + right ^= (temp << -16); + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= (temp << 8); + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= (temp << 1); + + //the right side needs to be shifted and to get the last four bits of the left side + temp = (left << 8) | ((right >>> 20) & 0x000000f0); + //left needs to be put upside down + left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0); + right = temp; + + //now go through and perform these shifts on the left and right keys + for (i = 0; i < shifts.length; i++) { + //shift the keys either one or two bits to the left + if (shifts[i]) { + left = (left << 2) | (left >>> 26); + right = (right << 2) | (right >>> 26); + } else { + left = (left << 1) | (left >>> 27); + right = (right << 1) | (right >>> 27); + } + left &= -0xf; + right &= -0xf; + + //now apply PC-2, in such a way that E is easier when encrypting or decrypting + //this conversion will look like PC-2 except only the last 6 bits of each byte are used + //rather than 48 consecutive bits and the order of lines will be according to + //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 + lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[( + left >>> 16) & 0xf] | pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | pc2bytes6[(left >>> 4) & + 0xf]; + righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | pc2bytes9[(right >>> 20) & 0xf] | + pc2bytes10[(right >>> 16) & 0xf] | pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] | + pc2bytes13[(right >>> 4) & 0xf]; + temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff; + keys[n++] = lefttemp ^ temp; + keys[n++] = righttemp ^ (temp << 16); + } + } //for each iterations + //return the keys we've created + return keys; +} //end of des_createKeys + + +function des_addPadding(message, padding) { + var padLength = 8 - (message.length % 8); + if ((padding == 2) && (padLength < 8)) { //pad the message with spaces + message += " ".substr(0, padLength); + } else if (padding == 1) { //PKCS7 padding + message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength, + padLength).substr(0, padLength); + } else if (!padding && (padLength < 8)) { //pad the message out with null bytes + message += "\0\0\0\0\0\0\0\0".substr(0, padLength); + } + return message; +} + +function des_removePadding(message, padding) { + if (padding == 2) { // space padded + message = message.replace(/ *$/g, ""); + } else if (padding == 1) { // PKCS7 + var padCount = message.charCodeAt(message.length - 1); + message = message.substr(0, message.length - padCount); + } else if (!padding) { // null padding + message = message.replace(/\0*$/g, ""); + } + return message; +} + + +var util = require('../../util'); + +// added by Recurity Labs + +function Des(key) { + this.key = []; + + for (var i = 0; i < 3; i++) { + this.key.push(key.substr(i * 8, 8)); + } + + this.encrypt = function(block) { + return util.str2bin(des(des_createKeys(this.key[2]), + des(des_createKeys(this.key[1]), + des(des_createKeys(this.key[0]), + util.bin2str(block), true, 0, null, null), + false, 0, null, null), true, 0, null, null)); + } +} + +Des.keySize = Des.prototype.keySize = 24; +Des.blockSize = Des.prototype.blockSize = 8; + +// This is "original" DES - Des is actually Triple DES. +// This is only exported so we can unit test. + +function OriginalDes(key) { + this.key = key; + + this.encrypt = function(block, padding) { + var keys = des_createKeys(this.key); + return util.str2bin(des(keys, util.bin2str(block), true, 0, null, padding)); + } + + this.decrypt = function(block, padding) { + var keys = des_createKeys(this.key); + return util.str2bin(des(keys, util.bin2str(block), false, 0, null, padding)); + } +} + +module.exports = { + /** @static */ + des: Des, + /** @static */ + originalDes: OriginalDes +} diff --git a/src/crypto/cipher/index.js b/src/crypto/cipher/index.js new file mode 100644 index 00000000..99462457 --- /dev/null +++ b/src/crypto/cipher/index.js @@ -0,0 +1,28 @@ +/** + * @requires crypto/cipher/aes + * @requires crypto/cipher/blowfish + * @requires crypto/cipher/cast5 + * @requires crypto/cipher/twofish + * @module crypto/cipher + */ + +var desModule = require('./des.js'); + +module.exports = { + /** @see module:crypto/cipher/des.des */ + des: desModule['des'], + /** @see module:crypto/cipher/des.originalDes */ + originalDes: desModule['originalDes'], + /** @see module:crypto/cipher/cast5 */ + cast5: require('./cast5.js'), + /** @see module:crypto/cipher/twofish */ + twofish: require('./twofish.js'), + /** @see module:crypto/cipher/blowfish */ + blowfish: require('./blowfish.js') +} + +var aes = require('./aes.js'); + +for (var i in aes) { + module.exports['aes' + i] = aes[i]; +} diff --git a/src/crypto/cipher/package.json b/src/crypto/cipher/package.json new file mode 100644 index 00000000..1d957c70 --- /dev/null +++ b/src/crypto/cipher/package.json @@ -0,0 +1,5 @@ +{ + "name": "openpgp-crypto-cipher", + "version": "0.0.1", + "main": "./index.js" +} diff --git a/src/crypto/cipher/twofish.js b/src/crypto/cipher/twofish.js new file mode 100644 index 00000000..5e99834f --- /dev/null +++ b/src/crypto/cipher/twofish.js @@ -0,0 +1,382 @@ +/* Modified by Recurity Labs GmbH + * + * Cipher.js + * A block-cipher algorithm implementation on JavaScript + * See Cipher.readme.txt for further information. + * + * Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ] + * This script file is distributed under the LGPL + * + * ACKNOWLEDGMENT + * + * The main subroutines are written by Michiel van Everdingen. + * + * Michiel van Everdingen + * http://home.versatel.nl/MAvanEverdingen/index.html + * + * All rights for these routines are reserved to Michiel van Everdingen. + * + */ + +/** + * @module crypto/cipher/twofish + */ + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Math +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +var MAXINT = 0xFFFFFFFF; + +function rotb(b, n) { + return (b << n | b >>> (8 - n)) & 0xFF; +} + +function rotw(w, n) { + return (w << n | w >>> (32 - n)) & MAXINT; +} + +function getW(a, i) { + return a[i] | a[i + 1] << 8 | a[i + 2] << 16 | a[i + 3] << 24; +} + +function setW(a, i, w) { + a.splice(i, 4, w & 0xFF, (w >>> 8) & 0xFF, (w >>> 16) & 0xFF, (w >>> 24) & 0xFF); +} + +function setWInv(a, i, w) { + a.splice(i, 4, (w >>> 24) & 0xFF, (w >>> 16) & 0xFF, (w >>> 8) & 0xFF, w & 0xFF); +} + +function getB(x, n) { + return (x >>> (n * 8)) & 0xFF; +} + +function getNrBits(i) { + var n = 0; + while (i > 0) { + n++; + i >>>= 1; + } + return n; +} + +function getMask(n) { + return (1 << n) - 1; +} + +//added 2008/11/13 XXX MUST USE ONE-WAY HASH FUNCTION FOR SECURITY REASON + +function randByte() { + return Math.floor(Math.random() * 256); +} +// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Twofish +// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +function createTwofish() { + // + var keyBytes = null; + var dataBytes = null; + var dataOffset = -1; + // var dataLength = -1; + var algorithmName = null; + // var idx2 = -1; + // + + algorithmName = "twofish"; + + var tfsKey = []; + var tfsM = [ + [], + [], + [], + [] + ]; + + function tfsInit(key) { + keyBytes = key; + var i, a, b, c, d, meKey = [], + moKey = [], + inKey = []; + var kLen; + var sKey = []; + var f01, f5b, fef; + + var q0 = [ + [8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4], + [2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5] + ]; + var q1 = [ + [14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13], + [1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8] + ]; + var q2 = [ + [11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1], + [4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15] + ]; + var q3 = [ + [13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10], + [11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10] + ]; + var ror4 = [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15]; + var ashx = [0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7]; + var q = [ + [], + [] + ]; + var m = [ + [], + [], + [], + [] + ]; + + function ffm5b(x) { + return x ^ (x >> 2) ^ [0, 90, 180, 238][x & 3]; + } + + function ffmEf(x) { + return x ^ (x >> 1) ^ (x >> 2) ^ [0, 238, 180, 90][x & 3]; + } + + function mdsRem(p, q) { + var i, t, u; + for (i = 0; i < 8; i++) { + t = q >>> 24; + q = ((q << 8) & MAXINT) | p >>> 24; + p = (p << 8) & MAXINT; + u = t << 1; + if (t & 128) { + u ^= 333; + } + q ^= t ^ (u << 16); + u ^= t >>> 1; + if (t & 1) { + u ^= 166; + } + q ^= u << 24 | u << 8; + } + return q; + } + + function qp(n, x) { + var a, b, c, d; + a = x >> 4; + b = x & 15; + c = q0[n][a ^ b]; + d = q1[n][ror4[b] ^ ashx[a]]; + return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d]; + } + + function hFun(x, key) { + var a = getB(x, 0), + b = getB(x, 1), + c = getB(x, 2), + d = getB(x, 3); + switch (kLen) { + case 4: + a = q[1][a] ^ getB(key[3], 0); + b = q[0][b] ^ getB(key[3], 1); + c = q[0][c] ^ getB(key[3], 2); + d = q[1][d] ^ getB(key[3], 3); + case 3: + a = q[1][a] ^ getB(key[2], 0); + b = q[1][b] ^ getB(key[2], 1); + c = q[0][c] ^ getB(key[2], 2); + d = q[0][d] ^ getB(key[2], 3); + case 2: + a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0); + b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1); + c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2); + d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3); + } + return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d]; + } + + keyBytes = keyBytes.slice(0, 32); + i = keyBytes.length; + while (i != 16 && i != 24 && i != 32) + keyBytes[i++] = 0; + + for (i = 0; i < keyBytes.length; i += 4) { + inKey[i >> 2] = getW(keyBytes, i); + } + for (i = 0; i < 256; i++) { + q[0][i] = qp(0, i); + q[1][i] = qp(1, i); + } + for (i = 0; i < 256; i++) { + f01 = q[1][i]; + f5b = ffm5b(f01); + fef = ffmEf(f01); + m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24); + m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24); + f01 = q[0][i]; + f5b = ffm5b(f01); + fef = ffmEf(f01); + m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24); + m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24); + } + + kLen = inKey.length / 2; + for (i = 0; i < kLen; i++) { + a = inKey[i + i]; + meKey[i] = a; + b = inKey[i + i + 1]; + moKey[i] = b; + sKey[kLen - i - 1] = mdsRem(a, b); + } + for (i = 0; i < 40; i += 2) { + a = 0x1010101 * i; + b = a + 0x1010101; + a = hFun(a, meKey); + b = rotw(hFun(b, moKey), 8); + tfsKey[i] = (a + b) & MAXINT; + tfsKey[i + 1] = rotw(a + 2 * b, 9); + } + for (i = 0; i < 256; i++) { + a = b = c = d = i; + switch (kLen) { + case 4: + a = q[1][a] ^ getB(sKey[3], 0); + b = q[0][b] ^ getB(sKey[3], 1); + c = q[0][c] ^ getB(sKey[3], 2); + d = q[1][d] ^ getB(sKey[3], 3); + case 3: + a = q[1][a] ^ getB(sKey[2], 0); + b = q[1][b] ^ getB(sKey[2], 1); + c = q[0][c] ^ getB(sKey[2], 2); + d = q[0][d] ^ getB(sKey[2], 3); + case 2: + tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)] ^ getB(sKey[0], 0)]; + tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)] ^ getB(sKey[0], 1)]; + tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)] ^ getB(sKey[0], 2)]; + tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)] ^ getB(sKey[0], 3)]; + } + } + } + + function tfsG0(x) { + return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)] ^ tfsM[3][getB(x, 3)]; + } + + function tfsG1(x) { + return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)] ^ tfsM[3][getB(x, 2)]; + } + + function tfsFrnd(r, blk) { + var a = tfsG0(blk[0]); + var b = tfsG1(blk[1]); + blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31); + blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT; + a = tfsG0(blk[2]); + b = tfsG1(blk[3]); + blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31); + blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT; + } + + function tfsIrnd(i, blk) { + var a = tfsG0(blk[0]); + var b = tfsG1(blk[1]); + blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT; + blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31); + a = tfsG0(blk[2]); + b = tfsG1(blk[3]); + blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT; + blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31); + } + + function tfsClose() { + tfsKey = []; + tfsM = [ + [], + [], + [], + [] + ]; + } + + function tfsEncrypt(data, offset) { + dataBytes = data; + dataOffset = offset; + var blk = [getW(dataBytes, dataOffset) ^ tfsKey[0], + getW(dataBytes, dataOffset + 4) ^ tfsKey[1], + getW(dataBytes, dataOffset + 8) ^ tfsKey[2], + getW(dataBytes, dataOffset + 12) ^ tfsKey[3] + ]; + for (var j = 0; j < 8; j++) { + tfsFrnd(j, blk); + } + setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]); + setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]); + setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]); + setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]); + dataOffset += 16; + return dataBytes; + } + + function tfsDecrypt(data, offset) { + dataBytes = data; + dataOffset = offset; + var blk = [getW(dataBytes, dataOffset) ^ tfsKey[4], + getW(dataBytes, dataOffset + 4) ^ tfsKey[5], + getW(dataBytes, dataOffset + 8) ^ tfsKey[6], + getW(dataBytes, dataOffset + 12) ^ tfsKey[7] + ]; + for (var j = 7; j >= 0; j--) { + tfsIrnd(j, blk); + } + setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]); + setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]); + setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]); + setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]); + dataOffset += 16; + } + + // added by Recurity Labs + + function tfsFinal() { + return dataBytes; + } + + return { + name: "twofish", + blocksize: 128 / 8, + open: tfsInit, + close: tfsClose, + encrypt: tfsEncrypt, + decrypt: tfsDecrypt, + // added by Recurity Labs + finalize: tfsFinal + }; +} + +var util = require('../../util'); + +// added by Recurity Labs + +function TFencrypt(block, key) { + var block_copy = [].concat(block); + var tf = createTwofish(); + tf.open(util.str2bin(key), 0); + var result = tf.encrypt(block_copy, 0); + tf.close(); + return result; +} + +function TF(key) { + this.tf = createTwofish(); + this.tf.open(util.str2bin(key), 0); + + this.encrypt = function(block) { + return this.tf.encrypt([].concat(block), 0); + } +} + + +module.exports = TF; +module.exports.keySize = TF.prototype.keySize = 32; +module.exports.blockSize = TF.prototype.blockSize = 16; diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js new file mode 100644 index 00000000..5799cf2c --- /dev/null +++ b/src/crypto/crypto.js @@ -0,0 +1,223 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +// The GPG4Browsers crypto interface + +/** + * @requires crypto/cipher + * @requires crypto/public_key + * @requires crypto/random + * @requires type/mpi + * @module crypto/crypto + */ + +var random = require('./random.js'), + cipher = require('./cipher'), + publicKey = require('./public_key'), + type_mpi = require('../type/mpi.js'); + +module.exports = { + /** + * Encrypts data using the specified public key multiprecision integers + * and the specified algorithm. + * @param {Integer} algo Algorithm to be used (See RFC4880 9.1) + * @param {Array} publicMPIs Algorithm dependent multiprecision integers + * @param {module:type/mpi} data Data to be encrypted as MPI + * @return {Array} if RSA an module:type/mpi; + * if elgamal encryption an array of two module:type/mpi is returned; otherwise null + */ + publicKeyEncrypt: function(algo, publicMPIs, data) { + var result = (function() { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + var rsa = new publicKey.rsa(); + var n = publicMPIs[0].toBigInteger(); + var e = publicMPIs[1].toBigInteger(); + var m = data.toBigInteger(); + return [rsa.encrypt(m, e, n)]; + + case 'elgamal': + var elgamal = new publicKey.elgamal(); + var p = publicMPIs[0].toBigInteger(); + var g = publicMPIs[1].toBigInteger(); + var y = publicMPIs[2].toBigInteger(); + var m = data.toBigInteger(); + return elgamal.encrypt(m, g, p, y); + + default: + return []; + } + })(); + + return result.map(function(bn) { + var mpi = new type_mpi(); + mpi.fromBigInteger(bn); + return mpi; + }); + }, + + /** + * Decrypts data using the specified public key multiprecision integers of the private key, + * the specified secretMPIs of the private key and the specified algorithm. + * @param {Integer} algo Algorithm to be used (See RFC4880 9.1) + * @param {Array} publicMPIs Algorithm dependent multiprecision integers + * of the public key part of the private key + * @param {Array} secretMPIs Algorithm dependent multiprecision integers + * of the private key used + * @param {module:type/mpi} data Data to be encrypted as MPI + * @return {module:type/mpi} returns a big integer containing the decrypted data; otherwise null + */ + + publicKeyDecrypt: function(algo, keyIntegers, dataIntegers) { + var bn = (function() { + switch (algo) { + case 'rsa_encrypt_sign': + case 'rsa_encrypt': + var rsa = new publicKey.rsa(); + // 0 and 1 are the public key. + var d = keyIntegers[2].toBigInteger(); + var p = keyIntegers[3].toBigInteger(); + var q = keyIntegers[4].toBigInteger(); + var u = keyIntegers[5].toBigInteger(); + var m = dataIntegers[0].toBigInteger(); + return rsa.decrypt(m, d, p, q, u); + case 'elgamal': + var elgamal = new publicKey.elgamal(); + var x = keyIntegers[3].toBigInteger(); + var c1 = dataIntegers[0].toBigInteger(); + var c2 = dataIntegers[1].toBigInteger(); + var p = keyIntegers[0].toBigInteger(); + return elgamal.decrypt(c1, c2, p, x); + default: + return null; + } + })(); + + var result = new type_mpi(); + result.fromBigInteger(bn); + return result; + }, + + /** Returns the number of integers comprising the private key of an algorithm + * @param {String} algo The public key algorithm + * @return {Integer} The number of integers. + */ + getPrivateMpiCount: function(algo) { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + case 'rsa_sign': + // Algorithm-Specific Fields for RSA secret keys: + // - multiprecision integer (MPI) of RSA secret exponent d. + // - MPI of RSA secret prime value p. + // - MPI of RSA secret prime value q (p < q). + // - MPI of u, the multiplicative inverse of p, mod q. + return 4; + case 'elgamal': + // Algorithm-Specific Fields for Elgamal secret keys: + // - MPI of Elgamal secret exponent x. + return 1; + case 'dsa': + // Algorithm-Specific Fields for DSA secret keys: + // - MPI of DSA secret exponent x. + return 1; + default: + throw new Error('Unknown algorithm'); + } + }, + + getPublicMpiCount: function(algo) { + // - A series of multiprecision integers comprising the key material: + // Algorithm-Specific Fields for RSA public keys: + // - a multiprecision integer (MPI) of RSA public modulus n; + // - an MPI of RSA public encryption exponent e. + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + case 'rsa_sign': + return 2; + + // Algorithm-Specific Fields for Elgamal public keys: + // - MPI of Elgamal prime p; + // - MPI of Elgamal group generator g; + // - MPI of Elgamal public key value y (= g**x mod p where x is secret). + case 'elgamal': + return 3; + + // Algorithm-Specific Fields for DSA public keys: + // - MPI of DSA prime p; + // - MPI of DSA group order q (q is a prime divisor of p-1); + // - MPI of DSA group generator g; + // - MPI of DSA public-key value y (= g**x mod p where x is secret). + case 'dsa': + return 4; + + default: + throw new Error('Unknown algorithm.'); + } + }, + + generateMpi: function(algo, bits) { + var result = (function() { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + case 'rsa_sign': + //remember "publicKey" refers to the crypto/public_key dir + var rsa = new publicKey.rsa(); + var keyObject = rsa.generate(bits, "10001"); + var output = []; + output.push(keyObject.n); + output.push(keyObject.ee); + output.push(keyObject.d); + output.push(keyObject.p); + output.push(keyObject.q); + output.push(keyObject.u); + return output; + default: + throw new Error('Unsupported algorithm for key generation.'); + } + })(); + + return result.map(function(bn) { + var mpi = new type_mpi(); + mpi.fromBigInteger(bn); + return mpi; + }); + }, + + + /** + * generate random byte prefix as string for the specified algorithm + * @param {Integer} algo Algorithm to use (see RFC4880 9.2) + * @return {String} Random bytes with length equal to the block + * size of the cipher + */ + getPrefixRandom: function(algo) { + return random.getRandomBytes(cipher[algo].blockSize); + }, + + /** + * Generating a session key for the specified symmetric algorithm + * @param {Integer} algo Algorithm to use (see RFC4880 9.2) + * @return {String} Random bytes as a string to be used as a key + */ + generateSessionKey: function(algo) { + return random.getRandomBytes(cipher[algo].keySize); + } +}; diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js new file mode 100644 index 00000000..f6b7a97c --- /dev/null +++ b/src/crypto/hash/index.js @@ -0,0 +1,88 @@ +/** + * @requires crypto/hash/sha + * @module crypto/hash + */ +var sha = require('./sha.js'); + +module.exports = { + /** @see module:crypto/hash/md5 */ + md5: require('./md5.js'), + /** @see module:crypto/hash/sha.sha1 */ + sha1: sha.sha1, + /** @see module:crypto/hash/sha.sha224 */ + sha224: sha.sha224, + /** @see module:crypto/hash/sha.sha256 */ + sha256: sha.sha256, + /** @see module:crypto/hash/sha.sha384 */ + sha384: sha.sha384, + /** @see module:crypto/hash/sha.sha512 */ + sha512: sha.sha512, + /** @see module:crypto/hash/ripe-md */ + ripemd: require('./ripe-md.js'), + + /** + * Create a hash on the specified data using the specified algorithm + * @param {Integer} algo Hash algorithm type (see RFC4880 9.4) + * @param {String} data Data to be hashed + * @return {String} hash value + */ + digest: function(algo, data) { + switch (algo) { + case 1: + // - MD5 [HAC] + return this.md5(data); + case 2: + // - SHA-1 [FIPS180] + return this.sha1(data); + case 3: + // - RIPE-MD/160 [HAC] + return this.ripemd(data); + case 8: + // - SHA256 [FIPS180] + return this.sha256(data); + case 9: + // - SHA384 [FIPS180] + return this.sha384(data); + case 10: + // - SHA512 [FIPS180] + return this.sha512(data); + case 11: + // - SHA224 [FIPS180] + return this.sha224(data); + default: + throw new Error('Invalid hash function.'); + } + }, + + /** + * Returns the hash size in bytes of the specified hash algorithm type + * @param {Integer} algo Hash algorithm type (See RFC4880 9.4) + * @return {Integer} Size in bytes of the resulting hash + */ + getHashByteLength: function(algo) { + switch (algo) { + case 1: + // - MD5 [HAC] + return 16; + case 2: + // - SHA-1 [FIPS180] + case 3: + // - RIPE-MD/160 [HAC] + return 20; + case 8: + // - SHA256 [FIPS180] + return 32; + case 9: + // - SHA384 [FIPS180] + return 48 + case 10: + // - SHA512 [FIPS180] + return 64; + case 11: + // - SHA224 [FIPS180] + return 28; + default: + throw new Error('Invalid hash algorithm.'); + } + } +} diff --git a/src/crypto/hash/md5.js b/src/crypto/hash/md5.js new file mode 100644 index 00000000..07f70adc --- /dev/null +++ b/src/crypto/hash/md5.js @@ -0,0 +1,217 @@ +/** + * A fast MD5 JavaScript implementation + * Copyright (c) 2012 Joseph Myers + * http://www.myersdaily.org/joseph/javascript/md5-text.html + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for any purposes and without + * fee is hereby granted provided that this copyright notice + * appears in all copies. + * + * Of course, this soft is provided "as is" without express or implied + * warranty of any kind. + */ + +/** + * @requires util + * @module crypto/hash/md5 + */ + +var util = require('../../util'); + +/** + * MD5 hash + * @param {String} entree string to hash + */ +module.exports = function (entree) { + var hex = md5(entree); + var bin = util.hex2bin(hex); + return bin; +} + +function md5cycle(x, k) { + var a = x[0], + b = x[1], + c = x[2], + d = x[3]; + + a = ff(a, b, c, d, k[0], 7, -680876936); + d = ff(d, a, b, c, k[1], 12, -389564586); + c = ff(c, d, a, b, k[2], 17, 606105819); + b = ff(b, c, d, a, k[3], 22, -1044525330); + a = ff(a, b, c, d, k[4], 7, -176418897); + d = ff(d, a, b, c, k[5], 12, 1200080426); + c = ff(c, d, a, b, k[6], 17, -1473231341); + b = ff(b, c, d, a, k[7], 22, -45705983); + a = ff(a, b, c, d, k[8], 7, 1770035416); + d = ff(d, a, b, c, k[9], 12, -1958414417); + c = ff(c, d, a, b, k[10], 17, -42063); + b = ff(b, c, d, a, k[11], 22, -1990404162); + a = ff(a, b, c, d, k[12], 7, 1804603682); + d = ff(d, a, b, c, k[13], 12, -40341101); + c = ff(c, d, a, b, k[14], 17, -1502002290); + b = ff(b, c, d, a, k[15], 22, 1236535329); + + a = gg(a, b, c, d, k[1], 5, -165796510); + d = gg(d, a, b, c, k[6], 9, -1069501632); + c = gg(c, d, a, b, k[11], 14, 643717713); + b = gg(b, c, d, a, k[0], 20, -373897302); + a = gg(a, b, c, d, k[5], 5, -701558691); + d = gg(d, a, b, c, k[10], 9, 38016083); + c = gg(c, d, a, b, k[15], 14, -660478335); + b = gg(b, c, d, a, k[4], 20, -405537848); + a = gg(a, b, c, d, k[9], 5, 568446438); + d = gg(d, a, b, c, k[14], 9, -1019803690); + c = gg(c, d, a, b, k[3], 14, -187363961); + b = gg(b, c, d, a, k[8], 20, 1163531501); + a = gg(a, b, c, d, k[13], 5, -1444681467); + d = gg(d, a, b, c, k[2], 9, -51403784); + c = gg(c, d, a, b, k[7], 14, 1735328473); + b = gg(b, c, d, a, k[12], 20, -1926607734); + + a = hh(a, b, c, d, k[5], 4, -378558); + d = hh(d, a, b, c, k[8], 11, -2022574463); + c = hh(c, d, a, b, k[11], 16, 1839030562); + b = hh(b, c, d, a, k[14], 23, -35309556); + a = hh(a, b, c, d, k[1], 4, -1530992060); + d = hh(d, a, b, c, k[4], 11, 1272893353); + c = hh(c, d, a, b, k[7], 16, -155497632); + b = hh(b, c, d, a, k[10], 23, -1094730640); + a = hh(a, b, c, d, k[13], 4, 681279174); + d = hh(d, a, b, c, k[0], 11, -358537222); + c = hh(c, d, a, b, k[3], 16, -722521979); + b = hh(b, c, d, a, k[6], 23, 76029189); + a = hh(a, b, c, d, k[9], 4, -640364487); + d = hh(d, a, b, c, k[12], 11, -421815835); + c = hh(c, d, a, b, k[15], 16, 530742520); + b = hh(b, c, d, a, k[2], 23, -995338651); + + a = ii(a, b, c, d, k[0], 6, -198630844); + d = ii(d, a, b, c, k[7], 10, 1126891415); + c = ii(c, d, a, b, k[14], 15, -1416354905); + b = ii(b, c, d, a, k[5], 21, -57434055); + a = ii(a, b, c, d, k[12], 6, 1700485571); + d = ii(d, a, b, c, k[3], 10, -1894986606); + c = ii(c, d, a, b, k[10], 15, -1051523); + b = ii(b, c, d, a, k[1], 21, -2054922799); + a = ii(a, b, c, d, k[8], 6, 1873313359); + d = ii(d, a, b, c, k[15], 10, -30611744); + c = ii(c, d, a, b, k[6], 15, -1560198380); + b = ii(b, c, d, a, k[13], 21, 1309151649); + a = ii(a, b, c, d, k[4], 6, -145523070); + d = ii(d, a, b, c, k[11], 10, -1120210379); + c = ii(c, d, a, b, k[2], 15, 718787259); + b = ii(b, c, d, a, k[9], 21, -343485551); + + x[0] = add32(a, x[0]); + x[1] = add32(b, x[1]); + x[2] = add32(c, x[2]); + x[3] = add32(d, x[3]); + +} + +function cmn(q, a, b, x, s, t) { + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); +} + +function ff(a, b, c, d, x, s, t) { + return cmn((b & c) | ((~b) & d), a, b, x, s, t); +} + +function gg(a, b, c, d, x, s, t) { + return cmn((b & d) | (c & (~d)), a, b, x, s, t); +} + +function hh(a, b, c, d, x, s, t) { + return cmn(b ^ c ^ d, a, b, x, s, t); +} + +function ii(a, b, c, d, x, s, t) { + return cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +function md51(s) { + txt = ''; + var n = s.length, + state = [1732584193, -271733879, -1732584194, 271733878], + i; + for (i = 64; i <= s.length; i += 64) { + md5cycle(state, md5blk(s.substring(i - 64, i))); + } + s = s.substring(i - 64); + var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < s.length; i++) + tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3); + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i++) tail[i] = 0; + } + tail[14] = n * 8; + md5cycle(state, tail); + return state; +} + +/* there needs to be support for Unicode here, + * unless we pretend that we can redefine the MD-5 + * algorithm for multi-byte characters (perhaps + * by adding every four 16-bit characters and + * shortening the sum to 32 bits). Otherwise + * I suggest performing MD-5 as if every character + * was two bytes--e.g., 0040 0025 = @%--but then + * how will an ordinary MD-5 sum be matched? + * There is no way to standardize text to something + * like UTF-8 before transformation; speed cost is + * utterly prohibitive. The JavaScript standard + * itself needs to look at this: it should start + * providing access to strings as preformed UTF-8 + * 8-bit unsigned value arrays. + */ +function md5blk(s) { /* I figured global was faster. */ + var md5blks = [], + i; /* Andy King said do it this way. */ + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << + 24); + } + return md5blks; +} + +var hex_chr = '0123456789abcdef'.split(''); + +function rhex(n) { + var s = '', + j = 0; + for (; j < 4; j++) + s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F]; + return s; +} + +function hex(x) { + for (var i = 0; i < x.length; i++) + x[i] = rhex(x[i]); + return x.join(''); +} + +function md5(s) { + return hex(md51(s)); +} + +/* this function is much faster, +so if possible we use it. Some IEs +are the only ones I know of that +need the idiotic second function, +generated by an if clause. */ + +function add32(a, b) { + return (a + b) & 0xFFFFFFFF; +} + +if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') { + function add32(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } +} diff --git a/src/crypto/hash/package.json b/src/crypto/hash/package.json new file mode 100644 index 00000000..0912d37c --- /dev/null +++ b/src/crypto/hash/package.json @@ -0,0 +1,5 @@ +{ + "name": "openpgp-crypto-hash", + "version": "0.0.1", + "main": "./index.js" +} diff --git a/src/crypto/hash/ripe-md.js b/src/crypto/hash/ripe-md.js new file mode 100644 index 00000000..d93ba764 --- /dev/null +++ b/src/crypto/hash/ripe-md.js @@ -0,0 +1,295 @@ +/* + * CryptoMX Tools + * Copyright (C) 2004 - 2006 Derek Buitenhuis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified by Recurity Labs GmbH + */ + +/** + * @module crypto/hash/ripe-md + */ + +var RMDsize = 160; +var X = new Array(); + +function ROL(x, n) { + return new Number((x << n) | (x >>> (32 - n))); +} + +function F(x, y, z) { + return new Number(x ^ y ^ z); +} + +function G(x, y, z) { + return new Number((x & y) | (~x & z)); +} + +function H(x, y, z) { + return new Number((x | ~y) ^ z); +} + +function I(x, y, z) { + return new Number((x & z) | (y & ~z)); +} + +function J(x, y, z) { + return new Number(x ^ (y | ~z)); +} + +function mixOneRound(a, b, c, d, e, x, s, roundNumber) { + switch (roundNumber) { + case 0: + a += F(b, c, d) + x + 0x00000000; + break; + case 1: + a += G(b, c, d) + x + 0x5a827999; + break; + case 2: + a += H(b, c, d) + x + 0x6ed9eba1; + break; + case 3: + a += I(b, c, d) + x + 0x8f1bbcdc; + break; + case 4: + a += J(b, c, d) + x + 0xa953fd4e; + break; + case 5: + a += J(b, c, d) + x + 0x50a28be6; + break; + case 6: + a += I(b, c, d) + x + 0x5c4dd124; + break; + case 7: + a += H(b, c, d) + x + 0x6d703ef3; + break; + case 8: + a += G(b, c, d) + x + 0x7a6d76e9; + break; + case 9: + a += F(b, c, d) + x + 0x00000000; + break; + + default: + document.write("Bogus round number"); + break; + } + + a = ROL(a, s) + e; + c = ROL(c, 10); + + a &= 0xffffffff; + b &= 0xffffffff; + c &= 0xffffffff; + d &= 0xffffffff; + e &= 0xffffffff; + + var retBlock = new Array(); + retBlock[0] = a; + retBlock[1] = b; + retBlock[2] = c; + retBlock[3] = d; + retBlock[4] = e; + retBlock[5] = x; + retBlock[6] = s; + + return retBlock; +} + +function MDinit(MDbuf) { + MDbuf[0] = 0x67452301; + MDbuf[1] = 0xefcdab89; + MDbuf[2] = 0x98badcfe; + MDbuf[3] = 0x10325476; + MDbuf[4] = 0xc3d2e1f0; +} + +var ROLs = [ + [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8], + [7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12], + [11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5], + [11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12], + [9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6], + [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6], + [9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11], + [9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5], + [15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8], + [8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11] +]; + +var indexes = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8], + [3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12], + [1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2], + [4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], + [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12], + [6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2], + [15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13], + [8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14], + [12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11] +]; + +function compress(MDbuf, X) { + blockA = new Array(); + blockB = new Array(); + + var retBlock; + + for (var i = 0; i < 5; i++) { + blockA[i] = new Number(MDbuf[i]); + blockB[i] = new Number(MDbuf[i]); + } + + var step = 0; + for (var j = 0; j < 5; j++) { + for (var i = 0; i < 16; i++) { + retBlock = mixOneRound( + blockA[(step + 0) % 5], + blockA[(step + 1) % 5], + blockA[(step + 2) % 5], + blockA[(step + 3) % 5], + blockA[(step + 4) % 5], + X[indexes[j][i]], + ROLs[j][i], + j); + + blockA[(step + 0) % 5] = retBlock[0]; + blockA[(step + 1) % 5] = retBlock[1]; + blockA[(step + 2) % 5] = retBlock[2]; + blockA[(step + 3) % 5] = retBlock[3]; + blockA[(step + 4) % 5] = retBlock[4]; + + step += 4; + } + } + + step = 0; + for (var j = 5; j < 10; j++) { + for (var i = 0; i < 16; i++) { + retBlock = mixOneRound( + blockB[(step + 0) % 5], + blockB[(step + 1) % 5], + blockB[(step + 2) % 5], + blockB[(step + 3) % 5], + blockB[(step + 4) % 5], + X[indexes[j][i]], + ROLs[j][i], + j); + + blockB[(step + 0) % 5] = retBlock[0]; + blockB[(step + 1) % 5] = retBlock[1]; + blockB[(step + 2) % 5] = retBlock[2]; + blockB[(step + 3) % 5] = retBlock[3]; + blockB[(step + 4) % 5] = retBlock[4]; + + step += 4; + } + } + + blockB[3] += blockA[2] + MDbuf[1]; + MDbuf[1] = MDbuf[2] + blockA[3] + blockB[4]; + MDbuf[2] = MDbuf[3] + blockA[4] + blockB[0]; + MDbuf[3] = MDbuf[4] + blockA[0] + blockB[1]; + MDbuf[4] = MDbuf[0] + blockA[1] + blockB[2]; + MDbuf[0] = blockB[3]; +} + +function zeroX(X) { + for (var i = 0; i < 16; i++) { + X[i] = 0; + } +} + +function MDfinish(MDbuf, strptr, lswlen, mswlen) { + var X = new Array(16); + zeroX(X); + + var j = 0; + for (var i = 0; i < (lswlen & 63); i++) { + X[i >>> 2] ^= (strptr.charCodeAt(j++) & 255) << (8 * (i & 3)); + } + + X[(lswlen >>> 2) & 15] ^= 1 << (8 * (lswlen & 3) + 7); + + if ((lswlen & 63) > 55) { + compress(MDbuf, X); + var X = new Array(16); + zeroX(X); + } + + X[14] = lswlen << 3; + X[15] = (lswlen >>> 29) | (mswlen << 3); + + compress(MDbuf, X); +} + +function BYTES_TO_DWORD(fourChars) { + var tmp = (fourChars.charCodeAt(3) & 255) << 24; + tmp |= (fourChars.charCodeAt(2) & 255) << 16; + tmp |= (fourChars.charCodeAt(1) & 255) << 8; + tmp |= (fourChars.charCodeAt(0) & 255); + + return tmp; +} + +function RMD(message) { + var MDbuf = new Array(RMDsize / 32); + var hashcode = new Array(RMDsize / 8); + var length; + var nbytes; + + MDinit(MDbuf); + length = message.length; + + var X = new Array(16); + zeroX(X); + + var j = 0; + for (var nbytes = length; nbytes > 63; nbytes -= 64) { + for (var i = 0; i < 16; i++) { + X[i] = BYTES_TO_DWORD(message.substr(j, 4)); + j += 4; + } + compress(MDbuf, X); + } + + MDfinish(MDbuf, message.substr(j), length, 0); + + for (var i = 0; i < RMDsize / 8; i += 4) { + hashcode[i] = MDbuf[i >>> 2] & 255; + hashcode[i + 1] = (MDbuf[i >>> 2] >>> 8) & 255; + hashcode[i + 2] = (MDbuf[i >>> 2] >>> 16) & 255; + hashcode[i + 3] = (MDbuf[i >>> 2] >>> 24) & 255; + } + + return hashcode; +} + + +function RMDstring(message) { + var hashcode = RMD(message); + var retString = ""; + + for (var i = 0; i < RMDsize / 8; i++) { + retString += String.fromCharCode(hashcode[i]); + } + + return retString; +} + +module.exports = RMDstring; diff --git a/src/crypto/hash/sha.js b/src/crypto/hash/sha.js new file mode 100644 index 00000000..f77b7efb --- /dev/null +++ b/src/crypto/hash/sha.js @@ -0,0 +1,1125 @@ +/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS + * PUB 180-2 as well as the corresponding HMAC implementation as defined in + * FIPS PUB 198a + * + * Version 1.3 Copyright Brian Turek 2008-2010 + * Distributed under the BSD License + * See http://jssha.sourceforge.net/ for more information + * + * Several functions taken from Paul Johnson + */ + +/* Modified by Recurity Labs GmbH + * + * This code has been slightly modified direct string output: + * - bin2bstr has been added + * - following wrappers of this library have been added: + * - str_sha1 + * - str_sha256 + * - str_sha224 + * - str_sha384 + * - str_sha512 + */ + +/** + * @module crypto/hash/sha + */ + +var jsSHA = (function() { + + /* + * Configurable variables. Defaults typically work + */ + /* Number of Bits Per character (8 for ASCII, 16 for Unicode) */ + var charSize = 8, + /* base-64 pad character. "=" for strict RFC compliance */ + b64pad = "", + /* hex output format. 0 - lowercase; 1 - uppercase */ + hexCase = 0, + + /* + * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number + * + * @constructor + * @param {Number} msint_32 The most significant 32-bits of a 64-bit number + * @param {Number} lsint_32 The least significant 32-bits of a 64-bit number + */ + Int_64 = function(msint_32, lsint_32) { + this.highOrder = msint_32; + this.lowOrder = lsint_32; + }, + + /* + * Convert a string to an array of big-endian words + * If charSize is ASCII, characters >255 have their hi-byte silently + * ignored. + * + * @param {String} str String to be converted to binary representation + * @return Integer array representation of the parameter + */ + str2binb = function(str) { + var bin = [], + mask = (1 << charSize) - 1, + length = str.length * charSize, + i; + + for (i = 0; i < length; i += charSize) { + bin[i >> 5] |= (str.charCodeAt(i / charSize) & mask) << + (32 - charSize - (i % 32)); + } + + return bin; + }, + + /* + * Convert a hex string to an array of big-endian words + * + * @param {String} str String to be converted to binary representation + * @return Integer array representation of the parameter + */ + hex2binb = function(str) { + var bin = [], + length = str.length, + i, num; + + for (i = 0; i < length; i += 2) { + num = parseInt(str.substr(i, 2), 16); + if (!isNaN(num)) { + bin[i >> 3] |= num << (24 - (4 * (i % 8))); + } else { + return "INVALID HEX STRING"; + } + } + + return bin; + }, + + /* + * Convert an array of big-endian words to a hex string. + * + * @private + * @param {Array} binarray Array of integers to be converted to hexidecimal + * representation + * @return Hexidecimal representation of the parameter in String form + */ + binb2hex = function(binarray) { + var hex_tab = (hexCase) ? "0123456789ABCDEF" : "0123456789abcdef", + str = "", + length = binarray.length * 4, + i, srcByte; + + for (i = 0; i < length; i += 1) { + srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); + str += hex_tab.charAt((srcByte >> 4) & 0xF) + + hex_tab.charAt(srcByte & 0xF); + } + + return str; + }, + + /* + * Convert an array of big-endian words to a base-64 string + * + * @private + * @param {Array} binarray Array of integers to be converted to base-64 + * representation + * @return Base-64 encoded representation of the parameter in String form + */ + binb2b64 = function(binarray) { + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + + "0123456789+/", + str = "", + length = binarray.length * 4, + i, j, + triplet; + + for (i = 0; i < length; i += 3) { + triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | + (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | + ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); + for (j = 0; j < 4; j += 1) { + if (i * 8 + j * 6 <= binarray.length * 32) { + str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); + } else { + str += b64pad; + } + } + } + return str; + }, + + /* + * Convert an array of big-endian words to a string + */ + binb2str = function(bin) { + var str = ""; + var mask = (1 << 8) - 1; + for (var i = 0; i < bin.length * 32; i += 8) + str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask); + return str; + }, + /* + * The 32-bit implementation of circular rotate left + * + * @private + * @param {Number} x The 32-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted circularly by n bits + */ + rotl_32 = function(x, n) { + return (x << n) | (x >>> (32 - n)); + }, + + /* + * The 32-bit implementation of circular rotate right + * + * @private + * @param {Number} x The 32-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted circularly by n bits + */ + rotr_32 = function(x, n) { + return (x >>> n) | (x << (32 - n)); + }, + + /* + * The 64-bit implementation of circular rotate right + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted circularly by n bits + */ + rotr_64 = function(x, n) { + if (n <= 32) { + return new Int_64( + (x.highOrder >>> n) | (x.lowOrder << (32 - n)), (x.lowOrder >>> n) | (x.highOrder << (32 - n))); + } else { + return new Int_64( + (x.lowOrder >>> n) | (x.highOrder << (32 - n)), (x.highOrder >>> n) | (x.lowOrder << (32 - n))); + } + }, + + /* + * The 32-bit implementation of shift right + * + * @private + * @param {Number} x The 32-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted by n bits + */ + shr_32 = function(x, n) { + return x >>> n; + }, + + /* + * The 64-bit implementation of shift right + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @param {Number} n The number of bits to shift + * @return The x shifted by n bits + */ + shr_64 = function(x, n) { + if (n <= 32) { + return new Int_64( + x.highOrder >>> n, + x.lowOrder >>> n | (x.highOrder << (32 - n))); + } else { + return new Int_64( + 0, + x.highOrder << (32 - n)); + } + }, + + /* + * The 32-bit implementation of the NIST specified Parity function + * + * @private + * @param {Number} x The first 32-bit integer argument + * @param {Number} y The second 32-bit integer argument + * @param {Number} z The third 32-bit integer argument + * @return The NIST specified output of the function + */ + parity_32 = function(x, y, z) { + return x ^ y ^ z; + }, + + /* + * The 32-bit implementation of the NIST specified Ch function + * + * @private + * @param {Number} x The first 32-bit integer argument + * @param {Number} y The second 32-bit integer argument + * @param {Number} z The third 32-bit integer argument + * @return The NIST specified output of the function + */ + ch_32 = function(x, y, z) { + return (x & y) ^ (~x & z); + }, + + /* + * The 64-bit implementation of the NIST specified Ch function + * + * @private + * @param {Int_64} x The first 64-bit integer argument + * @param {Int_64} y The second 64-bit integer argument + * @param {Int_64} z The third 64-bit integer argument + * @return The NIST specified output of the function + */ + ch_64 = function(x, y, z) { + return new Int_64( + (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder)); + }, + + /* + * The 32-bit implementation of the NIST specified Maj function + * + * @private + * @param {Number} x The first 32-bit integer argument + * @param {Number} y The second 32-bit integer argument + * @param {Number} z The third 32-bit integer argument + * @return The NIST specified output of the function + */ + maj_32 = function(x, y, z) { + return (x & y) ^ (x & z) ^ (y & z); + }, + + /* + * The 64-bit implementation of the NIST specified Maj function + * + * @private + * @param {Int_64} x The first 64-bit integer argument + * @param {Int_64} y The second 64-bit integer argument + * @param {Int_64} z The third 64-bit integer argument + * @return The NIST specified output of the function + */ + maj_64 = function(x, y, z) { + return new Int_64( + (x.highOrder & y.highOrder) ^ + (x.highOrder & z.highOrder) ^ + (y.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ + (x.lowOrder & z.lowOrder) ^ + (y.lowOrder & z.lowOrder)); + }, + + /* + * The 32-bit implementation of the NIST specified Sigma0 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + sigma0_32 = function(x) { + return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22); + }, + + /* + * The 64-bit implementation of the NIST specified Sigma0 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + sigma0_64 = function(x) { + var rotr28 = rotr_64(x, 28), + rotr34 = rotr_64(x, 34), + rotr39 = rotr_64(x, 39); + + return new Int_64( + rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, + rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder); + }, + + /* + * The 32-bit implementation of the NIST specified Sigma1 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + sigma1_32 = function(x) { + return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25); + }, + + /* + * The 64-bit implementation of the NIST specified Sigma1 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + sigma1_64 = function(x) { + var rotr14 = rotr_64(x, 14), + rotr18 = rotr_64(x, 18), + rotr41 = rotr_64(x, 41); + + return new Int_64( + rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, + rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder); + }, + + /* + * The 32-bit implementation of the NIST specified Gamma0 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + gamma0_32 = function(x) { + return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3); + }, + + /* + * The 64-bit implementation of the NIST specified Gamma0 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + gamma0_64 = function(x) { + var rotr1 = rotr_64(x, 1), + rotr8 = rotr_64(x, 8), + shr7 = shr_64(x, 7); + + return new Int_64( + rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, + rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder); + }, + + /* + * The 32-bit implementation of the NIST specified Gamma1 function + * + * @private + * @param {Number} x The 32-bit integer argument + * @return The NIST specified output of the function + */ + gamma1_32 = function(x) { + return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10); + }, + + /* + * The 64-bit implementation of the NIST specified Gamma1 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return The NIST specified output of the function + */ + gamma1_64 = function(x) { + var rotr19 = rotr_64(x, 19), + rotr61 = rotr_64(x, 61), + shr6 = shr_64(x, 6); + + return new Int_64( + rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, + rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder); + }, + + /* + * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Number} x The first 32-bit integer argument to be added + * @param {Number} y The second 32-bit integer argument to be added + * @return The sum of x + y + */ + safeAdd_32_2 = function(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + }, + + /* + * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Number} a The first 32-bit integer argument to be added + * @param {Number} b The second 32-bit integer argument to be added + * @param {Number} c The third 32-bit integer argument to be added + * @param {Number} d The fourth 32-bit integer argument to be added + * @return The sum of a + b + c + d + */ + safeAdd_32_4 = function(a, b, c, d) { + var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF), + msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + }, + + /* + * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Number} a The first 32-bit integer argument to be added + * @param {Number} b The second 32-bit integer argument to be added + * @param {Number} c The third 32-bit integer argument to be added + * @param {Number} d The fourth 32-bit integer argument to be added + * @param {Number} e The fifth 32-bit integer argument to be added + * @return The sum of a + b + c + d + e + */ + safeAdd_32_5 = function(a, b, c, d, e) { + var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) + + (e & 0xFFFF), + msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + + (e >>> 16) + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + }, + + /* + * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} x The first 64-bit integer argument to be added + * @param {Int_64} y The second 64-bit integer argument to be added + * @return The sum of x + y + */ + safeAdd_64_2 = function(x, y) { + var lsw, msw, lowOrder, highOrder; + + lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF); + msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16); + msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + }, + + /* + * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} a The first 64-bit integer argument to be added + * @param {Int_64} b The second 64-bit integer argument to be added + * @param {Int_64} c The third 64-bit integer argument to be added + * @param {Int_64} d The fouth 64-bit integer argument to be added + * @return The sum of a + b + c + d + */ + safeAdd_64_4 = function(a, b, c, d) { + var lsw, msw, lowOrder, highOrder; + + lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF); + msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16); + msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + }, + + /* + * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} a The first 64-bit integer argument to be added + * @param {Int_64} b The second 64-bit integer argument to be added + * @param {Int_64} c The third 64-bit integer argument to be added + * @param {Int_64} d The fouth 64-bit integer argument to be added + * @param {Int_64} e The fouth 64-bit integer argument to be added + * @return The sum of a + b + c + d + e + */ + safeAdd_64_5 = function(a, b, c, d, e) { + var lsw, msw, lowOrder, highOrder; + + lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + + (e.lowOrder & 0xFFFF); + msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + + (e.highOrder & 0xFFFF) + (msw >>> 16); + msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + (d.highOrder >>> 16) + + (e.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + }, + + /* + * Calculates the SHA-1 hash of the string set at instantiation + * + * @private + * @param {Array} message The binary array representation of the string to + * hash + * @param {Number} messageLen The number of bits in the message + * @return The array of integers representing the SHA-1 hash of message + */ + coreSHA1 = function(message, messageLen) { + var W = [], + a, b, c, d, e, T, ch = ch_32, + parity = parity_32, + maj = maj_32, + rotl = rotl_32, + safeAdd_2 = safeAdd_32_2, + i, t, + safeAdd_5 = safeAdd_32_5, + appendedMessageLength, + H = [ + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 + ], + K = [ + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, + 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 + ]; + + /* Append '1' at the end of the binary string */ + message[messageLen >> 5] |= 0x80 << (24 - (messageLen % 32)); + /* Append length of binary string in the position such that the new + length is a multiple of 512. Logic does not work for even multiples + of 512 but there can never be even multiples of 512 */ + message[(((messageLen + 65) >> 9) << 4) + 15] = messageLen; + + appendedMessageLength = message.length; + + for (i = 0; i < appendedMessageLength; i += 16) { + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + + for (t = 0; t < 80; t += 1) { + if (t < 16) { + W[t] = message[t + i]; + } else { + W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + } + + if (t < 20) { + T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, K[t], W[t]); + } else if (t < 40) { + T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); + } else if (t < 60) { + T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, K[t], W[t]); + } else { + T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); + } + + e = d; + d = c; + c = rotl(b, 30); + b = a; + a = T; + } + + H[0] = safeAdd_2(a, H[0]); + H[1] = safeAdd_2(b, H[1]); + H[2] = safeAdd_2(c, H[2]); + H[3] = safeAdd_2(d, H[3]); + H[4] = safeAdd_2(e, H[4]); + } + + return H; + }, + + /* + * Calculates the desired SHA-2 hash of the string set at instantiation + * + * @private + * @param {Array} The binary array representation of the string to hash + * @param {Number} The number of bits in message + * @param {String} variant The desired SHA-2 variant + * @return The array of integers representing the SHA-2 hash of message + */ + coreSHA2 = function(message, messageLen, variant) { + var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t, + binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5, + gamma0, gamma1, sigma0, sigma1, ch, maj, Int, K, W = [], + appendedMessageLength; + + /* Set up the various function handles and variable for the specific + * variant */ + if (variant === "SHA-224" || variant === "SHA-256") { + /* 32-bit variant */ + numRounds = 64; + lengthPosition = (((messageLen + 65) >> 9) << 4) + 15; + binaryStringInc = 16; + binaryStringMult = 1; + Int = Number; + safeAdd_2 = safeAdd_32_2; + safeAdd_4 = safeAdd_32_4; + safeAdd_5 = safeAdd_32_5; + gamma0 = gamma0_32; + gamma1 = gamma1_32; + sigma0 = sigma0_32; + sigma1 = sigma1_32; + maj = maj_32; + ch = ch_32; + K = [ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 + ]; + + if (variant === "SHA-224") { + H = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]; + } else { + H = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 + ]; + } + } else if (variant === "SHA-384" || variant === "SHA-512") { + /* 64-bit variant */ + numRounds = 80; + lengthPosition = (((messageLen + 128) >> 10) << 5) + 31; + binaryStringInc = 32; + binaryStringMult = 2; + Int = Int_64; + safeAdd_2 = safeAdd_64_2; + safeAdd_4 = safeAdd_64_4; + safeAdd_5 = safeAdd_64_5; + gamma0 = gamma0_64; + gamma1 = gamma1_64; + sigma0 = sigma0_64; + sigma1 = sigma1_64; + maj = maj_64; + ch = ch_64; + + K = [ + new Int(0x428a2f98, 0xd728ae22), new Int(0x71374491, 0x23ef65cd), + new Int(0xb5c0fbcf, 0xec4d3b2f), new Int(0xe9b5dba5, 0x8189dbbc), + new Int(0x3956c25b, 0xf348b538), new Int(0x59f111f1, 0xb605d019), + new Int(0x923f82a4, 0xaf194f9b), new Int(0xab1c5ed5, 0xda6d8118), + new Int(0xd807aa98, 0xa3030242), new Int(0x12835b01, 0x45706fbe), + new Int(0x243185be, 0x4ee4b28c), new Int(0x550c7dc3, 0xd5ffb4e2), + new Int(0x72be5d74, 0xf27b896f), new Int(0x80deb1fe, 0x3b1696b1), + new Int(0x9bdc06a7, 0x25c71235), new Int(0xc19bf174, 0xcf692694), + new Int(0xe49b69c1, 0x9ef14ad2), new Int(0xefbe4786, 0x384f25e3), + new Int(0x0fc19dc6, 0x8b8cd5b5), new Int(0x240ca1cc, 0x77ac9c65), + new Int(0x2de92c6f, 0x592b0275), new Int(0x4a7484aa, 0x6ea6e483), + new Int(0x5cb0a9dc, 0xbd41fbd4), new Int(0x76f988da, 0x831153b5), + new Int(0x983e5152, 0xee66dfab), new Int(0xa831c66d, 0x2db43210), + new Int(0xb00327c8, 0x98fb213f), new Int(0xbf597fc7, 0xbeef0ee4), + new Int(0xc6e00bf3, 0x3da88fc2), new Int(0xd5a79147, 0x930aa725), + new Int(0x06ca6351, 0xe003826f), new Int(0x14292967, 0x0a0e6e70), + new Int(0x27b70a85, 0x46d22ffc), new Int(0x2e1b2138, 0x5c26c926), + new Int(0x4d2c6dfc, 0x5ac42aed), new Int(0x53380d13, 0x9d95b3df), + new Int(0x650a7354, 0x8baf63de), new Int(0x766a0abb, 0x3c77b2a8), + new Int(0x81c2c92e, 0x47edaee6), new Int(0x92722c85, 0x1482353b), + new Int(0xa2bfe8a1, 0x4cf10364), new Int(0xa81a664b, 0xbc423001), + new Int(0xc24b8b70, 0xd0f89791), new Int(0xc76c51a3, 0x0654be30), + new Int(0xd192e819, 0xd6ef5218), new Int(0xd6990624, 0x5565a910), + new Int(0xf40e3585, 0x5771202a), new Int(0x106aa070, 0x32bbd1b8), + new Int(0x19a4c116, 0xb8d2d0c8), new Int(0x1e376c08, 0x5141ab53), + new Int(0x2748774c, 0xdf8eeb99), new Int(0x34b0bcb5, 0xe19b48a8), + new Int(0x391c0cb3, 0xc5c95a63), new Int(0x4ed8aa4a, 0xe3418acb), + new Int(0x5b9cca4f, 0x7763e373), new Int(0x682e6ff3, 0xd6b2b8a3), + new Int(0x748f82ee, 0x5defb2fc), new Int(0x78a5636f, 0x43172f60), + new Int(0x84c87814, 0xa1f0ab72), new Int(0x8cc70208, 0x1a6439ec), + new Int(0x90befffa, 0x23631e28), new Int(0xa4506ceb, 0xde82bde9), + new Int(0xbef9a3f7, 0xb2c67915), new Int(0xc67178f2, 0xe372532b), + new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207), + new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178), + new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6), + new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b), + new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493), + new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c), + new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a), + new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817) + ]; + + if (variant === "SHA-384") { + H = [ + new Int(0xcbbb9d5d, 0xc1059ed8), new Int(0x0629a292a, 0x367cd507), + new Int(0x9159015a, 0x3070dd17), new Int(0x0152fecd8, 0xf70e5939), + new Int(0x67332667, 0xffc00b31), new Int(0x98eb44a87, 0x68581511), + new Int(0xdb0c2e0d, 0x64f98fa7), new Int(0x047b5481d, 0xbefa4fa4) + ]; + } else { + H = [ + new Int(0x6a09e667, 0xf3bcc908), new Int(0xbb67ae85, 0x84caa73b), + new Int(0x3c6ef372, 0xfe94f82b), new Int(0xa54ff53a, 0x5f1d36f1), + new Int(0x510e527f, 0xade682d1), new Int(0x9b05688c, 0x2b3e6c1f), + new Int(0x1f83d9ab, 0xfb41bd6b), new Int(0x5be0cd19, 0x137e2179) + ]; + } + } + + /* Append '1' at the end of the binary string */ + message[messageLen >> 5] |= 0x80 << (24 - messageLen % 32); + /* Append length of binary string in the position such that the new + * length is correct */ + message[lengthPosition] = messageLen; + + appendedMessageLength = message.length; + + for (i = 0; i < appendedMessageLength; i += binaryStringInc) { + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + + for (t = 0; t < numRounds; t += 1) { + if (t < 16) { + /* Bit of a hack - for 32-bit, the second term is ignored */ + W[t] = new Int(message[t * binaryStringMult + i], + message[t * binaryStringMult + i + 1]); + } else { + W[t] = safeAdd_4( + gamma1(W[t - 2]), W[t - 7], + gamma0(W[t - 15]), W[t - 16]); + } + + T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]); + T2 = safeAdd_2(sigma0(a), maj(a, b, c)); + h = g; + g = f; + f = e; + e = safeAdd_2(d, T1); + d = c; + c = b; + b = a; + a = safeAdd_2(T1, T2); + } + + H[0] = safeAdd_2(a, H[0]); + H[1] = safeAdd_2(b, H[1]); + H[2] = safeAdd_2(c, H[2]); + H[3] = safeAdd_2(d, H[3]); + H[4] = safeAdd_2(e, H[4]); + H[5] = safeAdd_2(f, H[5]); + H[6] = safeAdd_2(g, H[6]); + H[7] = safeAdd_2(h, H[7]); + } + + switch (variant) { + case "SHA-224": + return [ + H[0], H[1], H[2], H[3], + H[4], H[5], H[6]]; + case "SHA-256": + return H; + case "SHA-384": + return [ + H[0].highOrder, H[0].lowOrder, + H[1].highOrder, H[1].lowOrder, + H[2].highOrder, H[2].lowOrder, + H[3].highOrder, H[3].lowOrder, + H[4].highOrder, H[4].lowOrder, + H[5].highOrder, H[5].lowOrder]; + case "SHA-512": + return [ + H[0].highOrder, H[0].lowOrder, + H[1].highOrder, H[1].lowOrder, + H[2].highOrder, H[2].lowOrder, + H[3].highOrder, H[3].lowOrder, + H[4].highOrder, H[4].lowOrder, + H[5].highOrder, H[5].lowOrder, + H[6].highOrder, H[6].lowOrder, + H[7].highOrder, H[7].lowOrder]; + default: + /* This should never be reached */ + return []; + } + }, + + /* + * jsSHA is the workhorse of the library. Instantiate it with the string to + * be hashed as the parameter + * + * @constructor + * @param {String} srcString The string to be hashed + * @param {String} inputFormat The format of srcString, ASCII or HEX + */ + jsSHA = function(srcString, inputFormat) { + + this.sha1 = null; + this.sha224 = null; + this.sha256 = null; + this.sha384 = null; + this.sha512 = null; + + this.strBinLen = null; + this.strToHash = null; + + /* Convert the input string into the correct type */ + if ("HEX" === inputFormat) { + if (0 !== (srcString.length % 2)) { + return "TEXT MUST BE IN BYTE INCREMENTS"; + } + this.strBinLen = srcString.length * 4; + this.strToHash = hex2binb(srcString); + } else if (("ASCII" === inputFormat) || + ('undefined' === typeof(inputFormat))) { + this.strBinLen = srcString.length * charSize; + this.strToHash = str2binb(srcString); + } else { + return "UNKNOWN TEXT INPUT TYPE"; + } + }; + + jsSHA.prototype = { + /* + * Returns the desired SHA hash of the string specified at instantiation + * using the specified parameters + * + * @param {String} variant The desired SHA variant (SHA-1, SHA-224, + * SHA-256, SHA-384, or SHA-512) + * @param {String} format The desired output formatting (B64 or HEX) + * @return The string representation of the hash in the format specified + */ + getHash: function(variant, format) { + var formatFunc = null, + message = this.strToHash.slice(); + + switch (format) { + case "HEX": + formatFunc = binb2hex; + break; + case "B64": + formatFunc = binb2b64; + break; + case "ASCII": + formatFunc = binb2str; + break; + default: + return "FORMAT NOT RECOGNIZED"; + } + + switch (variant) { + case "SHA-1": + if (null === this.sha1) { + this.sha1 = coreSHA1(message, this.strBinLen); + } + return formatFunc(this.sha1); + case "SHA-224": + if (null === this.sha224) { + this.sha224 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha224); + case "SHA-256": + if (null === this.sha256) { + this.sha256 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha256); + case "SHA-384": + if (null === this.sha384) { + this.sha384 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha384); + case "SHA-512": + if (null === this.sha512) { + this.sha512 = coreSHA2(message, this.strBinLen, variant); + } + return formatFunc(this.sha512); + default: + return "HASH NOT RECOGNIZED"; + } + }, + + /* + * Returns the desired HMAC of the string specified at instantiation + * using the key and variant param. + * + * @param {String} key The key used to calculate the HMAC + * @param {String} inputFormat The format of key, ASCII or HEX + * @param {String} variant The desired SHA variant (SHA-1, SHA-224, + * SHA-256, SHA-384, or SHA-512) + * @param {String} outputFormat The desired output formatting + * (B64 or HEX) + * @return The string representation of the hash in the format specified + */ + getHMAC: function(key, inputFormat, variant, outputFormat) { + var formatFunc, keyToUse, blockByteSize, blockBitSize, i, + retVal, lastArrayIndex, keyBinLen, hashBitSize, + keyWithIPad = [], + keyWithOPad = []; + + /* Validate the output format selection */ + switch (outputFormat) { + case "HEX": + formatFunc = binb2hex; + break; + case "B64": + formatFunc = binb2b64; + break; + case "ASCII": + formatFunc = binb2str; + break; + default: + return "FORMAT NOT RECOGNIZED"; + } + + /* Validate the hash variant selection and set needed variables */ + switch (variant) { + case "SHA-1": + blockByteSize = 64; + hashBitSize = 160; + break; + case "SHA-224": + blockByteSize = 64; + hashBitSize = 224; + break; + case "SHA-256": + blockByteSize = 64; + hashBitSize = 256; + break; + case "SHA-384": + blockByteSize = 128; + hashBitSize = 384; + break; + case "SHA-512": + blockByteSize = 128; + hashBitSize = 512; + break; + default: + return "HASH NOT RECOGNIZED"; + } + + /* Validate input format selection */ + if ("HEX" === inputFormat) { + /* Nibbles must come in pairs */ + if (0 !== (key.length % 2)) { + return "KEY MUST BE IN BYTE INCREMENTS"; + } + keyToUse = hex2binb(key); + keyBinLen = key.length * 4; + } else if ("ASCII" === inputFormat) { + keyToUse = str2binb(key); + keyBinLen = key.length * charSize; + } else { + return "UNKNOWN KEY INPUT TYPE"; + } + + /* These are used multiple times, calculate and store them */ + blockBitSize = blockByteSize * 8; + lastArrayIndex = (blockByteSize / 4) - 1; + + /* Figure out what to do with the key based on its size relative to + * the hash's block size */ + if (blockByteSize < (keyBinLen / 8)) { + if ("SHA-1" === variant) { + keyToUse = coreSHA1(keyToUse, keyBinLen); + } else { + keyToUse = coreSHA2(keyToUse, keyBinLen, variant); + } + /* For all variants, the block size is bigger than the output + * size so there will never be a useful byte at the end of the + * string */ + keyToUse[lastArrayIndex] &= 0xFFFFFF00; + } else if (blockByteSize > (keyBinLen / 8)) { + /* If the blockByteSize is greater than the key length, there + * will always be at LEAST one "useless" byte at the end of the + * string */ + keyToUse[lastArrayIndex] &= 0xFFFFFF00; + } + + /* Create ipad and opad */ + for (i = 0; i <= lastArrayIndex; i += 1) { + keyWithIPad[i] = keyToUse[i] ^ 0x36363636; + keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C; + } + + /* Calculate the HMAC */ + if ("SHA-1" === variant) { + retVal = coreSHA1( + keyWithIPad.concat(this.strToHash), + blockBitSize + this.strBinLen); + retVal = coreSHA1( + keyWithOPad.concat(retVal), + blockBitSize + hashBitSize); + } else { + retVal = coreSHA2( + keyWithIPad.concat(this.strToHash), + blockBitSize + this.strBinLen, variant); + retVal = coreSHA2( + keyWithOPad.concat(retVal), + blockBitSize + hashBitSize, variant); + } + + return (formatFunc(retVal)); + } + }; + + return jsSHA; +}()); + +module.exports = { + /** SHA1 hash */ + sha1: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-1", "ASCII"); + }, + /** SHA224 hash */ + sha224: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-224", "ASCII"); + }, + /** SHA256 hash */ + sha256: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-256", "ASCII"); + }, + /** SHA384 hash */ + sha384: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-384", "ASCII"); + + }, + /** SHA512 hash */ + sha512: function(str) { + var shaObj = new jsSHA(str, "ASCII"); + return shaObj.getHash("SHA-512", "ASCII"); + } +} diff --git a/src/crypto/index.js b/src/crypto/index.js new file mode 100644 index 00000000..ac1ddb79 --- /dev/null +++ b/src/crypto/index.js @@ -0,0 +1,26 @@ +/** + * @see module:crypto/crypto + * @module crypto + */ +module.exports = { + /** @see module:crypto/cipher */ + cipher: require('./cipher'), + /** @see module:crypto/hash */ + hash: require('./hash'), + /** @see module:crypto/cfb */ + cfb: require('./cfb.js'), + /** @see module:crypto/public_key */ + publicKey: require('./public_key'), + /** @see module:crypto/signature */ + signature: require('./signature.js'), + /** @see module:crypto/random */ + random: require('./random.js'), + /** @see module:crypto/pkcs1 */ + pkcs1: require('./pkcs1.js') + +} + +var crypto = require('./crypto.js'); + +for (var i in crypto) + module.exports[i] = crypto[i]; diff --git a/src/crypto/package.json b/src/crypto/package.json new file mode 100644 index 00000000..56ca0ca3 --- /dev/null +++ b/src/crypto/package.json @@ -0,0 +1,5 @@ +{ + "name": "openpgp-crypto", + "version": "0.0.1", + "main": "./index.js" +} diff --git a/src/crypto/pkcs1.js b/src/crypto/pkcs1.js new file mode 100644 index 00000000..86838366 --- /dev/null +++ b/src/crypto/pkcs1.js @@ -0,0 +1,144 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * PKCS1 encoding + * @requires crypto/crypto + * @requires crypto/hash + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/pkcs1 + */ + +/** + * ASN1 object identifiers for hashes (See RFC4880 5.2.2) + */ +hash_headers = new Array(); +hash_headers[1] = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, + 0x10 +]; +hash_headers[2] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14]; +hash_headers[3] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14]; +hash_headers[8] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, + 0x04, 0x20 +]; +hash_headers[9] = [0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, + 0x04, 0x30 +]; +hash_headers[10] = [0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40 +]; +hash_headers[11] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, + 0x00, 0x04, 0x1C +]; + +var crypto = require('./crypto.js'), + random = require('./random.js'), + util = require('../util'), + BigInteger = require('./public_key/jsbn.js'), + hash = require('./hash'); + +module.exports = { + eme: { + /** + * create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1) + * @param {String} message message to be padded + * @param {Integer} length Length to the resulting message + * @return {String} EME-PKCS1 padded message + */ + encode: function(message, length) { + if (message.length > length - 11) + return -1; + var result = ""; + result += String.fromCharCode(0); + result += String.fromCharCode(2); + for (var i = 0; i < length - message.length - 3; i++) { + result += String.fromCharCode(random.getPseudoRandom(1, 255)); + } + result += String.fromCharCode(0); + result += message; + return result; + }, + + /** + * decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2) + * @param {String} message EME-PKCS1 padded message + * @return {String} decoded message + */ + decode: function(message, len) { + if (message.length < len) + message = String.fromCharCode(0) + message; + if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2) + return -1; + var i = 2; + while (message.charCodeAt(i) != 0 && message.length > i) + i++; + return message.substring(i + 1, message.length); + } + }, + + emsa: { + + /** + * create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3) + * @param {Integer} algo Hash algorithm type used + * @param {String} data Data to be hashed + * @param {Integer} keylength Key size of the public mpi in bytes + * @returns {String} Hashcode with pkcs1padding as string + */ + encode: function(algo, data, keylength) { + var data2 = ""; + data2 += String.fromCharCode(0x00); + data2 += String.fromCharCode(0x01); + for (var i = 0; i < (keylength - hash_headers[algo].length - 3 - + hash.getHashByteLength(algo)); i++) + + data2 += String.fromCharCode(0xff); + + data2 += String.fromCharCode(0x00); + + for (var i = 0; i < hash_headers[algo].length; i++) + data2 += String.fromCharCode(hash_headers[algo][i]); + + data2 += hash.digest(algo, data); + return new BigInteger(util.hexstrdump(data2), 16); + }, + + /** + * extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3) + * @param {String} data Hash in pkcs1 encoding + * @returns {String} The hash as string + */ + decode: function(algo, data) { + var i = 0; + if (data.charCodeAt(0) == 0) i++; + else if (data.charCodeAt(0) != 1) return -1; + else i++; + + while (data.charCodeAt(i) == 0xFF) i++; + if (data.charCodeAt(i++) != 0) return -1; + var j = 0; + for (j = 0; j < hash_headers[algo].length && j + i < data.length; j++) { + if (data.charCodeAt(j + i) != hash_headers[algo][j]) return -1; + } + i += j; + if (data.substring(i).length < hash.getHashByteLength(algo)) return -1; + return data.substring(i); + } + } +} diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js new file mode 100644 index 00000000..d488e3dc --- /dev/null +++ b/src/crypto/public_key/dsa.js @@ -0,0 +1,171 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// A Digital signature algorithm implementation + +/** + * @requires crypto/hash + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/public_key/dsa + */ + +var BigInteger = require('./jsbn.js'), + random = require('../random.js'), + hashModule = require('../hash'), + util = require('../../util'), + config = require('../../config'); + +function DSA() { + // s1 = ((g**s) mod p) mod q + // s1 = ((s**-1)*(sha-1(m)+(s1*x) mod q) + function sign(hashalgo, m, g, p, q, x) { + // If the output size of the chosen hash is larger than the number of + // bits of q, the hash result is truncated to fit by taking the number + // of leftmost bits equal to the number of bits of q. This (possibly + // truncated) hash function result is treated as a number and used + // directly in the DSA signature algorithm. + var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength()); + var hash = new BigInteger(util.hexstrdump(hashed_data), 16); + var k = random.getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE)); + var s1 = (g.modPow(k, p)).mod(q); + var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q); + var result = new Array(); + result[0] = s1.toMPI(); + result[1] = s2.toMPI(); + return result; + } + + function select_hash_algorithm(q) { + var usersetting = config.prefer_hash_algorithm; + /* + * 1024-bit key, 160-bit q, SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512 hash + * 2048-bit key, 224-bit q, SHA-224, SHA-256, SHA-384, or SHA-512 hash + * 2048-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash + * 3072-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash + */ + switch (Math.round(q.bitLength() / 8)) { + case 20: + // 1024 bit + if (usersetting != 2 && + usersetting > 11 && + usersetting != 10 && + usersetting < 8) + return 2; // prefer sha1 + return usersetting; + case 28: + // 2048 bit + if (usersetting > 11 && + usersetting < 8) + return 11; + return usersetting; + case 32: + // 4096 bit // prefer sha224 + if (usersetting > 10 && + usersetting < 8) + return 8; // prefer sha256 + return usersetting; + default: + util.print_debug("DSA select hash algorithm: returning null for an unknown length of q"); + return null; + + } + } + this.select_hash_algorithm = select_hash_algorithm; + + function verify(hashalgo, s1, s2, m, p, q, g, y) { + var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength()); + var hash = new BigInteger(util.hexstrdump(hashed_data), 16); + if (BigInteger.ZERO.compareTo(s1) > 0 || + s1.compareTo(q) > 0 || + BigInteger.ZERO.compareTo(s2) > 0 || + s2.compareTo(q) > 0) { + util.print_debug("invalid DSA Signature"); + return null; + } + var w = s2.modInverse(q); + var u1 = hash.multiply(w).mod(q); + var u2 = s1.multiply(w).mod(q); + return g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); + } + + /* + * unused code. This can be used as a start to write a key generator + * function. + + function generateKey(bitcount) { + var qi = new BigInteger(bitcount, primeCenterie); + var pi = generateP(q, 512); + var gi = generateG(p, q, bitcount); + var xi; + do { + xi = new BigInteger(q.bitCount(), rand); + } while (x.compareTo(BigInteger.ZERO) != 1 && x.compareTo(q) != -1); + var yi = g.modPow(x, p); + return {x: xi, q: qi, p: pi, g: gi, y: yi}; + } + + function generateP(q, bitlength, randomfn) { + if (bitlength % 64 != 0) { + return false; + } + var pTemp; + var pTemp2; + do { + pTemp = randomfn(bitcount, true); + pTemp2 = pTemp.subtract(BigInteger.ONE); + pTemp = pTemp.subtract(pTemp2.remainder(q)); + } while (!pTemp.isProbablePrime(primeCenterie) || pTemp.bitLength() != l); + return pTemp; + } + + function generateG(p, q, bitlength, randomfn) { + var aux = p.subtract(BigInteger.ONE); + var pow = aux.divide(q); + var gTemp; + do { + gTemp = randomfn(bitlength); + } while (gTemp.compareTo(aux) != -1 && gTemp.compareTo(BigInteger.ONE) != 1); + return gTemp.modPow(pow, p); + } + + function generateK(q, bitlength, randomfn) { + var tempK; + do { + tempK = randomfn(bitlength, false); + } while (tempK.compareTo(q) != -1 && tempK.compareTo(BigInteger.ZERO) != 1); + return tempK; + } + + function generateR(q,p) { + k = generateK(q); + var r = g.modPow(k, p).mod(q); + return r; + } + + function generateS(hashfn,k,r,m,q,x) { + var hash = hashfn(m); + s = (k.modInverse(q).multiply(hash.add(x.multiply(r)))).mod(q); + return s; + } */ + this.sign = sign; + this.verify = verify; + // this.generate = generateKey; +} + +module.exports = DSA; diff --git a/src/crypto/public_key/elgamal.js b/src/crypto/public_key/elgamal.js new file mode 100644 index 00000000..4cc3a686 --- /dev/null +++ b/src/crypto/public_key/elgamal.js @@ -0,0 +1,60 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// ElGamal implementation + +/** + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/public_key/elgamal + */ + +var BigInteger = require('./jsbn.js'), + random = require('../random.js'), + util = require('../../util'); + +function Elgamal() { + + function encrypt(m, g, p, y) { + // choose k in {2,...,p-2} + var two = BigInteger.ONE.add(BigInteger.ONE); + var pMinus2 = p.subtract(two); + var k = random.getRandomBigIntegerInRange(two, pMinus2); + k = k.mod(pMinus2).add(BigInteger.ONE); + var c = []; + c[0] = g.modPow(k, p); + c[1] = y.modPow(k, p).multiply(m).mod(p); + return c; + } + + function decrypt(c1, c2, p, x) { + util.print_debug("Elgamal Decrypt:\nc1:" + util.hexstrdump(c1.toMPI()) + "\n" + + "c2:" + util.hexstrdump(c2.toMPI()) + "\n" + + "p:" + util.hexstrdump(p.toMPI()) + "\n" + + "x:" + util.hexstrdump(x.toMPI())); + return (c1.modPow(x, p).modInverse(p)).multiply(c2).mod(p); + //var c = c1.pow(x).modInverse(p); // c0^-a mod p + //return c.multiply(c2).mod(p); + } + + // signing and signature verification using Elgamal is not required by OpenPGP. + this.encrypt = encrypt; + this.decrypt = decrypt; +} + +module.exports = Elgamal; diff --git a/src/crypto/public_key/index.js b/src/crypto/public_key/index.js new file mode 100644 index 00000000..beafaf9f --- /dev/null +++ b/src/crypto/public_key/index.js @@ -0,0 +1,14 @@ +/** + * @requires crypto/public_key/dsa + * @requires crypto/public_key/elgamal + * @requires crypto/public_key/rsa + * @module crypto/public_key + */ +module.exports = { + /** @see module:crypto/public_key/rsa */ + rsa: require('./rsa.js'), + /** @see module:crypto/public_key/elgamal */ + elgamal: require('./elgamal.js'), + /** @see module:crypto/public_key/dsa */ + dsa: require('./dsa.js') +} diff --git a/src/crypto/public_key/jsbn.js b/src/crypto/public_key/jsbn.js new file mode 100644 index 00000000..845fd44a --- /dev/null +++ b/src/crypto/public_key/jsbn.js @@ -0,0 +1,1710 @@ +/* + * Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU) + * All Rights Reserved. + * + * Modified by Recurity Labs GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +/** + * @requires util + * @module crypto/public_key/jsbn + */ + +var util = require('../../util'); + +// Basic JavaScript BN library - subset useful for RSA encryption. + +// Bits per digit +var dbits; + +// JavaScript engine analysis +var canary = 0xdeadbeefcafe; +var j_lm = ((canary & 0xffffff) == 0xefcafe); + +// (public) Constructor + +function BigInteger(a, b, c) { + if (a != null) + if ("number" == typeof a) this.fromNumber(a, b, c); + else if (b == null && "string" != typeof a) this.fromString(a, 256); + else this.fromString(a, b); +} + +// return new, unset BigInteger + +function nbi() { + return new BigInteger(null); +} + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) + +function am1(i, x, w, j, c, n) { + while (--n >= 0) { + var v = x * this[i++] + w[j] + c; + c = Math.floor(v / 0x4000000); + w[j++] = v & 0x3ffffff; + } + return c; +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) + +function am2(i, x, w, j, c, n) { + var xl = x & 0x7fff, + xh = x >> 15; + while (--n >= 0) { + var l = this[i] & 0x7fff; + var h = this[i++] >> 15; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); + w[j++] = l & 0x3fffffff; + } + return c; +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. + +function am3(i, x, w, j, c, n) { + var xl = x & 0x3fff, + xh = x >> 14; + while (--n >= 0) { + var l = this[i] & 0x3fff; + var h = this[i++] >> 14; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; + c = (l >> 28) + (m >> 14) + xh * h; + w[j++] = l & 0xfffffff; + } + return c; +} +/*if(j_lm && (navigator != undefined && + navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; +} +else if(j_lm && (navigator != undefined && navigator.appName != "Netscape")) {*/ +BigInteger.prototype.am = am1; +dbits = 26; +/*} +else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; +}*/ + +BigInteger.prototype.DB = dbits; +BigInteger.prototype.DM = ((1 << dbits) - 1); +BigInteger.prototype.DV = (1 << dbits); + +var BI_FP = 52; +BigInteger.prototype.FV = Math.pow(2, BI_FP); +BigInteger.prototype.F1 = BI_FP - dbits; +BigInteger.prototype.F2 = 2 * dbits - BI_FP; + +// Digit conversions +var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; +var BI_RC = new Array(); +var rr, vv; +rr = "0".charCodeAt(0); +for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; +rr = "a".charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; +rr = "A".charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + +function int2char(n) { + return BI_RM.charAt(n); +} + +function intAt(s, i) { + var c = BI_RC[s.charCodeAt(i)]; + return (c == null) ? -1 : c; +} + +// (protected) copy this to r + +function bnpCopyTo(r) { + for (var i = this.t - 1; i >= 0; --i) r[i] = this[i]; + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV + +function bnpFromInt(x) { + this.t = 1; + this.s = (x < 0) ? -1 : 0; + if (x > 0) this[0] = x; + else if (x < -1) this[0] = x + DV; + else this.t = 0; +} + +// return bigint initialized to value + +function nbv(i) { + var r = nbi(); + r.fromInt(i); + return r; +} + +// (protected) set from string and radix + +function bnpFromString(s, b) { + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 256) k = 8; // byte array + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else { + this.fromRadix(s, b); + return; + } + this.t = 0; + this.s = 0; + var i = s.length, + mi = false, + sh = 0; + while (--i >= 0) { + var x = (k == 8) ? s[i] & 0xff : intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if (sh == 0) + this[this.t++] = x; + else if (sh + k > this.DB) { + this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; + this[this.t++] = (x >> (this.DB - sh)); + } else + this[this.t - 1] |= x << sh; + sh += k; + if (sh >= this.DB) sh -= this.DB; + } + if (k == 8 && (s[0] & 0x80) != 0) { + this.s = -1; + if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh; + } + this.clamp(); + if (mi) BigInteger.ZERO.subTo(this, this); +} + +// (protected) clamp off excess high words + +function bnpClamp() { + var c = this.s & this.DM; + while (this.t > 0 && this[this.t - 1] == c)--this.t; +} + +// (public) return string representation in given radix + +function bnToString(b) { + if (this.s < 0) return "-" + this.negate().toString(b); + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else return this.toRadix(b); + var km = (1 << k) - 1, + d, m = false, + r = "", + i = this.t; + var p = this.DB - (i * this.DB) % k; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) > 0) { + m = true; + r = int2char(d); + } + while (i >= 0) { + if (p < k) { + d = (this[i] & ((1 << p) - 1)) << (k - p); + d |= this[--i] >> (p += this.DB - k); + } else { + d = (this[i] >> (p -= k)) & km; + if (p <= 0) { + p += this.DB; + --i; + } + } + if (d > 0) m = true; + if (m) r += int2char(d); + } + } + return m ? r : "0"; +} + +// (public) -this + +function bnNegate() { + var r = nbi(); + BigInteger.ZERO.subTo(this, r); + return r; +} + +// (public) |this| + +function bnAbs() { + return (this.s < 0) ? this.negate() : this; +} + +// (public) return + if this > a, - if this < a, 0 if equal + +function bnCompareTo(a) { + var r = this.s - a.s; + if (r != 0) return r; + var i = this.t; + r = i - a.t; + if (r != 0) return r; + while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; + return 0; +} + +// returns bit length of the integer x + +function nbits(x) { + var r = 1, + t; + if ((t = x >>> 16) != 0) { + x = t; + r += 16; + } + if ((t = x >> 8) != 0) { + x = t; + r += 8; + } + if ((t = x >> 4) != 0) { + x = t; + r += 4; + } + if ((t = x >> 2) != 0) { + x = t; + r += 2; + } + if ((t = x >> 1) != 0) { + x = t; + r += 1; + } + return r; +} + +// (public) return the number of bits in "this" + +function bnBitLength() { + if (this.t <= 0) return 0; + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)); +} + +// (protected) r = this << n*DB + +function bnpDLShiftTo(n, r) { + var i; + for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i]; + for (i = n - 1; i >= 0; --i) r[i] = 0; + r.t = this.t + n; + r.s = this.s; +} + +// (protected) r = this >> n*DB + +function bnpDRShiftTo(n, r) { + for (var i = n; i < this.t; ++i) r[i - n] = this[i]; + r.t = Math.max(this.t - n, 0); + r.s = this.s; +} + +// (protected) r = this << n + +function bnpLShiftTo(n, r) { + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << cbs) - 1; + var ds = Math.floor(n / this.DB), + c = (this.s << bs) & this.DM, + i; + for (i = this.t - 1; i >= 0; --i) { + r[i + ds + 1] = (this[i] >> cbs) | c; + c = (this[i] & bm) << bs; + } + for (i = ds - 1; i >= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t + ds + 1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n + +function bnpRShiftTo(n, r) { + r.s = this.s; + var ds = Math.floor(n / this.DB); + if (ds >= this.t) { + r.t = 0; + return; + } + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << bs) - 1; + r[0] = this[ds] >> bs; + for (var i = ds + 1; i < this.t; ++i) { + r[i - ds - 1] |= (this[i] & bm) << cbs; + r[i - ds] = this[i] >> bs; + } + if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; + r.t = this.t - ds; + r.clamp(); +} + +// (protected) r = this - a + +function bnpSubTo(a, r) { + var i = 0, + c = 0, + m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] - a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c -= a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while (i < a.t) { + c -= a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c < -1) r[i++] = this.DV + c; + else if (c > 0) r[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. + +function bnpMultiplyTo(a, r) { + var x = this.abs(), + y = a.abs(); + var i = x.t; + r.t = i + y.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); + r.s = 0; + r.clamp(); + if (this.s != a.s) BigInteger.ZERO.subTo(r, r); +} + +// (protected) r = this^2, r != this (HAC 14.16) + +function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2 * x.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < x.t - 1; ++i) { + var c = x.am(i, x[i], r, 2 * i, 0, 1); + if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { + r[i + x.t] -= x.DV; + r[i + x.t + 1] = 1; + } + } + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. + +function bnpDivRemTo(m, q, r) { + var pm = m.abs(); + if (pm.t <= 0) return; + var pt = this.abs(); + if (pt.t < pm.t) { + if (q != null) q.fromInt(0); + if (r != null) this.copyTo(r); + return; + } + if (r == null) r = nbi(); + var y = nbi(), + ts = this.s, + ms = m.s; + var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus + if (nsh > 0) { + pm.lShiftTo(nsh, y); + pt.lShiftTo(nsh, r); + } else { + pm.copyTo(y); + pt.copyTo(r); + } + var ys = y.t; + var y0 = y[ys - 1]; + if (y0 == 0) return; + var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0); + var d1 = this.FV / yt, + d2 = (1 << this.F1) / yt, + e = 1 << this.F2; + var i = r.t, + j = i - ys, + t = (q == null) ? nbi() : q; + y.dlShiftTo(j, t); + if (r.compareTo(t) >= 0) { + r[r.t++] = 1; + r.subTo(t, r); + } + BigInteger.ONE.dlShiftTo(ys, t); + t.subTo(y, y); // "negative" y so we can replace sub with am later + while (y.t < ys) y[y.t++] = 0; + while (--j >= 0) { + // Estimate quotient digit + var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); + if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out + y.dlShiftTo(j, t); + r.subTo(t, r); + while (r[i] < --qd) r.subTo(t, r); + } + } + if (q != null) { + r.drShiftTo(ys, q); + if (ts != ms) BigInteger.ZERO.subTo(q, q); + } + r.t = ys; + r.clamp(); + if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder + if (ts < 0) BigInteger.ZERO.subTo(r, r); +} + +// (public) this mod a + +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a, null, r); + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); + return r; +} + +// Modular reduction using "classic" algorithm + +function Classic(m) { + this.m = m; +} + +function cConvert(x) { + if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} + +function cRevert(x) { + return x; +} + +function cReduce(x) { + x.divRemTo(this.m, null, x); +} + +function cMulTo(x, y, r) { + x.multiplyTo(y, r); + this.reduce(r); +} + +function cSqrTo(x, r) { + x.squareTo(r); + this.reduce(r); +} + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. + +function bnpInvDigit() { + if (this.t < 1) return 0; + var x = this[0]; + if ((x & 1) == 0) return 0; + var y = x & 3; // y == 1/x mod 2^2 + y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4 + y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y > 0) ? this.DV - y : -y; +} + +// Montgomery reduction + +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp & 0x7fff; + this.mph = this.mp >> 15; + this.um = (1 << (m.DB - 15)) - 1; + this.mt2 = 2 * m.t; +} + +// xR mod m + +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t, r); + r.divRemTo(this.m, null, r); + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); + return r; +} + +// x/R mod m + +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) + +function montReduce(x) { + while (x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for (var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i] & 0x7fff; + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; + // use am to combine the multiply-shift-add into one call + j = i + this.m.t; + x[j] += this.m.am(0, u0, x, i, 0, this.m.t); + // propagate carry + while (x[j] >= x.DV) { + x[j] -= x.DV; + x[++j]++; + } + } + x.clamp(); + x.drShiftTo(this.m.t, x); + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); +} + +// r = "x^2/R mod m"; x != r + +function montSqrTo(x, r) { + x.squareTo(r); + this.reduce(r); +} + +// r = "xy/R mod m"; x,y != r + +function montMulTo(x, y, r) { + x.multiplyTo(y, r); + this.reduce(r); +} + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even + +function bnpIsEven() { + return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; +} + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) + +function bnpExp(e, z) { + if (e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), + r2 = nbi(), + g = z.convert(this), + i = nbits(e) - 1; + g.copyTo(r); + while (--i >= 0) { + z.sqrTo(r, r2); + if ((e & (1 << i)) > 0) z.mulTo(r2, g, r); + else { + var t = r; + r = r2; + r2 = t; + } + } + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 + +function bnModPowInt(e, m) { + var z; + if (e < 256 || m.isEven()) z = new Classic(m); + else z = new Montgomery(m); + return this.exp(e, z); +} + +// protected +BigInteger.prototype.copyTo = bnpCopyTo; +BigInteger.prototype.fromInt = bnpFromInt; +BigInteger.prototype.fromString = bnpFromString; +BigInteger.prototype.clamp = bnpClamp; +BigInteger.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger.prototype.drShiftTo = bnpDRShiftTo; +BigInteger.prototype.lShiftTo = bnpLShiftTo; +BigInteger.prototype.rShiftTo = bnpRShiftTo; +BigInteger.prototype.subTo = bnpSubTo; +BigInteger.prototype.multiplyTo = bnpMultiplyTo; +BigInteger.prototype.squareTo = bnpSquareTo; +BigInteger.prototype.divRemTo = bnpDivRemTo; +BigInteger.prototype.invDigit = bnpInvDigit; +BigInteger.prototype.isEven = bnpIsEven; +BigInteger.prototype.exp = bnpExp; + +// public +BigInteger.prototype.toString = bnToString; +BigInteger.prototype.negate = bnNegate; +BigInteger.prototype.abs = bnAbs; +BigInteger.prototype.compareTo = bnCompareTo; +BigInteger.prototype.bitLength = bnBitLength; +BigInteger.prototype.mod = bnMod; +BigInteger.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); + +module.exports = BigInteger; + + + + + + + + + + + + + + + + + + + +/* + * Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU) + * All Rights Reserved. + * + * Modified by Recurity Labs GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +// Extended JavaScript BN functions, required for RSA private ops. + +// Version 1.1: new BigInteger("0", 10) returns "proper" zero +// Version 1.2: square() API, isProbablePrime fix + +// (public) +function bnClone() { + var r = nbi(); + this.copyTo(r); + return r; +} + +// (public) return value as integer + +function bnIntValue() { + if (this.s < 0) { + if (this.t == 1) return this[0] - this.DV; + else if (this.t == 0) return -1; + } else if (this.t == 1) return this[0]; + else if (this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0]; +} + +// (public) return value as byte + +function bnByteValue() { + return (this.t == 0) ? this.s : (this[0] << 24) >> 24; +} + +// (public) return value as short (assumes DB>=16) + +function bnShortValue() { + return (this.t == 0) ? this.s : (this[0] << 16) >> 16; +} + +// (protected) return x s.t. r^x < DV + +function bnpChunkSize(r) { + return Math.floor(Math.LN2 * this.DB / Math.log(r)); +} + +// (public) 0 if this == 0, 1 if this > 0 + +function bnSigNum() { + if (this.s < 0) return -1; + else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; + else return 1; +} + +// (protected) convert to radix string + +function bnpToRadix(b) { + if (b == null) b = 10; + if (this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b, cs); + var d = nbv(a), + y = nbi(), + z = nbi(), + r = ""; + this.divRemTo(d, y, z); + while (y.signum() > 0) { + r = (a + z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d, y, z); + } + return z.intValue().toString(b) + r; +} + +// (protected) convert from radix string + +function bnpFromRadix(s, b) { + this.fromInt(0); + if (b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b, cs), + mi = false, + j = 0, + w = 0; + for (var i = 0; i < s.length; ++i) { + var x = intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b * w + x; + if (++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w, 0); + j = 0; + w = 0; + } + } + if (j > 0) { + this.dMultiply(Math.pow(b, j)); + this.dAddOffset(w, 0); + } + if (mi) BigInteger.ZERO.subTo(this, this); +} + +// (protected) alternate constructor + +function bnpFromNumber(a, b, c) { + if ("number" == typeof b) { + // new BigInteger(int,int,RNG) + if (a < 2) this.fromInt(1); + else { + this.fromNumber(a, c); + if (!this.testBit(a - 1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this); + if (this.isEven()) this.dAddOffset(1, 0); // force odd + while (!this.isProbablePrime(b)) { + this.dAddOffset(2, 0); + if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this); + } + } + } else { + // new BigInteger(int,RNG) + var x = new Array(), + t = a & 7; + x.length = (a >> 3) + 1; + b.nextBytes(x); + if (t > 0) x[0] &= ((1 << t) - 1); + else x[0] = 0; + this.fromString(x, 256); + } +} + +// (public) convert to bigendian byte array + +function bnToByteArray() { + var i = this.t, + r = new Array(); + r[0] = this.s; + var p = this.DB - (i * this.DB) % 8, + d, k = 0; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) + r[k++] = d | (this.s << (this.DB - p)); + while (i >= 0) { + if (p < 8) { + d = (this[i] & ((1 << p) - 1)) << (8 - p); + d |= this[--i] >> (p += this.DB - 8); + } else { + d = (this[i] >> (p -= 8)) & 0xff; + if (p <= 0) { + p += this.DB; + --i; + } + } + //if((d&0x80) != 0) d |= -256; + //if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; + if (k > 0 || d != this.s) r[k++] = d; + } + } + return r; +} + +function bnEquals(a) { + return (this.compareTo(a) == 0); +} + +function bnMin(a) { + return (this.compareTo(a) < 0) ? this : a; +} + +function bnMax(a) { + return (this.compareTo(a) > 0) ? this : a; +} + +// (protected) r = this op a (bitwise) + +function bnpBitwiseTo(a, op, r) { + var i, f, m = Math.min(a.t, this.t); + for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]); + if (a.t < this.t) { + f = a.s & this.DM; + for (i = m; i < this.t; ++i) r[i] = op(this[i], f); + r.t = this.t; + } else { + f = this.s & this.DM; + for (i = m; i < a.t; ++i) r[i] = op(f, a[i]); + r.t = a.t; + } + r.s = op(this.s, a.s); + r.clamp(); +} + +// (public) this & a + +function op_and(x, y) { + return x & y; +} + +function bnAnd(a) { + var r = nbi(); + this.bitwiseTo(a, op_and, r); + return r; +} + +// (public) this | a + +function op_or(x, y) { + return x | y; +} + +function bnOr(a) { + var r = nbi(); + this.bitwiseTo(a, op_or, r); + return r; +} + +// (public) this ^ a + +function op_xor(x, y) { + return x ^ y; +} + +function bnXor(a) { + var r = nbi(); + this.bitwiseTo(a, op_xor, r); + return r; +} + +// (public) this & ~a + +function op_andnot(x, y) { + return x & ~y; +} + +function bnAndNot(a) { + var r = nbi(); + this.bitwiseTo(a, op_andnot, r); + return r; +} + +// (public) ~this + +function bnNot() { + var r = nbi(); + for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i]; + r.t = this.t; + r.s = ~this.s; + return r; +} + +// (public) this << n + +function bnShiftLeft(n) { + var r = nbi(); + if (n < 0) this.rShiftTo(-n, r); + else this.lShiftTo(n, r); + return r; +} + +// (public) this >> n + +function bnShiftRight(n) { + var r = nbi(); + if (n < 0) this.lShiftTo(-n, r); + else this.rShiftTo(n, r); + return r; +} + +// return index of lowest 1-bit in x, x < 2^31 + +function lbit(x) { + if (x == 0) return -1; + var r = 0; + if ((x & 0xffff) == 0) { + x >>= 16; + r += 16; + } + if ((x & 0xff) == 0) { + x >>= 8; + r += 8; + } + if ((x & 0xf) == 0) { + x >>= 4; + r += 4; + } + if ((x & 3) == 0) { + x >>= 2; + r += 2; + } + if ((x & 1) == 0)++r; + return r; +} + +// (public) returns index of lowest 1-bit (or -1 if none) + +function bnGetLowestSetBit() { + for (var i = 0; i < this.t; ++i) + if (this[i] != 0) return i * this.DB + lbit(this[i]); + if (this.s < 0) return this.t * this.DB; + return -1; +} + +// return number of 1 bits in x + +function cbit(x) { + var r = 0; + while (x != 0) { + x &= x - 1; + ++r; + } + return r; +} + +// (public) return number of set bits + +function bnBitCount() { + var r = 0, + x = this.s & this.DM; + for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x); + return r; +} + +// (public) true iff nth bit is set + +function bnTestBit(n) { + var j = Math.floor(n / this.DB); + if (j >= this.t) return (this.s != 0); + return ((this[j] & (1 << (n % this.DB))) != 0); +} + +// (protected) this op (1<>= this.DB; + } + if (a.t < this.t) { + c += a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while (i < a.t) { + c += a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c > 0) r[i++] = c; + else if (c < -1) r[i++] = this.DV + c; + r.t = i; + r.clamp(); +} + +// (public) this + a + +function bnAdd(a) { + var r = nbi(); + this.addTo(a, r); + return r; +} + +// (public) this - a + +function bnSubtract(a) { + var r = nbi(); + this.subTo(a, r); + return r; +} + +// (public) this * a + +function bnMultiply(a) { + var r = nbi(); + this.multiplyTo(a, r); + return r; +} + +// (public) this^2 + +function bnSquare() { + var r = nbi(); + this.squareTo(r); + return r; +} + +// (public) this / a + +function bnDivide(a) { + var r = nbi(); + this.divRemTo(a, r, null); + return r; +} + +// (public) this % a + +function bnRemainder(a) { + var r = nbi(); + this.divRemTo(a, null, r); + return r; +} + +// (public) [this/a,this%a] + +function bnDivideAndRemainder(a) { + var q = nbi(), + r = nbi(); + this.divRemTo(a, q, r); + return new Array(q, r); +} + +// (protected) this *= n, this >= 0, 1 < n < DV + +function bnpDMultiply(n) { + this[this.t] = this.am(0, n - 1, this, 0, 0, this.t); + ++this.t; + this.clamp(); +} + +// (protected) this += n << w words, this >= 0 + +function bnpDAddOffset(n, w) { + if (n == 0) return; + while (this.t <= w) this[this.t++] = 0; + this[w] += n; + while (this[w] >= this.DV) { + this[w] -= this.DV; + if (++w >= this.t) this[this.t++] = 0; + ++this[w]; + } +} + +// A "null" reducer + +function NullExp() {} + +function nNop(x) { + return x; +} + +function nMulTo(x, y, r) { + x.multiplyTo(y, r); +} + +function nSqrTo(x, r) { + x.squareTo(r); +} + +NullExp.prototype.convert = nNop; +NullExp.prototype.revert = nNop; +NullExp.prototype.mulTo = nMulTo; +NullExp.prototype.sqrTo = nSqrTo; + +// (public) this^e + +function bnPow(e) { + return this.exp(e, new NullExp()); +} + +// (protected) r = lower n words of "this * a", a.t <= n +// "this" should be the larger one if appropriate. + +function bnpMultiplyLowerTo(a, n, r) { + var i = Math.min(this.t + a.t, n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while (i > 0) r[--i] = 0; + var j; + for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t); + for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i); + r.clamp(); +} + +// (protected) r = "this * a" without lower n words, n > 0 +// "this" should be the larger one if appropriate. + +function bnpMultiplyUpperTo(a, n, r) { + --n; + var i = r.t = this.t + a.t - n; + r.s = 0; // assumes a,this >= 0 + while (--i >= 0) r[i] = 0; + for (i = Math.max(n - this.t, 0); i < a.t; ++i) + r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n); + r.clamp(); + r.drShiftTo(1, r); +} + +// Barrett modular reduction + +function Barrett(m) { + // setup Barrett + this.r2 = nbi(); + this.q3 = nbi(); + BigInteger.ONE.dlShiftTo(2 * m.t, this.r2); + this.mu = this.r2.divide(m); + this.m = m; +} + +function barrettConvert(x) { + if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m); + else if (x.compareTo(this.m) < 0) return x; + else { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; + } +} + +function barrettRevert(x) { + return x; +} + +// x = x mod m (HAC 14.42) + +function barrettReduce(x) { + x.drShiftTo(this.m.t - 1, this.r2); + if (x.t > this.m.t + 1) { + x.t = this.m.t + 1; + x.clamp(); + } + this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3); + this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); + while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1); + x.subTo(this.r2, x); + while (x.compareTo(this.m) >= 0) x.subTo(this.m, x); +} + +// r = x^2 mod m; x != r + +function barrettSqrTo(x, r) { + x.squareTo(r); + this.reduce(r); +} + +// r = x*y mod m; x,y != r + +function barrettMulTo(x, y, r) { + x.multiplyTo(y, r); + this.reduce(r); +} + +Barrett.prototype.convert = barrettConvert; +Barrett.prototype.revert = barrettRevert; +Barrett.prototype.reduce = barrettReduce; +Barrett.prototype.mulTo = barrettMulTo; +Barrett.prototype.sqrTo = barrettSqrTo; + +// (public) this^e % m (HAC 14.85) + +function bnModPow(e, m) { + var i = e.bitLength(), + k, r = nbv(1), + z; + if (i <= 0) return r; + else if (i < 18) k = 1; + else if (i < 48) k = 3; + else if (i < 144) k = 4; + else if (i < 768) k = 5; + else k = 6; + if (i < 8) + z = new Classic(m); + else if (m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), + n = 3, + k1 = k - 1, + km = (1 << k) - 1; + g[1] = z.convert(this); + if (k > 1) { + var g2 = nbi(); + z.sqrTo(g[1], g2); + while (n <= km) { + g[n] = nbi(); + z.mulTo(g2, g[n - 2], g[n]); + n += 2; + } + } + + var j = e.t - 1, + w, is1 = true, + r2 = nbi(), + t; + i = nbits(e[j]) - 1; + while (j >= 0) { + if (i >= k1) w = (e[j] >> (i - k1)) & km; + else { + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1); + } + + n = k; + while ((w & 1) == 0) { + w >>= 1; + --n; + } + if ((i -= n) < 0) { + i += this.DB; + --j; + } + if (is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } else { + while (n > 1) { + z.sqrTo(r, r2); + z.sqrTo(r2, r); + n -= 2; + } + if (n > 0) z.sqrTo(r, r2); + else { + t = r; + r = r2; + r2 = t; + } + z.mulTo(r2, g[w], r); + } + + while (j >= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2); + t = r; + r = r2; + r2 = t; + if (--i < 0) { + i = this.DB - 1; + --j; + } + } + } + return z.revert(r); +} + +// (public) gcd(this,a) (HAC 14.54) + +function bnGCD(a) { + var x = (this.s < 0) ? this.negate() : this.clone(); + var y = (a.s < 0) ? a.negate() : a.clone(); + if (x.compareTo(y) < 0) { + var t = x; + x = y; + y = t; + } + var i = x.getLowestSetBit(), + g = y.getLowestSetBit(); + if (g < 0) return x; + if (i < g) g = i; + if (g > 0) { + x.rShiftTo(g, x); + y.rShiftTo(g, y); + } + while (x.signum() > 0) { + if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x); + if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y); + if (x.compareTo(y) >= 0) { + x.subTo(y, x); + x.rShiftTo(1, x); + } else { + y.subTo(x, y); + y.rShiftTo(1, y); + } + } + if (g > 0) y.lShiftTo(g, y); + return y; +} + +// (protected) this % n, n < 2^26 + +function bnpModInt(n) { + if (n <= 0) return 0; + var d = this.DV % n, + r = (this.s < 0) ? n - 1 : 0; + if (this.t > 0) + if (d == 0) r = this[0] % n; + else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n; + return r; +} + +// (public) 1/this % m (HAC 14.61) + +function bnModInverse(m) { + var ac = m.isEven(); + if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), + v = this.clone(); + var a = nbv(1), + b = nbv(0), + c = nbv(0), + d = nbv(1); + while (u.signum() != 0) { + while (u.isEven()) { + u.rShiftTo(1, u); + if (ac) { + if (!a.isEven() || !b.isEven()) { + a.addTo(this, a); + b.subTo(m, b); + } + a.rShiftTo(1, a); + } else if (!b.isEven()) b.subTo(m, b); + b.rShiftTo(1, b); + } + while (v.isEven()) { + v.rShiftTo(1, v); + if (ac) { + if (!c.isEven() || !d.isEven()) { + c.addTo(this, c); + d.subTo(m, d); + } + c.rShiftTo(1, c); + } else if (!d.isEven()) d.subTo(m, d); + d.rShiftTo(1, d); + } + if (u.compareTo(v) >= 0) { + u.subTo(v, u); + if (ac) a.subTo(c, a); + b.subTo(d, b); + } else { + v.subTo(u, v); + if (ac) c.subTo(a, c); + d.subTo(b, d); + } + } + if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if (d.compareTo(m) >= 0) return d.subtract(m); + if (d.signum() < 0) d.addTo(m, d); + else return d; + if (d.signum() < 0) return d.add(m); + else return d; +} + +var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, + 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, + 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, + 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, + 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, + 977, 983, 991, 997 +]; +var lplim = (1 << 26) / lowprimes[lowprimes.length - 1]; + +// (public) test primality with certainty >= 1-.5^t + +function bnIsProbablePrime(t) { + var i, x = this.abs(); + if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) { + for (i = 0; i < lowprimes.length; ++i) + if (x[0] == lowprimes[i]) return true; + return false; + } + if (x.isEven()) return false; + i = 1; + while (i < lowprimes.length) { + var m = lowprimes[i], + j = i + 1; + while (j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while (i < j) if (m % lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); +} + +/* added by Recurity Labs */ + +function nbits(x) { + var n = 1, + t; + if ((t = x >>> 16) != 0) { + x = t; + n += 16; + } + if ((t = x >> 8) != 0) { + x = t; + n += 8; + } + if ((t = x >> 4) != 0) { + x = t; + n += 4; + } + if ((t = x >> 2) != 0) { + x = t; + n += 2; + } + if ((t = x >> 1) != 0) { + x = t; + n += 1; + } + return n; +} + +function bnToMPI() { + var ba = this.toByteArray(); + var size = (ba.length - 1) * 8 + nbits(ba[0]); + var result = ""; + result += String.fromCharCode((size & 0xFF00) >> 8); + result += String.fromCharCode(size & 0xFF); + result += util.bin2str(ba); + return result; +} +/* END of addition */ + +// (protected) true if probably prime (HAC 4.24, Miller-Rabin) +function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if (k <= 0) return false; + var r = n1.shiftRight(k); + t = (t + 1) >> 1; + if (t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + var j, bases = []; + for (var i = 0; i < t; ++i) { + //Pick bases at random, instead of starting at 2 + for (;;) { + j = lowprimes[Math.floor(Math.random() * lowprimes.length)]; + if (bases.indexOf(j) == -1) break; + } + bases.push(j); + a.fromInt(j); + var y = a.modPow(r, this); + if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while (j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2, this); + if (y.compareTo(BigInteger.ONE) == 0) return false; + } + if (y.compareTo(n1) != 0) return false; + } + } + return true; +} + +var BigInteger = require('./jsbn.js'); + +// protected +BigInteger.prototype.chunkSize = bnpChunkSize; +BigInteger.prototype.toRadix = bnpToRadix; +BigInteger.prototype.fromRadix = bnpFromRadix; +BigInteger.prototype.fromNumber = bnpFromNumber; +BigInteger.prototype.bitwiseTo = bnpBitwiseTo; +BigInteger.prototype.changeBit = bnpChangeBit; +BigInteger.prototype.addTo = bnpAddTo; +BigInteger.prototype.dMultiply = bnpDMultiply; +BigInteger.prototype.dAddOffset = bnpDAddOffset; +BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; +BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; +BigInteger.prototype.modInt = bnpModInt; +BigInteger.prototype.millerRabin = bnpMillerRabin; + +// public +BigInteger.prototype.clone = bnClone; +BigInteger.prototype.intValue = bnIntValue; +BigInteger.prototype.byteValue = bnByteValue; +BigInteger.prototype.shortValue = bnShortValue; +BigInteger.prototype.signum = bnSigNum; +BigInteger.prototype.toByteArray = bnToByteArray; +BigInteger.prototype.equals = bnEquals; +BigInteger.prototype.min = bnMin; +BigInteger.prototype.max = bnMax; +BigInteger.prototype.and = bnAnd; +BigInteger.prototype.or = bnOr; +BigInteger.prototype.xor = bnXor; +BigInteger.prototype.andNot = bnAndNot; +BigInteger.prototype.not = bnNot; +BigInteger.prototype.shiftLeft = bnShiftLeft; +BigInteger.prototype.shiftRight = bnShiftRight; +BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; +BigInteger.prototype.bitCount = bnBitCount; +BigInteger.prototype.testBit = bnTestBit; +BigInteger.prototype.setBit = bnSetBit; +BigInteger.prototype.clearBit = bnClearBit; +BigInteger.prototype.flipBit = bnFlipBit; +BigInteger.prototype.add = bnAdd; +BigInteger.prototype.subtract = bnSubtract; +BigInteger.prototype.multiply = bnMultiply; +BigInteger.prototype.divide = bnDivide; +BigInteger.prototype.remainder = bnRemainder; +BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; +BigInteger.prototype.modPow = bnModPow; +BigInteger.prototype.modInverse = bnModInverse; +BigInteger.prototype.pow = bnPow; +BigInteger.prototype.gcd = bnGCD; +BigInteger.prototype.isProbablePrime = bnIsProbablePrime; +BigInteger.prototype.toMPI = bnToMPI; + +// JSBN-specific extension +BigInteger.prototype.square = bnSquare; diff --git a/src/crypto/public_key/package.json b/src/crypto/public_key/package.json new file mode 100644 index 00000000..28e5b904 --- /dev/null +++ b/src/crypto/public_key/package.json @@ -0,0 +1,5 @@ +{ + "name": "openpgp-crypto-public-key", + "version": "0.0.1", + "main": "./index.js" +} diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js new file mode 100644 index 00000000..3338238e --- /dev/null +++ b/src/crypto/public_key/rsa.js @@ -0,0 +1,152 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// RSA implementation + +/** + * @requires crypto/public_key/jsbn + * @requires crypto/random + * @requires util + * @module crypto/public_key/rsa + */ + +var BigInteger = require('./jsbn.js'), + util = require('../../util'), + random = require('../random.js'); + +function SecureRandom() { + function nextBytes(byteArray) { + for (var n = 0; n < byteArray.length; n++) { + byteArray[n] = random.getSecureRandomOctet(); + } + } + this.nextBytes = nextBytes; +} + +function RSA() { + /** + * This function uses jsbn Big Num library to decrypt RSA + * @param m + * message + * @param d + * RSA d as BigInteger + * @param p + * RSA p as BigInteger + * @param q + * RSA q as BigInteger + * @param u + * RSA u as BigInteger + * @return {BigInteger} The decrypted value of the message + */ + function decrypt(m, d, p, q, u) { + var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); + var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); + util.print_debug("rsa.js decrypt\nxpn:" + util.hexstrdump(xp.toMPI()) + "\nxqn:" + util.hexstrdump(xq.toMPI())); + + var t = xq.subtract(xp); + if (t[0] == 0) { + t = xp.subtract(xq); + t = t.multiply(u).mod(q); + t = q.subtract(t); + } else { + t = t.multiply(u).mod(q); + } + return t.multiply(p).add(xp); + } + + /** + * encrypt message + * @param m message as BigInteger + * @param e public MPI part as BigInteger + * @param n public MPI part as BigInteger + * @return BigInteger + */ + function encrypt(m, e, n) { + return m.modPowInt(e, n); + } + + /* Sign and Verify */ + function sign(m, d, n) { + return m.modPow(d, n); + } + + function verify(x, e, n) { + return x.modPowInt(e, n); + } + + // "empty" RSA key constructor + + function keyObject() { + this.n = null; + this.e = 0; + this.ee = null; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.u = null; + } + + // Generate a new random private key B bits long, using public expt E + + function generate(B, E) { + var key = new keyObject(); + var rng = new SecureRandom(); + var qs = B >> 1; + key.e = parseInt(E, 16); + key.ee = new BigInteger(E, 16); + for (;;) { + for (;;) { + key.p = new BigInteger(B - qs, 1, rng); + if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) + break; + } + for (;;) { + key.q = new BigInteger(qs, 1, rng); + if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) + break; + } + if (key.p.compareTo(key.q) <= 0) { + var t = key.p; + key.p = key.q; + key.q = t; + } + var p1 = key.p.subtract(BigInteger.ONE); + var q1 = key.q.subtract(BigInteger.ONE); + var phi = p1.multiply(q1); + if (phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) { + key.n = key.p.multiply(key.q); + key.d = key.ee.modInverse(phi); + key.dmp1 = key.d.mod(p1); + key.dmq1 = key.d.mod(q1); + key.u = key.p.modInverse(key.q); + break; + } + } + return key; + } + + this.encrypt = encrypt; + this.decrypt = decrypt; + this.verify = verify; + this.sign = sign; + this.generate = generate; + this.keyObject = keyObject; +} + +module.exports = RSA; diff --git a/src/crypto/random.js b/src/crypto/random.js new file mode 100644 index 00000000..774acda3 --- /dev/null +++ b/src/crypto/random.js @@ -0,0 +1,109 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +// The GPG4Browsers crypto interface + +/** + * @requires type/mpi + * @module crypto/random + */ + +var type_mpi = require('../type/mpi.js'); + +module.exports = { + /** + * Retrieve secure random byte string of the specified length + * @param {Integer} length Length in bytes to generate + * @return {String} Random byte string + */ + getRandomBytes: function(length) { + var result = ''; + for (var i = 0; i < length; i++) { + result += String.fromCharCode(this.getSecureRandomOctet()); + } + return result; + }, + + /** + * Return a pseudo-random number in the specified range + * @param {Integer} from Min of the random number + * @param {Integer} to Max of the random number (max 32bit) + * @return {Integer} A pseudo random number + */ + getPseudoRandom: function(from, to) { + return Math.round(Math.random() * (to - from)) + from; + }, + + /** + * Return a secure random number in the specified range + * @param {Integer} from Min of the random number + * @param {Integer} to Max of the random number (max 32bit) + * @return {Integer} A secure random number + */ + getSecureRandom: function(from, to) { + var buf = new Uint32Array(1); + window.crypto.getRandomValues(buf); + var bits = ((to - from)).toString(2).length; + while ((buf[0] & (Math.pow(2, bits) - 1)) > (to - from)) + window.crypto.getRandomValues(buf); + return from + (Math.abs(buf[0] & (Math.pow(2, bits) - 1))); + }, + + getSecureRandomOctet: function() { + var buf = new Uint32Array(1); + window.crypto.getRandomValues(buf); + return buf[0] & 0xFF; + }, + + /** + * Create a secure random big integer of bits length + * @param {Integer} bits Bit length of the MPI to create + * @return {BigInteger} Resulting big integer + */ + getRandomBigInteger: function(bits) { + if (bits < 0) { + return null; + } + var numBytes = Math.floor((bits + 7) / 8); + + var randomBits = this.getRandomBytes(numBytes); + if (bits % 8 > 0) { + + randomBits = String.fromCharCode( + (Math.pow(2, bits % 8) - 1) & + randomBits.charCodeAt(0)) + + randomBits.substring(1); + } + var mpi = new type_mpi(); + mpi.fromBytes(randomBits); + return mpi.toBigInteger(); + }, + + getRandomBigIntegerInRange: function(min, max) { + if (max.compareTo(min) <= 0) { + return; + } + + var range = max.subtract(min); + var r = this.getRandomBigInteger(range.bitLength()); + while (r > range) { + r = this.getRandomBigInteger(range.bitLength()); + } + return min.add(r); + } + +}; diff --git a/src/crypto/signature.js b/src/crypto/signature.js new file mode 100644 index 00000000..5d51c374 --- /dev/null +++ b/src/crypto/signature.js @@ -0,0 +1,111 @@ +/** + * @requires crypto/hash + * @requires crypto/pkcs1 + * @requires crypto/public_key + * @module crypto/signature */ + +var publicKey = require('./public_key'), + pkcs1 = require('./pkcs1.js'), + hashModule = require('./hash'); + +module.exports = { + /** + * + * @param {Integer} algo public Key algorithm + * @param {Integer} hash_algo Hash algorithm + * @param {Array} msg_MPIs Signature multiprecision integers + * @param {Array} publickey_MPIs Public key multiprecision integers + * @param {String} data Data on where the signature was computed on. + * @return {Boolean} true if signature (sig_data was equal to data over hash) + */ + verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) { + var calc_hash = hashModule.digest(hash_algo, data); + + switch (algo) { + case 1: + // RSA (Encrypt or Sign) [HAC] + case 2: + // RSA Encrypt-Only [HAC] + case 3: + // RSA Sign-Only [HAC] + var rsa = new publicKey.rsa(); + var n = publickey_MPIs[0].toBigInteger(); + var e = publickey_MPIs[1].toBigInteger(); + var x = msg_MPIs[0].toBigInteger(); + var dopublic = rsa.verify(x, e, n); + var hash = pkcs1.emsa.decode(hash_algo, dopublic.toMPI().substring(2)); + if (hash == -1) { + throw new Error('PKCS1 padding in message or key incorrect. Aborting...'); + } + return hash == calc_hash; + + case 16: + // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] + throw new Error("signing with Elgamal is not defined in the OpenPGP standard."); + case 17: + // DSA (Digital Signature Algorithm) [FIPS186] [HAC] + var dsa = new publicKey.dsa(); + var s1 = msg_MPIs[0].toBigInteger(); + var s2 = msg_MPIs[1].toBigInteger(); + var p = publickey_MPIs[0].toBigInteger(); + var q = publickey_MPIs[1].toBigInteger(); + var g = publickey_MPIs[2].toBigInteger(); + var y = publickey_MPIs[3].toBigInteger(); + var m = data; + var dopublic = dsa.verify(hash_algo, s1, s2, m, p, q, g, y); + return dopublic.compareTo(s1) == 0; + default: + throw new Error('Invalid signature algorithm.'); + } + + }, + + /** + * Create a signature on data using the specified algorithm + * @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4) + * @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1) + * @param {Array} publicMPIs Public key multiprecision integers + * of the private key + * @param {Array} secretMPIs Private key multiprecision + * integers which is used to sign the data + * @param {String} data Data to be signed + * @return {Array} + */ + sign: function(hash_algo, algo, keyIntegers, data) { + + switch (algo) { + case 1: + // RSA (Encrypt or Sign) [HAC] + case 2: + // RSA Encrypt-Only [HAC] + case 3: + // RSA Sign-Only [HAC] + var rsa = new publicKey.rsa(); + var d = keyIntegers[2].toBigInteger(); + var n = keyIntegers[0].toBigInteger(); + var m = pkcs1.emsa.encode(hash_algo, + data, keyIntegers[0].byteLength()); + + return rsa.sign(m, d, n).toMPI(); + + case 17: + // DSA (Digital Signature Algorithm) [FIPS186] [HAC] + var dsa = new publicKey.dsa(); + + var p = keyIntegers[0].toBigInteger(); + var q = keyIntegers[1].toBigInteger(); + var g = keyIntegers[2].toBigInteger(); + var y = keyIntegers[3].toBigInteger(); + var x = keyIntegers[4].toBigInteger(); + var m = data; + var result = dsa.sign(hash_algo, m, g, p, q, x); + + return result[0].toString() + result[1].toString(); + case 16: + // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] + throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.'); + default: + throw new Error('Invalid signature algorithm.'); + } + } +} diff --git a/src/encoding/armor.js b/src/encoding/armor.js new file mode 100644 index 00000000..11efddae --- /dev/null +++ b/src/encoding/armor.js @@ -0,0 +1,378 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires encoding/base64 + * @requires enums + * @requires config + * @module encoding/armor + */ + +var base64 = require('./base64.js'), + enums = require('../enums.js'), + config = require('../config'); + +/** + * Finds out which Ascii Armoring type is used. This is an internal function + * @param {String} text [String] ascii armored text + * @returns {Integer} 0 = MESSAGE PART n of m + * 1 = MESSAGE PART n + * 2 = SIGNED MESSAGE + * 3 = PGP MESSAGE + * 4 = PUBLIC KEY BLOCK + * 5 = PRIVATE KEY BLOCK + * null = unknown + */ +function getType(text) { + var reHeader = /^-----([^-]+)-----$\n/m; + + var header = text.match(reHeader); + + // BEGIN PGP MESSAGE, PART X/Y + // Used for multi-part messages, where the armor is split amongst Y + // parts, and this is the Xth part out of Y. + if (header[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) { + return enums.armor.multipart_section; + } else + // BEGIN PGP MESSAGE, PART X + // Used for multi-part messages, where this is the Xth part of an + // unspecified number of parts. Requires the MESSAGE-ID Armor + // Header to be used. + if (header[1].match(/BEGIN PGP MESSAGE, PART \d+/)) { + return enums.armor.multipart_last; + + } else + // BEGIN PGP SIGNATURE + // Used for detached signatures, OpenPGP/MIME signatures, and + // cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE + // for detached signatures. + if (header[1].match(/BEGIN PGP SIGNED MESSAGE/)) { + return enums.armor.signed; + + } else + // BEGIN PGP MESSAGE + // Used for signed, encrypted, or compressed files. + if (header[1].match(/BEGIN PGP MESSAGE/)) { + return enums.armor.message; + + } else + // BEGIN PGP PUBLIC KEY BLOCK + // Used for armoring public keys. + if (header[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) { + return enums.armor.public_key; + + } else + // BEGIN PGP PRIVATE KEY BLOCK + // Used for armoring private keys. + if (header[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) { + return enums.armor.private_key; + } +} + +/** + * Add additional information to the armor version of an OpenPGP binary + * packet block. + * @author Alex + * @version 2011-12-16 + * @returns {String} The header information + */ +function addheader() { + var result = ""; + if (config.show_version) { + result += "Version: " + config.versionstring + '\r\n'; + } + if (config.show_comment) { + result += "Comment: " + config.commentstring + '\r\n'; + } + result += '\r\n'; + return result; +} + + + +/** + * Calculates a checksum over the given data and returns it base64 encoded + * @param {String} data Data to create a CRC-24 checksum for + * @return {String} Base64 encoded checksum + */ +function getCheckSum(data) { + var c = createcrc24(data); + var str = "" + String.fromCharCode(c >> 16) + + String.fromCharCode((c >> 8) & 0xFF) + + String.fromCharCode(c & 0xFF); + return base64.encode(str); +} + +/** + * Calculates the checksum over the given data and compares it with the + * given base64 encoded checksum + * @param {String} data Data to create a CRC-24 checksum for + * @param {String} checksum Base64 encoded checksum + * @return {Boolean} True if the given checksum is correct; otherwise false + */ +function verifyCheckSum(data, checksum) { + var c = getCheckSum(data); + var d = checksum; + return c[0] == d[0] && c[1] == d[1] && c[2] == d[2]; +} +/** + * Internal function to calculate a CRC-24 checksum over a given string (data) + * @param {String} data Data to create a CRC-24 checksum for + * @return {Integer} The CRC-24 checksum as number + */ +var crc_table = [ + 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139, + 0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, + 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd, + 0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, + 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631, + 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, + 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5, + 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, + 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b, + 0x315aa1a0, + 0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f, + 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, + 0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3, + 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, + 0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67, + 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, + 0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d, + 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, + 0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340, + 0x62330fbb, + 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, + 0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de, + 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, + 0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61, + 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, + 0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d, + 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, + 0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50, + 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, + 0x51f6d10c, + 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3, + 0x57dd8538 +]; + +function createcrc24(input) { + var crc = 0xB704CE; + var index = 0; + + while ((input.length - index) > 16) { + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 1)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 2)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 3)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 4)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 5)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 6)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 7)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 8)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 9)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 10)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 11)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 12)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 13)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 14)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 15)) & 0xff]; + index += 16; + } + + for (var j = index; j < input.length; j++) { + crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff]; + } + return crc & 0xffffff; +} + +/** + * Splits a message into two parts, the headers and the body. This is an internal function + * @param {String} text OpenPGP armored message part + * @returns {(Boolean|Object)} Either false in case of an error + * or an object with attribute "headers" containing the headers and + * and an attribute "body" containing the body. + */ +function splitHeaders(text) { + var reEmptyLine = /^[\t ]*\n/m; + var headers = ""; + var body = text; + + var matchResult = reEmptyLine.exec(text); + + if (matchResult != null) { + headers = text.slice(0, matchResult.index); + body = text.slice(matchResult.index + matchResult[0].length); + } + + return { headers: headers, body: body }; +} + +/** + * Splits a message into two parts, the body and the checksum. This is an internal function + * @param {String} text OpenPGP armored message part + * @returns {(Boolean|Object)} Either false in case of an error + * or an object with attribute "body" containing the body + * and an attribute "checksum" containing the checksum. + */ +function splitChecksum(text) { + var reChecksumStart = /^=/m; + var body = text; + var checksum = ""; + + var matchResult = reChecksumStart.exec(text); + + if (matchResult != null) { + body = text.slice(0, matchResult.index); + checksum = text.slice(matchResult.index + 1); + } + + return { body: body, checksum: checksum }; +} + +/** + * DeArmor an OpenPGP armored message; verify the checksum and return + * the encoded bytes + * @param {String} text OpenPGP armored message + * @returns {Object} An object with attribute "text" containing the message text, + * an attribute "data" containing the bytes and "type" for the ASCII armor type + * @static + */ +function dearmor(text) { + var reSplit = /^-----[^-]+-----$\n/m; + + text = text.replace(/\r/g, ''); + + var type = getType(text); + if (!type) { + throw new Error('Unknow ASCII armor type'); + } + + var splittext = text.split(reSplit); + + // IE has a bug in split with a re. If the pattern matches the beginning of the + // string it doesn't create an empty array element 0. So we need to detect this + // so we know the index of the data we are interested in. + var indexBase = 1; + + var result, checksum; + + if (text.search(reSplit) != splittext[0].length) { + indexBase = 0; + } + + if (type != 2) { + var msg = splitHeaders(splittext[indexBase]); + var msg_sum = splitChecksum(msg.body); + + result = { + data: base64.decode(msg_sum.body), + type: type + }; + + checksum = msg_sum.checksum; + } else { + // Reverse dash-escaping for msg and remove trailing whitespace at end of line + var msg = splitHeaders(splittext[indexBase].replace(/^- /mg, '').replace(/[\t ]+\n/g, "\n")); + var sig = splitHeaders(splittext[indexBase + 1].replace(/^- /mg, '')); + var sig_sum = splitChecksum(sig.body); + + result = { + text: msg.body.replace(/\n$/, '').replace(/\n/g, "\r\n"), + data: base64.decode(sig_sum.body), + type: type + }; + + checksum = sig_sum.checksum; + } + + if (!verifyCheckSum(result.data, checksum)) { + throw new Error("Ascii armor integrity check on message failed: '" + + checksum + + "' should be '" + + getCheckSum(result) + "'"); + } else { + return result; + } +} + + +/** + * Armor an OpenPGP binary packet block + * @param {Integer} messagetype type of the message + * @param body + * @param {Integer} partindex + * @param {Integer} parttotal + * @returns {String} Armored text + * @static + */ +function armor(messagetype, body, partindex, parttotal) { + var result = ""; + switch (messagetype) { + case enums.armor.multipart_section: + result += "-----BEGIN PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n"; + break; + case enums.armor.mutlipart_last: + result += "-----BEGIN PGP MESSAGE, PART " + partindex + "-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP MESSAGE, PART " + partindex + "-----\r\n"; + break; + case enums.armor.signed: + result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\n"; + result += "Hash: " + body.hash + "\r\n\r\n"; + result += body.text.replace(/\n-/g, "\n- -"); + result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n"; + result += addheader(); + result += base64.encode(body.data); + result += "\r\n=" + getCheckSum(body.data) + "\r\n"; + result += "-----END PGP SIGNATURE-----\r\n"; + break; + case enums.armor.message: + result += "-----BEGIN PGP MESSAGE-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP MESSAGE-----\r\n"; + break; + case enums.armor.public_key: + result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n"; + break; + case enums.armor.private_key: + result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n"; + result += addheader(); + result += base64.encode(body); + result += "\r\n=" + getCheckSum(body) + "\r\n"; + result += "-----END PGP PRIVATE KEY BLOCK-----\r\n"; + break; + } + + return result; +} + +module.exports = { + encode: armor, + decode: dearmor +}; diff --git a/src/encoding/base64.js b/src/encoding/base64.js index 90f76c06..e88b9d14 100644 --- a/src/encoding/base64.js +++ b/src/encoding/base64.js @@ -1,77 +1,101 @@ -/* OpenPGP radix-64/base64 string encoding/decoding - * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de - * version 1.0, check www.haneWIN.de for the latest version - * - * This software is provided as-is, without express or implied warranty. - * Permission to use, copy, modify, distribute or sell this software, with or - * without fee, for any purpose and by any individual or organization, is hereby - * granted, provided that the above copyright notice and this paragraph appear - * in all copies. Distribution as a part of an application or binary must - * include the above copyright notice in the documentation and/or other materials - * provided with the application or distribution. - */ - -var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - -function s2r(t) { - var a, c, n; - var r = '', l = 0, s = 0; - var tl = t.length; - - for (n = 0; n < tl; n++) { - c = t.charCodeAt(n); - if (s == 0) { - r += b64s.charAt((c >> 2) & 63); - a = (c & 3) << 4; - } else if (s == 1) { - r += b64s.charAt((a | (c >> 4) & 15)); - a = (c & 15) << 2; - } else if (s == 2) { - r += b64s.charAt(a | ((c >> 6) & 3)); - l += 1; - if ((l % 60) == 0) - r += "\n"; - r += b64s.charAt(c & 63); - } - l += 1; - if ((l % 60) == 0) - r += "\n"; - - s += 1; - if (s == 3) - s = 0; - } - if (s > 0) { - r += b64s.charAt(a); - l += 1; - if ((l % 60) == 0) - r += "\n"; - r += '='; - l += 1; - } - if (s == 1) { - if ((l % 60) == 0) - r += "\n"; - r += '='; - } - if (r.charAt(r.length-1)==="\n") - r=r.slice(0,-1); - return r; -} - -function r2s(t) { - var c, n; - var r = '', s = 0, a = 0; - var tl = t.length; - - for (n = 0; n < tl; n++) { - c = b64s.indexOf(t.charAt(n)); - if (c >= 0) { - if (s) - r += String.fromCharCode(a | (c >> (6 - s)) & 255); - s = (s + 2) & 7; - a = (c << s) & 255; - } - } - return r; -} +/* OpenPGP radix-64/base64 string encoding/decoding + * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de + * version 1.0, check www.haneWIN.de for the latest version + * + * This software is provided as-is, without express or implied warranty. + * Permission to use, copy, modify, distribute or sell this software, with or + * without fee, for any purpose and by any individual or organization, is hereby + * granted, provided that the above copyright notice and this paragraph appear + * in all copies. Distribution as a part of an application or binary must + * include the above copyright notice in the documentation and/or other materials + * provided with the application or distribution. + */ + +/** + * @module encoding/base64 + */ + +var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +/** + * Convert binary string to radix-64 + * @param {String} t binary string to convert + * @returns {string} radix-64 version of input string + * @static + */ +function s2r(t) { + var a, c, n; + var r = '', + l = 0, + s = 0; + var tl = t.length; + + for (n = 0; n < tl; n++) { + c = t.charCodeAt(n); + if (s == 0) { + r += b64s.charAt((c >> 2) & 63); + a = (c & 3) << 4; + } else if (s == 1) { + r += b64s.charAt((a | (c >> 4) & 15)); + a = (c & 15) << 2; + } else if (s == 2) { + r += b64s.charAt(a | ((c >> 6) & 3)); + l += 1; + if ((l % 60) == 0) + r += "\n"; + r += b64s.charAt(c & 63); + } + l += 1; + if ((l % 60) == 0) + r += "\n"; + + s += 1; + if (s == 3) + s = 0; + } + if (s > 0) { + r += b64s.charAt(a); + l += 1; + if ((l % 60) == 0) + r += "\n"; + r += '='; + l += 1; + } + if (s == 1) { + if ((l % 60) == 0) + r += "\n"; + r += '='; + } + + return r; +} + +/** + * Convert radix-64 to binary string + * @param {String} t radix-64 string to convert + * @returns {string} binary version of input string + * @static + */ +function r2s(t) { + var c, n; + var r = '', + s = 0, + a = 0; + var tl = t.length; + + for (n = 0; n < tl; n++) { + c = b64s.indexOf(t.charAt(n)); + if (c >= 0) { + if (s) + r += String.fromCharCode(a | (c >> (6 - s)) & 255); + s = (s + 2) & 7; + a = (c << s) & 255; + } + } + return r; +} + +module.exports = { + encode: s2r, + decode: r2s +} diff --git a/src/encoding/openpgp.encoding.js b/src/encoding/openpgp.encoding.js deleted file mode 100644 index ca61448d..00000000 --- a/src/encoding/openpgp.encoding.js +++ /dev/null @@ -1,141 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * Wrapper function for the base64 codec. - * This function encodes a String (message) in base64 (radix-64) - * @param {String} message The message to encode - * @return {String} The base64 encoded data - */ -function openpgp_encoding_base64_encode(message) { - return s2r(message); -} - - -/** - * Wrapper function for the base64 codec. - * This function decodes a String(message) in base64 (radix-64) - * @param {String} message Base64 encoded data - * @return {String} Raw data after decoding - */ -function openpgp_encoding_base64_decode(message) { - return r2s(message); -} - -/** - * Wrapper function for jquery library. - * This function escapes HTML characters within a string. This is used - * to prevent XSS. - * @param {String} message Message to escape - * @return {String} Html encoded string - */ -function openpgp_encoding_html_encode(message) { - if (message == null) - return ""; - return $('
      ').text(message).html(); -} - -/** - * create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1) - * @param {String} message message to be padded - * @param {Integer} length Length to the resulting message - * @return {String} EME-PKCS1 padded message - */ -function openpgp_encoding_eme_pkcs1_encode(message, length) { - if (message.length > length-11) - return -1; - var result = ""; - result += String.fromCharCode(0); - result += String.fromCharCode(2); - for (var i = 0; i < length - message.length - 3; i++) { - result += String.fromCharCode(openpgp_crypto_getPseudoRandom(1,255)); - } - result += String.fromCharCode(0); - result += message; - return result; -} - -/** - * decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2) - * @param {String} message EME-PKCS1 padded message - * @return {String} decoded message - */ -function openpgp_encoding_eme_pkcs1_decode(message, len) { - if (message.length < len) - message = String.fromCharCode(0)+message; - if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2) - return -1; - var i = 2; - while (message.charCodeAt(i) != 0 && message.length > i) - i++; - return message.substring(i+1, message.length); -} -/** - * ASN1 object identifiers for hashes (See RFC4880 5.2.2) - */ -hash_headers = new Array(); -hash_headers[1] = [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10]; -hash_headers[3] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14]; -hash_headers[2] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14]; -hash_headers[8] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20]; -hash_headers[9] = [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30]; -hash_headers[10] = [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40]; -hash_headers[11] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1C]; - -/** - * create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3) - * @param {Integer} algo Hash algorithm type used - * @param {String} data Data to be hashed - * @param {Integer} keylength Key size of the public mpi in bytes - * @returns {String} Hashcode with pkcs1padding as string - */ -function openpgp_encoding_emsa_pkcs1_encode(algo, data, keylength) { - var data2 = ""; - data2 += String.fromCharCode(0x00); - data2 += String.fromCharCode(0x01); - for (var i = 0; i < (keylength - hash_headers[algo].length - 3 - openpgp_crypto_getHashByteLength(algo)); i++) - data2 += String.fromCharCode(0xff); - data2 += String.fromCharCode(0x00); - - for (var i = 0; i < hash_headers[algo].length; i++) - data2 += String.fromCharCode(hash_headers[algo][i]); - - data2 += openpgp_crypto_hashData(algo, data); - return new BigInteger(util.hexstrdump(data2),16); -} - -/** - * extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3) - * @param {String} data Hash in pkcs1 encoding - * @returns {String} The hash as string - */ -function openpgp_encoding_emsa_pkcs1_decode(algo, data) { - var i = 0; - if (data.charCodeAt(0) == 0) i++; - else if (data.charCodeAt(0) != 1) return -1; - else i++; - - while (data.charCodeAt(i) == 0xFF) i++; - if (data.charCodeAt(i++) != 0) return -1; - var j = 0; - for (j = 0; j < hash_headers[algo].length && j+i < data.length; j++) { - if (data.charCodeAt(j+i) != hash_headers[algo][j]) return -1; - } - i+= j; - if (data.substring(i).length < openpgp_crypto_getHashByteLength(algo)) return -1; - return data.substring(i); -} diff --git a/src/enums.js b/src/enums.js new file mode 100644 index 00000000..ccb995dd --- /dev/null +++ b/src/enums.js @@ -0,0 +1,317 @@ +/** + * @module enums + */ + +module.exports = { + + /** A string to key specifier type + * @enum {Integer} + * @readonly + */ + s2k: { + simple: 0, + salted: 1, + iterated: 3, + gnu: 101 + }, + + /** RFC4880, section 9.1 + * @enum {Integer} + * @readonly + */ + publicKey: { + rsa_encrypt_sign: 1, + rsa_encrypt: 2, + rsa_sign: 3, + elgamal: 16, + dsa: 17 + }, + + /** RFC4880, section 9.2 + * @enum {Integer} + * @readonly + */ + symmetric: { + plaintext: 0, + /** Not implemented! */ + idea: 1, + tripledes: 2, + cast5: 3, + blowfish: 4, + aes128: 7, + aes192: 8, + aes256: 9, + twofish: 10 + }, + + /** RFC4880, section 9.3 + * @enum {Integer} + * @readonly + */ + compression: { + uncompressed: 0, + /** RFC1951 */ + zip: 1, + /** RFC1950 */ + zlib: 2, + bzip2: 3 + }, + + /** RFC4880, section 9.4 + * @enum {Integer} + * @readonly + */ + hash: { + md5: 1, + sha1: 2, + ripemd: 3, + sha256: 8, + sha384: 9, + sha512: 10, + sha224: 11 + }, + + /** A list of packet types and numeric tags associated with them. + * @enum {Integer} + * @readonly + */ + packet: { + public_key_encrypted_session_key: 1, + signature: 2, + sym_encrypted_session_key: 3, + one_pass_signature: 4, + secret_key: 5, + public_key: 6, + secret_subkey: 7, + compressed: 8, + symmetrically_encrypted: 9, + marker: 10, + literal: 11, + trust: 12, + userid: 13, + public_subkey: 14, + user_attribute: 17, + sym_encrypted_integrity_protected: 18, + modification_detection_code: 19 + }, + + /** Data types in the literal packet + * @enum {Integer} + * @readonly + */ + literal: { + /** Binary data 'b' */ + binary: 'b'.charCodeAt(), + /** Text data 't' */ + text: 't'.charCodeAt(), + /** Utf8 data 'u' */ + utf8: 'u'.charCodeAt() + }, + + + /** One pass signature packet type + * @enum {Integer} + * @readonly + */ + signature: { + /** 0x00: Signature of a binary document. */ + binary: 0, + /** 0x01: Signature of a canonical text document.
      + * Canonicalyzing the document by converting line endings. */ + text: 1, + /** 0x02: Standalone signature.
      + * This signature is a signature of only its own subpacket contents. + * It is calculated identically to a signature over a zero-lengh + * binary document. Note that it doesn't make sense to have a V3 + * standalone signature. */ + standalone: 2, + /** 0x10: Generic certification of a User ID and Public-Key packet.
      + * The issuer of this certification does not make any particular + * assertion as to how well the certifier has checked that the owner + * of the key is in fact the person described by the User ID. */ + cert_generic: 16, + /** 0x11: Persona certification of a User ID and Public-Key packet.
      + * The issuer of this certification has not done any verification of + * the claim that the owner of this key is the User ID specified. */ + cert_persona: 17, + /** 0x12: Casual certification of a User ID and Public-Key packet.
      + * The issuer of this certification has done some casual + * verification of the claim of identity. */ + cert_casual: 18, + /** 0x13: Positive certification of a User ID and Public-Key packet.
      + * The issuer of this certification has done substantial + * verification of the claim of identity.
      + *
      + * Most OpenPGP implementations make their "key signatures" as 0x10 + * certifications. Some implementations can issue 0x11-0x13 + * certifications, but few differentiate between the types. */ + cert_positive: 19, + /** 0x30: Certification revocation signature
      + * This signature revokes an earlier User ID certification signature + * (signature class 0x10 through 0x13) or direct-key signature + * (0x1F). It should be issued by the same key that issued the + * revoked signature or an authorized revocation key. The signature + * is computed over the same data as the certificate that it + * revokes, and should have a later creation date than that + * certificate. */ + cert_revocation: 48, + /** 0x18: Subkey Binding Signature
      + * This signature is a statement by the top-level signing key that + * indicates that it owns the subkey. This signature is calculated + * directly on the primary key and subkey, and not on any User ID or + * other packets. A signature that binds a signing subkey MUST have + * an Embedded Signature subpacket in this binding signature that + * contains a 0x19 signature made by the signing subkey on the + * primary key and subkey. */ + subkey_binding: 24, + /** 0x19: Primary Key Binding Signature
      + * This signature is a statement by a signing subkey, indicating + * that it is owned by the primary key and subkey. This signature + * is calculated the same way as a 0x18 signature: directly on the + * primary key and subkey, and not on any User ID or other packets.
      + *
      + * When a signature is made over a key, the hash data starts with the + * octet 0x99, followed by a two-octet length of the key, and then body + * of the key packet. (Note that this is an old-style packet header for + * a key packet with two-octet length.) A subkey binding signature + * (type 0x18) or primary key binding signature (type 0x19) then hashes + * the subkey using the same format as the main key (also using 0x99 as + * the first octet). */ + key_binding: 25, + /** 0x1F: Signature directly on a key
      + * This signature is calculated directly on a key. It binds the + * information in the Signature subpackets to the key, and is + * appropriate to be used for subpackets that provide information + * about the key, such as the Revocation Key subpacket. It is also + * appropriate for statements that non-self certifiers want to make + * about the key itself, rather than the binding between a key and a + * name. */ + key: 31, + /** 0x20: Key revocation signature
      + * The signature is calculated directly on the key being revoked. A + * revoked key is not to be used. Only revocation signatures by the + * key being revoked, or by an authorized revocation key, should be + * considered valid revocation signatures.a */ + key_revocation: 32, + /** 0x28: Subkey revocation signature
      + * The signature is calculated directly on the subkey being revoked. + * A revoked subkey is not to be used. Only revocation signatures + * by the top-level signature key that is bound to this subkey, or + * by an authorized revocation key, should be considered valid + * revocation signatures.
      + *
      + * Key revocation signatures (types 0x20 and 0x28) + * hash only the key being revoked. */ + subkey_revocation: 40, + /** 0x40: Timestamp signature.
      + * This signature is only meaningful for the timestamp contained in + * it. */ + timestamp: 64, + /** 0x50: Third-Party Confirmation signature.
      + * This signature is a signature over some other OpenPGP Signature + * packet(s). It is analogous to a notary seal on the signed data. + * A third-party signature SHOULD include Signature Target + * subpacket(s) to give easy identification. Note that we really do + * mean SHOULD. There are plausible uses for this (such as a blind + * party that only sees the signature, not the key or source + * document) that cannot include a target subpacket. */ + third_party: 80 + }, + + /** Signature subpacket type + * @enum {Integer} + * @readonly + */ + signatureSubpacket: { + signature_creation_time: 2, + signature_expiration_time: 3, + exportable_certification: 4, + trust_signature: 5, + regular_expression: 6, + revocable: 7, + key_expiration_time: 9, + placeholder_backwards_compatibility: 10, + preferred_symmetric_algorithms: 11, + revocation_key: 12, + issuer: 16, + notation_data: 20, + preferred_hash_algorithms: 21, + preferred_compression_algorithms: 22, + key_server_preferences: 23, + preferred_key_server: 24, + primary_user_id: 25, + policy_uri: 26, + key_flags: 27, + signers_user_id: 28, + reason_for_revocation: 29, + features: 30, + signature_target: 31, + embedded_signature: 32 + }, + + /** Key flags + * @enum {Integer} + * @readonly + */ + keyFlags: { + /** 0x01 - This key may be used to certify other keys. */ + certify_keys: 1, + /** 0x02 - This key may be used to sign data. */ + sign_data: 2, + /** 0x04 - This key may be used to encrypt communications. */ + encrypt_communication: 4, + /** 0x08 - This key may be used to encrypt storage. */ + encrypt_storage: 8, + /** 0x10 - The private component of this key may have been split + * by a secret-sharing mechanism. */ + split_private_key: 16, + /** 0x20 - This key may be used for authentication. */ + authentication: 32, + /** 0x80 - The private component of this key may be in the + * possession of more than one person. */ + shared_private_key: 128 + }, + + /** Key status + * @enum {Integer} + * @readonly + */ + keyStatus: { + invalid: 0, + expired: 1, + revoked: 2, + valid: 3, + no_self_cert: 4 + }, + + /** Armor type + * @enum {Integer} + * @readonly + */ + armor: { + multipart_section: 0, + multipart_last: 1, + signed: 2, + message: 3, + public_key: 4, + private_key: 5 + }, + + /** Asserts validity and converts from string/integer to integer. */ + write: function(type, e) { + if (typeof e == 'number') { + e = this.read(type, e); + } + + if (type[e] !== undefined) { + return type[e]; + } else throw new Error('Invalid enum value.'); + }, + /** Converts from an integer to string. */ + read: function(type, e) { + for (var i in type) + if (type[i] == e) return i; + + throw new Error('Invalid enum value.'); + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..d6709e6c --- /dev/null +++ b/src/index.js @@ -0,0 +1,39 @@ + +module.exports = require('./openpgp.js'); + +module.exports.key = require('./key.js'); +module.exports.message = require('./message.js'); +module.exports.cleartext = require('./cleartext.js'); +/** + * @see module:util/util + * @module util + */ +module.exports.util = require('./util/util.js'); +module.exports.packet = require('./packet'); +/** + * @see module:type/mpi + * @module mpi + */ +module.exports.mpi = require('./type/mpi.js'); +/** + * @see module:type/s2k + * @module s2k + */ +module.exports.s2k = require('./type/s2k.js'); +/** + * @see module:type/keyid + * @module keyid + */ +module.exports.keyid = require('./type/keyid.js'); +/** + * @see module:encoding/armor + * @module armor + */ +module.exports.armor = require('./encoding/armor.js'); +module.exports.enums = require('./enums.js'); +/** + * @see module:config/config + * @module config + */ +module.exports.config = require('./config/config.js'); +module.exports.crypto = require('./crypto'); diff --git a/src/key.js b/src/key.js new file mode 100644 index 00000000..11b4c9a2 --- /dev/null +++ b/src/key.js @@ -0,0 +1,766 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires config + * @requires encoding/armor + * @requires enums + * @requires packet + * @module key + */ + +var packet = require('./packet'), + enums = require('./enums.js'), + armor = require('./encoding/armor.js'), + config = require('./config'); + +/** + * @class + * @classdesc Class that represents an OpenPGP key. Must contain a primary key. + * Can contain additional subkeys, signatures, user ids, user attributes. + * @param {module:packet/packetlist} packetlist The packets that form this key + */ + +function Key(packetlist) { + if (!(this instanceof Key)) { + return new Key(packetlist); + } + // same data as in packetlist but in structured form + this.primaryKey = null; + this.revocationSignature = null; + this.directSignatures = null; + this.users = null; + this.subKeys = null; + this.packetlist2structure(packetlist); + if (!this.primaryKey || !this.users) { + throw new Error('Invalid key: need at least key and user ID packet'); + } +} + +/** + * Transforms packetlist to structured key data + * @param {module:packet/packetlist} packetlist The packets that form a key + */ +Key.prototype.packetlist2structure = function(packetlist) { + var user, primaryKeyId, subKey; + for (var i = 0; i < packetlist.length; i++) { + switch (packetlist[i].tag) { + case enums.packet.public_key: + case enums.packet.secret_key: + this.primaryKey = packetlist[i]; + primaryKeyId = this.primaryKey.getKeyId(); + break; + case enums.packet.userid: + case enums.packet.user_attribute: + user = new User(packetlist[i]); + if (!this.users) this.users = []; + this.users.push(user); + break; + case enums.packet.public_subkey: + case enums.packet.secret_subkey: + user = null; + if (!this.subKeys) this.subKeys = []; + subKey = new SubKey(packetlist[i]); + this.subKeys.push(subKey); + break; + case enums.packet.signature: + switch (packetlist[i].signatureType) { + case enums.signature.cert_generic: + case enums.signature.cert_persona: + case enums.signature.cert_casual: + case enums.signature.cert_positive: + if (packetlist[i].issuerKeyId.equals(primaryKeyId)) { + if (!user.selfCertifications) user.selfCertifications = []; + user.selfCertifications.push(packetlist[i]); + } else { + if (!user.otherCertifications) user.otherCertifications = []; + user.otherCertifications.push(packetlist[i]); + } + break; + case enums.signature.cert_revocation: + if (user) { + if (!user.revocationCertifications) user.revocationCertifications = []; + user.revocationCertifications.push(packetlist[i]); + } else { + if (!this.directSignatures) this.directSignatures = []; + this.directSignatures.push(packetlist[i]); + } + break; + case enums.signature.key: + if (!this.directSignatures) this.directSignatures = []; + this.directSignatures.push(packetlist[i]); + break; + case enums.signature.subkey_binding: + subKey.bindingSignature = packetlist[i]; + break; + case enums.signature.key_revocation: + this.revocationSignature = packetlist[i]; + break; + case enums.signature.subkey_revocation: + subKey.revocationSignature = packetlist[i]; + break; + } + break; + } + } +}; + +/** + * Transforms structured key data to packetlist + * @return {module:packet/packetlist} The packets that form a key + */ +Key.prototype.toPacketlist = function() { + var packetlist = new packet.list(); + packetlist.push(this.primaryKey); + packetlist.push(this.revocationSignature); + packetlist.concat(this.directSignatures); + for (var i = 0; i < this.users.length; i++) { + packetlist.concat(this.users[i].toPacketlist()); + } + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + packetlist.concat(this.subKeys[i].toPacketlist()); + } + } + return packetlist; +}; + +/** + * Returns the primary key packet (secret or public) + * @returns {(module:packet/secret_key|module:packet/public_key|null)} + */ +Key.prototype.getKeyPacket = function() { + return this.primaryKey; +}; + +/** + * Returns all the private and public subkey packets + * @returns {Array<(module:packet/public_subkey|module:packet/secret_subkey)>} + */ +Key.prototype.getSubkeyPackets = function() { + var subKeys = []; + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + subKeys.push(this.subKeys[i].subKey); + } + } + return subKeys; +}; + +/** + * Returns all the private and public key and subkey packets + * @returns {Array<(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key)>} + */ +Key.prototype.getAllKeyPackets = function() { + return [this.getKeyPacket()].concat(this.getSubkeyPackets()); +}; + +/** + * Returns key IDs of all key packets + * @returns {Array} + */ +Key.prototype.getKeyIds = function() { + var keyIds = []; + var keys = this.getAllKeyPackets(); + for (var i = 0; i < keys.length; i++) { + keyIds.push(keys[i].getKeyId()); + } + return keyIds; +}; + +function findKey(keys, keyIds) { + for (var i = 0; i < keys.length; i++) { + var keyId = keys[i].getKeyId(); + for (var j = 0; j < keyIds.length; j++) { + if (keyId.equals(keyIds[j])) { + return keys[i]; + } + } + } + return null; +} + +/** + * Returns first public key packet for given array of key IDs + * @param {Array} keyIds + * @return {(module:packet/public_subkey|module:packet/public_key|null)} + */ +Key.prototype.getPublicKeyPacket = function(keyIds) { + if (this.primaryKey.tag == enums.packet.public_key) { + return findKey(this.getAllKeyPackets(), keyIds); + } else { + return null; + } +}; + +/** + * Returns first private key packet for given array of key IDs + * @param {Array} keyIds + * @return {(module:packet/secret_subkey|module:packet/secret_key|null)} + */ +Key.prototype.getPrivateKeyPacket = function(keyIds) { + if (this.primaryKey.tag == enums.packet.secret_key) { + return findKey(this.getAllKeyPackets(), keyIds); + } else { + return null; + } +}; + +/** + * Returns userids + * @return {Array} array of userids + */ +Key.prototype.getUserIds = function() { + var userids = []; + for (var i = 0; i < this.users.length; i++) { + if (this.users[i].userId) { + userids.push(this.users[i].userId.write()); + } + } + return userids; +}; + +/** + * Returns true if this is a public key + * @return {Boolean} + */ +Key.prototype.isPublic = function() { + return this.primaryKey.tag == enums.packet.public_key; +}; + +/** + * Returns true if this is a private key + * @return {Boolean} + */ +Key.prototype.isPrivate = function() { + return this.primaryKey.tag == enums.packet.secret_key; +}; + +/** + * Returns key as public key (shallow copy) + * @return {module:key~Key} new public Key + */ +Key.prototype.toPublic = function() { + var packetlist = new packet.list(); + var keyPackets = this.toPacketlist(); + for (var i = 0; i < keyPackets.length; i++) { + switch (keyPackets[i].tag) { + case enums.packet.secret_key: + var bytes = keyPackets[i].writePublicKey(); + var pubKeyPacket = new packet.public_key(); + pubKeyPacket.read(bytes); + packetlist.push(pubKeyPacket); + break; + case enums.packet.secret_subkey: + var bytes = keyPackets[i].writePublicKey(); + var pubSubkeyPacket = new packet.public_subkey(); + pubSubkeyPacket.read(bytes); + packetlist.push(pubSubkeyPacket); + break; + default: + packetlist.push(keyPackets[i]); + } + } + return new Key(packetlist); +}; + +/** + * Returns ASCII armored text of key + * @return {String} ASCII armor + */ +Key.prototype.armor = function() { + var type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key; + return armor.encode(type, this.toPacketlist().write()); +}; + +/** + * Returns first key packet that is available for signing + * @return {(module:packet/secret_subkey|module:packet/secret_key|null)} key packet or null if no signing key has been found + */ +Key.prototype.getSigningKeyPacket = function() { + if (this.isPublic()) { + throw new Error('Need private key for signing'); + } + var primaryUser = this.getPrimaryUser(); + if (primaryUser && + isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate)) { + return this.primaryKey; + } + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + if (this.subKeys[i].isValidSigningKey(this.primaryKey)) { + return this.subKeys[i].subKey; + } + } + } + return null; +}; + +/** + * Returns preferred signature hash algorithm of this key + * @return {String} + */ +Key.prototype.getPreferredHashAlgorithm = function() { + var primaryUser = this.getPrimaryUser(); + if (primaryUser && primaryUser.selfCertificate.preferredHashAlgorithms) { + return primaryUser.selfCertificate.preferredHashAlgorithms[0]; + } + return config.prefer_hash_algorithm; +}; + +function isValidEncryptionKeyPacket(keyPacket, signature) { + return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) && + keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_sign) && + ((signature.keyFlags & enums.keyFlags.encrypt_communication) !== 0 || + (signature.keyFlags & enums.keyFlags.encrypt_storage) !== 0 || + !signature.keyFlags); +}; + +function isValidSigningKeyPacket(keyPacket, signature) { + return (keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.dsa) || + keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.rsa_sign) || + keyPacket.algorithm == enums.read(enums.publicKey, enums.publicKey.rsa_encrypt_sign)) && + ((signature.keyFlags & enums.keyFlags.sign_data) !== 0 || + !signature.keyFlags); +}; + +/** + * Returns the first valid encryption key packet for this key + * @returns {(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key|null)} key packet or null if no encryption key has been found + */ +Key.prototype.getEncryptionKeyPacket = function() { + // V4: by convention subkeys are prefered for encryption service + // V3: keys MUST NOT have subkeys + if (this.subKeys) { + for (var i = 0; i < this.subKeys.length; i++) { + if (this.subKeys[i].isValidEncryptionKey(this.primaryKey)) { + return this.subKeys[i].subKey; + } + } + } + // if no valid subkey for encryption, evaluate primary key + var primaryUser = this.getPrimaryUser(); + if (primaryUser && + isValidEncryptionKeyPacket(this.primaryKey, primaryUser.selfCertificate)) { + return this.primaryKey; + } + return null; +}; + +/** + * Decrypts all secret key and subkey packets + * @param {String} passphrase + * @return {Boolean} true if all key and subkey packets decrypted successfully + */ +Key.prototype.decrypt = function(passphrase) { + if (this.isPrivate()) { + var keys = this.getAllKeyPackets(); + for (var i = 0; i < keys.length; i++) { + var success = keys[i].decrypt(passphrase); + if (!success) return false; + } + } else { + throw new Error("Nothing to decrypt in a public key"); + } + return true; +}; + +/** + * Decrypts specific key packets by key ID + * @param {Array} keyIds + * @param {String} passphrase + * @return {Boolean} true if all key packets decrypted successfully + */ +Key.prototype.decryptKeyPacket = function(keyIds, passphrase) { + if (this.isPrivate()) { + var keys = this.getAllKeyPackets(); + for (var i = 0; i < keys.length; i++) { + var keyId = keys[i].getKeyId(); + for (var j = 0; j < keyIds.length; j++) { + if (keyId.equals(keyIds[j])) { + var success = keys[i].decrypt(passphrase); + if (!success) return false; + } + } + } + } else { + throw new Error("Nothing to decrypt in a public key"); + } + return true; +}; + +/** + * Verify primary key. Checks for revocation signatures, expiration time + * and valid self signature + * @return {module:enums.keyStatus} The status of the primary key + */ +Key.prototype.verifyPrimaryKey = function() { + // check revocation signature + if (this.revocationSignature && !this.revocationSignature.isExpired() && + (this.revocationSignature.verified || + this.revocationSignature.verify(this.primaryKey, {key: this.primaryKey}))) { + return enums.keyStatus.revoked; + } + // check V3 expiration time + if (this.primaryKey.version == 3 && this.primaryKey.expirationTimeV3 !== 0 && + Date.now() > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) { + return enums.keyStatus.expired; + } + // check for at least one self signature. Self signature of user ID not mandatory + // See http://tools.ietf.org/html/rfc4880#section-11.1 + var selfSigned = false; + for (var i = 0; i < this.users.length; i++) { + if (this.users[i].userId && this.users[i].selfCertifications) { + selfSigned = true; + } + } + if (!selfSigned) { + return enums.keyStatus.no_self_cert; + } + // check for valid self signature + var primaryUser = this.getPrimaryUser(); + if (!primaryUser) { + return enums.keyStatus.invalid; + } + // check V4 expiration time + if (this.primaryKey.version == 4 && primaryUser.selfCertificate.keyNeverExpires === false && + Date.now() > (primaryUser.selfCertificate.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) { + return enums.keyStatus.expired; + } + return enums.keyStatus.valid; +}; + +/** + * Returns primary user and most significant (latest valid) self signature + * - if multiple users are marked as primary users returns the one with the latest self signature + * - if no primary user is found returns the user with the latest self signature + * @return {{user: Array, selfCertificate: Array}} The primary user and the self signature + */ +Key.prototype.getPrimaryUser = function() { + var user = null; + var userSelfCert; + for (var i = 0; i < this.users.length; i++) { + if (!this.users[i].userId) { + continue; + } + var selfCert = this.users[i].getValidSelfCertificate(this.primaryKey); + if (!selfCert) { + continue; + } + if (!user || + !userSelfCert.isPrimaryUserID && selfCert.isPrimaryUserID || + userSelfCert.created < selfCert.created) { + user = this.users[i]; + userSelfCert = selfCert; + } + } + return user ? {user: user, selfCertificate: userSelfCert} : null; +} + +// TODO +Key.prototype.revoke = function() { + +}; + +/** + * @class + * @classdesc Class that represents an user ID or attribute packet and the relevant signatures. + */ +function User(userPacket) { + if (!(this instanceof User)) { + return new User(userPacket); + } + this.userId = userPacket.tag == enums.packet.userid ? userPacket : null; + this.userAttribute = userPacket.tag == enums.packet.user_attribute ? userPacket : null + this.selfCertifications = null; + this.otherCertifications = null; + this.revocationCertifications = null; +} + +/** + * Transforms structured user data to packetlist + * @return {module:packet/packetlist} + */ +User.prototype.toPacketlist = function() { + var packetlist = new packet.list(); + packetlist.push(this.userId || this.userAttribute); + packetlist.concat(this.revocationCertifications); + packetlist.concat(this.selfCertifications); + packetlist.concat(this.otherCertifications); + return packetlist; +}; + +/** + * Checks if a self signature of the user is revoked + * @param {module:packet/signature} certificate + * @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet + * @return {Boolean} True if the certificate is revoked + */ +User.prototype.isRevoked = function(certificate, primaryKey) { + if (this.revocationCertifications) { + var that = this; + return this.revocationCertifications.some(function(revCert) { + return revCert.issuerKeyId.equals(certificate.issuerKeyId) && + !revCert.isExpired() && + (revCert.verified || + revCert.verify(primaryKey, {userid: that.userId || that.userAttribute, key: primaryKey})); + }); + } else { + return false; + } +}; + +/** + * Returns the most significant (latest valid) self signature of the user + * @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet + * @return {module:packet/signature} The self signature + */ +User.prototype.getValidSelfCertificate = function(primaryKey) { + if (!this.selfCertifications) { + return null; + } + var validCert = []; + for (var i = 0; i < this.selfCertifications.length; i++) { + if (this.isRevoked(this.selfCertifications[i], primaryKey)) { + continue; + } + if (!this.selfCertifications[i].isExpired() && + (this.selfCertifications[i].verified || + this.selfCertifications[i].verify(primaryKey, {userid: this.userId || this.userAttribute, key: primaryKey}))) { + validCert.push(this.selfCertifications[i]); + } + } + // most recent first + validCert = validCert.sort(function(a, b) { + a = a.created; + b = b.created; + return a>b ? -1 : a (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) { + return enums.keyStatus.expired; + } + // check subkey binding signature + if (!this.bindingSignature) { + return enums.keyStatus.invalid; + } + if (this.bindingSignature.isExpired()) { + return enums.keyStatus.expired; + } + if (!(this.bindingSignature.verified || + this.bindingSignature.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) { + return enums.keyStatus.invalid; + } + // check V4 expiration time + if (this.subKey.version == 4 && + this.bindingSignature.keyNeverExpires === false && + Date.now() > (this.subKey.created.getTime() + this.bindingSignature.keyExpirationTime*1000)) { + return enums.keyStatus.expired; + } + return enums.keyStatus.valid; +}; + +/** + * Reads an OpenPGP armored text and returns one or multiple key objects + * @param {String} armoredText text to be parsed + * @return {{keys: Array, err: (Array|null)}} result object with key and error arrays + * @static + */ +function readArmored(armoredText) { + var result = {}; + result.keys = []; + try { + var input = armor.decode(armoredText); + if (!(input.type == enums.armor.public_key || input.type == enums.armor.private_key)) { + throw new Error('Armored text not of type key'); + } + var packetlist = new packet.list(); + packetlist.read(input.data); + var keyIndex = packetlist.indexOfTag(enums.packet.public_key, enums.packet.secret_key); + if (keyIndex.length == 0) { + throw new Error('No key packet found in armored text') + } + for (var i = 0; i < keyIndex.length; i++) { + var oneKeyList = packetlist.slice(keyIndex[i], keyIndex[i + 1]); + try { + var newKey = new Key(oneKeyList); + result.keys.push(newKey); + } catch (e) { + result.err = result.err || []; + result.err.push(e); + } + } + } catch (e) { + result.err = result.err || []; + result.err.push(e); + } + return result; +} + +/** + * Generates a new OpenPGP key. Currently only supports RSA keys. + * Primary and subkey will be of same type. + * @param {Integer} keyType to indicate what type of key to make. + * RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1 + * @param {Integer} numBits number of bits for the key creation. + * @param {String} userId assumes already in form of "User Name " + * @param {String} passphrase The passphrase used to encrypt the resulting private key + * @return {module:key~Key} + * @static + */ +function generate(keyType, numBits, userId, passphrase) { + var packetlist = new packet.list(); + + var secretKeyPacket = new packet.secret_key(); + secretKeyPacket.algorithm = enums.read(enums.publicKey, keyType); + secretKeyPacket.generate(numBits); + secretKeyPacket.encrypt(passphrase); + + var userIdPacket = new packet.userid(); + userIdPacket.read(userId); + + var dataToSign = {}; + dataToSign.userid = userIdPacket; + dataToSign.key = secretKeyPacket; + var signaturePacket = new packet.signature(); + signaturePacket.signatureType = enums.signature.cert_generic; + signaturePacket.publicKeyAlgorithm = keyType; + //TODO we should load preferred hash from config, or as input to this function + signaturePacket.hashAlgorithm = enums.hash.sha256; + signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data]; + signaturePacket.sign(secretKeyPacket, dataToSign); + + var secretSubkeyPacket = new packet.secret_subkey(); + secretSubkeyPacket.algorithm = enums.read(enums.publicKey, keyType); + secretSubkeyPacket.generate(numBits); + secretSubkeyPacket.encrypt(passphrase); + + dataToSign = {}; + dataToSign.key = secretKeyPacket; + dataToSign.bind = secretSubkeyPacket; + var subkeySignaturePacket = new packet.signature(); + subkeySignaturePacket.signatureType = enums.signature.subkey_binding; + subkeySignaturePacket.publicKeyAlgorithm = keyType; + //TODO we should load preferred hash from config, or as input to this function + subkeySignaturePacket.hashAlgorithm = enums.hash.sha256; + subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage]; + subkeySignaturePacket.sign(secretKeyPacket, dataToSign); + + packetlist.push(secretKeyPacket); + packetlist.push(userIdPacket); + packetlist.push(signaturePacket); + packetlist.push(secretSubkeyPacket); + packetlist.push(subkeySignaturePacket); + + return new Key(packetlist); +} + +exports.Key = Key; +exports.readArmored = readArmored; +exports.generate = generate; diff --git a/src/keyring/index.js b/src/keyring/index.js new file mode 100644 index 00000000..867b80b7 --- /dev/null +++ b/src/keyring/index.js @@ -0,0 +1,3 @@ + +module.exports = require('./keyring.js'); +module.exports.localstore = require('./localstore.js'); diff --git a/src/keyring/keyring.js b/src/keyring/keyring.js new file mode 100644 index 00000000..22f33db3 --- /dev/null +++ b/src/keyring/keyring.js @@ -0,0 +1,190 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. + * @requires openpgp + * @module keyring/keyring + */ + +var openpgp = require('openpgp'); + +/** + * Callback to check if a key matches the input + * @callback module:keyring/keyring.checkCallback + * @param {String} input input to search for + * @param {module:key~Key} key The key to be checked. + * @return {Boolean} True if the input matches the specified key + */ + +/** + * Initialization routine for the keyring. This method reads the + * keyring from HTML5 local storage and initializes this instance. + * @constructor + * @param {class} [storeHandler] class implementing load() and store() methods + */ +module.exports = function(storeHandler) { + if (!storeHandler) { + storeHandler = new (require('./localstore.js'))(); + } + this.storeHandler = storeHandler; + this.keys = this.storeHandler.load(); + + /** + * Calls the storeHandler to save the keys + */ + this.store = function () { + this.storeHandler.store(this.keys); + }; + + /** + * Clear the keyring - erase all the keys + */ + this.clear = function() { + this.keys = []; + }; + + /** + * Checks a key to see if it matches the specified email address + * @param {String} email email address to search for + * @param {module:key~Key} key The key to be checked. + * @return {Boolean} True if the email address is defined in the specified key + */ + function emailCheck(email, key) { + email = email.toLowerCase(); + var keyEmails = key.getUserIds(); + for (var i; i < keyEmails.length; i++) { + //we need to get just the email from the userid key + keyEmail = keyEmails[i].split('<')[1].split('>')[0].trim().toLowerCase(); + if (keyEmail == email) { + return true; + } + } + return false; + } + + /** + * Checks a key to see if it matches the specified keyid + * @param {String} id hex string keyid to search for + * @param {module:key~Key} key the key to be checked. + * @return {Boolean} true if the email address is defined in the specified key + * @inner + */ + function idCheck(id, key) { + var keyids = key.getKeyIds(); + for (var i = 0; i < keyids.length; i++) { + if (openpgp.util.hexstrdump(keyids[i].write()) == id) { + return true; + } + } + return false; + } + + /** + * searches all public keys in the keyring matching the address or address part of the user ids + * @param {Array} keys array of keys to search + * @param {module:keyring/keyring.checkCallback} identityFunction callback function which checks for a match + * @param {String} identityInput input to check against + * @param {module:enums.packet} keyType packet types of keys to check + * @return {Array} array of keys which match + */ + function checkForIdentityAndKeyTypeMatch(keys, identityFunction, identityInput, keyType) { + var results = []; + for (var p = 0; p < keys.length; p++) { + var key = keys[p]; + switch (keyType) { + case openpgp.enums.packet.public_key: + if (key.isPublic() && identityFunction(identityInput, key)) { + results.push(key); + } + break; + case openpgp.enums.packet.private_key: + if (key.isPrivate() && identityFunction(identityInput, key)) { + results.push(key); + } + break; + } + } + return results; + } + + /** + * searches all public keys in the keyring matching the address or address part of the user ids + * @param {String} email email address to search for + * @return {Array} The public keys associated with provided email address. + */ + this.getPublicKeyForAddress = function (email) { + return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, openpgp.enums.packet.public_key); + }; + + /** + * Searches the keyring for a private key containing the specified email address + * @param {String} email email address to search for + * @return {Array} private keys found + */ + this.getPrivateKeyForAddress = function (email) { + return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, openpgp.enums.packet.secret_key); + }; + + /** + * Searches the keyring for public keys having the specified key id + * @param {String} keyId provided as string of hex number (lowercase) + * @return {Array} public keys found + */ + this.getKeysForKeyId = function (keyId) { + return checkForIdentityAndKeyTypeMatch(this.keys, idCheck, keyId, openpgp.enums.packet.public_key); + }; + + /** + * Imports a key from an ascii armored message + * @param {String} armored message to read the keys/key from + */ + this.importKey = function (armored) { + this.keys = this.keys.concat(openpgp.key.readArmored(armored).keys); + + return true; + }; + + /** + * returns the armored message representation of the key at key ring index + * @param {Integer} index the index of the key within the array + * @return {String} armored message representing the key object + */ + this.exportKey = function (index) { + return this.keys[index].armor(); + }; + + /** + * Removes a public key from the public key keyring at the specified index + * @param {Integer} index the index of the public key within the publicKeys array + * @return {module:key~Key} The public key object which has been removed + */ + this.removeKey = function (index) { + var removed = this.keys.splice(index, 1); + + return removed; + }; + + /** + * returns the armored message representation of the public key portion of the key at key ring index + * @param {Integer} index the index of the key within the array + * @return {String} armored message representing the public key object + */ + this.exportPublicKey = function (index) { + return this.keys[index].toPublic().armor(); + }; +}; diff --git a/src/keyring/localstore.js b/src/keyring/localstore.js new file mode 100644 index 00000000..48e329a7 --- /dev/null +++ b/src/keyring/localstore.js @@ -0,0 +1,56 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. + * @requires openpgp + * @module keyring/localstore + */ + +var openpgp = require('openpgp'); + +module.exports = function () { + /** + * Load the keyring from HTML5 local storage and initializes this instance. + * @return {Array} array of keys retrieved from localstore + */ + this.load = function () { + var armoredKeys = JSON.parse(window.localStorage.getItem("armoredKeys")); + var keys = []; + if (armoredKeys !== null && armoredKeys.length !== 0) { + var key; + for (var i = 0; i < armoredKeys.length; i++) { + key = openpgp.key.readArmored(armoredKeys[i]); + keys.push(key); + } + } + return keys; + } + + /** + * Saves the current state of the keyring to HTML5 local storage. + * The privateKeys array and publicKeys array gets Stringified using JSON + * @param {Array} keys array of keys to save in localstore + */ + this.store = function (keys) { + var armoredKeys = []; + for (var i = 0; i < keys.length; i++) { + armoredKeys.push(keys[i].armor()); + } + window.localStorage.setItem("armoredKeys", JSON.stringify(armoredKeys)); + } +}; diff --git a/src/message.js b/src/message.js new file mode 100644 index 00000000..cf4b5f38 --- /dev/null +++ b/src/message.js @@ -0,0 +1,316 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires config + * @requires crypto + * @requires encoding/armor + * @requires enums + * @requires packet + * @module message + */ + +var packet = require('./packet'), + enums = require('./enums.js'), + armor = require('./encoding/armor.js'), + config = require('./config'), + crypto = require('./crypto'); + +/** + * @class + * @classdesc Class that represents an OpenPGP message. + * Can be an encrypted message, signed message, compressed message or literal message + * @param {module:packet/packetlist} packetlist The packets that form this message + * See http://tools.ietf.org/html/rfc4880#section-11.3 + */ + +function Message(packetlist) { + if (!(this instanceof Message)) { + return new Message(packetlist); + } + this.packets = packetlist || new packet.list(); +} + +/** + * Returns the key IDs of the keys to which the session key is encrypted + * @return {Array} array of keyid objects + */ +Message.prototype.getEncryptionKeyIds = function() { + var keyIds = []; + var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key); + pkESKeyPacketlist.forEach(function(packet) { + keyIds.push(packet.publicKeyId); + }); + return keyIds; +}; + +/** + * Returns the key IDs of the keys that signed the message + * @return {Array} array of keyid objects + */ +Message.prototype.getSigningKeyIds = function() { + var keyIds = []; + var msg = this.unwrapCompressed(); + // search for one pass signatures + var onePassSigList = msg.packets.filterByTag(enums.packet.one_pass_signature); + onePassSigList.forEach(function(packet) { + keyIds.push(packet.signingKeyId); + }); + // if nothing found look for signature packets + if (!keyIds.length) { + var signatureList = msg.packets.filterByTag(enums.packet.signature); + signatureList.forEach(function(packet) { + keyIds.push(packet.issuerKeyId); + }); + } + return keyIds; +}; + +/** + * Decrypt the message + * @param {module:key~Key} privateKey private key with decrypted secret data + * @return {Array} new message with decrypted content + */ +Message.prototype.decrypt = function(privateKey) { + var encryptionKeyIds = this.getEncryptionKeyIds(); + if (!encryptionKeyIds.length) { + // nothing to decrypt return unmodified message + return this; + } + var privateKeyPacket = privateKey.getPrivateKeyPacket(encryptionKeyIds); + if (!privateKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.'); + var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key); + var pkESKeyPacket; + for (var i = 0; i < pkESKeyPacketlist.length; i++) { + if (pkESKeyPacketlist[i].publicKeyId.equals(privateKeyPacket.getKeyId())) { + pkESKeyPacket = pkESKeyPacketlist[i]; + pkESKeyPacket.decrypt(privateKeyPacket); + break; + } + } + if (pkESKeyPacket) { + var symEncryptedPacketlist = this.packets.filterByTag(enums.packet.symmetrically_encrypted, enums.packet.sym_encrypted_integrity_protected); + if (symEncryptedPacketlist.length !== 0) { + var symEncryptedPacket = symEncryptedPacketlist[0]; + symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey); + return new Message(symEncryptedPacket.packets); + } + } +}; + +/** + * Get literal data that is the body of the message + * @return {(String|null)} literal body of the message as string + */ +Message.prototype.getLiteralData = function() { + var literal = this.packets.findPacket(enums.packet.literal); + return literal && literal.data || null; +}; + +/** + * Get literal data as text + * @return {(String|null)} literal body of the message interpreted as text + */ +Message.prototype.getText = function() { + var literal = this.packets.findPacket(enums.packet.literal); + if (literal) { + return literal.getText(); + } else { + return null; + } +}; + +/** + * Encrypt the message + * @param {Array} keys array of keys, used to encrypt the message + * @return {Array} new message with encrypted content + */ +Message.prototype.encrypt = function(keys) { + var packetlist = new packet.list(); + //TODO get preferred algo from signature + var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, config.encryption_cipher)); + keys.forEach(function(key) { + var encryptionKeyPacket = key.getEncryptionKeyPacket(); + if (encryptionKeyPacket) { + var pkESKeyPacket = new packet.public_key_encrypted_session_key(); + pkESKeyPacket.publicKeyId = encryptionKeyPacket.getKeyId(); + pkESKeyPacket.publicKeyAlgorithm = encryptionKeyPacket.algorithm; + pkESKeyPacket.sessionKey = sessionKey; + //TODO get preferred algo from signature + pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, config.encryption_cipher); + pkESKeyPacket.encrypt(encryptionKeyPacket); + packetlist.push(pkESKeyPacket); + } else { + throw new Error('Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex()); + } + }); + var symEncryptedPacket; + if (config.integrity_protect) { + symEncryptedPacket = new packet.sym_encrypted_integrity_protected(); + } else { + symEncryptedPacket = new packet.symmetrically_encrypted(); + } + symEncryptedPacket.packets = this.packets; + //TODO get preferred algo from signature + symEncryptedPacket.encrypt(enums.read(enums.symmetric, config.encryption_cipher), sessionKey); + packetlist.push(symEncryptedPacket); + return new Message(packetlist); +}; + +/** + * Sign the message (the literal data packet of the message) + * @param {Array} privateKey private keys with decrypted secret key data for signing + * @return {module:message~Message} new message with signed content + */ +Message.prototype.sign = function(privateKeys) { + + var packetlist = new packet.list(); + + var literalDataPacket = this.packets.findPacket(enums.packet.literal); + if (!literalDataPacket) throw new Error('No literal data packet to sign.'); + + var literalFormat = enums.write(enums.literal, literalDataPacket.format); + var signatureType = literalFormat == enums.literal.binary + ? enums.signature.binary : enums.signature.text; + + for (var i = 0; i < privateKeys.length; i++) { + var onePassSig = new packet.one_pass_signature(); + onePassSig.type = signatureType; + //TODO get preferred hashg algo from key signature + onePassSig.hashAlgorithm = config.prefer_hash_algorithm; + var signingKeyPacket = privateKeys[i].getSigningKeyPacket(); + if (!signingKeyPacket) { + throw new Error('Could not find valid key packet for signing in key ' + privateKeys[i].primaryKey.getKeyId().toHex()); + } + onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm; + onePassSig.signingKeyId = signingKeyPacket.getKeyId(); + packetlist.push(onePassSig); + } + + packetlist.push(literalDataPacket); + + for (var i = privateKeys.length - 1; i >= 0; i--) { + var signaturePacket = new packet.signature(); + signaturePacket.signatureType = signatureType; + signaturePacket.hashAlgorithm = config.prefer_hash_algorithm; + signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; + if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.'); + signaturePacket.sign(signingKeyPacket, literalDataPacket); + packetlist.push(signaturePacket); + } + + return new Message(packetlist); +}; + +/** + * Verify message signatures + * @param {Array} publicKeys public keys to verify signatures + * @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature + */ +Message.prototype.verify = function(publicKeys) { + var result = []; + var msg = this.unwrapCompressed(); + var literalDataList = msg.packets.filterByTag(enums.packet.literal); + if (literalDataList.length !== 1) throw new Error('Can only verify message with one literal data packet.'); + var signatureList = msg.packets.filterByTag(enums.packet.signature); + publicKeys.forEach(function(pubKey) { + for (var i = 0; i < signatureList.length; i++) { + var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]); + if (publicKeyPacket) { + var verifiedSig = {}; + verifiedSig.keyid = signatureList[i].issuerKeyId; + verifiedSig.valid = signatureList[i].verify(publicKeyPacket, literalDataList[0]); + result.push(verifiedSig); + break; + } + } + }); + return result; +}; + +/** + * Unwrap compressed message + * @return {module:message~Message} message Content of compressed message + */ +Message.prototype.unwrapCompressed = function() { + var compressed = this.packets.filterByTag(enums.packet.compressed); + if (compressed.length) { + return new Message(compressed[0].packets); + } else { + return this; + } +}; + +/** + * Returns ASCII armored text of message + * @return {String} ASCII armor + */ +Message.prototype.armor = function() { + return armor.encode(enums.armor.message, this.packets.write()); +}; + +/** + * reads an OpenPGP armored message and returns a message object + * @param {String} armoredText text to be parsed + * @return {module:message~Message} new message object + * @static + */ +function readArmored(armoredText) { + //TODO how do we want to handle bad text? Exception throwing + //TODO don't accept non-message armored texts + var input = armor.decode(armoredText).data; + var packetlist = new packet.list(); + packetlist.read(input); + var newMessage = new Message(packetlist); + return newMessage; +} + +/** + * creates new message object from text + * @param {String} text + * @return {module:message~Message} new message object + * @static + */ +function fromText(text) { + var literalDataPacket = new packet.literal(); + // text will be converted to UTF8 + literalDataPacket.setText(text); + var literalDataPacketlist = new packet.list(); + literalDataPacketlist.push(literalDataPacket); + var newMessage = new Message(literalDataPacketlist); + return newMessage; +} + +/** + * creates new message object from binary data + * @param {String} bytes + * @return {module:message~Message} new message object + * @static + */ +function fromBinary(bytes) { + var literalDataPacket = new packet.literal(); + literalDataPacket.setBytes(bytes, enums.read(enums.literal, enums.literal.binary)); + var literalDataPacketlist = new packet.list(); + literalDataPacketlist.push(literalDataPacket); + var newMessage = new Message(literalDataPacketlist); + return newMessage; +} + +exports.Message = Message; +exports.readArmored = readArmored; +exports.fromText = fromText; +exports.fromBinary = fromBinary; diff --git a/src/openpgp.js b/src/openpgp.js index c0108c75..9463d407 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -16,448 +16,149 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * @fileoverview The openpgp base class should provide all of the functionality + * @fileoverview The openpgp base module should provide all of the functionality * to consume the openpgp.js library. All additional classes are documented * for extending and developing on top of the base library. */ /** - * GPG4Browsers Core interface. A single instance is hold - * from the beginning. To use this library call "openpgp.init()" - * @alias openpgp - * @class - * @classdesc Main Openpgp.js class. Use this to initiate and make all calls to this library. + * @requires cleartext + * @requires config + * @requires encoding/armor + * @requires enums + * @requires message + * @requires packet + * @module openpgp */ -function _openpgp () { - this.tostring = ""; - - /** - * initializes the library: - * - reading the keyring from local storage - * - reading the config from local storage - */ - function init() { - this.config = new openpgp_config(); - this.config.read(); - this.keyring = new openpgp_keyring(); - this.keyring.init(); - } - - /** - * reads several publicKey objects from a ascii armored - * representation an returns openpgp_msg_publickey packets - * @param {String} armoredText OpenPGP armored text containing - * the public key(s) - * @return {openpgp_msg_publickey[]} on error the function - * returns null - */ - function read_publicKey(armoredText) { - var mypos = 0; - var publicKeys = new Array(); - var publicKeyCount = 0; - var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp; - var l = input.length; - while (mypos != input.length) { - var first_packet = openpgp_packet.read_packet(input, mypos, l); - // public key parser - if (input.charCodeAt(mypos) == 0x99 || first_packet.tagType == 6) { - publicKeys[publicKeyCount] = new openpgp_msg_publickey(); - publicKeys[publicKeyCount].header = input.substring(mypos,mypos+3); - if (input.charCodeAt(mypos) == 0x99) { - // parse the length and read a tag6 packet - mypos++; - var l = (input.charCodeAt(mypos++) << 8) - | input.charCodeAt(mypos++); - publicKeys[publicKeyCount].publicKeyPacket = new openpgp_packet_keymaterial(); - publicKeys[publicKeyCount].publicKeyPacket.header = publicKeys[publicKeyCount].header; - publicKeys[publicKeyCount].publicKeyPacket.read_tag6(input, mypos, l); - mypos += publicKeys[publicKeyCount].publicKeyPacket.packetLength; - mypos += publicKeys[publicKeyCount].read_nodes(publicKeys[publicKeyCount].publicKeyPacket, input, mypos, (input.length - mypos)); - } else { - publicKeys[publicKeyCount] = new openpgp_msg_publickey(); - publicKeys[publicKeyCount].publicKeyPacket = first_packet; - mypos += first_packet.headerLength+first_packet.packetLength; - mypos += publicKeys[publicKeyCount].read_nodes(first_packet, input, mypos, input.length -mypos); - } - } else { - util.print_error("no public key found!"); - return null; - } - publicKeys[publicKeyCount].data = input.substring(0,mypos); - publicKeyCount++; - } - return publicKeys; - } - - /** - * reads several privateKey objects from a ascii armored - * representation an returns openpgp_msg_privatekey objects - * @param {String} armoredText OpenPGP armored text containing - * the private key(s) - * @return {openpgp_msg_privatekey[]} on error the function - * returns null - */ - function read_privateKey(armoredText) { - var privateKeys = new Array(); - var privateKeyCount = 0; - var mypos = 0; - var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp; - var l = input.length; - while (mypos != input.length) { - var first_packet = openpgp_packet.read_packet(input, mypos, l); - if (first_packet.tagType == 5) { - privateKeys[privateKeys.length] = new openpgp_msg_privatekey(); - mypos += first_packet.headerLength+first_packet.packetLength; - mypos += privateKeys[privateKeyCount].read_nodes(first_packet, input, mypos, l); - // other blocks - } else { - util.print_error('no block packet found!'); - return null; - } - privateKeys[privateKeyCount].data = input.substring(0,mypos); - privateKeyCount++; - } - return privateKeys; - } - /** - * reads message packets out of an OpenPGP armored text and - * returns an array of message objects - * @param {String} armoredText text to be parsed - * @return {openpgp_msg_message[]} on error the function - * returns null - */ - function read_message(armoredText) { - var dearmored; - try{ - dearmored = openpgp_encoding_deArmor(armoredText); - } - catch(e){ - util.print_error('no message found!'); - return null; - } - return read_messages_dearmored(dearmored); - } - - /** - * reads message packets out of an OpenPGP armored text and - * returns an array of message objects. Can be called externally or internally. - * External call will parse a de-armored messaged and return messages found. - * Internal will be called to read packets wrapped in other packets (i.e. compressed) - * @param {String} input dearmored text of OpenPGP packets, to be parsed - * @return {openpgp_msg_message[]} on error the function - * returns null - */ - function read_messages_dearmored(input){ - var messageString = input.openpgp; - var signatureText = input.text; //text to verify signatures against. Modified by Tag11. - var messages = new Array(); - var messageCount = 0; - var mypos = 0; - var l = messageString.length; - while (mypos < messageString.length) { - var first_packet = openpgp_packet.read_packet(messageString, mypos, l); - if (!first_packet) { - break; - } - // public key parser (definition from the standard:) - // OpenPGP Message :- Encrypted Message | Signed Message | - // Compressed Message | Literal Message. - // Compressed Message :- Compressed Data Packet. - // - // Literal Message :- Literal Data Packet. - // - // ESK :- Public-Key Encrypted Session Key Packet | - // Symmetric-Key Encrypted Session Key Packet. - // - // ESK Sequence :- ESK | ESK Sequence, ESK. - // - // Encrypted Data :- Symmetrically Encrypted Data Packet | - // Symmetrically Encrypted Integrity Protected Data Packet - // - // Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data. - // - // One-Pass Signed Message :- One-Pass Signature Packet, - // OpenPGP Message, Corresponding Signature Packet. +var armor = require('./encoding/armor.js'), + packet = require('./packet'), + enums = require('./enums.js'), + config = require('./config'), + message = require('./message.js'), + cleartext = require('./cleartext.js'), + key = require('./key.js'); - // Signed Message :- Signature Packet, OpenPGP Message | - // One-Pass Signed Message. - if (first_packet.tagType == 1 || - (first_packet.tagType == 2 && first_packet.signatureType < 16) || - first_packet.tagType == 3 || - first_packet.tagType == 4 || - first_packet.tagType == 8 || - first_packet.tagType == 9 || - first_packet.tagType == 10 || - first_packet.tagType == 11 || - first_packet.tagType == 18 || - first_packet.tagType == 19) { - messages[messages.length] = new openpgp_msg_message(); - messages[messageCount].messagePacket = first_packet; - messages[messageCount].type = input.type; - // Encrypted Message - if (first_packet.tagType == 9 || - first_packet.tagType == 1 || - first_packet.tagType == 3 || - first_packet.tagType == 18) { - if (first_packet.tagType == 9) { - util.print_error("unexpected openpgp packet"); - break; - } else if (first_packet.tagType == 1) { - util.print_debug("session key found:\n "+first_packet.toString()); - var issessionkey = true; - messages[messageCount].sessionKeys = new Array(); - var sessionKeyCount = 0; - while (issessionkey) { - messages[messageCount].sessionKeys[sessionKeyCount] = first_packet; - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - first_packet = openpgp_packet.read_packet(messageString, mypos, l); - - if (first_packet.tagType != 1 && first_packet.tagType != 3) - issessionkey = false; - sessionKeyCount++; - } - if (first_packet.tagType == 18 || first_packet.tagType == 9) { - util.print_debug("encrypted data found:\n "+first_packet.toString()); - messages[messageCount].encryptedData = first_packet; - mypos += first_packet.packetLength+first_packet.headerLength; - l -= (first_packet.packetLength+first_packet.headerLength); - messageCount++; - - } else { - util.print_debug("something is wrong: "+first_packet.tagType); - } - - } else if (first_packet.tagType == 18) { - util.print_debug("symmetric encrypted data"); - break; - } - } else - if (first_packet.tagType == 2 && first_packet.signatureType < 3) { - // Signed Message - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - messages[messageCount].text = signatureText; - messages[messageCount].signature = first_packet; - messageCount++; - } else - // Signed Message - if (first_packet.tagType == 4) { - //TODO: Implement check - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } else - if (first_packet.tagType == 8) { - // Compressed Message - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - var decompressedText = first_packet.decompress(); - messages = messages.concat(openpgp.read_messages_dearmored({text: decompressedText, openpgp: decompressedText})); - } else - // Marker Packet (Obsolete Literal Packet) (Tag 10) - // "Such a packet MUST be ignored when received." see http://tools.ietf.org/html/rfc4880#section-5.8 - if (first_packet.tagType == 10) { - // reset messages - messages.length = 0; - // continue with next packet - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } else - if (first_packet.tagType == 11) { - // Literal Message -- work is already done in read_packet - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - signatureText = first_packet.data; - messages[messageCount].data = first_packet.data; - messageCount++; - } else - if (first_packet.tagType == 19) { - // Modification Detect Code - mypos += first_packet.packetLength + first_packet.headerLength; - l -= (first_packet.packetLength + first_packet.headerLength); - } - } else { - util.print_error('no message found!'); - return null; - } - } - - return messages; - } - - /** - * creates a binary string representation of an encrypted and signed message. - * The message will be encrypted with the public keys specified and signed - * with the specified private key. - * @param {Object} privatekey {obj: [openpgp_msg_privatekey]} Private key - * to be used to sign the message - * @param {Object[]} publickeys An arraf of {obj: [openpgp_msg_publickey]} - * - public keys to be used to encrypt the message - * @param {String} messagetext message text to encrypt and sign - * @return {String} a binary string representation of the message which - * can be OpenPGP armored - */ - function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) { - var result = ""; - var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r/g,'').replace(/\n/g,"\r\n")); - util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal); - for (var i = 0; i < publickeys.length; i++) { - var onepasssignature = new openpgp_packet_onepasssignature(); - var onepasssigstr = ""; - if (i == 0) - onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false); - else - onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false); - util.print_debug_hexstr_dump("onepasssigstr: |"+onepasssigstr+"|\n",onepasssigstr); - var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey); - util.print_debug_hexstr_dump("datasignature: |"+datasignature.openpgp+"|\n",datasignature.openpgp); - if (i == 0) { - result = onepasssigstr+literal+datasignature.openpgp; - } else { - result = onepasssigstr+result+datasignature.openpgp; - } - } - - util.print_debug_hexstr_dump("signed packet: |"+result+"|\n",result); - // signatures done.. now encryption - var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); - var result2 = ""; - - // creating session keys for each recipient - for (var i = 0; i < publickeys.length; i++) { - var pkey = publickeys[i].getEncryptionKey(); - if (pkey == null) { - util.print_error("no encryption key found! Key is for signing only."); - return null; - } - result2 += new openpgp_packet_encryptedsessionkey(). - write_pub_key_packet( - pkey.getKeyId(), - pkey.MPIs, - pkey.publicKeyAlgorithm, - openpgp.config.config.encryption_cipher, - sessionkey); - } - if (openpgp.config.config.integrity_protect) { - result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } else { - result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } - return openpgp_encoding_armor(3,result2,null,null); - } - /** - * creates a binary string representation of an encrypted message. - * The message will be encrypted with the public keys specified - * @param {Object[]} publickeys An array of {obj: [openpgp_msg_publickey]} - * -public keys to be used to encrypt the message - * @param {String} messagetext message text to encrypt - * @return {String} a binary string representation of the message - * which can be OpenPGP armored - */ - function write_encrypted_message(publickeys, messagetext) { - var result = ""; - var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r/g,'').replace(/\n/g,"\r\n")); - util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal); - result = literal; - - // signatures done.. now encryption - var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); - var result2 = ""; - - // creating session keys for each recipient - for (var i = 0; i < publickeys.length; i++) { - var pkey = publickeys[i].getEncryptionKey(); - if (pkey == null) { - util.print_error("no encryption key found! Key is for signing only."); - return null; - } - result2 += new openpgp_packet_encryptedsessionkey(). - write_pub_key_packet( - pkey.getKeyId(), - pkey.MPIs, - pkey.publicKeyAlgorithm, - openpgp.config.config.encryption_cipher, - sessionkey); - } - if (openpgp.config.config.integrity_protect) { - result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } else { - result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result); - } - return openpgp_encoding_armor(3,result2,null,null); - } - - /** - * creates a binary string representation a signed message. - * The message will be signed with the specified private key. - * @param {Object} privatekey {obj: [openpgp_msg_privatekey]} - * - the private key to be used to sign the message - * @param {String} messagetext message text to sign - * @return {Object} {Object: text [String]}, openpgp: {String} a binary - * string representation of the message which can be OpenPGP - * armored(openpgp) and a text representation of the message (text). - * This can be directly used to OpenPGP armor the message - */ - function write_signed_message(privatekey, messagetext) { - var canonicalMsgText = messagetext.replace(/\r/g,'').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n"); - var sig = new openpgp_packet_signature().write_message_signature(1, canonicalMsgText, privatekey); - var result = {text: canonicalMsgText, openpgp: sig.openpgp, hash: sig.hash}; - return openpgp_encoding_armor(2, result, null, null) - } - - /** - * generates a new key pair for openpgp. Beta stage. Currently only - * supports RSA keys, and no subkeys. - * @param {Integer} keyType to indicate what type of key to make. - * RSA is 1. Follows algorithms outlined in OpenPGP. - * @param {Integer} numBits number of bits for the key creation. (should - * be 1024+, generally) - * @param {String} userId assumes already in form of "User Name - * " - * @param {String} passphrase The passphrase used to encrypt the resulting private key - * @return {Object} {privateKey: [openpgp_msg_privatekey], - * privateKeyArmored: [string], publicKeyArmored: [string]} - */ - function generate_key_pair(keyType, numBits, userId, passphrase){ - var userIdPacket = new openpgp_packet_userid(); - var userIdString = userIdPacket.write_packet(userId); - - var keyPair = openpgp_crypto_generateKeyPair(keyType,numBits, passphrase, openpgp.config.config.prefer_hash_algorithm, 3); - var privKeyString = keyPair.privateKey; - var privKeyPacket = new openpgp_packet_keymaterial().read_priv_key(privKeyString.string,3,privKeyString.string.length); - if(!privKeyPacket.decryptSecretMPIs(passphrase)) - util.print_error('Issue creating key. Unable to read resulting private key'); - var privKey = new openpgp_msg_privatekey(); - privKey.privateKeyPacket = privKeyPacket; - privKey.getPreferredSignatureHashAlgorithm = function(){return openpgp.config.config.prefer_hash_algorithm};//need to override this to solve catch 22 to generate signature. 8 is value for SHA256 - - var publicKeyString = privKey.privateKeyPacket.publicKey.data; - userId = util.encode_utf8(userId); // needs same encoding as in userIdString - var hashData = String.fromCharCode(0x99)+ String.fromCharCode(((publicKeyString.length) >> 8) & 0xFF) - + String.fromCharCode((publicKeyString.length) & 0xFF) +publicKeyString+String.fromCharCode(0xB4) + - String.fromCharCode((userId.length) >> 24) +String.fromCharCode(((userId.length) >> 16) & 0xFF) - + String.fromCharCode(((userId.length) >> 8) & 0xFF) + String.fromCharCode((userId.length) & 0xFF) + userId - var signature = new openpgp_packet_signature(); - signature = signature.write_message_signature(16,hashData, privKey); - var publicArmored = openpgp_encoding_armor(4, keyPair.publicKey.string + userIdString + signature.openpgp ); - var privArmored = openpgp_encoding_armor(5,privKeyString.string+userIdString+signature.openpgp); - - return {privateKey : privKey, privateKeyArmored: privArmored, publicKeyArmored: publicArmored} - } - - this.generate_key_pair = generate_key_pair; - this.write_signed_message = write_signed_message; - this.write_signed_and_encrypted_message = write_signed_and_encrypted_message; - this.write_encrypted_message = write_encrypted_message; - this.read_message = read_message; - this.read_messages_dearmored = read_messages_dearmored; - this.read_publicKey = read_publicKey; - this.read_privateKey = read_privateKey; - this.init = init; +/** + * Encrypts message text with keys + * @param {Array} keys array of keys, used to encrypt the message + * @param {String} text message as native JavaScript string + * @return {String} encrypted ASCII armored message + * @static + */ +function encryptMessage(keys, text) { + var msg = message.fromText(text); + msg = msg.encrypt(keys); + var armored = armor.encode(enums.armor.message, msg.packets.write()); + return armored; } -var openpgp = new _openpgp(); +/** + * Signs message text and encrypts it + * @param {Array} publicKeys array of keys, used to encrypt the message + * @param {module:key~Key} privateKey private key with decrypted secret key data for signing + * @param {String} text message as native JavaScript string + * @return {String} encrypted ASCII armored message + * @static + */ +function signAndEncryptMessage(publicKeys, privateKey, text) { + var msg = message.fromText(text); + msg = msg.sign([privateKey]); + msg = msg.encrypt(publicKeys); + var armored = armor.encode(enums.armor.message, msg.packets.write()); + return armored; +} +/** + * Decrypts message + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {module:message~Message} message the message object with the encrypted data + * @return {(String|null)} decrypted message as as native JavaScript string + * or null if no literal data found + * @static + */ +function decryptMessage(privateKey, message) { + message = message.decrypt(privateKey); + return message.getText(); +} +/** + * Decrypts message and verifies signatures + * @param {module:key~Key} privateKey private key with decrypted secret key data + * @param {Array} publicKeys public keys to verify signatures + * @param {module:message~Message} message the message object with signed and encrypted data + * @return {{text: String, signatures: Array<{keyid: module:type/keyid, valid: Boolean}>}} + * decrypted message as as native JavaScript string + * with verified signatures or null if no literal data found + * @static + */ +function decryptAndVerifyMessage(privateKey, publicKeys, message) { + var result = {}; + message = message.decrypt(privateKey); + result.text = message.getText(); + if (result.text) { + result.signatures = message.verify(publicKeys); + return result; + } + return null; +} + +/** + * Signs a cleartext message + * @param {Array} privateKeys private key with decrypted secret key data to sign cleartext + * @param {String} text cleartext + * @return {String} ASCII armored message + * @static + */ +function signClearMessage(privateKeys, text) { + var cleartextMessage = new cleartext.CleartextMessage(text); + cleartextMessage.sign(privateKeys); + return cleartextMessage.armor(); +} + +/** + * Verifies signatures of cleartext signed message + * @param {Array} publicKeys public keys to verify signatures + * @param {module:cleartext~CleartextMessage} message cleartext message object with signatures + * @return {{text: String, signatures: Array<{keyid: module:type/keyid, valid: Boolean}>}} + * cleartext with status of verified signatures + * @static + */ +function verifyClearSignedMessage(publicKeys, message) { + var result = {}; + if (!(message instanceof cleartext.CleartextMessage)) { + throw new Error('Parameter [message] needs to be of type CleartextMessage.'); + } + result.text = message.getText(); + result.signatures = message.verify(publicKeys); + return result; +} + +/** + * Generates a new OpenPGP key pair. Currently only supports RSA keys. + * Primary and subkey will be of same type. + * @param {Integer} keyType to indicate what type of key to make. + * RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1 + * @param {Integer} numBits number of bits for the key creation. (should be 1024+, generally) + * @param {String} userId assumes already in form of "User Name " + * @param {String} passphrase The passphrase used to encrypt the resulting private key + * @return {Object} {key: Array, privateKeyArmored: Array, publicKeyArmored: Array} + * @static + */ +function generateKeyPair(keyType, numBits, userId, passphrase) { + var result = {}; + var newKey = key.generate(keyType, numBits, userId, passphrase); + result.key = newKey; + result.privateKeyArmored = newKey.armor(); + result.publicKeyArmored = newKey.toPublic().armor(); + return result; +} + +exports.encryptMessage = encryptMessage; +exports.signAndEncryptMessage = signAndEncryptMessage; +exports.decryptMessage = decryptMessage; +exports.decryptAndVerifyMessage = decryptAndVerifyMessage +exports.signClearMessage = signClearMessage; +exports.verifyClearSignedMessage = verifyClearSignedMessage; +exports.generateKeyPair = generateKeyPair; diff --git a/src/openpgp.keyring.js b/src/openpgp.keyring.js deleted file mode 100644 index 92c953bc..00000000 --- a/src/openpgp.keyring.js +++ /dev/null @@ -1,264 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. - */ -function openpgp_keyring() { - - /** - * Initialization routine for the keyring. This method reads the - * keyring from HTML5 local storage and initializes this instance. - * This method is called by openpgp.init(). - */ - function init() { - var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys")); - var spublickeys = JSON.parse(window.localStorage.getItem("publickeys")); - if (sprivatekeys == null || sprivatekeys.length == 0) { - sprivatekeys = new Array(); - } - - if (spublickeys == null || spublickeys.length == 0) { - spublickeys = new Array(); - } - this.publicKeys = new Array(); - this.privateKeys = new Array(); - var k = 0; - for (var i =0; i < sprivatekeys.length; i++) { - var r = openpgp.read_privateKey(sprivatekeys[i]); - this.privateKeys[k] = { armored: sprivatekeys[i], obj: r[0], keyId: r[0].getKeyId()}; - k++; - } - k = 0; - for (var i =0; i < spublickeys.length; i++) { - var r = openpgp.read_publicKey(spublickeys[i]); - if (r[0] != null) { - this.publicKeys[k] = { armored: spublickeys[i], obj: r[0], keyId: r[0].getKeyId()}; - k++; - } - } - } - this.init = init; - - /** - * Checks if at least one private key is in the keyring - * @return {Boolean} True if there are private keys, else false. - */ - function hasPrivateKey() { - return this.privateKeys.length > 0; - } - this.hasPrivateKey = hasPrivateKey; - - /** - * Saves the current state of the keyring to HTML5 local storage. - * The privateKeys array and publicKeys array gets Stringified using JSON - */ - function store() { - var priv = new Array(); - for (var i = 0; i < this.privateKeys.length; i++) { - priv[i] = this.privateKeys[i].armored; - } - var pub = new Array(); - for (var i = 0; i < this.publicKeys.length; i++) { - pub[i] = this.publicKeys[i].armored; - } - window.localStorage.setItem("privatekeys",JSON.stringify(priv)); - window.localStorage.setItem("publickeys",JSON.stringify(pub)); - } - this.store = store; - /** - * searches all public keys in the keyring matching the address or address part of the user ids - * @param {String} email_address - * @return {openpgp_msg_publickey[]} The public keys associated with provided email address. - */ - function getPublicKeyForAddress(email_address) { - var results = new Array(); - var spl = email_address.split("<"); - var email = ""; - if (spl.length > 1) { - email = spl[1].split(">")[0]; - } else { - email = email_address.trim(); - } - email = email.toLowerCase(); - if(!util.emailRegEx.test(email)){ - return results; - } - for (var i =0; i < this.publicKeys.length; i++) { - for (var j = 0; j < this.publicKeys[i].obj.userIds.length; j++) { - if (this.publicKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0) - results[results.length] = this.publicKeys[i]; - } - } - return results; - } - this.getPublicKeyForAddress = getPublicKeyForAddress; - - /** - * Searches the keyring for a private key containing the specified email address - * @param {String} email_address email address to search for - * @return {openpgp_msg_privatekey[]} private keys found - */ - function getPrivateKeyForAddress(email_address) { - var results = new Array(); - var spl = email_address.split("<"); - var email = ""; - if (spl.length > 1) { - email = spl[1].split(">")[0]; - } else { - email = email_address.trim(); - } - email = email.toLowerCase(); - if(!util.emailRegEx.test(email)){ - return results; - } - for (var i =0; i < this.privateKeys.length; i++) { - for (var j = 0; j < this.privateKeys[i].obj.userIds.length; j++) { - if (this.privateKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0) - results[results.length] = this.privateKeys[i]; - } - } - return results; - } - - this.getPrivateKeyForAddress = getPrivateKeyForAddress; - /** - * Searches the keyring for public keys having the specified key id - * @param {String} keyId provided as string of hex number (lowercase) - * @return {openpgp_msg_privatekey[]} public keys found - */ - function getPublicKeysForKeyId(keyId) { - var result = new Array(); - for (var i=0; i < this.publicKeys.length; i++) { - var key = this.publicKeys[i]; - if (keyId == key.obj.getKeyId()) - result[result.length] = key; - else if (key.obj.subKeys != null) { - for (var j=0; j < key.obj.subKeys.length; j++) { - var subkey = key.obj.subKeys[j]; - if (keyId == subkey.getKeyId()) { - result[result.length] = { - obj: key.obj.getSubKeyAsKey(j), - keyId: subkey.getKeyId() - } - } - } - } - } - return result; - } - this.getPublicKeysForKeyId = getPublicKeysForKeyId; - - /** - * Searches the keyring for private keys having the specified key id - * @param {String} keyId 8 bytes as string containing the key id to look for - * @return {openpgp_msg_privatekey[]} private keys found - */ - function getPrivateKeyForKeyId(keyId) { - var result = new Array(); - for (var i=0; i < this.privateKeys.length; i++) { - if (keyId == this.privateKeys[i].obj.getKeyId()) { - result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.privateKeyPacket}; - } - if (this.privateKeys[i].obj.subKeys != null) { - var subkeyids = this.privateKeys[i].obj.getSubKeyIds(); - for (var j=0; j < subkeyids.length; j++) - if (keyId == util.hexstrdump(subkeyids[j])) { - result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.subKeys[j]}; - } - } - } - return result; - } - this.getPrivateKeyForKeyId = getPrivateKeyForKeyId; - - /** - * Imports a public key from an exported ascii armored message - * @param {String} armored_text PUBLIC KEY BLOCK message to read the public key from - */ - function importPublicKey (armored_text) { - var result = openpgp.read_publicKey(armored_text); - for (var i = 0; i < result.length; i++) { - this.publicKeys[this.publicKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()}; - } - return true; - } - - /** - * Imports a private key from an exported ascii armored message - * @param {String} armored_text PRIVATE KEY BLOCK message to read the private key from - */ - function importPrivateKey (armored_text, password) { - var result = openpgp.read_privateKey(armored_text); - if(!result[0].decryptSecretMPIs(password)) - return false; - for (var i = 0; i < result.length; i++) { - this.privateKeys[this.privateKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()}; - } - return true; - } - - this.importPublicKey = importPublicKey; - this.importPrivateKey = importPrivateKey; - - /** - * returns the openpgp_msg_privatekey representation of the public key at public key ring index - * @param {Integer} index the index of the public key within the publicKeys array - * @return {openpgp_msg_privatekey} the public key object - */ - function exportPublicKey(index) { - return this.publicKey[index]; - } - this.exportPublicKey = exportPublicKey; - - - /** - * Removes a public key from the public key keyring at the specified index - * @param {Integer} index the index of the public key within the publicKeys array - * @return {openpgp_msg_privatekey} The public key object which has been removed - */ - function removePublicKey(index) { - var removed = this.publicKeys.splice(index,1); - this.store(); - return removed; - } - this.removePublicKey = removePublicKey; - - /** - * returns the openpgp_msg_privatekey representation of the private key at private key ring index - * @param {Integer} index the index of the private key within the privateKeys array - * @return {openpgp_msg_privatekey} the private key object - */ - function exportPrivateKey(index) { - return this.privateKeys[index]; - } - this.exportPrivateKey = exportPrivateKey; - - /** - * Removes a private key from the private key keyring at the specified index - * @param {Integer} index the index of the private key within the privateKeys array - * @return {openpgp_msg_privatekey} The private key object which has been removed - */ - function removePrivateKey(index) { - var removed = this.privateKeys.splice(index,1); - this.store(); - return removed; - } - this.removePrivateKey = removePrivateKey; - -} diff --git a/src/openpgp.msg.privatekey.js b/src/openpgp.msg.privatekey.js deleted file mode 100644 index b122ae1c..00000000 --- a/src/openpgp.msg.privatekey.js +++ /dev/null @@ -1,193 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Class that represents a decoded private key for internal openpgp.js use - */ - -function openpgp_msg_privatekey() { - this.subKeys = new Array(); - this.privateKeyPacket = null; - this.userIds = new Array(); - this.userAttributes = new Array(); - this.revocationSignatures = new Array(); - this.subKeys = new Array(); - - /** - * - * @return last position - */ - function read_nodes(parent_node, input, position, len) { - this.privateKeyPacket = parent_node; - - var pos = position; - while (input.length > pos) { - var result = openpgp_packet.read_packet(input, pos, input.length - pos); - if (result == null) { - util.print_error("openpgp.msg.messge decrypt:\n"+'[pub/priv_key]parsing ends here @:' + pos + " l:" + len); - break; - } else { - switch (result.tagType) { - case 2: // public key revocation signature - if (result.signatureType == 32) - this.revocationSignatures[this.revocationSignatures.length] = result; - else if (result.signatureType > 15 && result.signatureType < 20) { - if (this.certificationsignatures == null) - this.certificationSignatures = new Array(); - this.certificationSignatures[this.certificationSignatures.length] = result; - } else - util.print_error("openpgp.msg.messge decrypt:\n"+"unknown signature type directly on key "+result.signatureType+" @"+pos); - pos += result.packetLength + result.headerLength; - break; - case 7: // PrivateSubkey Packet - this.subKeys[this.subKeys.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos); - break; - case 17: // User Attribute Packet - this.userAttributes[this.userAttributes.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos); - break; - case 13: // User ID Packet - this.userIds[this.userIds.length] = result; - pos += result.packetLength + result.headerLength; - pos += result.read_nodes(this.privateKeyPacket, input, pos, input.length - pos); - break; - default: - this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength; - this.len = pos - position; - return this.len; - } - } - } - this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength; - this.len = pos - position; - - return this.len; - } - - function getKeyId() { - return this.privateKeyPacket.publicKey.getKeyId(); - } - - - function getSubKeyIds() { - if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys. - var result = new Array(); - for (var i = 0; i < this.subKeys.length; i++) { - result[i] = str_sha1(this.subKeys[i].publicKey.header+this.subKeys[i].publicKey.data).substring(12,20); - } - return result; - } - - - function getSigningKey() { - if ((this.privateKeyPacket.publicKey.publicKeyAlgorithm == 17 || - this.privateKeyPacket.publicKey.publicKeyAlgorithm != 2) - && this.privateKeyPacket.publicKey.verifyKey() == 3) - return this.privateKeyPacket; - else if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys. - for (var j = 0; j < this.privateKeyPacket.subKeys.length; j++) { - if ((this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm == 17 || - this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm != 2) && - this.privateKeyPacket.subKeys[j].publicKey.verifyKey() == 3) - return this.privateKeyPacket.subKeys[j]; - } - return null; - } - - function getPreferredSignatureHashAlgorithm() { - var pkey = this.getSigningKey(); - if (pkey == null) { - util.print_error("private key is for encryption only! Cannot create a signature.") - return null; - } - if (pkey.publicKey.publicKeyAlgorithm == 17) { - var dsa = new DSA(); - return dsa.select_hash_algorithm(pkey.publicKey.MPIs[1].toBigInteger()); // q - } - //TODO implement: https://tools.ietf.org/html/rfc4880#section-5.2.3.8 - //separate private key preference from digest preferences - return openpgp.config.config.prefer_hash_algorithm; - - } - - function decryptSecretMPIs(str_passphrase) { - return this.privateKeyPacket.decryptSecretMPIs(str_passphrase); - } - - function getFingerprint() { - return this.privateKeyPacket.publicKey.getFingerprint(); - } - - // TODO need to implement this - function revoke() { - - } - - /** - * extracts the public key part - * @return {String} OpenPGP armored text containing the public key - * returns null if no sufficient data to extract public key - */ - function extractPublicKey() { - // add public key - var key = this.privateKeyPacket.publicKey.header + this.privateKeyPacket.publicKey.data; - for (var i = 0; i < this.userIds.length; i++) { - // verify userids - if (this.userIds[i].certificationSignatures.length === 0) { - util.print_error("extractPublicKey - missing certification signatures"); - return null; - } - var userIdPacket = new openpgp_packet_userid(); - // add userids - key += userIdPacket.write_packet(this.userIds[i].text); - for (var j = 0; j < this.userIds[i].certificationSignatures.length; j++) { - var certSig = this.userIds[i].certificationSignatures[j]; - // add signatures - key += openpgp_packet.write_packet_header(2, certSig.data.length) + certSig.data; - } - } - for (var k = 0; k < this.subKeys.length; k++) { - var pubSubKey = this.subKeys[k].publicKey; - // add public subkey package - key += openpgp_packet.write_old_packet_header(14, pubSubKey.data.length) + pubSubKey.data; - var subKeySig = this.subKeys[k].subKeySignature; - if (subKeySig !== null) { - // add subkey signature - key += openpgp_packet.write_packet_header(2, subKeySig.data.length) + subKeySig.data; - } else { - util.print_error("extractPublicKey - missing subkey signature"); - return null; - } - } - var publicArmored = openpgp_encoding_armor(4, key); - return publicArmored; - } - - this.extractPublicKey = extractPublicKey; - this.getSigningKey = getSigningKey; - this.getFingerprint = getFingerprint; - this.getPreferredSignatureHashAlgorithm = getPreferredSignatureHashAlgorithm; - this.read_nodes = read_nodes; - this.decryptSecretMPIs = decryptSecretMPIs; - this.getSubKeyIds = getSubKeyIds; - this.getKeyId = getKeyId; - -} diff --git a/src/packet/all_packets.js b/src/packet/all_packets.js new file mode 100644 index 00000000..8d7207c8 --- /dev/null +++ b/src/packet/all_packets.js @@ -0,0 +1,49 @@ +/** + * @requires enums + * @module packet + */ +var enums = require('../enums.js'); + +// This is pretty ugly, but browserify needs to have the requires explicitly written. + +module.exports = { + /** @see module:packet/compressed */ + compressed: require('./compressed.js'), + /** @see module:packet/sym_encrypted_integrity_protected */ + sym_encrypted_integrity_protected: require('./sym_encrypted_integrity_protected.js'), + /** @see module:packet/public_key_encrypted_session_key */ + public_key_encrypted_session_key: require('./public_key_encrypted_session_key.js'), + /** @see module:packet/sym_encrypted_session_key */ + sym_encrypted_session_key: require('./sym_encrypted_session_key.js'), + /** @see module:packet/literal */ + literal: require('./literal.js'), + /** @see module:packet/public_key */ + public_key: require('./public_key.js'), + /** @see module:packet/symmetrically_encrypted */ + symmetrically_encrypted: require('./symmetrically_encrypted.js'), + /** @see module:packet/marker */ + marker: require('./marker.js'), + /** @see module:packet/public_subkey */ + public_subkey: require('./public_subkey.js'), + /** @see module:packet/user_attribute */ + user_attribute: require('./user_attribute.js'), + /** @see module:packet/one_pass_signature */ + one_pass_signature: require('./one_pass_signature.js'), + /** @see module:packet/secret_key */ + secret_key: require('./secret_key.js'), + /** @see module:packet/userid */ + userid: require('./userid.js'), + /** @see module:packet/secret_subkey */ + secret_subkey: require('./secret_subkey.js'), + /** @see module:packet/signature */ + signature: require('./signature.js'), + /** @see module:packet/trust */ + trust: require('./trust.js') +} + +for (var i in enums.packet) { + var packetClass = module.exports[i]; + + if (packetClass != undefined) + packetClass.prototype.tag = enums.packet[i]; +} diff --git a/src/packet/compressed.js b/src/packet/compressed.js new file mode 100644 index 00000000..0cde6263 --- /dev/null +++ b/src/packet/compressed.js @@ -0,0 +1,174 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Compressed Data Packet (Tag 8)
      + *
      + * RFC4880 5.6: The Compressed Data packet contains compressed data. Typically, + * this packet is found as the contents of an encrypted packet, or following + * a Signature or One-Pass Signature packet, and contains a literal data packet. + * @requires compression/jxg + * @requires encoding/base64 + * @requires enums + * @module packet/compressed + */ + +var enums = require('../enums.js'), + JXG = require('../compression/jxg.js'), + base64 = require('../encoding/base64.js'); + +/** + * @constructor + */ +module.exports = function compressed() { + /** + * List of packets + * @type {module:packet/packetlist} + */ + this.packets = null; + /** + * Compression algorithm + * @type {compression} + */ + this.algorithm = 'uncompressed'; + + /** + * Compressed packet data + * @type {String} + */ + this.compressed = null; + + + /** + * Parsing function for the packet. + * @param {String} bytes Payload of a tag 8 packet + */ + this.read = function(bytes) { + // One octet that gives the algorithm used to compress the packet. + this.algorithm = enums.read(enums.compression, bytes.charCodeAt(0)); + + // Compressed data, which makes up the remainder of the packet. + this.compressed = bytes.substr(1); + + this.decompress(); + } + + + + /** + * Return the compressed packet. + * @return {String} binary compressed packet + */ + this.write = function() { + if (this.compressed == null) + this.compress(); + + return String.fromCharCode(enums.write(enums.compression, this.algorithm)) + this.compressed; + } + + + /** + * Decompression method for decompressing the compressed data + * read by read_packet + */ + this.decompress = function() { + var decompressed; + + switch (this.algorithm) { + case 'uncompressed': + decompressed = this.compressed; + break; + + case 'zip': + var compData = this.compressed; + + var radix = base64.encode(compData).replace(/\n/g, ""); + // no header in this case, directly call deflate + var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix)); + + decompressed = unescape(jxg_obj.deflate()[0][0]); + break; + + case 'zlib': + //RFC 1950. Bits 0-3 Compression Method + var compressionMethod = this.compressed.charCodeAt(0) % 0x10; + + //Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size. + // 2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary + // (how is this defined). Basic checksum, and compression level. + + if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951 + // remove 4 bytes ADLER32 checksum from the end + var compData = this.compressed.substring(0, this.compressed.length - 4); + var radix = base64.encode(compData).replace(/\n/g, ""); + //TODO check ADLER32 checksum + decompressed = JXG.decompress(radix); + break; + + } else { + throw new Error("Compression algorithm ZLIB only supports " + + "DEFLATE compression method."); + } + break; + + case 'bzip2': + // TODO: need to implement this + throw new Error('Compression algorithm BZip2 [BZ2] is not implemented.'); + break; + + default: + throw new Error("Compression algorithm unknown :" + this.alogrithm); + break; + } + + this.packets.read(decompressed); + } + + /** + * Compress the packet data (member decompressedData) + */ + this.compress = function() { + switch (this.algorithm) { + + case 'uncompressed': + // - Uncompressed + this.compressed = this.packets.write(); + break; + + case 'zip': + // - ZIP [RFC1951] + throw new Error("Compression algorithm ZIP [RFC1951] is not implemented."); + break; + + case 'zlib': + // - ZLIB [RFC1950] + // TODO: need to implement this + throw new Error("Compression algorithm ZLIB [RFC1950] is not implemented."); + break; + + case 'bzip2': + // - BZip2 [BZ2] + // TODO: need to implement this + throw new Error("Compression algorithm BZip2 [BZ2] is not implemented."); + break; + + default: + throw new Error("Compression algorithm unknown :" + this.type); + break; + } + } +}; diff --git a/src/packet/index.js b/src/packet/index.js new file mode 100644 index 00000000..4396464c --- /dev/null +++ b/src/packet/index.js @@ -0,0 +1,10 @@ +var enums = require('../enums.js'); + +module.exports = { + list: require('./packetlist.js') +}; + +var packets = require('./all_packets.js'); + +for (var i in packets) + module.exports[i] = packets[i]; diff --git a/src/packet/literal.js b/src/packet/literal.js new file mode 100644 index 00000000..209b99e2 --- /dev/null +++ b/src/packet/literal.js @@ -0,0 +1,129 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Literal Data Packet (Tag 11)
      + *
      + * RFC4880 5.9: A Literal Data packet contains the body of a message; data that + * is not to be further interpreted. + * @requires enums + * @requires util + * @module packet/literal + */ + +var util = require('../util'), + enums = require('../enums.js'); + +/** + * @constructor + */ +module.exports = function literal() { + this.format = 'utf8'; // default format for literal data packets + this.data = ''; // literal data representation as native JavaScript string or bytes + this.date = new Date(); + + + /** + * Set the packet data to a javascript native string, end of line + * will be normalized to \r\n and by default text is converted to UTF8 + * @param {String} text Any native javascript string + */ + this.setText = function (text) { + // normalize EOL to \r\n + text = text.replace(/\r/g, '').replace(/\n/g, '\r\n'); + // encode UTF8 + this.data = this.format == 'utf8' ? util.encode_utf8(text) : text; + } + + /** + * Returns literal data packets as native JavaScript string + * with normalized end of line to \n + * @return {String} literal data as text + */ + this.getText = function () { + // decode UTF8 + var text = util.decode_utf8(this.data); + // normalize EOL to \n + return text.replace(/\r\n/g, '\n'); + } + + /** + * Set the packet data to value represented by the provided string of bytes. + * @param {String} bytes The string of bytes + * @param {utf8|binary|text} format The format of the string of bytes + */ + this.setBytes = function (bytes, format) { + this.format = format; + this.data = bytes; + } + + + /** + * Get the byte sequence representing the literal packet data + * @returns {String} A sequence of bytes + */ + this.getBytes = function () { + return this.data; + } + + + /** + * Parsing function for a literal data packet (tag 11). + * + * @param {String} input Payload of a tag 11 packet + * @param {Integer} position + * Position to start reading from the input string + * @param {Integer} len + * Length of the packet or the remaining length of + * input at position + * @return {module:packet/literal} object representation + */ + this.read = function (bytes) { + // - A one-octet field that describes how the data is formatted. + + var format = enums.read(enums.literal, bytes.charCodeAt(0)); + + var filename_len = bytes.charCodeAt(1); + this.filename = util.decode_utf8(bytes.substr(2, filename_len)); + + this.date = util.readDate(bytes.substr(2 + filename_len, 4)); + + var data = bytes.substring(6 + filename_len); + + this.setBytes(data, format); + } + + /** + * Creates a string representation of the packet + * + * @param {String} data The data to be inserted as body + * @return {String} string-representation of the packet + */ + this.write = function () { + var filename = util.encode_utf8("msg.txt"); + + var data = this.getBytes(); + + var result = ''; + result += String.fromCharCode(enums.write(enums.literal, this.format)); + result += String.fromCharCode(filename.length); + result += filename; + result += util.writeDate(this.date); + result += data; + return result; + } +} diff --git a/src/packet/marker.js b/src/packet/marker.js new file mode 100644 index 00000000..ef93f390 --- /dev/null +++ b/src/packet/marker.js @@ -0,0 +1,54 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +/** + * Implementation of the strange "Marker packet" (Tag 10)
      + *
      + * RFC4880 5.8: An experimental version of PGP used this packet as the Literal + * packet, but no released version of PGP generated Literal packets with this + * tag. With PGP 5.x, this packet has been reassigned and is reserved for use as + * the Marker packet.
      + *
      + * Such a packet MUST be ignored when received. + * @module packet/marker + */ + +/** + * @constructor + */ +module.exports = function marker() { + /** + * Parsing function for a literal data packet (tag 10). + * + * @param {String} input Payload of a tag 10 packet + * @param {Integer} position + * Position to start reading from the input string + * @param {Integer} len + * Length of the packet or the remaining length of + * input at position + * @return {module:packet/marker} Object representation + */ + this.read = function (bytes) { + if (bytes.charCodeAt(0) == 0x50 && // P + bytes.charCodeAt(1) == 0x47 && // G + bytes.charCodeAt(2) == 0x50) // P + return true; + // marker packet does not contain "PGP" + return false; + } +} diff --git a/src/packet/one_pass_signature.js b/src/packet/one_pass_signature.js new file mode 100644 index 00000000..5a546df4 --- /dev/null +++ b/src/packet/one_pass_signature.js @@ -0,0 +1,95 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the One-Pass Signature Packets (Tag 4)
      + *
      + * RFC4880 5.4: + * The One-Pass Signature packet precedes the signed data and contains + * enough information to allow the receiver to begin calculating any + * hashes needed to verify the signature. It allows the Signature + * packet to be placed at the end of the message, so that the signer + * can compute the entire signed message in one pass. + * @requires enums + * @requires type/keyid + * @module packet/one_pass_signature +*/ + +var enums = require('../enums.js'), + type_keyid = require('../type/keyid.js'); + +/** + * @constructor + */ +module.exports = function one_pass_signature() { + this.version = null; // A one-octet version number. The current version is 3. + this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1. + this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4) + this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1) + this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key. + this.flags = null; // A one-octet number holding a flag showing whether the signature is nested. A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data. + + /** + * parsing function for a one-pass signature packet (tag 4). + * @param {String} bytes payload of a tag 4 packet + * @return {module:packet/one_pass_signature} object representation + */ + this.read = function (bytes) { + var mypos = 0; + // A one-octet version number. The current version is 3. + this.version = bytes.charCodeAt(mypos++); + + // A one-octet signature type. Signature types are described in + // Section 5.2.1. + this.type = enums.read(enums.signature, bytes.charCodeAt(mypos++)); + + // A one-octet number describing the hash algorithm used. + this.hashAlgorithm = enums.read(enums.hash, bytes.charCodeAt(mypos++)); + + // A one-octet number describing the public-key algorithm used. + this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(mypos++)); + + // An eight-octet number holding the Key ID of the signing key. + this.signingKeyId = new type_keyid(); + this.signingKeyId.read(bytes.substr(mypos)); + mypos += 8; + + // A one-octet number holding a flag showing whether the signature + // is nested. A zero value indicates that the next packet is + // another One-Pass Signature packet that describes another + // signature to be applied to the same message data. + this.flags = bytes.charCodeAt(mypos++); + return this; + } + + /** + * creates a string representation of a one-pass signature packet + * @return {String} a string representation of a one-pass signature packet + */ + this.write = function () { + var result = ""; + + result += String.fromCharCode(3); + result += String.fromCharCode(enums.write(enums.signature, this.type)); + result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm)); + result += String.fromCharCode(enums.write(enums.publicKey, this.publicKeyAlgorithm)); + result += this.signingKeyId.write(); + result += String.fromCharCode(this.flags); + + return result; + } +}; diff --git a/src/packet/openpgp.packet.compressed.js b/src/packet/openpgp.packet.compressed.js deleted file mode 100644 index e02ee4da..00000000 --- a/src/packet/openpgp.packet.compressed.js +++ /dev/null @@ -1,164 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the Compressed Data Packet (Tag 8) - * - * RFC4880 5.6: - * The Compressed Data packet contains compressed data. Typically, this - * packet is found as the contents of an encrypted packet, or following - * a Signature or One-Pass Signature packet, and contains a literal data - * packet. - */ -function openpgp_packet_compressed() { - this.tagType = 8; - this.decompressedData = null; - - /** - * Parsing function for the packet. - * @param {String} input Payload of a tag 8 packet - * @param {Integer} position Position to start reading from the input string - * @param {Integer} len Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_compressed} Object representation - */ - function read_packet (input, position, len) { - this.packetLength = len; - var mypos = position; - // One octet that gives the algorithm used to compress the packet. - this.type = input.charCodeAt(mypos++); - // Compressed data, which makes up the remainder of the packet. - this.compressedData = input.substring(position+1, position+len); - return this; - } - /** - * Decompression method for decompressing the compressed data - * read by read_packet - * @return {String} The decompressed data - */ - function decompress() { - if (this.decompressedData != null) - return this.decompressedData; - - if (this.type == null) - return null; - - switch (this.type) { - case 0: // - Uncompressed - this.decompressedData = this.compressedData; - break; - case 1: // - ZIP [RFC1951] - util.print_info('Decompressed packet [Type 1-ZIP]: ' + this.toString()); - var compData = this.compressedData; - var radix = s2r(compData).replace(/\n/g,""); - // no header in this case, directly call deflate - var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix)); - this.decompressedData = unescape(jxg_obj.deflate()[0][0]); - break; - case 2: // - ZLIB [RFC1950] - util.print_info('Decompressed packet [Type 2-ZLIB]: ' + this.toString()); - var compressionMethod = this.compressedData.charCodeAt(0) % 0x10; //RFC 1950. Bits 0-3 Compression Method - //Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size. - //2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary (how is this defined). Basic checksum, and compression level. - if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951 - // remove 4 bytes ADLER32 checksum from the end - var compData = this.compressedData.substring(0, this.compressedData.length - 4); - var radix = s2r(compData).replace(/\n/g,""); - //TODO check ADLER32 checksum - this.decompressedData = JXG.decompress(radix); - break; - } else { - util.print_error("Compression algorithm ZLIB only supports DEFLATE compression method."); - } - break; - case 3: // - BZip2 [BZ2] - // TODO: need to implement this - util.print_error("Compression algorithm BZip2 [BZ2] is not implemented."); - break; - default: - util.print_error("Compression algorithm unknown :"+this.type); - break; - } - util.print_debug("decompressed:"+util.hexstrdump(this.decompressedData)); - return this.decompressedData; - } - - /** - * Compress the packet data (member decompressedData) - * @param {Integer} type Algorithm to be used // See RFC 4880 9.3 - * @param {String} data Data to be compressed - * @return {String} The compressed data stored in attribute compressedData - */ - function compress(type, data) { - this.type = type; - this.decompressedData = data; - switch (this.type) { - case 0: // - Uncompressed - this.compressedData = this.decompressedData; - break; - case 1: // - ZIP [RFC1951] - util.print_error("Compression algorithm ZIP [RFC1951] is not implemented."); - break; - case 2: // - ZLIB [RFC1950] - // TODO: need to implement this - util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented."); - break; - case 3: // - BZip2 [BZ2] - // TODO: need to implement this - util.print_error("Compression algorithm BZip2 [BZ2] is not implemented."); - break; - default: - util.print_error("Compression algorithm unknown :"+this.type); - break; - } - this.packetLength = this.compressedData.length +1; - return this.compressedData; - } - - /** - * Creates a string representation of the packet - * @param {Integer} algorithm Algorithm to be used // See RFC 4880 9.3 - * @param {String} data Data to be compressed - * @return {String} String-representation of the packet - */ - function write_packet(algorithm, data) { - this.decompressedData = data; - if (algorithm == null) { - this.type = 1; - } - var result = String.fromCharCode(this.type)+this.compress(this.type); - return openpgp_packet.write_packet_header(8, result.length)+result; - } - - /** - * Pretty printing the packet (useful for debug purposes) - * @return {String} - */ - function toString() { - return '5.6. Compressed Data Packet (Tag 8)\n'+ - ' length: '+this.packetLength+'\n'+ - ' Compression Algorithm = '+this.type+'\n'+ - ' Compressed Data: Byte ['+util.hexstrdump(this.compressedData)+']\n'; - } - - this.read_packet = read_packet; - this.toString = toString; - this.compress = compress; - this.decompress = decompress; - this.write_packet = write_packet; -}; diff --git a/src/packet/openpgp.packet.encrypteddata.js b/src/packet/openpgp.packet.encrypteddata.js deleted file mode 100644 index be31467e..00000000 --- a/src/packet/openpgp.packet.encrypteddata.js +++ /dev/null @@ -1,99 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the Symmetrically Encrypted Data Packet (Tag 9) - * - * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted - * with a symmetric-key algorithm. When it has been decrypted, it contains other - * packets (usually a literal data packet or compressed data packet, but in - * theory other Symmetrically Encrypted Data packets or sequences of packets - * that form whole OpenPGP messages). - */ - -function openpgp_packet_encrypteddata() { - this.tagType = 9; - this.packetLength = null; - this.encryptedData = null; - this.decryptedData = null; - - /** - * Parsing function for the packet. - * - * @param {String} input Payload of a tag 9 packet - * @param {Integer} position Position to start reading from the input string - * @param {Integer} len Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} Object representation - */ - function read_packet(input, position, len) { - var mypos = position; - this.packetLength = len; - // - Encrypted data, the output of the selected symmetric-key cipher - // operating in OpenPGP's variant of Cipher Feedback (CFB) mode. - this.encryptedData = input.substring(position, position + len); - return this; - } - - /** - * Symmetrically decrypt the packet data - * - * @param {Integer} symmetric_algorithm_type - * Symmetric key algorithm to use // See RFC4880 9.2 - * @param {String} key - * Key as string with the corresponding length to the - * algorithm - * @return The decrypted data; - */ - function decrypt_sym(symmetric_algorithm_type, key) { - this.decryptedData = openpgp_crypto_symmetricDecrypt( - symmetric_algorithm_type, key, this.encryptedData, true); - util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+ - "data: "+util.hexstrdump(this.decryptedData)); - return this.decryptedData; - } - - /** - * Creates a string representation of the packet - * - * @param {Integer} algo Symmetric key algorithm to use // See RFC4880 9.2 - * @param {String} key Key as string with the corresponding length to the - * algorithm - * @param {String} data Data to be - * @return {String} String-representation of the packet - */ - function write_packet(algo, key, data) { - var result = ""; - result += openpgp_crypto_symmetricEncrypt( - openpgp_crypto_getPrefixRandom(algo), algo, key, data, true); - result = openpgp_packet.write_packet_header(9, result.length) + result; - return result; - } - - function toString() { - return '5.7. Symmetrically Encrypted Data Packet (Tag 9)\n' - + ' length: ' + this.packetLength + '\n' - + ' Used symmetric algorithm: ' + this.algorithmType + '\n' - + ' encrypted data: Bytes [' - + util.hexstrdump(this.encryptedData) + ']\n'; - } - this.decrypt_sym = decrypt_sym; - this.toString = toString; - this.read_packet = read_packet; - this.write_packet = write_packet; -}; diff --git a/src/packet/openpgp.packet.literaldata.js b/src/packet/openpgp.packet.literaldata.js deleted file mode 100644 index 4dfecd19..00000000 --- a/src/packet/openpgp.packet.literaldata.js +++ /dev/null @@ -1,155 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the Literal Data Packet (Tag 11) - * - * RFC4880 5.9: A Literal Data packet contains the body of a message; data that - * is not to be further interpreted. - */ -function openpgp_packet_literaldata() { - this.tagType = 11; - - - /** - * Set the packet data to a javascript native string or a squence of - * bytes. Conversion to a proper utf8 encoding takes place when the - * packet is written. - * @param {String} str Any native javascript string - * @param {openpgp_packet_literaldata.formats} format - */ - this.set_data = function(str, format) { - this.format = format; - this.data = str; - } - - /** - * Set the packet data to value represented by the provided string - * of bytes together with the appropriate conversion format. - * @param {String} bytes The string of bytes - * @param {openpgp_packet_literaldata.formats} format - */ - this.set_data_bytes = function(bytes, format) { - this.format = format; - - if(format == openpgp_packet_literaldata.formats.utf8) - bytes = util.decode_utf8(bytes); - - this.data = bytes; - } - - /** - * Get the byte sequence representing the literal packet data - * @returns {String} A sequence of bytes - */ - this.get_data_bytes = function() { - if(this.format == openpgp_packet_literaldata.formats.utf8) - return util.encode_utf8(this.data); - else - return this.data; - } - - - - /** - * Parsing function for a literal data packet (tag 11). - * - * @param {String} input Payload of a tag 11 packet - * @param {Integer} position - * Position to start reading from the input string - * @param {Integer} len - * Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - this.read_packet = function(input, position, len) { - this.packetLength = len; - // - A one-octet field that describes how the data is formatted. - - var format = input[position]; - - this.filename = util.decode_utf8(input.substr(position + 2, input - .charCodeAt(position + 1))); - - this.date = new Date(parseInt(input.substr(position + 2 - + input.charCodeAt(position + 1), 4)) * 1000); - - var bytes = input.substring(position + 6 - + input.charCodeAt(position + 1)); - - this.set_data_bytes(bytes, format); - return this; - } - - /** - * Creates a string representation of the packet - * - * @param {String} data The data to be inserted as body - * @return {String} string-representation of the packet - */ - this.write_packet = function(data) { - this.set_data(data, openpgp_packet_literaldata.formats.utf8); - this.filename = util.encode_utf8("msg.txt"); - this.date = new Date(); - - data = this.get_data_bytes(); - - var result = openpgp_packet.write_packet_header(11, data.length + 6 - + this.filename.length); - result += this.format; - result += String.fromCharCode(this.filename.length); - result += this.filename; - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 24) & 0xFF); - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 16) & 0xFF); - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 8) & 0xFF); - result += String - .fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF); - result += data; - return result; - } - - /** - * Generates debug output (pretty print) - * - * @return {String} String which gives some information about the keymaterial - */ - this.toString = function() { - return '5.9. Literal Data Packet (Tag 11)\n' + ' length: ' - + this.packetLength + '\n' + ' format: ' + this.format - + '\n' + ' filename:' + this.filename + '\n' - + ' date: ' + this.date + '\n' + ' data: |' - + this.data + '|\n' + ' rdata: |' + this.real_data + '|\n'; - } -} - -/** - * Data types in the literal packet - * @readonly - * @enum {String} - */ -openpgp_packet_literaldata.formats = { - /** Binary data */ - binary: 'b', - /** Text data */ - text: 't', - /** Utf8 data */ - utf8: 'u' -}; diff --git a/src/packet/openpgp.packet.modificationdetectioncode.js b/src/packet/openpgp.packet.modificationdetectioncode.js deleted file mode 100644 index 36e4a2c6..00000000 --- a/src/packet/openpgp.packet.modificationdetectioncode.js +++ /dev/null @@ -1,79 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the Modification Detection Code Packet (Tag 19) - * - * RFC4880 5.14: The Modification Detection Code packet contains a SHA-1 hash of - * plaintext data, which is used to detect message modification. It is only used - * with a Symmetrically Encrypted Integrity Protected Data packet. The - * Modification Detection Code packet MUST be the last packet in the plaintext - * data that is encrypted in the Symmetrically Encrypted Integrity Protected - * Data packet, and MUST appear in no other place. - */ - -function openpgp_packet_modificationdetectioncode() { - this.tagType = 19; - this.hash = null; - /** - * parsing function for a modification detection code packet (tag 19). - * - * @param {String} input payload of a tag 19 packet - * @param {Integer} position - * position to start reading from the input string - * @param {Integer} len - * length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - function read_packet(input, position, len) { - this.packetLength = len; - - if (len != 20) { - util - .print_error("openpgp.packet.modificationdetectioncode.js\n" - + 'invalid length for a modification detection code packet!' - + len); - return null; - } - // - A 20-octet SHA-1 hash of the preceding plaintext data of the - // Symmetrically Encrypted Integrity Protected Data packet, - // including prefix data, the tag octet, and length octet of the - // Modification Detection Code packet. - this.hash = input.substring(position, position + 20); - return this; - } - - /* - * this packet is created within the encryptedintegrityprotected packet - * function write_packet(data) { } - */ - - /** - * generates debug output (pretty print) - * - * @return {String} String which gives some information about the - * modification detection code - */ - function toString() { - return '5.14 Modification detection code packet\n' + ' bytes (' - + this.hash.length + '): [' + util.hexstrdump(this.hash) + ']'; - } - this.read_packet = read_packet; - this.toString = toString; -}; diff --git a/src/packet/openpgp.packet.onepasssignature.js b/src/packet/openpgp.packet.onepasssignature.js deleted file mode 100644 index d6b61944..00000000 --- a/src/packet/openpgp.packet.onepasssignature.js +++ /dev/null @@ -1,119 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the One-Pass Signature Packets (Tag 4) - * - * RFC4880 5.4: - * The One-Pass Signature packet precedes the signed data and contains - * enough information to allow the receiver to begin calculating any - * hashes needed to verify the signature. It allows the Signature - * packet to be placed at the end of the message, so that the signer - * can compute the entire signed message in one pass. - */ -function openpgp_packet_onepasssignature() { - this.tagType = 4; - this.version = null; // A one-octet version number. The current version is 3. - this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1. - this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4) - this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1) - this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key. - this.flags = null; // A one-octet number holding a flag showing whether the signature is nested. A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data. - - /** - * parsing function for a one-pass signature packet (tag 4). - * @param {String} input payload of a tag 4 packet - * @param {Integer} position position to start reading from the input string - * @param {Integer} len length of the packet or the remaining length of input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - function read_packet(input, position, len) { - this.packetLength = len; - var mypos = position; - // A one-octet version number. The current version is 3. - this.version = input.charCodeAt(mypos++); - - // A one-octet signature type. Signature types are described in - // Section 5.2.1. - this.type = input.charCodeAt(mypos++); - - // A one-octet number describing the hash algorithm used. - this.hashAlgorithm = input.charCodeAt(mypos++); - - // A one-octet number describing the public-key algorithm used. - this.publicKeyAlgorithm = input.charCodeAt(mypos++); - // An eight-octet number holding the Key ID of the signing key. - this.signingKeyId = new openpgp_type_keyid(); - this.signingKeyId.read_packet(input,mypos); - mypos += 8; - - // A one-octet number holding a flag showing whether the signature - // is nested. A zero value indicates that the next packet is - // another One-Pass Signature packet that describes another - // signature to be applied to the same message data. - this.flags = input.charCodeAt(mypos++); - return this; - } - - /** - * creates a string representation of a one-pass signature packet - * @param {Integer} type Signature types as described in RFC4880 Section 5.2.1. - * @param {Integer} hashalgorithm the hash algorithm used within the signature - * @param {openpgp_msg_privatekey} privatekey the private key used to generate the signature - * @param {Integer} length length of data to be signed - * @param {boolean} nested boolean showing whether the signature is nested. - * "true" indicates that the next packet is another One-Pass Signature packet - * that describes another signature to be applied to the same message data. - * @return {String} a string representation of a one-pass signature packet - */ - function write_packet(type, hashalgorithm, privatekey,length, nested) { - var result =""; - - result += openpgp_packet.write_packet_header(4,13); - result += String.fromCharCode(3); - result += String.fromCharCode(type); - result += String.fromCharCode(hashalgorithm); - result += String.fromCharCode(privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm); - result += privatekey.getKeyId(); - if (nested) - result += String.fromCharCode(0); - else - result += String.fromCharCode(1); - - return result; - } - - /** - * generates debug output (pretty print) - * @return {String} String which gives some information about the one-pass signature packet - */ - function toString() { - return '5.4. One-Pass Signature Packets (Tag 4)\n'+ - ' length: '+this.packetLength+'\n'+ - ' type: '+this.type+'\n'+ - ' keyID: '+this.signingKeyId.toString()+'\n'+ - ' hashA: '+this.hashAlgorithm+'\n'+ - ' pubKeyA:'+this.publicKeyAlgorithm+'\n'+ - ' flags: '+this.flags+'\n'+ - ' version:'+this.version+'\n'; - } - - this.read_packet = read_packet; - this.toString = toString; - this.write_packet = write_packet; -}; diff --git a/src/packet/package.json b/src/packet/package.json new file mode 100644 index 00000000..680692aa --- /dev/null +++ b/src/packet/package.json @@ -0,0 +1,5 @@ +{ + "name": "openpgp-packets", + "version": "0.0.1", + "main": "./index.js" +} diff --git a/src/packet/packet.js b/src/packet/packet.js new file mode 100644 index 00000000..7486038c --- /dev/null +++ b/src/packet/packet.js @@ -0,0 +1,263 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires enums + * @requires util + * @module packet/packet + */ + +var enums = require('../enums.js'), + util = require('../util'); + + +module.exports = { + readSimpleLength: function(bytes) { + var len = 0, + offset, + type = bytes.charCodeAt(0); + + + if (type < 192) { + len = bytes.charCodeAt(0); + offset = 1; + } else if (type < 255) { + len = ((bytes.charCodeAt(0) - 192) << 8) + (bytes.charCodeAt(1)) + 192; + offset = 2; + } else if (type == 255) { + len = util.readNumber(bytes.substr(1, 4)); + offset = 5; + } + + return { + len: len, + offset: offset + }; + }, + + /** + * Encodes a given integer of length to the openpgp length specifier to a + * string + * + * @param {Integer} length The length to encode + * @return {String} String with openpgp length representation + */ + writeSimpleLength: function(length) { + var result = ""; + if (length < 192) { + result += String.fromCharCode(length); + } else if (length > 191 && length < 8384) { + /* + * let a = (total data packet length) - 192 let bc = two octet + * representation of a let d = b + 192 + */ + result += String.fromCharCode(((length - 192) >> 8) + 192); + result += String.fromCharCode((length - 192) & 0xFF); + } else { + result += String.fromCharCode(255); + result += util.writeNumber(length, 4); + } + return result; + }, + + /** + * Writes a packet header version 4 with the given tag_type and length to a + * string + * + * @param {Integer} tag_type Tag type + * @param {Integer} length Length of the payload + * @return {String} String of the header + */ + writeHeader: function(tag_type, length) { + /* we're only generating v4 packet headers here */ + var result = ""; + result += String.fromCharCode(0xC0 | tag_type); + result += this.writeSimpleLength(length); + return result; + }, + + /** + * Writes a packet header Version 3 with the given tag_type and length to a + * string + * + * @param {Integer} tag_type Tag type + * @param {Integer} length Length of the payload + * @return {String} String of the header + */ + writeOldHeader: function(tag_type, length) { + var result = ""; + if (length < 256) { + result += String.fromCharCode(0x80 | (tag_type << 2)); + result += String.fromCharCode(length); + } else if (length < 65536) { + result += String.fromCharCode(0x80 | (tag_type << 2) | 1); + result += util.writeNumber(length, 2); + } else { + result += String.fromCharCode(0x80 | (tag_type << 2) | 2); + result += util.writeNumber(length, 4); + } + return result; + }, + + /** + * Generic static Packet Parser function + * + * @param {String} input Input stream as string + * @param {integer} position Position to start parsing + * @param {integer} len Length of the input from position on + * @return {Object} Returns a parsed module:packet/packet + */ + read: function(input, position, len) { + // some sanity checks + if (input == null || input.length <= position || input.substring(position).length < 2 || (input.charCodeAt(position) & + 0x80) == 0) { + throw new Error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."); + } + var mypos = position; + var tag = -1; + var format = -1; + var packet_length; + + format = 0; // 0 = old format; 1 = new format + if ((input.charCodeAt(mypos) & 0x40) != 0) { + format = 1; + } + + var packet_length_type; + if (format) { + // new format header + tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0 + } else { + // old format header + tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2 + packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0 + } + + // header octet parsing done + mypos++; + + // parsed length from length field + var bodydata = null; + + // used for partial body lengths + var real_packet_length = -1; + if (!format) { + // 4.2.1. Old Format Packet Lengths + switch (packet_length_type) { + case 0: + // The packet has a one-octet length. The header is 2 octets + // long. + packet_length = input.charCodeAt(mypos++); + break; + case 1: + // The packet has a two-octet length. The header is 3 octets + // long. + packet_length = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); + break; + case 2: + // The packet has a four-octet length. The header is 5 + // octets long. + packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << + 8) | input.charCodeAt(mypos++); + break; + default: + // 3 - The packet is of indeterminate length. The header is 1 + // octet long, and the implementation must determine how long + // the packet is. If the packet is in a file, this means that + // the packet extends until the end of the file. In general, + // an implementation SHOULD NOT use indeterminate-length + // packets except where the end of the data will be clear + // from the context, and even then it is better to use a + // definite length, or a new format header. The new format + // headers described below have a mechanism for precisely + // encoding data of indeterminate length. + packet_length = len; + break; + } + + } else // 4.2.2. New Format Packet Lengths + { + + // 4.2.2.1. One-Octet Lengths + if (input.charCodeAt(mypos) < 192) { + packet_length = input.charCodeAt(mypos++); + util.print_debug("1 byte length:" + packet_length); + // 4.2.2.2. Two-Octet Lengths + } else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) { + packet_length = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192; + util.print_debug("2 byte length:" + packet_length); + // 4.2.2.4. Partial Body Lengths + } else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) { + packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F); + util.print_debug("4 byte length:" + packet_length); + // EEEK, we're reading the full data here... + var mypos2 = mypos + packet_length; + bodydata = input.substring(mypos, mypos + packet_length); + while (true) { + if (input.charCodeAt(mypos2) < 192) { + var tmplen = input.charCodeAt(mypos2++); + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + break; + } else if (input.charCodeAt(mypos2) >= 192 && input.charCodeAt(mypos2) < 224) { + var tmplen = ((input.charCodeAt(mypos2++) - 192) << 8) + (input.charCodeAt(mypos2++)) + 192; + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + break; + } else if (input.charCodeAt(mypos2) > 223 && input.charCodeAt(mypos2) < 255) { + var tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F); + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + } else { + mypos2++; + var tmplen = (input.charCodeAt(mypos2++) << 24) | (input.charCodeAt(mypos2++) << 16) | (input[mypos2++] + .charCodeAt() << 8) | input.charCodeAt(mypos2++); + bodydata += input.substring(mypos2, mypos2 + tmplen); + packet_length += tmplen; + mypos2 += tmplen; + break; + } + } + real_packet_length = mypos2; + // 4.2.2.3. Five-Octet Lengths + } else { + mypos++; + packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << + 8) | input.charCodeAt(mypos++); + } + } + + // if there was'nt a partial body length: use the specified + // packet_length + if (real_packet_length == -1) { + real_packet_length = packet_length; + } + + if (bodydata == null) { + bodydata = input.substring(mypos, mypos + real_packet_length); + } + + return { + tag: tag, + packet: bodydata, + offset: mypos + real_packet_length + }; + } +} diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js new file mode 100644 index 00000000..fdebc164 --- /dev/null +++ b/src/packet/packetlist.js @@ -0,0 +1,177 @@ +/** + * This class represents a list of openpgp packets. + * Take care when iterating over it - the packets themselves + * are stored as numerical indices. + * @requires enums + * @requires packet + * @requires packet/packet + * @module packet/packetlist + */ + +var packetParser = require('./packet.js'), + packets = require('./all_packets.js'), + enums = require('../enums.js'); + +/** + * @constructor + */ +module.exports = function packetlist() { + /** The number of packets contained within the list. + * @readonly + * @type {Integer} */ + this.length = 0; + + /** + * Reads a stream of binary data and interprents it as a list of packets. + * @param {String} A binary string of bytes. + */ + this.read = function (bytes) { + var i = 0; + + while (i < bytes.length) { + var parsed = packetParser.read(bytes, i, bytes.length - i); + i = parsed.offset; + + var tag = enums.read(enums.packet, parsed.tag); + var packet = new packets[tag](); + + this.push(packet); + + packet.read(parsed.packet); + } + } + + /** + * Creates a binary representation of openpgp objects contained within the + * class instance. + * @returns {String} A binary string of bytes containing valid openpgp packets. + */ + this.write = function () { + var bytes = ''; + + for (var i = 0; i < this.length; i++) { + var packetbytes = this[i].write(); + bytes += packetParser.writeHeader(this[i].tag, packetbytes.length); + bytes += packetbytes; + } + + return bytes; + } + + /** + * Adds a packet to the list. This is the only supported method of doing so; + * writing to packetlist[i] directly will result in an error. + */ + this.push = function (packet) { + if (!packet) return; + + packet.packets = packet.packets || new packetlist(); + + this[this.length] = packet; + this.length++; + } + + /** + * Creates a new packetList with all packets that pass the test implemented by the provided function. + */ + this.filter = function (callback) { + + var filtered = new packetlist(); + + for (var i = 0; i < this.length; i++) { + if (callback(this[i], i, this)) { + filtered.push(this[i]); + } + } + + return filtered; + } + + /** + * Creates a new packetList with all packets from the given types + */ + this.filterByTag = function () { + var args = Array.prototype.slice.call(arguments); + var filtered = new packetlist(); + var that = this; + + for (var i = 0; i < this.length; i++) { + if (args.some(function(packetType) {return that[i].tag == packetType})) { + filtered.push(this[i]); + } + } + + return filtered; + } + + /** + * Executes the provided callback once for each element + */ + this.forEach = function (callback) { + for (var i = 0; i < this.length; i++) { + callback(this[i]); + } + } + + /** + * Traverses packet tree and returns first matching packet + * @param {module:enums.packet} type The packet type + * @return {module:packet/packet|null} + */ + this.findPacket = function (type) { + var packetlist = this.filterByTag(type); + if (packetlist.length) { + return packetlist[0]; + } else { + var found = null; + for (var i = 0; i < this.length; i++) { + if (this[i].packets.length) { + found = this[i].packets.findPacket(type); + if (found) return found; + } + } + } + return null; + } + + /** + * Returns array of found indices by tag + */ + this.indexOfTag = function () { + var args = Array.prototype.slice.call(arguments); + var tagIndex = []; + var that = this; + for (var i = 0; i < this.length; i++) { + if (args.some(function(packetType) {return that[i].tag == packetType})) { + tagIndex.push(i); + } + } + return tagIndex; + } + + /** + * Returns slice of packetlist + */ + this.slice = function (begin, end) { + if (!end) { + end = this.length + } + var part = new packetlist(); + for (var i = begin; i < end; i++) { + part.push(this[i]); + } + return part; + } + + /** + * Concatenates packetlist or array of packets + */ + this.concat = function (packetlist) { + if (packetlist) { + for (var i = 0; i < packetlist.length; i++) { + this.push(packetlist[i]); + } + } + } + +} diff --git a/src/packet/public_key.js b/src/packet/public_key.js new file mode 100644 index 00000000..03b4e220 --- /dev/null +++ b/src/packet/public_key.js @@ -0,0 +1,187 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Key Material Packet (Tag 5,6,7,14)
      + *
      + * RFC4480 5.5: + * A key material packet contains all the information about a public or + * private key. There are four variants of this packet type, and two + * major versions. Consequently, this section is complex. + * @requires crypto + * @requires enums + * @requires type/keyid + * @requires type/mpi + * @requires util + * @module packet/public_key + */ + +var util = require('../util'), + type_mpi = require('../type/mpi.js'), + type_keyid = require('../type/keyid.js'), + enums = require('../enums.js'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function public_key() { + this.version = 4; + /** Key creation date. + * @type {Date} */ + this.created = new Date(); + /** A list of multiprecision integers + * @type {module:type/mpi} */ + this.mpi = []; + /** Public key algorithm + * @type {module:enums.publicKey} */ + this.algorithm = 'rsa_sign'; + // time in days (V3 only) + this.expirationTimeV3 = 0; + + + /** + * Internal Parser for public keys as specified in RFC 4880 section + * 5.5.2 Public-Key Packet Formats + * called by read_tag<num> + * @param {String} input Input string to read the packet from + * @return {Object} This object with attributes set by the parser + */ + this.read = function (bytes) { + var pos = 0; + // A one-octet version number (3 or 4). + this.version = bytes.charCodeAt(pos++); + + if (this.version == 3 || this.version == 4) { + // - A four-octet number denoting the time that the key was created. + this.created = util.readDate(bytes.substr(pos, 4)); + pos += 4; + + if (this.version == 3) { + // - A two-octet number denoting the time in days that this key is + // valid. If this number is zero, then it does not expire. + this.expirationTimeV3 = util.readNumber(bytes.substr(pos, 2)); + pos += 2; + } + + // - A one-octet number denoting the public-key algorithm of this key. + this.algorithm = enums.read(enums.publicKey, bytes.charCodeAt(pos++)); + + var mpicount = crypto.getPublicMpiCount(this.algorithm); + this.mpi = []; + + var bmpi = bytes.substr(pos); + var p = 0; + + for (var i = 0; i < mpicount && p < bmpi.length; i++) { + + this.mpi[i] = new type_mpi(); + + p += this.mpi[i].read(bmpi.substr(p)) + + if (p > bmpi.length) { + throw new Error('Error reading MPI @:' + p); + } + } + + return p + 6; + } else { + throw new Error('Version ' + version + ' of the key packet is unsupported.'); + } + }; + + /** + * Alias of read() + * @function module:packet/public_key#readPublicKey + * @see module:packet/public_key#read + */ + this.readPublicKey = this.read; + + /** + * Same as write_private_key, but has less information because of + * public key. + * @return {Object} {body: [string]OpenPGP packet body contents, + * header: [string] OpenPGP packet header, string: [string] header+body} + */ + this.write = function () { + // Version + var result = String.fromCharCode(this.version); + result += util.writeDate(this.created); + if (this.version == 3) { + result += util.writeNumber(this.expirationTimeV3, 2); + } + result += String.fromCharCode(enums.write(enums.publicKey, this.algorithm)); + + var mpicount = crypto.getPublicMpiCount(this.algorithm); + + for (var i = 0; i < mpicount; i++) { + result += this.mpi[i].write(); + } + + return result; + }; + + /** + * Alias of write() + * @function module:packet/public_key#writePublicKey + * @see module:packet/public_key#write + */ + this.writePublicKey = this.write; + + /** + * Write an old version packet - it's used by some of the internal routines. + */ + this.writeOld = function () { + var bytes = this.writePublicKey(); + + return String.fromCharCode(0x99) + + util.writeNumber(bytes.length, 2) + + bytes; + }; + + /** + * Calculates the key id of the key + * @return {String} A 8 byte key id + */ + this.getKeyId = function () { + var keyid = new type_keyid(); + if (this.version == 4) { + keyid.read(this.getFingerprint().substr(12, 8)); + } else if (this.version == 3) { + keyid.read(this.mpi[0].write().substr(-8)); + } + return keyid; + }; + + /** + * Calculates the fingerprint of the key + * @return {String} A string containing the fingerprint + */ + this.getFingerprint = function () { + var toHash = ''; + if (this.version == 4) { + toHash = this.writeOld(); + return crypto.hash.sha1(toHash); + } else if (this.version == 3) { + var mpicount = crypto.getPublicMpiCount(this.algorithm); + for (var i = 0; i < mpicount; i++) { + toHash += this.mpi[i].toBytes(); + } + return crypto.hash.md5(toHash) + } + }; +}; diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js new file mode 100644 index 00000000..dee89ecd --- /dev/null +++ b/src/packet/public_key_encrypted_session_key.js @@ -0,0 +1,182 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Public-Key Encrypted Session Key Packets (Tag 1)
      + *
      + * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key + * used to encrypt a message. Zero or more Public-Key Encrypted Session Key + * packets and/or Symmetric-Key Encrypted Session Key packets may precede a + * Symmetrically Encrypted Data Packet, which holds an encrypted message. The + * message is encrypted with the session key, and the session key is itself + * encrypted and stored in the Encrypted Session Key packet(s). The + * Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted + * Session Key packet for each OpenPGP key to which the message is encrypted. + * The recipient of the message finds a session key that is encrypted to their + * public key, decrypts the session key, and then uses the session key to + * decrypt the message. + * @requires crypto + * @requires enums + * @requires type/keyid + * @requires type/mpi + * @requires util + * @module packet/public_key_encrypted_session_key + */ + +var type_keyid = require('../type/keyid.js'), + util = require('../util'), + type_mpi = require('../type/mpi.js'), + enums = require('../enums.js'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function public_key_encrypted_session_key() { + this.version = 3; + + this.publicKeyId = new type_keyid(); + this.publicKeyAlgorithm = 'rsa_encrypt'; + + this.sessionKey = null; + this.sessionKeyAlgorithm = 'aes256'; + + /** @type {Array} */ + this.encrypted = []; + + /** + * Parsing function for a publickey encrypted session key packet (tag 1). + * + * @param {String} input Payload of a tag 1 packet + * @param {Integer} position Position to start reading from the input string + * @param {Integer} len Length of the packet or the remaining length of + * input at position + * @return {module:packet/public_key_encrypted_session_key} Object representation + */ + this.read = function (bytes) { + + this.version = bytes.charCodeAt(0); + this.publicKeyId.read(bytes.substr(1)); + this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(9)); + + var i = 10; + + var integerCount = (function(algo) { + switch (algo) { + case 'rsa_encrypt': + case 'rsa_encrypt_sign': + return 1; + + case 'elgamal': + return 2; + + default: + throw new Error("Invalid algorithm."); + } + })(this.publicKeyAlgorithm); + + this.encrypted = []; + + for (var j = 0; j < integerCount; j++) { + var mpi = new type_mpi(); + i += mpi.read(bytes.substr(i)); + this.encrypted.push(mpi); + } + }; + + /** + * Create a string representation of a tag 1 packet + * + * @param {String} publicKeyId + * The public key id corresponding to publicMPIs key as string + * @param {Array} publicMPIs + * Multiprecision integer objects describing the public key + * @param {Integer} pubalgo + * The corresponding public key algorithm // See RFC4880 9.1 + * @param {Integer} symmalgo + * The symmetric cipher algorithm used to encrypt the data + * within an encrypteddatapacket or encryptedintegrity- + * protecteddatapacket + * following this packet //See RFC4880 9.2 + * @param {String} sessionkey + * A string of randombytes representing the session key + * @return {String} The string representation + */ + this.write = function () { + + var result = String.fromCharCode(this.version); + result += this.publicKeyId.write(); + result += String.fromCharCode( + enums.write(enums.publicKey, this.publicKeyAlgorithm)); + + for (var i = 0; i < this.encrypted.length; i++) { + result += this.encrypted[i].write() + } + + return result; + }; + + this.encrypt = function (key) { + var data = String.fromCharCode( + enums.write(enums.symmetric, this.sessionKeyAlgorithm)); + + data += this.sessionKey; + var checksum = util.calc_checksum(this.sessionKey); + data += util.writeNumber(checksum, 2); + + var mpi = new type_mpi(); + mpi.fromBytes(crypto.pkcs1.eme.encode( + data, + key.mpi[0].byteLength())); + + this.encrypted = crypto.publicKeyEncrypt( + this.publicKeyAlgorithm, + key.mpi, + mpi); + }; + + /** + * Decrypts the session key (only for public key encrypted session key + * packets (tag 1) + * + * @param {module:packet/secret_key} key + * Private key with secMPIs unlocked + * @return {String} The unencrypted session key + */ + this.decrypt = function (key) { + var result = crypto.publicKeyDecrypt( + this.publicKeyAlgorithm, + key.mpi, + this.encrypted).toBytes(); + + var checksum = util.readNumber(result.substr(result.length - 2)); + + var decoded = crypto.pkcs1.eme.decode( + result, + key.mpi[0].byteLength()); + + var key = decoded.substring(1, decoded.length - 2); + + if (checksum != util.calc_checksum(key)) { + throw new Error('Checksum mismatch'); + } else { + this.sessionKey = key; + this.sessionKeyAlgorithm = + enums.read(enums.symmetric, decoded.charCodeAt(0)); + } + }; +}; diff --git a/src/packet/public_subkey.js b/src/packet/public_subkey.js new file mode 100644 index 00000000..cfea0376 --- /dev/null +++ b/src/packet/public_subkey.js @@ -0,0 +1,31 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires packet/public_key + * @module packet/public_subkey + */ + +var publicKey = require('./public_key.js'); + +/** + * @constructor + * @extends module:packet/public_key + */ +module.exports = function public_subkey() { + publicKey.call(this); +} diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js new file mode 100644 index 00000000..3b864057 --- /dev/null +++ b/src/packet/secret_key.js @@ -0,0 +1,266 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Key Material Packet (Tag 5,6,7,14)
      + *
      + * RFC4480 5.5: + * A key material packet contains all the information about a public or + * private key. There are four variants of this packet type, and two + * major versions. Consequently, this section is complex. + * @requires crypto + * @requires enums + * @requires packet/public_key + * @requires type/mpi + * @requires type/s2k + * @requires util + * @module packet/secret_key + */ + +var publicKey = require('./public_key.js'), + enums = require('../enums.js'), + util = require('../util'), + crypto = require('../crypto'), + type_mpi = require('../type/mpi.js'), + type_s2k = require('../type/s2k.js'); + +/** + * @constructor + * @extends module:packet/public_key + */ +module.exports = function secret_key() { + publicKey.call(this); + // encrypted secret-key data + this.encrypted = null; + // indicator if secret-key data is available in decrypted form + this.isDecrypted = false; + + + function get_hash_len(hash) { + if (hash == 'sha1') + return 20; + else + return 2; + } + + function get_hash_fn(hash) { + if (hash == 'sha1') + return crypto.hash.sha1; + else + return function(c) { + return util.writeNumber(util.calc_checksum(c), 2); + }; + } + + // Helper function + + function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) { + var hashlen = get_hash_len(hash_algorithm), + hashfn = get_hash_fn(hash_algorithm); + + var hashtext = cleartext.substr(cleartext.length - hashlen); + cleartext = cleartext.substr(0, cleartext.length - hashlen); + + var hash = hashfn(cleartext); + + if (hash != hashtext) + return new Error("Hash mismatch."); + + var mpis = crypto.getPrivateMpiCount(algorithm); + + var j = 0; + var mpi = []; + + for (var i = 0; i < mpis && j < cleartext.length; i++) { + mpi[i] = new type_mpi(); + j += mpi[i].read(cleartext.substr(j)); + } + + return mpi; + } + + function write_cleartext_mpi(hash_algorithm, algorithm, mpi) { + var bytes = ''; + var discard = crypto.getPublicMpiCount(algorithm); + + for (var i = discard; i < mpi.length; i++) { + bytes += mpi[i].write(); + } + + + bytes += get_hash_fn(hash_algorithm)(bytes); + + return bytes; + } + + + // 5.5.3. Secret-Key Packet Formats + + /** + * Internal parser for private keys as specified in RFC 4880 section 5.5.3 + * @param {String} bytes Input string to read the packet from + */ + this.read = function (bytes) { + // - A Public-Key or Public-Subkey packet, as described above. + var len = this.readPublicKey(bytes); + + bytes = bytes.substr(len); + + + // - One octet indicating string-to-key usage conventions. Zero + // indicates that the secret-key data is not encrypted. 255 or 254 + // indicates that a string-to-key specifier is being given. Any + // other value is a symmetric-key encryption algorithm identifier. + var isEncrypted = bytes.charCodeAt(0); + + if (isEncrypted) { + this.encrypted = bytes; + } else { + + // - Plain or encrypted multiprecision integers comprising the secret + // key data. These algorithm-specific fields are as described + // below. + var parsedMPI = parse_cleartext_mpi('mod', bytes.substr(1), this.algorithm); + if (parsedMPI instanceof Error) + throw parsedMPI; + this.mpi = this.mpi.concat(parsedMPI); + this.isDecrypted = true; + } + + }; + + /** Creates an OpenPGP key packet for the given key. + * @return {String} A string of bytes containing the secret key OpenPGP packet + */ + this.write = function () { + var bytes = this.writePublicKey(); + + if (!this.encrypted) { + bytes += String.fromCharCode(0); + + bytes += write_cleartext_mpi('mod', this.algorithm, this.mpi); + } else { + bytes += this.encrypted; + } + + return bytes; + }; + + + + + /** Encrypt the payload. By default, we use aes256 and iterated, salted string + * to key specifier + * @param {String} passphrase + */ + this.encrypt = function (passphrase) { + + var s2k = new type_s2k(), + symmetric = 'aes256', + cleartext = write_cleartext_mpi('sha1', this.algorithm, this.mpi), + key = produceEncryptionKey(s2k, passphrase, symmetric), + blockLen = crypto.cipher[symmetric].blockSize, + iv = crypto.random.getRandomBytes(blockLen); + + + this.encrypted = ''; + this.encrypted += String.fromCharCode(254); + this.encrypted += String.fromCharCode(enums.write(enums.symmetric, symmetric)); + this.encrypted += s2k.write(); + this.encrypted += iv; + + this.encrypted += crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv); + }; + + function produceEncryptionKey(s2k, passphrase, algorithm) { + return s2k.produce_key(passphrase, + crypto.cipher[algorithm].keySize); + } + + /** + * Decrypts the private key MPIs which are needed to use the key. + * @link module:packet/secret_key.isDecrypted should be + * false otherwise a call to this function is not needed + * + * @param {String} str_passphrase The passphrase for this private key + * as string + * @return {Boolean} True if the passphrase was correct or MPI already + * decrypted; false if not + */ + this.decrypt = function (passphrase) { + if (this.isDecrypted) + return true; + + var i = 0, + symmetric, + key; + + var s2k_usage = this.encrypted.charCodeAt(i++); + + // - [Optional] If string-to-key usage octet was 255 or 254, a one- + // octet symmetric encryption algorithm. + if (s2k_usage == 255 || s2k_usage == 254) { + symmetric = this.encrypted.charCodeAt(i++); + symmetric = enums.read(enums.symmetric, symmetric); + + // - [Optional] If string-to-key usage octet was 255 or 254, a + // string-to-key specifier. The length of the string-to-key + // specifier is implied by its type, as described above. + var s2k = new type_s2k(); + i += s2k.read(this.encrypted.substr(i)); + + key = produceEncryptionKey(s2k, passphrase, symmetric); + } else { + symmetric = s2k_usage; + symmetric = enums.read(enums.symmetric, symmetric); + key = crypto.hash.md5(passphrase); + } + + + // - [Optional] If secret data is encrypted (string-to-key usage octet + // not zero), an Initial Vector (IV) of the same length as the + // cipher's block size. + var iv = this.encrypted.substr(i, + crypto.cipher[symmetric].blockSize); + + i += iv.length; + + var cleartext, + ciphertext = this.encrypted.substr(i); + + cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv); + + var hash = s2k_usage == 254 ? + 'sha1' : + 'mod'; + + var parsedMPI = parse_cleartext_mpi(hash, cleartext, this.algorithm); + if (parsedMPI instanceof Error) + return false; + this.mpi = this.mpi.concat(parsedMPI); + this.isDecrypted = true; + return true; + }; + + this.generate = function (bits) { + this.mpi = crypto.generateMpi(this.algorithm, bits); + this.isDecrypted = true; + }; + +} + +module.exports.prototype = new publicKey(); diff --git a/src/packet/secret_subkey.js b/src/packet/secret_subkey.js new file mode 100644 index 00000000..5f00b1b3 --- /dev/null +++ b/src/packet/secret_subkey.js @@ -0,0 +1,31 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @requires packet/secret_key + * @module packet/secret_subkey + */ + +var secretKey = require('./secret_key.js'); + +/** + * @constructor + * @extends module:packet/secret_key + */ +module.exports = function secret_subkey() { + secretKey.call(this); +} diff --git a/src/packet/signature.js b/src/packet/signature.js new file mode 100644 index 00000000..3115f2d6 --- /dev/null +++ b/src/packet/signature.js @@ -0,0 +1,640 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Signature Packet (Tag 2)
      + *
      + * RFC4480 5.2: + * A Signature packet describes a binding between some public key and + * some data. The most common signatures are a signature of a file or a + * block of text, and a signature that is a certification of a User ID. + * @requires crypto + * @requires enums + * @requires packet/packet + * @requires type/keyid + * @requires type/mpi + * @requires util + * @module packet/signature + */ + +var util = require('../util'), + packet = require('./packet.js'), + enums = require('../enums.js'), + crypto = require('../crypto'), + type_mpi = require('../type/mpi.js'), + type_keyid = require('../type/keyid.js'); + +/** + * @constructor + */ +module.exports = function signature() { + + this.version = 4; + this.signatureType = null; + this.hashAlgorithm = null; + this.publicKeyAlgorithm = null; + + this.signatureData = null; + this.signedHashValue = null; + this.mpi = null; + + this.created = new Date(); + this.signatureExpirationTime = null; + this.signatureNeverExpires = true; + this.exportable = null; + this.trustLevel = null; + this.trustAmount = null; + this.regularExpression = null; + this.revocable = null; + this.keyExpirationTime = null; + this.keyNeverExpires = null; + this.preferredSymmetricAlgorithms = null; + this.revocationKeyClass = null; + this.revocationKeyAlgorithm = null; + this.revocationKeyFingerprint = null; + this.issuerKeyId = new type_keyid(); + this.notation = null; + this.preferredHashAlgorithms = null; + this.preferredCompressionAlgorithms = null; + this.keyServerPreferences = null; + this.preferredKeyServer = null; + this.isPrimaryUserID = null; + this.policyURI = null; + this.keyFlags = null; + this.signersUserId = null; + this.reasonForRevocationFlag = null; + this.reasonForRevocationString = null; + this.features = null; + this.signatureTargetPublicKeyAlgorithm = null; + this.signatureTargetHashAlgorithm = null; + this.signatureTargetHash = null; + this.embeddedSignature = null; + + this.verified = false; + + /** + * parsing function for a signature packet (tag 2). + * @param {String} bytes payload of a tag 2 packet + * @param {Integer} position position to start reading from the bytes string + * @param {Integer} len length of the packet or the remaining length of bytes at position + * @return {module:packet/signature} object representation + */ + this.read = function (bytes) { + var i = 0; + + this.version = bytes.charCodeAt(i++); + // switch on version (3 and 4) + switch (this.version) { + case 3: + // One-octet length of following hashed material. MUST be 5. + if (bytes.charCodeAt(i++) != 5) + util.print_debug("packet/signature.js\n" + + 'invalid One-octet length of following hashed material.' + + 'MUST be 5. @:' + (i - 1)); + + var sigpos = i; + // One-octet signature type. + this.signatureType = bytes.charCodeAt(i++); + + // Four-octet creation time. + this.created = util.readDate(bytes.substr(i, 4)); + i += 4; + + // storing data appended to data which gets verified + this.signatureData = bytes.substring(sigpos, i); + + // Eight-octet Key ID of signer. + this.issuerKeyId.read(bytes.substring(i, i + 8)); + i += 8; + + // One-octet public-key algorithm. + this.publicKeyAlgorithm = bytes.charCodeAt(i++); + + // One-octet hash algorithm. + this.hashAlgorithm = bytes.charCodeAt(i++); + break; + case 4: + this.signatureType = bytes.charCodeAt(i++); + this.publicKeyAlgorithm = bytes.charCodeAt(i++); + this.hashAlgorithm = bytes.charCodeAt(i++); + + function subpackets(bytes) { + // Two-octet scalar octet count for following subpacket data. + var subpacket_length = util.readNumber( + bytes.substr(0, 2)); + + var i = 2; + + // subpacket data set (zero or more subpackets) + var subpacked_read = 0; + while (i < 2 + subpacket_length) { + + var len = packet.readSimpleLength(bytes.substr(i)); + i += len.offset; + + this.read_sub_packet(bytes.substr(i, len.len)); + + i += len.len; + } + + return i; + } + + // hashed subpackets + i += subpackets.call(this, bytes.substr(i), true); + + // A V4 signature hashes the packet body + // starting from its first field, the version number, through the end + // of the hashed subpacket data. Thus, the fields hashed are the + // signature version, the signature type, the public-key algorithm, the + // hash algorithm, the hashed subpacket length, and the hashed + // subpacket body. + this.signatureData = bytes.substr(0, i); + + // unhashed subpackets + i += subpackets.call(this, bytes.substr(i), false); + + break; + default: + throw new Error('Version ' + version + ' of the signature is unsupported.'); + break; + } + + // Two-octet field holding left 16 bits of signed hash value. + this.signedHashValue = bytes.substr(i, 2); + i += 2; + + this.signature = bytes.substr(i); + }; + + this.write = function () { + return this.signatureData + + util.writeNumber(0, 2) + // Number of unsigned subpackets. + this.signedHashValue + + this.signature; + }; + + /** + * Signs provided data. This needs to be done prior to serialization. + * @param {module:packet/secret_key} key private key used to sign the message. + * @param {Object} data Contains packets to be signed. + */ + this.sign = function (key, data) { + var signatureType = enums.write(enums.signature, this.signatureType), + publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm), + hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); + + var result = String.fromCharCode(4); + result += String.fromCharCode(signatureType); + result += String.fromCharCode(publicKeyAlgorithm); + result += String.fromCharCode(hashAlgorithm); + + this.issuerKeyId = key.getKeyId(); + + // Add hashed subpackets + result += this.write_all_sub_packets(); + + this.signatureData = result; + + var trailer = this.calculateTrailer(); + + var toHash = this.toSign(signatureType, data) + + this.signatureData + trailer; + + var hash = crypto.hash.digest(hashAlgorithm, toHash); + + this.signedHashValue = hash.substr(0, 2); + + this.signature = crypto.signature.sign(hashAlgorithm, + publicKeyAlgorithm, key.mpi, toHash); + }; + + /** + * Creates string of bytes with all subpacket data + * @return {String} a string-representation of a all subpacket data + */ + this.write_all_sub_packets = function () { + var sub = enums.signatureSubpacket; + var result = ''; + var bytes = ''; + if (this.created !== null) { + result += write_sub_packet(sub.signature_creation_time, util.writeDate(this.created)); + } + if (this.signatureExpirationTime !== null) { + result += write_sub_packet(sub.signature_expiration_time, util.writeNumber(this.signatureExpirationTime, 4)); + } + if (this.exportable !== null) { + result += write_sub_packet(sub.exportable_certification, String.fromCharCode(this.exportable ? 1 : 0)); + } + if (this.trustLevel !== null) { + bytes = String.fromCharCode(this.trustLevel) + String.fromCharCode(this.trustAmount); + result += write_sub_packet(sub.trust_signature, bytes); + } + if (this.regularExpression !== null) { + result += write_sub_packet(sub.regular_expression, this.regularExpression); + } + if (this.revocable !== null) { + result += write_sub_packet(sub.revocable, String.fromCharCode(this.revocable ? 1 : 0)); + } + if (this.keyExpirationTime !== null) { + result += write_sub_packet(sub.key_expiration_time, util.writeNumber(this.keyExpirationTime, 4)); + } + if (this.preferredSymmetricAlgorithms !== null) { + bytes = util.bin2str(this.preferredSymmetricAlgorithms); + result += write_sub_packet(sub.preferred_symmetric_algorithms, bytes); + } + if (this.revocationKeyClass !== null) { + bytes = String.fromCharCode(this.revocationKeyClass); + bytes += String.fromCharCode(this.revocationKeyAlgorithm); + bytes += this.revocationKeyFingerprint; + result += write_sub_packet(sub.revocation_key, bytes); + } + if (!this.issuerKeyId.isNull()) { + result += write_sub_packet(sub.issuer, this.issuerKeyId.write()); + } + if (this.notation !== null) { + for (var name in this.notation) { + if (this.notation.hasOwnProperty(name)) { + var value = this.notation[name]; + bytes = String.fromCharCode(0x80); + bytes += String.fromCharCode(0); + bytes += String.fromCharCode(0); + bytes += String.fromCharCode(0); + // 2 octets of name length + bytes += util.writeNumber(name.length, 2); + // 2 octets of value length + bytes += util.writeNumber(value.length, 2); + bytes += name + value; + result += write_sub_packet(sub.notation_data, bytes); + } + } + } + if (this.preferredHashAlgorithms !== null) { + bytes = util.bin2str(this.preferredHashAlgorithms); + result += write_sub_packet(sub.preferred_hash_algorithms, bytes); + } + if (this.preferredCompressionAlgorithms !== null) { + bytes = util.bin2str(this.preferredCompressionAlgorithms); + result += write_sub_packet(sub.preferred_hash_algorithms, bytes); + } + if (this.keyServerPreferences !== null) { + bytes = util.bin2str(this.keyServerPreferences); + result += write_sub_packet(sub.key_server_preferences, bytes); + } + if (this.preferredKeyServer !== null) { + result += write_sub_packet(sub.preferred_key_server, this.preferredKeyServer); + } + if (this.isPrimaryUserID !== null) { + result += write_sub_packet(sub.primary_user_id, String.fromCharCode(this.isPrimaryUserID ? 1 : 0)); + } + if (this.policyURI !== null) { + result += write_sub_packet(sub.policy_uri, this.policyURI); + } + if (this.keyFlags !== null) { + bytes = util.bin2str(this.keyFlags); + result += write_sub_packet(sub.key_flags, bytes); + } + if (this.signersUserId !== null) { + result += write_sub_packet(sub.signers_user_id, this.signersUserId); + } + if (this.reasonForRevocationFlag !== null) { + bytes = String.fromCharCode(this.reasonForRevocationFlag); + bytes += this.reasonForRevocationString; + result += write_sub_packet(sub.reason_for_revocation, bytes); + } + if (this.features !== null) { + bytes = util.bin2str(this.features); + result += write_sub_packet(sub.features, bytes); + } + if (this.signatureTargetPublicKeyAlgorithm !== null) { + bytes = String.fromCharCode(this.signatureTargetPublicKeyAlgorithm); + bytes += String.fromCharCode(this.signatureTargetHashAlgorithm); + bytes += this.signatureTargetHash; + result += write_sub_packet(sub.signature_target, bytes); + } + if (this.embeddedSignature !== null) { + result += write_sub_packet(sub.embedded_signature, this.embeddedSignature.write()); + } + result = util.writeNumber(result.length, 2) + result; + return result; + }; + + /** + * creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1) + * @param {Integer} type subpacket signature type. Signature types as described + * in RFC4880 Section 5.2.3.2 + * @param {String} data data to be included + * @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1) + */ + function write_sub_packet(type, data) { + var result = ""; + result += packet.writeSimpleLength(data.length + 1); + result += String.fromCharCode(type); + result += data; + return result; + } + + // V4 signature sub packets + + this.read_sub_packet = function (bytes) { + var mypos = 0; + + function read_array(prop, bytes) { + this[prop] = []; + + for (var i = 0; i < bytes.length; i++) { + this[prop].push(bytes.charCodeAt(i)); + } + } + + // The leftwost bit denotes a "critical" packet, but we ignore it. + var type = bytes.charCodeAt(mypos++) & 0x7F; + + // subpacket type + switch (type) { + case 2: + // Signature Creation Time + this.created = util.readDate(bytes.substr(mypos)); + break; + case 3: + // Signature Expiration Time in seconds + var seconds = util.readNumber(bytes.substr(mypos)); + + this.signatureNeverExpires = seconds == 0; + this.signatureExpirationTime = seconds; + + break; + case 4: + // Exportable Certification + this.exportable = bytes.charCodeAt(mypos++) == 1; + break; + case 5: + // Trust Signature + this.trustLevel = bytes.charCodeAt(mypos++); + this.trustAmount = bytes.charCodeAt(mypos++); + break; + case 6: + // Regular Expression + this.regularExpression = bytes.substr(mypos); + break; + case 7: + // Revocable + this.revocable = bytes.charCodeAt(mypos++) == 1; + break; + case 9: + // Key Expiration Time in seconds + var seconds = util.readNumber(bytes.substr(mypos)); + + this.keyExpirationTime = seconds; + this.keyNeverExpires = seconds == 0; + + break; + case 11: + // Preferred Symmetric Algorithms + this.preferredSymmetricAlgorithms = []; + + while (mypos != bytes.length) { + this.preferredSymmetricAlgorithms.push(bytes.charCodeAt(mypos++)); + } + + break; + case 12: + // Revocation Key + // (1 octet of class, 1 octet of public-key algorithm ID, 20 + // octets of + // fingerprint) + this.revocationKeyClass = bytes.charCodeAt(mypos++); + this.revocationKeyAlgorithm = bytes.charCodeAt(mypos++); + this.revocationKeyFingerprint = bytes.substr(mypos, 20); + break; + + case 16: + // Issuer + this.issuerKeyId.read(bytes.substr(mypos)); + break; + + case 20: + // Notation Data + // We don't know how to handle anything but a text flagged data. + if (bytes.charCodeAt(mypos) == 0x80) { + + // We extract key/value tuple from the byte stream. + mypos += 4; + var m = util.readNumber(bytes.substr(mypos, 2)); + mypos += 2 + var n = util.readNumber(bytes.substr(mypos, 2)); + mypos += 2 + + var name = bytes.substr(mypos, m), + value = bytes.substr(mypos + m, n); + + this.notation = this.notation || {}; + this.notation[name] = value; + } else throw new Error("Unsupported notation flag."); + break; + case 21: + // Preferred Hash Algorithms + read_array.call(this, 'preferredHashAlgorithms', bytes.substr(mypos)); + break; + case 22: + // Preferred Compression Algorithms + read_array.call(this, 'preferredCompressionAlgorithms ', bytes.substr(mypos)); + break; + case 23: + // Key Server Preferences + read_array.call(this, 'keyServerPreferencess', bytes.substr(mypos)); + break; + case 24: + // Preferred Key Server + this.preferredKeyServer = bytes.substr(mypos); + break; + case 25: + // Primary User ID + this.isPrimaryUserID = bytes[mypos++] != 0; + break; + case 26: + // Policy URI + this.policyURI = bytes.substr(mypos); + break; + case 27: + // Key Flags + read_array.call(this, 'keyFlags', bytes.substr(mypos)); + break; + case 28: + // Signer's User ID + this.signersUserId += bytes.substr(mypos); + break; + case 29: + // Reason for Revocation + this.reasonForRevocationFlag = bytes.charCodeAt(mypos++); + this.reasonForRevocationString = bytes.substr(mypos); + break; + case 30: + // Features + read_array.call(this, 'features', bytes.substr(mypos)); + break; + case 31: + // Signature Target + // (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash) + this.signatureTargetPublicKeyAlgorithm = bytes.charCodeAt(mypos++); + this.signatureTargetHashAlgorithm = bytes.charCodeAt(mypos++); + + var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm); + + this.signatureTargetHash = bytes.substr(mypos, len); + break; + case 32: + // Embedded Signature + this.embeddedSignature = new signature(); + this.embeddedSignature.read(bytes.substr(mypos)); + break; + default: + throw new Error("Unknown signature subpacket type " + type + " @:" + mypos); + break; + } + }; + + // Produces data to produce signature on + this.toSign = function (type, data) { + var t = enums.signature; + + switch (type) { + case t.binary: + case t.text: + return data.getBytes(); + + case t.standalone: + return ''; + + case t.cert_generic: + case t.cert_persona: + case t.cert_casual: + case t.cert_positive: + case t.cert_revocation: + var packet, tag; + + if (data.userid !== undefined) { + tag = 0xB4; + packet = data.userid; + } else if (data.userattribute !== undefined) { + tag = 0xD1; + packet = data.userattribute; + } else throw new Error('Either a userid or userattribute packet needs to be ' + + 'supplied for certification.'); + + var bytes = packet.write(); + + if (this.version == 4) { + return this.toSign(t.key, data) + + String.fromCharCode(tag) + + util.writeNumber(bytes.length, 4) + + bytes; + } else if (this.version == 3) { + return this.toSign(t.key, data) + + bytes; + } + break; + + case t.subkey_binding: + case t.key_binding: + return this.toSign(t.key, data) + this.toSign(t.key, { + key: data.bind + }); + + case t.key: + if (data.key == undefined) + throw new Error('Key packet is required for this sigtature.'); + + return data.key.writeOld(); + + case t.key_revocation: + case t.subkey_revocation: + return this.toSign(t.key, data); + case t.timestamp: + return ''; + case t.third_party: + throw new Error('Not implemented'); + break; + default: + throw new Error('Unknown signature type.') + } + } + + + this.calculateTrailer = function () { + // calculating the trailer + var trailer = ''; + // V3 signatures don't have a trailer + if (this.version == 3) return trailer; + trailer += String.fromCharCode(4); // Version + trailer += String.fromCharCode(0xFF); + trailer += util.writeNumber(this.signatureData.length, 4); + return trailer + } + + + /** + * verifys the signature packet. Note: not signature types are implemented + * @param {String|Object} data data which on the signature applies + * @param {module:packet/public_subkey|module:packet/public_key} key the public key to verify the signature + * @return {boolean} True if message is verified, else false. + */ + this.verify = function (key, data) { + var signatureType = enums.write(enums.signature, this.signatureType), + publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm), + hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); + + var bytes = this.toSign(signatureType, data), + trailer = this.calculateTrailer(); + + + var mpicount = 0; + // Algorithm-Specific Fields for RSA signatures: + // - multiprecision number (MPI) of RSA signature value m**d mod n. + if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4) + mpicount = 1; + // Algorithm-Specific Fields for DSA signatures: + // - MPI of DSA value r. + // - MPI of DSA value s. + else if (publicKeyAlgorithm == 17) + mpicount = 2; + + var mpi = [], + i = 0; + for (var j = 0; j < mpicount; j++) { + mpi[j] = new type_mpi(); + i += mpi[j].read(this.signature.substr(i)); + } + + this.verified = crypto.signature.verify(publicKeyAlgorithm, + hashAlgorithm, mpi, key.mpi, + bytes + this.signatureData + trailer); + + return this.verified; + } + + /** + * Verifies signature expiration date + * @return {Boolean} true if expired + */ + this.isExpired = function () { + if (!this.signatureNeverExpires) { + return Date.now() > (this.created.getTime() + this.signatureExpirationTime*1000); + } + return false; + } +} diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js new file mode 100644 index 00000000..249069d6 --- /dev/null +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -0,0 +1,121 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Sym. Encrypted Integrity Protected Data + * Packet (Tag 18)
      + *
      + * RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is + * a variant of the Symmetrically Encrypted Data packet. It is a new feature + * created for OpenPGP that addresses the problem of detecting a modification to + * encrypted data. It is used in combination with a Modification Detection Code + * packet. + * @requires crypto + * @requires util + * @module packet/sym_encrypted_integrity_protected + */ + +var util = require('../util'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function sym_encrypted_integrity_protected() { + /** The encrypted payload. */ + this.encrypted = null; // string + /** + * If after decrypting the packet this is set to true, + * a modification has been detected and thus the contents + * should be discarded. + * @type {Boolean} + */ + this.modification = false; + this.packets = null; + + + this.read = function (bytes) { + // - A one-octet version number. The only currently defined value is 1. + var version = bytes.charCodeAt(0); + + if (version != 1) { + throw new Error('Invalid packet version.'); + } + + // - Encrypted data, the output of the selected symmetric-key cipher + // operating in Cipher Feedback mode with shift amount equal to the + // block size of the cipher (CFB-n where n is the block size). + this.encrypted = bytes.substr(1); + }; + + this.write = function () { + + return String.fromCharCode(1) // Version + + this.encrypted; + }; + + this.encrypt = function (sessionKeyAlgorithm, key) { + var bytes = this.packets.write() + + var prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm); + var prefix = prefixrandom + prefixrandom.charAt(prefixrandom.length - 2) + prefixrandom.charAt(prefixrandom.length - + 1) + + var tohash = bytes; + + + // Modification detection code packet. + tohash += String.fromCharCode(0xD3); + tohash += String.fromCharCode(0x14); + + + tohash += crypto.hash.sha1(prefix + tohash); + + + this.encrypted = crypto.cfb.encrypt(prefixrandom, + sessionKeyAlgorithm, tohash, key, false).substring(0, + prefix.length + tohash.length); + }; + + /** + * Decrypts the encrypted data contained in this object read_packet must + * have been called before + * + * @param {Integer} sessionKeyAlgorithm + * The selected symmetric encryption algorithm to be used + * @param {String} key The key of cipher blocksize length to be used + * @return {String} The decrypted data of this packet + */ + this.decrypt = function (sessionKeyAlgorithm, key) { + var decrypted = crypto.cfb.decrypt( + sessionKeyAlgorithm, key, this.encrypted, false); + + + // there must be a modification detection code packet as the + // last packet and everything gets hashed except the hash itself + this.hash = crypto.hash.sha1( + crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted) + decrypted.substring(0, decrypted.length - 20)); + + + var mdc = decrypted.substr(decrypted.length - 20, 20); + + if (this.hash != mdc) { + throw new Error('Modification detected.'); + } else + this.packets.read(decrypted.substr(0, decrypted.length - 22)); + }; +}; diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js new file mode 100644 index 00000000..825c4db7 --- /dev/null +++ b/src/packet/sym_encrypted_session_key.js @@ -0,0 +1,140 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Public-Key Encrypted Session Key Packets (Tag 1)
      + *
      + * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key + * used to encrypt a message. Zero or more Public-Key Encrypted Session Key + * packets and/or Symmetric-Key Encrypted Session Key packets may precede a + * Symmetrically Encrypted Data Packet, which holds an encrypted message. The + * message is encrypted with the session key, and the session key is itself + * encrypted and stored in the Encrypted Session Key packet(s). The + * Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted + * Session Key packet for each OpenPGP key to which the message is encrypted. + * The recipient of the message finds a session key that is encrypted to their + * public key, decrypts the session key, and then uses the session key to + * decrypt the message. + * @requires crypto + * @requires enums + * @requires type/s2k + * @module packet/sym_encrypted_session_key + */ + +var type_s2k = require('../type/s2k.js'), + enums = require('../enums.js'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function sym_encrypted_session_key() { + this.tag = 3; + this.sessionKeyEncryptionAlgorithm = null; + this.sessionKeyAlgorithm = 'aes256'; + this.encrypted = null; + this.s2k = new type_s2k(); + + /** + * Parsing function for a symmetric encrypted session key packet (tag 3). + * + * @param {String} input Payload of a tag 1 packet + * @param {Integer} position Position to start reading from the input string + * @param {Integer} len + * Length of the packet or the remaining length of + * input at position + * @return {module:packet/sym_encrypted_session_key} Object representation + */ + this.read = function(bytes) { + // A one-octet version number. The only currently defined version is 4. + this.version = bytes.charCodeAt(0); + + // A one-octet number describing the symmetric algorithm used. + var algo = enums.read(enums.symmetric, bytes.charCodeAt(1)); + + // A string-to-key (S2K) specifier, length as defined above. + var s2klength = this.s2k.read(bytes.substr(2)); + + // Optionally, the encrypted session key itself, which is decrypted + // with the string-to-key object. + var done = s2klength + 2; + + if (done < bytes.length) { + this.encrypted = bytes.substr(done); + this.sessionKeyEncryptionAlgorithm = algo + } else + this.sessionKeyAlgorithm = algo; + }; + + this.write = function() { + var algo = this.encrypted == null ? + this.sessionKeyAlgorithm : + this.sessionKeyEncryptionAlgorithm; + + var bytes = String.fromCharCode(this.version) + + String.fromCharCode(enums.write(enums.symmetric, algo)) + + this.s2k.write(); + + if (this.encrypted != null) + bytes += this.encrypted; + return bytes; + }; + + /** + * Decrypts the session key (only for public key encrypted session key + * packets (tag 1) + * + * @return {String} The unencrypted session key + */ + this.decrypt = function(passphrase) { + var algo = this.sessionKeyEncryptionAlgorithm != null ? + this.sessionKeyEncryptionAlgorithm : + this.sessionKeyAlgorithm; + + + var length = crypto.cipher[algo].keySize; + var key = this.s2k.produce_key(passphrase, length); + + if (this.encrypted == null) { + this.sessionKey = key; + + } else { + var decrypted = crypto.cfb.decrypt( + this.sessionKeyEncryptionAlgorithm, key, this.encrypted, true); + + this.sessionKeyAlgorithm = enums.read(enums.symmetric, + decrypted[0].keyCodeAt()); + + this.sessionKey = decrypted.substr(1); + } + }; + + this.encrypt = function(passphrase) { + var length = crypto.getKeyLength(this.sessionKeyEncryptionAlgorithm); + var key = this.s2k.produce_key(passphrase, length); + + var private_key = String.fromCharCode( + enums.write(enums.symmetric, this.sessionKeyAlgorithm)) + + + crypto.getRandomBytes( + crypto.getKeyLength(this.sessionKeyAlgorithm)); + + this.encrypted = crypto.cfb.encrypt( + crypto.getPrefixRandom(this.sessionKeyEncryptionAlgorithm), + this.sessionKeyEncryptionAlgorithm, key, private_key, true); + }; +}; diff --git a/src/packet/symmetrically_encrypted.js b/src/packet/symmetrically_encrypted.js new file mode 100644 index 00000000..cc949d93 --- /dev/null +++ b/src/packet/symmetrically_encrypted.js @@ -0,0 +1,71 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
      + *
      + * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted + * with a symmetric-key algorithm. When it has been decrypted, it contains other + * packets (usually a literal data packet or compressed data packet, but in + * theory other Symmetrically Encrypted Data packets or sequences of packets + * that form whole OpenPGP messages). + * @requires crypto + * @module packet/symmetrically_encrypted + */ + +var crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function symmetrically_encrypted() { + this.encrypted = null; + /** Decrypted packets contained within. + * @type {module:packet/packetlist} */ + this.packets = null; + + this.read = function(bytes) { + this.encrypted = bytes; + }; + + this.write = function() { + return this.encrypted; + }; + + /** + * Symmetrically decrypt the packet data + * + * @param {Integer} sessionKeyAlgorithm + * Symmetric key algorithm to use // See RFC4880 9.2 + * @param {String} key + * Key as string with the corresponding length to the + * algorithm + */ + this.decrypt = function(sessionKeyAlgorithm, key) { + var decrypted = crypto.cfb.decrypt( + sessionKeyAlgorithm, key, this.encrypted, true); + + this.packets.read(decrypted); + }; + + this.encrypt = function(algo, key) { + var data = this.packets.write(); + + this.encrypted = crypto.cfb.encrypt( + crypto.getPrefixRandom(algo), algo, data, key, true); + }; +}; diff --git a/src/packet/trust.js b/src/packet/trust.js new file mode 100644 index 00000000..f35ce337 --- /dev/null +++ b/src/packet/trust.js @@ -0,0 +1,10 @@ +/** + * @module packet/trust + */ + +/** + * @constructor + */ +module.exports = function trust() { + +}; diff --git a/src/packet/user_attribute.js b/src/packet/user_attribute.js new file mode 100644 index 00000000..fc344d21 --- /dev/null +++ b/src/packet/user_attribute.js @@ -0,0 +1,62 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the User Attribute Packet (Tag 17)
      + *
      + * The User Attribute packet is a variation of the User ID packet. It + * is capable of storing more types of data than the User ID packet, + * which is limited to text. Like the User ID packet, a User Attribute + * packet may be certified by the key owner ("self-signed") or any other + * key owner who cares to certify it. Except as noted, a User Attribute + * packet may be used anywhere that a User ID packet may be used. + *
      + * While User Attribute packets are not a required part of the OpenPGP + * standard, implementations SHOULD provide at least enough + * compatibility to properly handle a certification signature on the + * User Attribute packet. A simple way to do this is by treating the + * User Attribute packet as a User ID packet with opaque contents, but + * an implementation may use any method desired. + * module packet/user_attribute + * @module packet/user_attribute + */ + +var util = require('../util'), + packet = require('./packet.js'); + +/** + * @constructor + */ +module.exports = function user_attribute() { + this.tag = 17; + this.attributes = []; + + /** + * parsing function for a user attribute packet (tag 17). + * @param {String} input payload of a tag 17 packet + */ + this.read = function(bytes) { + var i = 0; + while (i < bytes.length) { + var len = packet.readSimpleLength(bytes.substr(i)); + i += len.offset; + + this.attributes.push(bytes.substr(i, len.len)); + i += len.len; + } + }; +}; diff --git a/src/packet/userid.js b/src/packet/userid.js new file mode 100644 index 00000000..5d3bdff2 --- /dev/null +++ b/src/packet/userid.js @@ -0,0 +1,58 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the User ID Packet (Tag 13)
      + *
      + * A User ID packet consists of UTF-8 text that is intended to represent + * the name and email address of the key holder. By convention, it + * includes an RFC 2822 [RFC2822] mail name-addr, but there are no + * restrictions on its content. The packet length in the header + * specifies the length of the User ID. + * @requires util + * @module packet/userid + */ + +var util = require('../util'); + +/** + * @constructor + */ +module.exports = function userid() { + /** A string containing the user id. Usually in the form + * John Doe + * @type {String} + */ + this.userid = ''; + + + /** + * Parsing function for a user id packet (tag 13). + * @param {String} input payload of a tag 13 packet + */ + this.read = function (bytes) { + this.userid = util.decode_utf8(bytes); + }; + + /** + * Creates a string representation of the user id packet + * @return {String} string representation + */ + this.write = function () { + return util.encode_utf8(this.userid); + }; +} diff --git a/src/type/keyid.js b/src/type/keyid.js new file mode 100644 index 00000000..b5835b77 --- /dev/null +++ b/src/type/keyid.js @@ -0,0 +1,66 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of type key id (RFC4880 3.3)
      + *
      + * A Key ID is an eight-octet scalar that identifies a key. + * Implementations SHOULD NOT assume that Key IDs are unique. The + * section "Enhanced Key Formats" below describes how Key IDs are + * formed. + * @requires util + * @module type/keyid + */ + +var util = require('../util'); + +/** + * @constructor + */ +module.exports = function keyid() { + + this.bytes = ''; + + + /** + * Parsing method for a key id + * @param {String} input Input to read the key id from + */ + this.read = function(bytes) { + this.bytes = bytes.substr(0, 8); + }; + + this.write = function() { + return this.bytes; + }; + + this.toHex = function() { + return util.hexstrdump(this.bytes); + }; + + this.equals = function(keyid) { + return this.bytes == keyid.bytes; + }; + + this.isNull = function() { + return this.bytes === ''; + }; +}; + +module.exports.mapToHex = function(keyId) { + return keyId.toHex(); +} diff --git a/src/type/mpi.js b/src/type/mpi.js new file mode 100644 index 00000000..98c70cb0 --- /dev/null +++ b/src/type/mpi.js @@ -0,0 +1,100 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two +// octet scalar: MPI: [a,b,c,d,e,f] +// - MPI size: (a << 8) | b +// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8) + +/** + * Implementation of type MPI (RFC4880 3.2)
      + *
      + * Multiprecision integers (also called MPIs) are unsigned integers used + * to hold large integers such as the ones used in cryptographic + * calculations. + * An MPI consists of two pieces: a two-octet scalar that is the length + * of the MPI in bits followed by a string of octets that contain the + * actual integer. + * @requires crypto/public_key/jsbn + * @requires util + * @module type/mpi + */ + +var BigInteger = require('../crypto/public_key/jsbn.js'), + util = require('../util'); + +/** + * @constructor + */ +module.exports = function mpi() { + /** An implementation dependent integer */ + this.data = null; + + /** + * Parsing function for a mpi (RFC 4880 3.2). + * @param {String} input Payload of mpi data + * @return {Integer} Length of data read + */ + this.read = function (bytes) { + var bits = (bytes.charCodeAt(0) << 8) | bytes.charCodeAt(1); + + // Additional rules: + // + // The size of an MPI is ((MPI.length + 7) / 8) + 2 octets. + // + // The length field of an MPI describes the length starting from its + // most significant non-zero bit. Thus, the MPI [00 02 01] is not + // formed correctly. It should be [00 01 01]. + + // TODO: Verification of this size method! This size calculation as + // specified above is not applicable in JavaScript + var bytelen = Math.ceil(bits / 8); + + var raw = bytes.substr(2, bytelen); + this.fromBytes(raw); + + return 2 + bytelen; + }; + + this.fromBytes = function (bytes) { + this.data = new BigInteger(util.hexstrdump(bytes), 16); + }; + + this.toBytes = function () { + return this.write().substr(2); + }; + + this.byteLength = function () { + return this.toBytes().length; + }; + + /** + * Converts the mpi object to a string as specified in RFC4880 3.2 + * @return {String} mpi Byte representation + */ + this.write = function () { + return this.data.toMPI(); + }; + + this.toBigInteger = function () { + return this.data.clone(); + }; + + this.fromBigInteger = function (bn) { + this.data = bn.clone(); + }; +} diff --git a/src/type/openpgp.type.keyid.js b/src/type/openpgp.type.keyid.js deleted file mode 100644 index d8c1ac7a..00000000 --- a/src/type/openpgp.type.keyid.js +++ /dev/null @@ -1,49 +0,0 @@ -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of type key id (RFC4880 3.3) - * A Key ID is an eight-octet scalar that identifies a key. - Implementations SHOULD NOT assume that Key IDs are unique. The - section "Enhanced Key Formats" below describes how Key IDs are - formed. - */ -function openpgp_type_keyid() { - /** - * Parsing method for a key id - * @param {String} input Input to read the key id from - * @param {integer} position Position where to start reading the key - * id from input - * @return {openpgp_type_keyid} This object - */ - function read_packet(input, position) { - this.bytes = input.substring(position, position+8); - return this; - } - - /** - * Generates debug output (pretty print) - * @return {String} Key Id as hexadecimal string - */ - function toString() { - return util.hexstrdump(this.bytes); - } - - this.read_packet = read_packet; - this.toString = toString; -}; diff --git a/src/type/s2k.js b/src/type/s2k.js new file mode 100644 index 00000000..11138e8a --- /dev/null +++ b/src/type/s2k.js @@ -0,0 +1,180 @@ +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * Implementation of the String-to-key specifier (RFC4880 3.7)
      + *
      + * String-to-key (S2K) specifiers are used to convert passphrase strings + * into symmetric-key encryption/decryption keys. They are used in two + * places, currently: to encrypt the secret part of private keys in the + * private keyring, and to convert passphrases to encryption keys for + * symmetrically encrypted messages. + * @requires crypto + * @requires enums + * @requires util + * @module type/s2k + */ + +var enums = require('../enums.js'), + util = require('../util'), + crypto = require('../crypto'); + +/** + * @constructor + */ +module.exports = function s2k() { + /** @type {module:enums.hash} */ + this.algorithm = 'sha256'; + /** @type {module:enums.s2k} */ + this.type = 'iterated'; + this.c = 96; + /** Eight bytes of salt in a binary string. + * @type {String} + */ + this.salt = crypto.random.getRandomBytes(8); + + + // Exponent bias, defined in RFC4880 + var expbias = 6; + + this.get_count = function () { + return (16 + (this.c & 15)) << ((this.c >> 4) + expbias); + }; + + /** + * Parsing function for a string-to-key specifier (RFC 4880 3.7). + * @param {String} input Payload of string-to-key specifier + * @return {Integer} Actual length of the object + */ + this.read = function (bytes) { + var i = 0; + this.type = enums.read(enums.s2k, bytes.charCodeAt(i++)); + this.algorithm = enums.read(enums.hash, bytes.charCodeAt(i++)); + + switch (this.type) { + case 'simple': + break; + + case 'salted': + this.salt = bytes.substr(i, 8); + i += 8; + break; + + case 'iterated': + this.salt = bytes.substr(i, 8); + i += 8; + + // Octet 10: count, a one-octet, coded value + this.c = bytes.charCodeAt(i++); + break; + + case 'gnu': + if (bytes.substr(i, 3) == "GNU") { + i += 3; // GNU + var gnuExtType = 1000 + bytes.charCodeAt(i++); + if (gnuExtType == 1001) { + this.type = gnuExtType; + // GnuPG extension mode 1001 -- don't write secret key at all + } else { + throw new Error("Unknown s2k gnu protection mode."); + } + } else { + throw new Error("Unknown s2k type."); + } + break; + + default: + throw new Error("Unknown s2k type."); + break; + } + + return i; + }; + + + /** + * writes an s2k hash based on the inputs. + * @return {String} Produced key of hashAlgorithm hash length + */ + this.write = function () { + var bytes = String.fromCharCode(enums.write(enums.s2k, this.type)); + bytes += String.fromCharCode(enums.write(enums.hash, this.algorithm)); + + switch (this.type) { + case 'simple': + break; + case 'salted': + bytes += this.salt; + break; + case 'iterated': + bytes += this.salt; + bytes += String.fromCharCode(this.c); + break; + } + + return bytes; + }; + + /** + * Produces a key using the specified passphrase and the defined + * hashAlgorithm + * @param {String} passphrase Passphrase containing user input + * @return {String} Produced key with a length corresponding to + * hashAlgorithm hash length + */ + this.produce_key = function (passphrase, numBytes) { + passphrase = util.encode_utf8(passphrase); + + function round(prefix, s2k) { + var algorithm = enums.write(enums.hash, s2k.algorithm); + + switch (s2k.type) { + case 'simple': + return crypto.hash.digest(algorithm, prefix + passphrase); + + case 'salted': + return crypto.hash.digest(algorithm, + prefix + s2k.salt + passphrase); + + case 'iterated': + var isp = [], + count = s2k.get_count(); + data = s2k.salt + passphrase; + + while (isp.length * data.length < count) + isp.push(data); + + isp = isp.join(''); + + if (isp.length > count) + isp = isp.substr(0, count); + + return crypto.hash.digest(algorithm, prefix + isp); + } + } + + var result = '', + prefix = ''; + + while (result.length <= numBytes) { + result += round(prefix, this); + prefix += String.fromCharCode(0); + } + + return result.substr(0, numBytes); + }; +}; diff --git a/src/util/package.json b/src/util/package.json new file mode 100644 index 00000000..c6e44558 --- /dev/null +++ b/src/util/package.json @@ -0,0 +1,5 @@ +{ + "name": "openpgp-util", + "version": "0.0.1", + "main": "./util.js" +} diff --git a/src/util/util.js b/src/util/util.js index eb308701..83450a96 100644 --- a/src/util/util.js +++ b/src/util/util.js @@ -15,320 +15,290 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -var Util = function() { +/** + * This object contains utility functions + * @requires config + * @module util/util + */ - this.emailRegEx = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; - - this.hexdump = function(str) { - var r=[]; - var e=str.length; - var c=0; - var h; - var i = 0; - while(c> (8 * (bytes - i - 1))) & 0xFF); + } + + return b; + }, + + readDate: function (bytes) { + var n = this.readNumber(bytes); + var d = new Date(); + d.setTime(n * 1000); + return d; + }, + + writeDate: function (time) { + var numeric = Math.round(time.getTime() / 1000); + + return this.writeNumber(numeric, 4); + }, + + emailRegEx: /^[+a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,6}$/, + + hexdump: function (str) { + var r = []; + var e = str.length; + var c = 0; + var h; + var i = 0; + while (c < e) { + h = str.charCodeAt(c++).toString(16); + while (h.length < 2) h = "0" + h; + r.push(" " + h); + i++; + if (i % 32 == 0) + r.push("\n "); + } + return r.join(''); + }, + + /** + * Create hexstring from a binary + * @param {String} str String to convert + * @return {String} String containing the hexadecimal values + */ + hexstrdump: function (str) { + if (str == null) + return ""; + var r = []; + var e = str.length; + var c = 0; + var h; + while (c < e) { + h = str.charCodeAt(c++).toString(16); + while (h.length < 2) h = "0" + h; + r.push("" + h); + } + return r.join(''); + }, + + /** + * Create binary string from a hex encoded string + * @param {String} str Hex string to convert + * @return {String} String containing the binary values + */ + hex2bin: function (hex) { + var str = ''; + for (var i = 0; i < hex.length; i += 2) + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + return str; + }, + + /** + * Creating a hex string from an binary array of integers (0..255) + * @param {String} str Array of bytes to convert + * @return {String} Hexadecimal representation of the array + */ + hexidump: function (str) { + var r = []; + var e = str.length; + var c = 0; + var h; + while (c < e) { + h = str[c++].toString(16); + while (h.length < 2) h = "0" + h; + r.push("" + h); + } + return r.join(''); + }, - /** - * Convert a native javascript string to a string of utf8 bytes - * @param {String} str The string to convert - * @return {String} A valid squence of utf8 bytes - */ - this.encode_utf8 = function(str) { - return unescape(encodeURIComponent(str)); - }; + /** + * Convert a native javascript string to a string of utf8 bytes + * @param {String} str The string to convert + * @return {String} A valid squence of utf8 bytes + */ + encode_utf8: function (str) { + return unescape(encodeURIComponent(str)); + }, - /** - * Convert a string of utf8 bytes to a native javascript string - * @param {String} utf8 A valid squence of utf8 bytes - * @return {String} A native javascript string - */ - this.decode_utf8 = function(utf8) { - try { + /** + * Convert a string of utf8 bytes to a native javascript string + * @param {String} utf8 A valid squence of utf8 bytes + * @return {String} A native javascript string + */ + decode_utf8: function (utf8) { + try { return decodeURIComponent(escape(utf8)); } catch (e) { return utf8; } - }; + }, - var str2bin = function(str, result) { - for (var i = 0; i < str.length; i++) { - result[i] = str.charCodeAt(i); - } + /** + * Convert an array of integers(0.255) to a string + * @param {Array} bin An array of (binary) integers to convert + * @return {String} The string representation of the array + */ + bin2str: function (bin) { + var result = []; - return result; - }; - - var bin2str = function(bin) { - var result = []; + for (var i = 0; i < bin.length; i++) { + result.push(String.fromCharCode(bin[i])); + } - for (var i = 0; i < bin.length; i++) { - result.push(String.fromCharCode(bin[i])); - } + return result.join(''); + }, - return result.join(''); - }; + _str2bin: function (str, result) { + for (var i = 0; i < str.length; i++) { + result[i] = str.charCodeAt(i); + } - /** - * Convert a string to an array of integers(0.255) - * @param {String} str String to convert - * @return {Integer[]} An array of (binary) integers - */ - this.str2bin = function(str) { - return str2bin(str, new Array(str.length)); - }; - - - /** - * Convert an array of integers(0.255) to a string - * @param {Integer[]} bin An array of (binary) integers to convert - * @return {String} The string representation of the array - */ - this.bin2str = bin2str; - - /** - * Convert a string to a Uint8Array - * @param {String} str String to convert - * @return {Uint8Array} The array of (binary) integers - */ - this.str2Uint8Array = function(str) { - return str2bin(str, new Uint8Array(new ArrayBuffer(str.length))); - }; - - /** - * Convert a Uint8Array to a string. This currently functions - * the same as bin2str. - * @param {Uint8Array} bin An array of (binary) integers to convert - * @return {String} String representation of the array - */ - this.Uint8Array2str = bin2str; - - /** - * Calculates a 16bit sum of a string by adding each character - * codes modulus 65535 - * @param {String} text String to create a sum of - * @return {Integer} An integer containing the sum of all character - * codes % 65535 - */ - this.calc_checksum = function(text) { - var checksum = { s: 0, add: function (sadd) { this.s = (this.s + sadd) % 65536; }}; - for (var i = 0; i < text.length; i++) { - checksum.add(text.charCodeAt(i)); - } - return checksum.s; - }; - - this.printLevel = { error: 1, warning: 2, info: 3, debug: 4 }; + return result; + }, - /** - * Helper function to print a debug message. Debug - * messages are only printed if - * openpgp.config.debug is set to true. The calling - * Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      ' - * @param {String} str String of the debug message - * @return {String} An HTML tt entity containing a paragraph with a - * style attribute where the debug message is HTMLencoded in. - */ - this.print_debug = function(str) { - if (openpgp.config.debug) { - this.print_output(this.printLevel.debug, str); - } - }; - - /** - * Helper function to print a debug message. Debug - * messages are only printed if - * openpgp.config.debug is set to true. The calling - * Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      ' - * Different than print_debug because will call hexstrdump iff necessary. - * @param {String} str String of the debug message - * @return {String} An HTML tt entity containing a paragraph with a - * style attribute where the debug message is HTMLencoded in. - */ - this.print_debug_hexstr_dump = function(str,strToHex) { - if (openpgp.config.debug) { - str = str + this.hexstrdump(strToHex); - this.print_output(this.printLevel.debug, str); - } - }; - - /** - * Helper function to print an error message. - * The calling Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      ' - * @param {String} str String of the error message - * @return {String} A HTML paragraph entity with a style attribute - * containing the HTML encoded error message - */ - this.print_error = function(str) { - this.print_output(this.printLevel.error, str); - }; - - /** - * Helper function to print an info message. - * The calling Javascript context MUST define - * a "showMessages(text)" function. Line feeds ('\n') - * are automatically converted to HTML line feeds '
      '. - * @param {String} str String of the info message - * @return {String} A HTML paragraph entity with a style attribute - * containing the HTML encoded info message - */ - this.print_info = function(str) { - this.print_output(this.printLevel.info, str); - }; - - this.print_warning = function(str) { - this.print_output(this.printLevel.warning, str); - }; - - this.print_output = function(level, str) { - var html; - str = openpgp_encoding_html_encode(str).replace(/\n/g,"
      "); - if (level == this.printLevel.debug) { - html = "

      "+str+"

      "; - } else { - var color, heading; - switch (level) { - case this.printLevel.error: - color = "FF8888"; - heading = "ERROR"; - break; - case this.printLevel.warning: - color = 'FFAA88'; - heading = "WARNING"; - break; - case this.printLevel.info: - color = '88FF88'; - heading = 'INFO'; - break; - } - html = "

      "+heading+":"+str+"

      "; - } - if (typeof showMessages === "function") { - // only call function if defined - showMessages(html); - } - } + /** + * Convert a string to an array of integers(0.255) + * @param {String} str String to convert + * @return {Array} An array of (binary) integers + */ + str2bin: function (str) { + return this._str2bin(str, new Array(str.length)); + }, - this.getLeftNBits = function (string, bitcount) { - var rest = bitcount % 8; - if (rest == 0) - return string.substring(0, bitcount / 8); - var bytes = (bitcount - rest) / 8 +1; - var result = string.substring(0, bytes); - return this.shiftRight(result, 8-rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF); - }; - /** - * Shifting a string to n bits right - * @param {String} value The string to shift - * @param {Integer} bitcount Amount of bits to shift (MUST be smaller - * than 9) - * @return {String} Resulting string. - */ - this.shiftRight = function(value, bitcount) { - var temp = util.str2bin(value); - if (bitcount % 8 != 0) { - for (var i = temp.length-1; i >= 0; i--) { - temp[i] >>= bitcount % 8; - if (i > 0) - temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF; - } - } else { - return value; - } - return util.bin2str(temp); - }; - - /** - * Return the algorithm type as string - * @return {String} String representing the message type - */ - this.get_hashAlgorithmString = function(algo) { - switch(algo) { - case 1: - return "MD5"; - case 2: - return "SHA1"; - case 3: - return "RIPEMD160"; - case 8: - return "SHA256"; - case 9: - return "SHA384"; - case 10: - return "SHA512"; - case 11: - return "SHA224"; - } - return "unknown"; - }; + /** + * Convert a string to a Uint8Array + * @param {String} str String to convert + * @return {Uint8Array} The array of (binary) integers + */ + str2Uint8Array: function (str) { + return this._str2bin(str, new Uint8Array(new ArrayBuffer(str.length))); + }, + + /** + * Convert a Uint8Array to a string. This currently functions + * the same as bin2str. + * @function module:util/util.Uint8Array2str + * @param {Uint8Array} bin An array of (binary) integers to convert + * @return {String} String representation of the array + */ + Uint8Array2str: function (bin) { + return this.bin2str(bin); + }, + + /** + * Calculates a 16bit sum of a string by adding each character + * codes modulus 65535 + * @param {String} text String to create a sum of + * @return {Integer} An integer containing the sum of all character + * codes % 65535 + */ + calc_checksum: function (text) { + var checksum = { + s: 0, + add: function (sadd) { + this.s = (this.s + sadd) % 65536; + } + }; + for (var i = 0; i < text.length; i++) { + checksum.add(text.charCodeAt(i)); + } + return checksum.s; + }, + + /** + * Helper function to print a debug message. Debug + * messages are only printed if + * @link module:config/config.debug is set to true. + * @param {String} str String of the debug message + */ + print_debug: function (str) { + if (config.debug) { + console.log(str); + } + }, + + /** + * Helper function to print a debug message. Debug + * messages are only printed if + * @link module:config/config.debug is set to true. + * Different than print_debug because will call hexstrdump iff necessary. + * @param {String} str String of the debug message + */ + print_debug_hexstr_dump: function (str, strToHex) { + if (config.debug) { + str = str + this.hexstrdump(strToHex); + console.log(str); + } + }, + + getLeftNBits: function (string, bitcount) { + var rest = bitcount % 8; + if (rest == 0) + return string.substring(0, bitcount / 8); + var bytes = (bitcount - rest) / 8 + 1; + var result = string.substring(0, bytes); + return this.shiftRight(result, 8 - rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF); + }, + + /** + * Shifting a string to n bits right + * @param {String} value The string to shift + * @param {Integer} bitcount Amount of bits to shift (MUST be smaller + * than 9) + * @return {String} Resulting string. + */ + shiftRight: function (value, bitcount) { + var temp = util.str2bin(value); + if (bitcount % 8 != 0) { + for (var i = temp.length - 1; i >= 0; i--) { + temp[i] >>= bitcount % 8; + if (i > 0) + temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF; + } + } else { + return value; + } + return util.bin2str(temp); + }, + + /** + * Return the algorithm type as string + * @return {String} String representing the message type + */ + get_hashAlgorithmString: function (algo) { + switch (algo) { + case 1: + return "MD5"; + case 2: + return "SHA1"; + case 3: + return "RIPEMD160"; + case 8: + return "SHA256"; + case 9: + return "SHA384"; + case 10: + return "SHA512"; + case 11: + return "SHA224"; + } + return "unknown"; + } }; - -/** - * an instance that should be used. - */ -var util = new Util(); diff --git a/test/README b/test/README deleted file mode 100644 index 2d9c652b..00000000 --- a/test/README +++ /dev/null @@ -1 +0,0 @@ -Create test cases here diff --git a/test/ci-quick.js b/test/ci-quick.js new file mode 100644 index 00000000..bcc64ffe --- /dev/null +++ b/test/ci-quick.js @@ -0,0 +1,237 @@ +var openpgp = require('openpgp'); + +'use strict'; + +var expect = chai.expect; + +describe('Openpgp integration tests', function() { + var user = 'test@t-online.de', + passphrase = 'asdf', + keySize = 512, + keyId = 'F6F60E9B42CDFF4C', + pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + + 'Version: OpenPGP.js v.1.20131011\n' + + 'Comment: http://openpgpjs.org\n' + + '\n' + + 'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\n' + + 'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\n' + + 'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\n' + + 'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\n' + + 'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\n' + + '=6XMW\n' + + '-----END PGP PUBLIC KEY BLOCK-----', + privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' + + 'Version: OpenPGP.js v.1.20131011\n' + + 'Comment: http://openpgpjs.org\n' + + '\n' + + 'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\n' + + 'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\n' + + 'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\n' + + 'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\n' + + 'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\n' + + 'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\n' + + 'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\n' + + 'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\n' + + 'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\n' + + 'IUNzVPLhrFIuKyBDTpLnC07Loce1\n' + + '=ULta\n' + + '-----END PGP PRIVATE KEY BLOCK-----'; + var keyringClass = require('keyring'); + var keyring = new keyringClass(); + + describe('Generate key pair', function() { + it('should work', function(done) { + // generate keypair (keytype 1=RSA) + var errMsg, err; + var keys = null; + + try { + var userId = 'Whiteout User <' + user + '>'; + var keys = openpgp.generateKeyPair(1, keySize, userId, passphrase); + var keyId = openpgp.util.hexstrdump(keys.key.getKeyPacket().getKeyId()).toUpperCase(); + expect(keyId).to.exist; + expect(keys.privateKeyArmored).to.exist; + expect(keys.publicKeyArmored).to.exist; + } catch (e) { + errMsg = 'Keygeneration failed!'; + err = e; + } + + expect(err).to.not.exist; + done(); + }); + }); + + describe('Keyring', function() { + describe('Import key pair', function() { + it('should work', function(done) { + // clear any keypair already in the keychain + keyring.clear(); + keyring.importKey(privkey); + keyring.importKey(pubkey); + done(); + }); + }); + describe('Retrieve keys', function() { + it('getPublicKeyForAddress() - unknown address', function(done) { + var key = keyring.getPublicKeyForAddress('nobody@example.com'); + expect(key).to.be.empty; + done(); + }); + it('getPublicKeyForAddress() - valid address', function(done) { + var key = keyring.getPublicKeyForAddress(user); + expect(key).to.exist; + done(); + }); + it('getPrivateKeyForAddress() - unknown address', function(done) { + var key = keyring.getPrivateKeyForAddress('nobody@example.com'); + expect(key).to.be.empty; + done(); + }); + it('getPrivateKeyForAddress() - valid address', function(done) { + var key = keyring.getPrivateKeyForAddress(user); + expect(key).to.exist; + done(); + }); + it('getKeysForKeyId() - unknown id', function(done) { + var keys = keyring.getKeysForKeyId('000102030405060708'); + expect(keys).to.be.empty; + done(); + }); + it('getKeysForKeyId() - valid id', function(done) { + var keys = keyring.getKeysForKeyId(keyId.toLowerCase()); + expect(keys).to.exist.and.have.length(1); + done(); + }); + }); + }); + + describe('Encryption', function() { + var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' + + '> asdf\n' + + '> \n' + + '> Thursday, Nov 21, 2013 7:32 PM asdf@example.com wrote:\n' + + '> > secret 3', + ciphertext; + + describe('Encrypt and Sign', function() { + it('should work', function(done) { + var signkey = openpgp.key.readArmored(privkey).keys[0]; + expect(signkey).to.exist; + var encryptkey = openpgp.key.readArmored(pubkey).keys[0]; + expect(encryptkey).to.exist; + expect(signkey.decrypt(passphrase)).to.be.true; + ciphertext = openpgp.signAndEncryptMessage([encryptkey], signkey, message); + expect(ciphertext).to.exist; + done(); + }); + }); + + describe('Decrypt and Verify', function() { + it('should work', function(done) { + var decryptkey = openpgp.key.readArmored(privkey).keys[0]; + expect(decryptkey, 'decryptkey').to.exist; + var verifykey = openpgp.key.readArmored(pubkey).keys[0]; + expect(verifykey, 'verifykey').to.exist; + var pgpmsg = openpgp.message.readArmored(ciphertext); + expect(pgpmsg, 'pgpmsg').to.exist; + var keyids = pgpmsg.getEncryptionKeyIds(); + expect(keyids, 'keyids').to.exist; + expect(decryptkey.decryptKeyPacket(keyids, passphrase), 'decryptKeyPacket()').to.be.true; + var result = openpgp.decryptAndVerifyMessage(decryptkey, [verifykey], pgpmsg); + expect(result, 'decryptAndVerifyMessage() result').to.exist; + expect(result.text, 'decryptAndVerifyMessage() result.text').to.exist.and.equal(message); + expect(result.signatures, 'decryptAndVerifyMessage() result.signatures').to.exist.and.not.be.empty; + expect(result.signatures[0].valid, 'decryptAndVerifyMessage() result.signatures[0].valid').to.be.true; + done(); + }); + }); + }); + + describe('Verify clearsign from gpg', function() { + describe('Verify V3 signature', function() { + var v3_clearsign_msg = '-----BEGIN PGP SIGNED MESSAGE-----\r\n' + + 'Hash: SHA1\r\n' + + '\r\n' + + 'This is a test message.\r\n' + + '\r\n' + + 'This paragraph is separated form the next by a line of dashes.\r\n' + + '\r\n' + + '- --------------------------------------------------------------------------\r\n' + + '\r\n' + + 'The next paragraph has a number of blank lines between this one and it.\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + 'This is the last paragraph.\r\n' + + '\r\n' + + '- --\r\n' + + '\r\n' + + 'Joe Test\r\n' + + '-----BEGIN PGP SIGNATURE-----\r\n' + + 'Version: GnuPG v1.4.15 (GNU/Linux)\r\n' + + '\r\n' + + 'iQBVAwUBUp/7GPb2DptCzf9MAQKviQH6A6Pqa63kxWI+atMiaSXz5uifgsBoiOof\r\n' + + 'E3/oVTIGyGTgB7KnwZiFkDMFrUNREJVSQGt6+4nxje8gARcuYpMnWw==\r\n' + + '=lOCC\r\n' + + '-----END PGP SIGNATURE-----\r\n'; + it('should work', function(done) { + var cleartext = openpgp.cleartext.readArmored(v3_clearsign_msg); + expect(cleartext).to.exist; + var verifykey = openpgp.key.readArmored(pubkey).keys[0]; + expect(verifykey, 'verifykey').to.exist; + var result = cleartext.verify([verifykey]) + expect(result, 'verify() result').to.exist.and.not.be.empty; + expect(result[0].keyid, 'verify() result[0].keyid').to.exist; + expect(result[0].valid, 'verify() result[0].valid').to.be.true; + done(); + }); + }); + + describe('Verify V4 signature', function() { + var v4_clearsign_msg = '-----BEGIN PGP SIGNED MESSAGE-----\r\n' + + 'Hash: SHA1\r\n' + + '\r\n' + + 'This is a test message.\r\n' + + '\r\n' + + 'This paragraph is separated form the next by a line of dashes.\r\n' + + '\r\n' + + '- --------------------------------------------------------------------------\r\n' + + '\r\n' + + 'The next paragraph has a number of blank lines between this one and it.\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + '\r\n' + + 'This is the last paragraph.\r\n' + + '\r\n' + + '- --\r\n' + + '\r\n' + + 'Joe Test\r\n' + + '-----BEGIN PGP SIGNATURE-----\r\n' + + 'Version: GnuPG v1.4.15 (GNU/Linux)\r\n' + + '\r\n' + + 'iFwEAQECAAYFAlKf5LcACgkQ9vYOm0LN/0ybVwH8CItdDh4kWKVcyUx3Q3hWZnWd\r\n' + + 'zP9CUbIa9uToIPABjV3GOTDM3ZgiP0/SE6Al5vG8hlx+/u2piVojoLovk/4LnA==\r\n' + + '=i6ew\r\n' + + '-----END PGP SIGNATURE-----\r\n'; + + it('should work', function(done) { + var cleartext = openpgp.cleartext.readArmored(v4_clearsign_msg); + expect(cleartext).to.exist; + var verifykey = openpgp.key.readArmored(pubkey).keys[0]; + expect(verifykey, 'verifykey').to.exist; + var result = cleartext.verify([verifykey]) + expect(result, 'verify() result').to.exist.and.not.be.empty; + expect(result[0].keyid, 'verify() result[0].keyid').to.exist; + expect(result[0].valid, 'verify() result[0].valid').to.be.true; + done(); + }); + }); + }); +}); diff --git a/test/ci-tests-all.js b/test/ci-tests-all.js new file mode 100644 index 00000000..50546202 --- /dev/null +++ b/test/ci-tests-all.js @@ -0,0 +1 @@ +require('./ci-quick.js'); diff --git a/test/ci-tests.html b/test/ci-tests.html new file mode 100644 index 00000000..23ea9f7d --- /dev/null +++ b/test/ci-tests.html @@ -0,0 +1,31 @@ + + + + + OpenPGPJS Continuous Integration Tests + + + + +
      + + + + + + + + + + + + diff --git a/test/ciphers/hash/ripe-md.js b/test/ciphers/hash/ripe-md.js deleted file mode 100644 index 38fc1d18..00000000 --- a/test/ciphers/hash/ripe-md.js +++ /dev/null @@ -1,13 +0,0 @@ - -unittests.register("RIPE-MD 160 bits test with test vectors from http://homes.esat.kuleuven.be/~bosselae/ripemd160.html", function() { - var result = new Array(); - result[0] = new test_result("RMDstring (\"\") = 9c1185a5c5e9fc54612808977ee8f548b2258d31", - util.hexstrdump(RMDstring("")) == "9c1185a5c5e9fc54612808977ee8f548b2258d31"); - result[1] = new test_result("RMDstring (\"a\") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", - util.hexstrdump(RMDstring("a")) == "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); - result[2] = new test_result("RMDstring (\"abc\") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", - util.hexstrdump(RMDstring("abc")) == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); - result[3] = new test_result("RMDstring (\"message digest\") = 5d0689ef49d2fae572b881b123a85ffa21595f36", - util.hexstrdump(RMDstring("message digest")) == "5d0689ef49d2fae572b881b123a85ffa21595f36"); - return result; -}); diff --git a/test/ciphers/hash/sha.js b/test/ciphers/hash/sha.js deleted file mode 100644 index be3a28cd..00000000 --- a/test/ciphers/hash/sha.js +++ /dev/null @@ -1,26 +0,0 @@ - -unittests.register("SHA* test with test vectors from NIST FIPS 180-2", function() { - var result = new Array(); - - result[0] = new test_result("SHA1 - a9993e364706816aba3e25717850c26c9cd0d89d = str_sha1(\"abc\") ", - "a9993e364706816aba3e25717850c26c9cd0d89d" == util.hexstrdump(str_sha1("abc"))); - result[1] = new test_result("SHA1 - 84983e441c3bd26ebaae4aa1f95129e5e54670f1 = str_sha1(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", - "84983e441c3bd26ebaae4aa1f95129e5e54670f1" == util.hexstrdump(str_sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); - result[2] = new test_result("SHA224 - 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 = str_sha224(\"abc\") ", - "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" == util.hexstrdump(str_sha224("abc"))); - result[3] = new test_result("SHA224 - 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525 = str_sha224(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", - "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" == util.hexstrdump(str_sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); - result[4] = new test_result("SHA256 - ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad = str_sha256(\"abc\") ", - "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" == util.hexstrdump(str_sha256("abc"))); - result[5] = new test_result("SHA256 - 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 = str_sha256(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", - "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" == util.hexstrdump(str_sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); - result[6] = new test_result("SHA384 - cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 = str_sha384(\"abc\") ", - "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" == util.hexstrdump(str_sha384("abc"))); - result[7] = new test_result("SHA384 - 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b = str384(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", - "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b" == util.hexstrdump(str_sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); - result[8] = new test_result("SHA512 - ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f = str_sha512(\"abc\") ", - "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" == util.hexstrdump(str_sha512("abc"))); - result[9] = new test_result("SHA512 - 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 = str_sha512(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", - "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" == util.hexstrdump(str_sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); - return result; -}); diff --git a/test/ciphers/openpgp.crypto.js b/test/ciphers/openpgp.crypto.js deleted file mode 100644 index 3b82477e..00000000 --- a/test/ciphers/openpgp.crypto.js +++ /dev/null @@ -1,267 +0,0 @@ - -unittests.register("Functional testing of openpgp_crypto_* methods", function() { - var result = new Array(); - var RSApubMPIstrs = [ - util.bin2str([0x08,0x00,0xac,0x15,0xb3,0xd6,0xd2,0x0f,0xf0,0x7a,0xdd,0x21,0xb7, - 0xbf,0x61,0xfa,0xca,0x93,0x86,0xc8,0x55,0x5a,0x4b,0xa6,0xa4,0x1a, - 0x60,0xa2,0x3a,0x37,0x06,0x08,0xd8,0x15,0x8e,0x85,0x45,0xaa,0xb7, - 0x1d,0x7b,0x0b,0x73,0x94,0x55,0x0c,0x5c,0xec,0xc0,0x22,0x4b,0xa1, - 0x64,0x20,0x7d,0x4d,0xa8,0x96,0x1a,0x64,0x38,0x93,0xcd,0xec,0x73, - 0x5d,0xf9,0x89,0x88,0x24,0x3d,0x48,0xff,0x3b,0x87,0x62,0xd0,0x84, - 0xea,0xff,0x39,0xb5,0x27,0x70,0xea,0x4a,0xb2,0x2e,0x9d,0xf1,0x7c, - 0x23,0xec,0xf4,0x5e,0xea,0x61,0x3d,0xe5,0xd8,0x0d,0xf9,0x59,0x6d, - 0x28,0x00,0xeb,0xcb,0xc9,0x55,0x00,0x72,0x30,0x1f,0x65,0x9d,0xd6, - 0x17,0x58,0x5f,0xa6,0x4a,0xa0,0xdd,0xe1,0x76,0xf2,0xef,0x21,0x9f, - 0x84,0xfc,0xaa,0x5b,0x52,0x6e,0xc1,0xa2,0xb9,0xbd,0xb9,0xf4,0x9e, - 0x49,0x92,0xf2,0xaf,0x57,0x86,0xf2,0xef,0x70,0xbf,0x51,0x40,0xfd, - 0xbf,0x56,0x51,0xe8,0x2c,0xa2,0x4f,0xf8,0xa4,0xd7,0x36,0x18,0x85, - 0xce,0x09,0x0d,0xbc,0x8d,0x65,0x5e,0x8a,0x1d,0x98,0xb0,0x4d,0x9d, - 0xc1,0xcf,0x82,0xe1,0xb7,0x43,0x5d,0x5a,0x72,0xcd,0x55,0xd2,0xff, - 0xb1,0xb4,0x78,0xbf,0xa1,0x7d,0xac,0xd9,0x1b,0xc4,0xfa,0x39,0x34, - 0x92,0x09,0xf9,0x08,0x2a,0x6b,0x9d,0x14,0x56,0x12,0x4c,0xe9,0xa6, - 0x29,0xc1,0xf3,0xa9,0x0b,0xfc,0x31,0x75,0x58,0x74,0x2a,0x88,0xaf, - 0xee,0xc9,0xa4,0xcd,0x15,0xdc,0x1b,0x8d,0x64,0xc1,0x36,0x17,0xc4, - 0x8d,0x5e,0x99,0x7a,0x5b,0x9f,0x39,0xd0,0x00,0x6e,0xf9]), - util.bin2str([0x00,0x11,0x01,0x00,0x01])]; - var RSAsecMPIstrs = [ - util.bin2str([0x07,0xfe,0x23,0xff,0xce,0x45,0x6c,0x60,0x65,0x40,0x6e,0xae,0x35, - 0x10,0x56,0x60,0xee,0xab,0xfa,0x10,0x42,0xba,0xc7,0x04,0xaf,0x63, - 0xcd,0x3f,0x62,0xca,0x4b,0xfa,0xe1,0xa9,0x70,0xcd,0x34,0x8b,0xc8, - 0x0e,0xe4,0xc4,0xba,0x83,0x17,0x5f,0xa4,0xb8,0xea,0x60,0xc2,0x4d, - 0x9a,0xf2,0xa9,0x03,0xeb,0xf6,0xaa,0xc2,0xb8,0x8b,0x43,0x12,0xe9, - 0xf7,0x88,0xd2,0x5a,0xa6,0xaa,0x23,0x71,0x31,0x74,0xdb,0x19,0x20, - 0x15,0x41,0x1b,0x43,0x68,0x62,0xd8,0xc0,0x93,0x91,0xe8,0xfc,0xb1, - 0xa9,0x9a,0x52,0x6c,0xe0,0xbf,0x43,0x01,0xa8,0x37,0x14,0x28,0xbf, - 0x0b,0x15,0x56,0x3e,0xa5,0x79,0xa0,0xc4,0x42,0x88,0xee,0xeb,0x1b, - 0xf4,0x7a,0x4a,0x58,0x31,0x58,0x81,0xd2,0x3e,0xde,0x07,0x64,0x92, - 0xf0,0x60,0xd3,0x9a,0x29,0xca,0xc6,0x67,0x75,0x07,0xca,0x92,0x39, - 0x56,0xf6,0x11,0x84,0xba,0x6d,0x4b,0xe6,0x6f,0x66,0xc2,0x17,0xeb, - 0x46,0x69,0x1c,0xbb,0xdf,0xc0,0x38,0x00,0xd6,0x01,0xe6,0x70,0x9d, - 0x4b,0x9b,0x70,0xed,0x5c,0xb8,0xcf,0xe8,0x68,0x71,0xbe,0x24,0x6d, - 0xb1,0xa3,0x13,0xcc,0xf1,0xbc,0x67,0xdc,0xe0,0x69,0x09,0x82,0x3c, - 0x3b,0x0f,0x14,0x98,0x48,0x30,0xb2,0x70,0xc6,0x9e,0xfa,0x46,0x8f, - 0xf1,0xc0,0x65,0x8e,0xc6,0xae,0xdc,0x47,0x91,0x13,0x1e,0xd6,0x4a, - 0xf2,0xad,0xda,0xc2,0xc7,0x39,0x78,0x99,0xde,0x57,0x14,0x45,0x7f, - 0x32,0x38,0xa3,0x44,0x0f,0xe7,0x39,0x4c,0x6f,0x0f,0x32,0x7e,0xf1, - 0x5c,0x84,0x97,0xdd,0xa0,0x0c,0x87,0x66,0x7d,0x75,0x79]), - util.bin2str([0x04,0x00,0xc2,0xbc,0x71,0xf7,0x41,0x4a,0x09,0x66,0x70,0x02,0x68, - 0x8b,0xeb,0xe2,0x34,0xd1,0x12,0x83,0x93,0x75,0xe9,0x71,0x32,0xe2, - 0xed,0x18,0x6f,0x8e,0x3a,0xff,0x22,0x70,0x28,0x01,0xbf,0x4a,0x39, - 0x41,0xbb,0x3c,0x4a,0xbc,0xb8,0x13,0xfc,0x14,0xf6,0x71,0xa1,0x44, - 0x1c,0x02,0xa1,0x73,0x81,0xcc,0xa0,0x35,0x02,0x3e,0x97,0xb5,0xc4, - 0x94,0x33,0xf1,0xd1,0xdf,0x14,0x3f,0xfb,0x8f,0xb9,0x75,0x70,0xdc, - 0x74,0x3f,0x07,0x35,0x8f,0x53,0xaa,0xb2,0xd6,0x88,0x51,0x71,0x4e, - 0x01,0x24,0xec,0x7d,0xca,0xf6,0xa2,0xb3,0xbb,0xad,0x2e,0x60,0xfb, - 0x1c,0xee,0x49,0xd0,0x4e,0x5c,0xe3,0x1f,0x88,0x48,0xe4,0x68,0x14, - 0x3d,0x71,0xba,0xd7,0x4d,0x35,0x10,0x86,0x37,0x62,0xe0,0xa5,0x0b]), - util.bin2str([0x04,0x00,0xe2,0x38,0xf9,0xc8,0x3c,0xd1,0xcf,0x62,0x93,0xc3,0x77, - 0x76,0x97,0x44,0xe8,0xc8,0xca,0x93,0x9a,0xef,0xf0,0x63,0x76,0x25, - 0x3b,0x1c,0x46,0xff,0x90,0x13,0x91,0x15,0x97,0x7e,0x88,0x95,0xd4, - 0x7f,0x2f,0x52,0x6e,0x0d,0x55,0x55,0x2e,0xf1,0x58,0x5c,0x7e,0x56, - 0xd4,0x48,0xaa,0xdb,0x8c,0x44,0x4d,0x84,0x69,0x33,0x87,0x07,0xb2, - 0x7e,0xf5,0xa0,0x60,0xfb,0x73,0x59,0x46,0x29,0xcb,0x1e,0x3f,0x7c, - 0x2f,0xa6,0x53,0xe3,0x8c,0xef,0xd5,0xeb,0xbb,0xc8,0x9a,0x8e,0x66, - 0x4a,0x47,0x2f,0xe1,0xba,0x5e,0x32,0xd4,0x52,0x04,0x88,0x9d,0x63, - 0x3e,0xba,0x71,0x2d,0xf7,0x61,0xd5,0xfc,0x26,0xbf,0xd8,0x60,0x92, - 0x7b,0x94,0xf8,0x6f,0x3d,0x97,0x0b,0x0c,0x52,0x8c,0xb3,0xb6,0x8b]), - util.bin2str([0x04,0x00,0xb7,0xc5,0x4d,0x6e,0x2f,0xdd,0xef,0xec,0x07,0x70,0xa2, - 0x7c,0x1c,0x9d,0x8e,0x66,0x60,0x7c,0x61,0x1e,0x45,0xe9,0xdc,0x82, - 0x2f,0xc5,0x7e,0x1a,0xc6,0xd0,0x92,0xc5,0x22,0x9b,0x9a,0xfb,0x73, - 0x95,0x99,0xf2,0x7c,0xdb,0x2a,0x93,0x7b,0x5a,0x29,0x73,0x24,0x16, - 0x41,0x49,0xb5,0xf2,0x5f,0xbe,0xe7,0x64,0x4d,0xda,0x52,0x9e,0xc1, - 0x41,0x40,0x5e,0x03,0x92,0x8d,0x39,0x95,0x1f,0x68,0x9f,0x00,0x2e, - 0x0c,0x6f,0xcf,0xd9,0x6d,0x68,0xf7,0x00,0x4f,0x0e,0xc8,0x0b,0xfa, - 0x51,0xe0,0x22,0xf0,0xff,0xa7,0x42,0xd4,0xde,0x0b,0x47,0x8f,0x2b, - 0xf5,0x4d,0x04,0x32,0x91,0x89,0x4b,0x0e,0x05,0x8d,0x70,0xf9,0xbb, - 0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])]; - - var DSApubMPIstrs = [ - util.bin2str([0x08,0x00,0xa8,0x85,0x5c,0x28,0x05,0x94,0x03,0xbe,0x07,0x6c,0x13,0x3e,0x65, - 0xfb,0xb5,0xe1,0x99,0x7c,0xfa,0x84,0xe3,0xac,0x47,0xa5,0xc4,0x46,0xd8,0x5f, - 0x44,0xe9,0xc1,0x6b,0x69,0xf7,0x10,0x76,0x49,0xa7,0x25,0x85,0xf4,0x1b,0xed, - 0xc6,0x60,0xc4,0x5b,0xaa,0xd4,0x87,0xd6,0x8f,0x92,0x56,0x7d,0x55,0x3f,0x45, - 0xae,0x12,0x73,0xda,0x29,0x8c,0xba,0x32,0xcc,0xd7,0xa4,0xd0,0x24,0xb0,0x7c, - 0xd8,0x0c,0x3a,0x91,0x6f,0x98,0x40,0x9c,0x9a,0xa8,0xcc,0x28,0x27,0x95,0x0b, - 0xe1,0x5b,0xb9,0x3b,0x1c,0x1c,0xd2,0xec,0xab,0x07,0x25,0x8d,0x7a,0x2a,0x2b, - 0x16,0x14,0xe8,0xda,0x71,0xd2,0xab,0xba,0x85,0x14,0x0d,0xc5,0xe0,0x88,0xeb, - 0xa5,0xe2,0xd5,0x48,0x3d,0x74,0x0c,0x41,0xeb,0xfd,0xb6,0x4e,0xf9,0x2c,0x82, - 0x17,0xdd,0x64,0x1e,0x19,0x39,0xa3,0x7f,0xf9,0x00,0xcd,0x9b,0xda,0x2e,0xbd, - 0x71,0x12,0xdf,0x0d,0x7c,0x0a,0x6b,0x2d,0x21,0x3b,0x9c,0x66,0x93,0x4a,0x1e, - 0x90,0x79,0xd3,0x5a,0x5b,0xe5,0xb9,0x94,0x1b,0xe6,0x47,0x99,0x06,0x98,0xd8, - 0x2a,0xe5,0xe2,0xa6,0x95,0x6a,0x07,0xc8,0xac,0x7c,0xe9,0xfc,0xa2,0x6a,0x16, - 0x2c,0x94,0x98,0xbd,0x91,0x0a,0x7c,0x7c,0x2c,0xb9,0x7e,0xa2,0x51,0x8b,0x45, - 0x1d,0x46,0x34,0xa8,0x52,0x2b,0xdd,0xd9,0xa8,0xbc,0x46,0x78,0x66,0xe1,0x72, - 0x11,0xf1,0xcb,0x1a,0xb6,0x4e,0x05,0x54,0xf7,0xe9,0xbe,0x4c,0x25,0x59,0x08, - 0x9f,0xf8,0xea,0x25,0x97,0x33,0xd6,0xc9,0x0f,0x59,0x0e,0xfd,0x9f,0xdc,0xe2, - 0xc0,0xcf,0x2f]), - util.bin2str([0x01,0x00,0xe1,0x72,0x2c,0xd0,0xbb,0x1a,0x4f,0xb6,0xb6,0x95,0x77,0x71,0x2e, - 0x01,0x48,0x3e,0x35,0x54,0x64,0x2b,0xed,0x40,0x5f,0x65,0x0c,0x57,0x28,0x5f, - 0xfd,0xfd,0xff,0xd7]), - util.bin2str([0x07,0xff,0x5d,0x9f,0xc4,0xb5,0x63,0x25,0x9d,0x72,0x88,0xe5,0x53,0x46,0x98, - 0xe3,0xe9,0x62,0xcb,0x0c,0xa1,0xb7,0x75,0x9f,0x18,0x41,0x94,0x32,0x28,0x29, - 0x6d,0x69,0xe0,0x3f,0x7d,0x7b,0x2b,0x06,0x5a,0x33,0x5c,0xd4,0x36,0x31,0x09, - 0x54,0x85,0x9d,0xb8,0x20,0xfe,0xda,0xfc,0xcd,0x1f,0xb1,0x2c,0x15,0x08,0x9d, - 0x32,0x53,0x2f,0xc1,0x42,0x22,0x69,0xff,0x67,0x2e,0x39,0x97,0x50,0x66,0x39, - 0xda,0xcf,0xfd,0x64,0x6f,0x91,0x05,0x64,0x37,0xc5,0x07,0x24,0xaa,0x40,0xa0, - 0x75,0x82,0x1d,0x97,0x96,0x12,0xf1,0xbd,0x9e,0x09,0x26,0x3c,0x97,0x5d,0x57, - 0xb8,0x5c,0x7d,0x89,0x03,0x82,0xcd,0x40,0xe5,0x03,0xe6,0x4a,0xfb,0xbc,0xd2, - 0xef,0x7a,0x89,0x02,0x08,0xc8,0x52,0xfa,0x97,0x74,0x66,0x32,0xae,0xa6,0x52, - 0x4b,0xef,0x5f,0xce,0x91,0x23,0x3f,0xab,0x9d,0x62,0x21,0xef,0x48,0x6d,0x07, - 0x5a,0xba,0xdf,0x00,0x91,0x54,0xea,0x5c,0xfa,0x4b,0x16,0x28,0x1a,0xce,0x48, - 0xb7,0x5c,0x50,0xa5,0x59,0xa4,0xb4,0xaf,0x1f,0xeb,0x8d,0x58,0x3f,0x0a,0xa5, - 0x97,0x2b,0x51,0x56,0xe8,0x88,0xf6,0x07,0xbc,0xdf,0xfa,0x2b,0x7b,0x88,0xe0, - 0x46,0xc8,0x7a,0x3e,0xd8,0x80,0xdb,0x4d,0x87,0x61,0x4f,0x64,0xcd,0xeb,0xe8, - 0x0d,0x86,0x16,0xcc,0xdd,0x6c,0x76,0x66,0xc1,0x73,0xb7,0x08,0x98,0x89,0x2f, - 0x67,0x69,0xd1,0xfc,0x97,0x4d,0xa2,0xce,0xad,0xbb,0x6f,0xab,0xa5,0xd6,0x18, - 0xb3,0x1a,0x96,0x02,0xbc,0x31,0x42,0xa2,0xad,0x77,0xe8,0xe2,0x4c,0x99,0xf9, - 0xdd,0xbe,0xcd]), - util.bin2str([0x07,0xff,0x5d,0xfe,0x9c,0x98,0xef,0x3a,0xa6,0x49,0xf0,0x10,0x67,0x79,0x2a, - 0x9d,0x79,0x43,0x06,0xa4,0xa8,0x6b,0x1a,0x6d,0x1f,0x77,0x6e,0x00,0x31,0xb9, - 0xed,0xc9,0x66,0xff,0xf1,0x21,0x32,0xfa,0x62,0x43,0xcd,0x97,0xd3,0x3d,0xaf, - 0xb4,0x29,0x29,0x26,0x4e,0x1c,0xa0,0xad,0x1c,0x07,0x28,0x3f,0xe5,0x43,0x10, - 0xba,0xb4,0x08,0xe0,0xdc,0xa2,0xc3,0x5b,0x1f,0xbd,0x94,0xc7,0x43,0xe5,0xf2, - 0x17,0x30,0x54,0x7f,0x14,0xbe,0xf4,0xbd,0x91,0x3b,0xe4,0x36,0xa4,0x50,0x5b, - 0x37,0x89,0x5e,0xcc,0xc7,0x74,0x54,0x32,0x20,0x09,0x63,0x98,0xb7,0xd9,0xaf, - 0x7f,0xb0,0x6c,0x27,0x43,0xfe,0x52,0xe6,0x1a,0x88,0x59,0x25,0xfc,0xeb,0x43, - 0x50,0xc7,0x65,0x43,0xc1,0x86,0x73,0x58,0x53,0x3a,0xcf,0x7a,0xa3,0x1d,0x56, - 0xc8,0x4a,0x80,0x70,0xb7,0xbf,0xf2,0xa3,0xec,0xe8,0x77,0x05,0x33,0x09,0x9d, - 0xaa,0xca,0xa0,0xe1,0x64,0x64,0x6f,0x76,0x99,0x41,0x75,0x78,0x90,0xf6,0xe7, - 0x23,0xe6,0xec,0x50,0xe5,0x99,0xa8,0x3e,0x1a,0x4b,0xc9,0x88,0x58,0x66,0xae, - 0x1a,0x53,0x5e,0xe4,0xb7,0x86,0xcf,0xa6,0xe5,0xad,0xb4,0x80,0xa0,0xf1,0x0d, - 0x96,0xb8,0x41,0xd0,0x07,0x9a,0x21,0x8d,0x50,0x7f,0x4f,0x73,0x13,0xa2,0xe2, - 0x02,0x07,0xc3,0xa3,0x0f,0x09,0x18,0x7f,0xf7,0x6b,0x90,0x70,0xc0,0xf9,0x0c, - 0x67,0x8d,0x9d,0x14,0xb6,0x9d,0x32,0x82,0xd0,0xb5,0xc6,0x57,0xf0,0x91,0xd9, - 0xc3,0x26,0xae,0x9f,0xa9,0x67,0x49,0x96,0x5c,0x07,0x3e,0x47,0x5c,0xed,0x60, - 0x07,0xac,0x6a])]; - var DSAsecMPIstrs = [util.bin2str([0x01,0x00,0x9b,0x58,0xa8,0xf4,0x04,0xb1,0xd5,0x14,0x09,0xe1, - 0xe1,0xa1,0x8a,0x0b,0xa3,0xc3,0xa3,0x66,0xaa,0x27,0x99,0x50, - 0x1c,0x4d,0xba,0x24,0xee,0xdf,0xdf,0xb8,0x8e,0x8e])]; - - var ElgamalpubMPIstrs = - [util.bin2str([0x08,0x00,0xea,0xcc,0xbe,0xe2,0xe4,0x5a,0x51,0x18,0x93,0xa1,0x12,0x2f, - 0x00,0x99,0x42,0xd8,0x5c,0x1c,0x2f,0xb6,0x3c,0xd9,0x94,0x61,0xb4,0x55, - 0x8d,0x4e,0x73,0xe6,0x69,0xbc,0x1d,0x33,0xe3,0x2d,0x91,0x23,0x69,0x95, - 0x98,0xd7,0x18,0x5a,0xaf,0xa7,0x93,0xc6,0x05,0x93,0x3a,0xc7,0xea,0xd0, - 0xb1,0xa9,0xc7,0xab,0x41,0x89,0xc8,0x38,0x99,0xdc,0x1a,0x57,0x35,0x1a, - 0x27,0x62,0x40,0x71,0x9f,0x36,0x1c,0x6d,0x18,0x1c,0x93,0xf7,0xba,0x35, - 0x06,0xed,0x30,0xb8,0xd9,0x8a,0x7c,0x03,0xaf,0xba,0x40,0x1f,0x62,0xf1, - 0x6d,0x87,0x2c,0xa6,0x2e,0x46,0xb0,0xaa,0xbc,0xbc,0x93,0xfa,0x9b,0x47, - 0x3f,0x70,0x1f,0x2a,0xc2,0x66,0x9c,0x7c,0x69,0xe0,0x2b,0x05,0xee,0xb7, - 0xa7,0x7f,0xf3,0x21,0x48,0x85,0xc2,0x95,0x5f,0x6f,0x1e,0xb3,0x9b,0x97, - 0xf8,0x14,0xc3,0xff,0x4d,0x97,0x25,0x29,0x94,0x41,0x4b,0x90,0xd8,0xba, - 0x71,0x45,0x4b,0x1e,0x2f,0xca,0x82,0x5f,0x56,0x77,0xe9,0xd3,0x88,0x5d, - 0x8b,0xec,0x92,0x8b,0x8a,0x23,0x88,0x05,0xf8,0x2c,0xa8,0xf1,0x70,0x76, - 0xe7,0xbf,0x75,0xa8,0x31,0x14,0x8e,0x76,0xc8,0x01,0xa6,0x25,0x27,0x49, - 0xaf,0xdc,0xf4,0xf6,0xf4,0xce,0x90,0x84,0x15,0x2b,0x4d,0xb3,0xcc,0x77, - 0xdb,0x65,0x71,0x75,0xd3,0x00,0x1d,0x22,0xc5,0x42,0x2f,0x51,0xfa,0x7b, - 0xeb,0x6e,0x03,0xd9,0x41,0xdd,0x2d,0x1a,0xdd,0x07,0x74,0x8b,0xb7,0xa2, - 0xfa,0xb2,0x59,0x0e,0x0e,0x94,0x7c,0x00,0xad,0x95,0x23,0x42,0x91,0x18, - 0x4c,0x97,0xf1,0x27,0x62,0x77]), - util.bin2str([0x00,0x03,0x05]), - util.bin2str([0x07,0xff,0x57,0x19,0x76,0xfc,0x09,0x6a,0x7a,0xf7,0xba,0xb2,0x42,0xbf, - 0xcd,0x2b,0xc1,0x1a,0x79,0x25,0x8c,0xad,0xf4,0x3a,0x0a,0x7a,0x9b,0x4c, - 0x46,0x3c,0xe0,0x4f,0xcc,0x6e,0xe5,0x7a,0x33,0x3a,0x4e,0x80,0xcb,0xd3, - 0x62,0xd7,0x8f,0xe2,0xc8,0xb0,0xd0,0xcb,0x49,0xc9,0x9e,0x2d,0x97,0x16, - 0x3a,0x7d,0xb1,0xe1,0xd3,0xd9,0xd7,0x3f,0x20,0x60,0xe3,0x3e,0x77,0xea, - 0x0c,0xe4,0x7b,0xf0,0x39,0x1a,0x0d,0xd9,0x8f,0x73,0xd2,0x51,0xb8,0x0c, - 0x0e,0x15,0x1e,0xad,0x7c,0xd8,0x9d,0x74,0x6e,0xa2,0x17,0x6b,0x58,0x14, - 0x2b,0xb7,0xad,0x8a,0xd7,0x66,0xc0,0xdf,0xea,0x2d,0xfc,0xc4,0x6e,0x68, - 0xb6,0x4c,0x9a,0x16,0xa4,0x3d,0xc2,0x26,0x0c,0xb7,0xd4,0x13,0x7b,0x22, - 0xfd,0x84,0xd7,0x0f,0xdc,0x42,0x75,0x05,0x85,0x29,0x00,0x31,0x1d,0xec, - 0x4e,0x22,0x8b,0xf6,0x37,0x83,0x45,0xe5,0xb3,0x31,0x61,0x2c,0x02,0xa1, - 0xc6,0x9d,0xea,0xba,0x3d,0x8a,0xab,0x0f,0x61,0x5e,0x14,0x64,0x69,0x1e, - 0xa0,0x15,0x48,0x86,0xe5,0x11,0x06,0xe8,0xde,0x34,0xc7,0xa7,0x3d,0x35, - 0xd1,0x76,0xc2,0xbe,0x01,0x82,0x61,0x8d,0xe7,0x7e,0x28,0x1d,0x4e,0x8c, - 0xb9,0xe8,0x7e,0xa4,0x5f,0xa6,0x3a,0x9e,0x5d,0xac,0xf3,0x60,0x22,0x14, - 0xd5,0xd5,0xbe,0x1f,0xf0,0x19,0xe6,0x81,0xfd,0x5d,0xe1,0xf8,0x76,0x5f, - 0xe3,0xda,0xba,0x19,0xf3,0xcb,0x10,0xa0,0x6b,0xd0,0x2d,0xbe,0x40,0x42, - 0x7b,0x9b,0x15,0xa4,0x2d,0xec,0xcf,0x09,0xd6,0xe3,0x92,0xc3,0x8d,0x65, - 0x6b,0x60,0x97,0xda,0x6b,0xca])]; - - var ElgamalsecMPIstrs = [ - util.bin2str([0x01,0x52,0x02,0x80,0x87,0xf6,0xe4,0x49,0xd7,0x2e,0x3e,0xfe,0x60,0xb9, - 0xa3,0x2a,0xf0,0x67,0x58,0xe9,0xf6,0x47,0x83,0xde,0x7e,0xfb,0xbb,0xbd, - 0xdf,0x48,0x12,0x1b,0x06,0x7d,0x13,0xbc,0x3b,0x49,0xf9,0x86,0xd4,0x53, - 0xed,0x2d,0x68])]; - - var RSApubMPIs = new Array(); - for (var i = 0; i < 2; i++) { - RSApubMPIs[i] = new openpgp_type_mpi(); - RSApubMPIs[i].read(RSApubMPIstrs[i],0,RSApubMPIstrs[i].length); - } - - var RSAsecMPIs = new Array(); - for (var i = 0; i < 4; i++) { - RSAsecMPIs[i] = new openpgp_type_mpi(); - RSAsecMPIs[i].read(RSAsecMPIstrs[i],0,RSAsecMPIstrs[i].length); - } - - var DSAsecMPIs = new Array(); - for (var i = 0; i < 1; i++) { - DSAsecMPIs[i] = new openpgp_type_mpi(); - DSAsecMPIs[i].read(DSAsecMPIstrs[i],0,DSAsecMPIstrs[i].length); - } - - var DSApubMPIs = new Array(); - for (var i = 0; i < 4; i++) { - DSApubMPIs[i] = new openpgp_type_mpi(); - DSApubMPIs[i].read(DSApubMPIstrs[i],0,DSApubMPIstrs[i].length); - } - var ElgamalsecMPIs = new Array(); - for (var i = 0; i < 1; i++) { - ElgamalsecMPIs[i] = new openpgp_type_mpi(); - ElgamalsecMPIs[i].read(ElgamalsecMPIstrs[i],0,ElgamalsecMPIstrs[i].length); - } - - var ElgamalpubMPIs = new Array(); - for (var i = 0; i < 3; i++) { - ElgamalpubMPIs[i] = new openpgp_type_mpi(); - ElgamalpubMPIs[i].read(ElgamalpubMPIstrs[i],0,ElgamalpubMPIstrs[i].length); - } - - // RSA - var RSAsignedData = openpgp_crypto_signData(2,1,RSApubMPIs, RSAsecMPIs, "foobar"); - var RSAsignedDataMPI = new openpgp_type_mpi(); - result[0] = new test_result("Testing RSA Sign and Verify", - openpgp_crypto_verifySignature(1, 2, [ RSAsignedDataMPI.read(RSAsignedData, 0, RSAsignedData.length)], RSApubMPIs, "foobar")); - - // DSA - var DSAsignedData = openpgp_crypto_signData(2, 17, DSApubMPIs, DSAsecMPIs, "foobar"); - - var DSAmsgMPIs = new Array(); - DSAmsgMPIs[0] = new openpgp_type_mpi(); - DSAmsgMPIs[1] = new openpgp_type_mpi(); - DSAmsgMPIs[0].read(DSAsignedData, 0, DSAsignedData.length); - DSAmsgMPIs[1].read(DSAsignedData, DSAmsgMPIs[0].packetLength, DSAsignedData.length); - result[1] = new test_result("Testing DSA Sign and Verify", - openpgp_crypto_verifySignature(17, 2, DSAmsgMPIs, DSApubMPIs, "foobar")); - - var symmAlgo = 9; // AES256 - var symmKey = openpgp_crypto_generateSessionKey(symmAlgo); - var symmencDataOCFB = openpgp_crypto_symmetricEncrypt(openpgp_crypto_getPrefixRandom(symmAlgo),symmAlgo, symmKey, "foobar",true); - var symmencDataCFB = openpgp_crypto_symmetricEncrypt(openpgp_crypto_getPrefixRandom(symmAlgo),symmAlgo, symmKey, "foobar",false); - - result[2] = new test_result("Testing symmetric encrypt and decrypt with OpenPGP CFB resync", - openpgp_crypto_symmetricDecrypt(symmAlgo,symmKey,symmencDataOCFB,true) == "foobar"); - result[3] = new test_result("Testing symmetric encrypt and decrypt without OpenPGP CFB resync (used in modification detection code \"MDC\" packets)", - openpgp_crypto_symmetricDecrypt(symmAlgo,symmKey,symmencDataCFB,false) == "foobar"); - - var RSAEncryptedData = openpgp_crypto_asymetricEncrypt(1, RSApubMPIs, new openpgp_type_mpi().create(openpgp_encoding_eme_pkcs1_encode(symmKey, RSApubMPIs[0].mpiByteLength))); - var RSAEncryptedDataMPI = new openpgp_type_mpi(); - RSAEncryptedDataMPI.read(RSAEncryptedData, 0,RSAEncryptedData.length); - - result[4] = new test_result("Testing asymmetric encrypt and decrypt using RSA with eme_pkcs1 padding", - openpgp_encoding_eme_pkcs1_decode(openpgp_crypto_asymetricDecrypt(1,RSApubMPIs,RSAsecMPIs,[RSAEncryptedDataMPI]).toMPI().substring(2), RSApubMPIs[0].mpiByteLength) == symmKey); - - var ElgamalEncryptedData = openpgp_crypto_asymetricEncrypt(16, ElgamalpubMPIs, new openpgp_type_mpi().create(openpgp_encoding_eme_pkcs1_encode(symmKey, ElgamalpubMPIs[0].mpiByteLength))); - var ElgamalEncryptedDataMPIs = new Array(); - ElgamalEncryptedDataMPIs[0] = new openpgp_type_mpi(); - ElgamalEncryptedDataMPIs[0].read(ElgamalEncryptedData[0], 0, ElgamalEncryptedData[0].length); - ElgamalEncryptedDataMPIs[1] = new openpgp_type_mpi(); - ElgamalEncryptedDataMPIs[1].read(ElgamalEncryptedData[1], 0, ElgamalEncryptedData[1].length); - - result[5] = new test_result("Testing asymmetric encrypt and decrypt using Elgamal with eme_pkcs1 padding", - openpgp_encoding_eme_pkcs1_decode(openpgp_crypto_asymetricDecrypt(16,ElgamalpubMPIs,ElgamalsecMPIs,ElgamalEncryptedDataMPIs).toMPI().substring(2), ElgamalpubMPIs[0].mpiByteLength) == symmKey); - - return result; -}); diff --git a/test/ciphers/openpgp.sigcheck.js b/test/ciphers/openpgp.sigcheck.js deleted file mode 100644 index 67b3de97..00000000 --- a/test/ciphers/openpgp.sigcheck.js +++ /dev/null @@ -1,167 +0,0 @@ -unittests.register("Testing of binary signature checking", function() { - var result = new Array(); - var priv_key = openpgp.read_privateKey([ - '-----BEGIN PGP PRIVATE KEY BLOCK-----', - 'Version: GnuPG v1.4.11 (GNU/Linux)', - '', - 'lQHhBFERnrMRBADmM0hIfkI3yosjgbWo9v0Lnr3CCE+8KsMszgVS+hBu0XfGraKm', - 'ivcA2aaJimHqVYOP7gEnwFAxHBBpeTJcu5wzCFyJwEYqVeS3nnaIhBPplSF14Duf', - 'i6bB9RV7KxVAg6aunmM2tAutqC+a0y2rDaf7jkJoZ9gWJe2zI+vraD6fiwCgxvHo', - '3IgULB9RqIqpLoMgXfcjC+cD/1jeJlKRm+n71ryYwT/ECKsspFz7S36z6q3XyS8Q', - 'QfrsUz2p1fbFicvJwIOJ8B20J/N2/nit4P0gBUTUxv3QEa7XCM/56/xrGkyBzscW', - 'AzBoy/AK9K7GN6z13RozuAS60F1xO7MQc6Yi2VU3eASDQEKiyL/Ubf/s/rkZ+sGj', - 'yJizBACtwCbQzA+z9XBZNUat5NPgcZz5Qeh1nwF9Nxnr6pyBv7tkrLh/3gxRGHqG', - '063dMbUk8pmUcJzBUyRsNiIPDoEUsLjY5zmZZmp/waAhpREsnK29WLCbqLdpUors', - 'c1JJBsObkA1IM8TZY8YUmvsMEvBLCCanuKpclZZXqeRAeOHJ0v4DAwK8WfuTe5B+', - 'M2BOOeZbN8BpfiA1l//fMMHLRS3UvbLBv4P1+4SyvhyYTR7M76Q0xPc03MFOWHL+', - 'S9VumbQWVGVzdDIgPHRlc3QyQHRlc3QuY29tPohiBBMRAgAiBQJREZ6zAhsDBgsJ', - 'CAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRARJ5QDyxae+MXNAKCzWSDR3tMrTrDb', - 'TAri73N1Xb3j1ACfSl9y+SAah2q7GvmiR1+6+/ekqJGdAVgEURGesxAEANlpMZjW', - '33jMxlKHDdyRFXtKOq8RreXhq00plorHbgz9zFEWm4VF53+E/KGnmHGyY5Cy8TKy', - 'ZjaueZZ9XuG0huZg5If68irFfNZtxdA26jv8//PdZ0Uj+X6J3RVa2peMLDDswTYL', - 'OL1ZO1fxdtDD40fdAiIZ1QyjwEG0APtz41EfAAMFBAC5/dtgBBPtHe8UjDBaUe4n', - 'NzHuUBBp6XE+H7eqHNFCuZAJ7yqJLGVHNIaQR419cNy08/OO/+YUQ7rg78LxjFiv', - 'CH7IzhfU+6yvELSbgRMicY6EnAP2GT+b1+MtFNa3lBGtBHcJla52c2rTAHthYZWk', - 'fT5R5DnJuQ2cJHBMS9HWyP4DAwK8WfuTe5B+M2C7a/YJSUv6SexdGCaiaTcAm6g/', - 'PvA6hw/FLzIEP67QcQSSTmhftQIwnddt4S4MyJJH3U4fJaFfYQ1zCniYJohJBBgR', - 'AgAJBQJREZ6zAhsMAAoJEBEnlAPLFp74QbMAn3V4857xwnO9/+vzIVnL93W3k0/8', - 'AKC8omYPPomN1E/UJFfXdLDIMi5LoA==', - '=LSrW', - '-----END PGP PRIVATE KEY BLOCK-----' - ].join("\n")); - var pub_key = openpgp.read_publicKey( - [ '-----BEGIN PGP PUBLIC KEY BLOCK-----', - 'Version: GnuPG v1.4.11 (GNU/Linux)', - '', - 'mQGiBFERlw4RBAD6Bmcf2w1dtUmtCLkdxeqZLArk3vYoQAjdibxA3gXVyur7fsWb', - 'ro0jVbBHqOCtC6jDxE2l52NP9+tTlWeVMaqqNvUE47LSaPq2DGI8Wx1Rj6bF3mTs', - 'obYEwhGbGh/MhJnME9AHODarvk8AZbzo0+k1EwrBWF6dTUBPfqO7rGU2ewCg80WV', - 'x5pt3evj8rRK3jQ8SMKTNRsD/1PhTdxdZTdXARAFzcW1VaaruWW0Rr1+XHKKwDCz', - 'i7HE76SO9qjnQfZCZG75CdQxI0h8GFeN3zsDqmhob2iSz2aJ1krtjM+iZ1FBFd57', - 'OqCV6wmk5IT0RBN12ZzMS19YvzN/ONXHrmTZlKExd9Mh9RKLeVNw+bf6JsKQEzcY', - 'JzFkBACX9X+hDYchO/2hiTwx4iOO9Fhsuh7eIWumB3gt+aUpm1jrSbas/QLTymmk', - 'uZuQVXI4NtnlvzlNgWv4L5s5RU5WqNGG7WSaKNdcrvJZRC2dgbUJt04J5CKrWp6R', - 'aIYal/81Ut1778lU01PEt563TcQnUBlnjU5OR25KhfSeN5CZY7QUVGVzdCA8dGVz', - 'dEB0ZXN0LmNvbT6IYgQTEQIAIgUCURGXDgIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC', - 'HgECF4AACgkQikDlZK/UvLSspgCfcNaOpTg1W2ucR1JwBbBGvaERfuMAnRgt3/rs', - 'EplqEakMckCtikEnpxYe', - '=b2Ln', - '-----END PGP PUBLIC KEY BLOCK-----' - ].join("\n")); - var msg = openpgp.read_message([ - '-----BEGIN PGP MESSAGE-----', - 'Version: GnuPG v1.4.11 (GNU/Linux)', - '', - 'hQEOA1N4OCSSjECBEAP/diDJCQn4e88193PgqhbfAkohk9RQ0v0MPnXpJbCRTHKO', - '8r9nxiAr/TQv4ZOingXdAp2JZEoE9pXxZ3r1UWew04czxmgJ8FP1ztZYWVFAWFVi', - 'Tj930TBD7L1fY/MD4fK6xjEG7z5GT8k4tn4mLm/PpWMbarIglfMopTy1M/py2cID', - '/2Sj7Ikh3UFiG+zm4sViYc5roNbMy8ixeoKixxi99Mx8INa2cxNfqbabjblFyc0Z', - 'BwmbIc+ZiY2meRNI5y/tk0gRD7hT84IXGGl6/mH00bsX/kkWdKGeTvz8s5G8RDHa', - 'Za4HgLbXItkX/QarvRS9kvkD01ujHfj+1ZvgmOBttNfP0p8BQLIICqvg1eYD9aPB', - '+GtOZ2F3+k5VyBL5yIn/s65SBjNO8Fqs3aL0x+p7s1cfUzx8J8a8nWpqq/qIQIqg', - 'ZJH6MZRKuQwscwH6NWgsSVwcnVCAXnYOpbHxFQ+j7RbF/+uiuqU+DFH/Rd5pik8b', - '0Dqnp0yfefrkjQ0nuvubgB6Rv89mHpnvuJfFJRInpg4lrHwLvRwdpN2HDozFHcKK', - 'aOU=', - '=4iGt', - '-----END PGP MESSAGE-----' - ].join("\n")); - priv_key[0].subKeys[0].decryptSecretMPIs("abcd"); - var ret = msg[0].decryptAndVerifySignature( - { key: priv_key[0], keymaterial: priv_key[0].subKeys[0]}, - msg[0].sessionKeys[0], - [{obj:pub_key[0], keyId: pub_key[0].getKeyId()}]); - result[0] = new test_result("Testing signature checking on CAST5-enciphered message", - ret.validSignatures[0] == true); - - // exercises the GnuPG s2k type 1001 extension: - // the secrets on the primary key have been stripped. - var priv_key_gnupg_ext = openpgp.read_privateKey([ - '-----BEGIN PGP PRIVATE KEY BLOCK-----', - 'Version: GnuPG v1.4.11 (GNU/Linux)', - '', - 'lQGqBFERnrMRBADmM0hIfkI3yosjgbWo9v0Lnr3CCE+8KsMszgVS+hBu0XfGraKm', - 'ivcA2aaJimHqVYOP7gEnwFAxHBBpeTJcu5wzCFyJwEYqVeS3nnaIhBPplSF14Duf', - 'i6bB9RV7KxVAg6aunmM2tAutqC+a0y2rDaf7jkJoZ9gWJe2zI+vraD6fiwCgxvHo', - '3IgULB9RqIqpLoMgXfcjC+cD/1jeJlKRm+n71ryYwT/ECKsspFz7S36z6q3XyS8Q', - 'QfrsUz2p1fbFicvJwIOJ8B20J/N2/nit4P0gBUTUxv3QEa7XCM/56/xrGkyBzscW', - 'AzBoy/AK9K7GN6z13RozuAS60F1xO7MQc6Yi2VU3eASDQEKiyL/Ubf/s/rkZ+sGj', - 'yJizBACtwCbQzA+z9XBZNUat5NPgcZz5Qeh1nwF9Nxnr6pyBv7tkrLh/3gxRGHqG', - '063dMbUk8pmUcJzBUyRsNiIPDoEUsLjY5zmZZmp/waAhpREsnK29WLCbqLdpUors', - 'c1JJBsObkA1IM8TZY8YUmvsMEvBLCCanuKpclZZXqeRAeOHJ0v4DZQJHTlUBtBZU', - 'ZXN0MiA8dGVzdDJAdGVzdC5jb20+iGIEExECACIFAlERnrMCGwMGCwkIBwMCBhUI', - 'AgkKCwQWAgMBAh4BAheAAAoJEBEnlAPLFp74xc0AoLNZINHe0ytOsNtMCuLvc3Vd', - 'vePUAJ9KX3L5IBqHarsa+aJHX7r796SokZ0BWARREZ6zEAQA2WkxmNbfeMzGUocN', - '3JEVe0o6rxGt5eGrTSmWisduDP3MURabhUXnf4T8oaeYcbJjkLLxMrJmNq55ln1e', - '4bSG5mDkh/ryKsV81m3F0DbqO/z/891nRSP5fondFVral4wsMOzBNgs4vVk7V/F2', - '0MPjR90CIhnVDKPAQbQA+3PjUR8AAwUEALn922AEE+0d7xSMMFpR7ic3Me5QEGnp', - 'cT4ft6oc0UK5kAnvKoksZUc0hpBHjX1w3LTz847/5hRDuuDvwvGMWK8IfsjOF9T7', - 'rK8QtJuBEyJxjoScA/YZP5vX4y0U1reUEa0EdwmVrnZzatMAe2FhlaR9PlHkOcm5', - 'DZwkcExL0dbI/gMDArxZ+5N7kH4zYLtr9glJS/pJ7F0YJqJpNwCbqD8+8DqHD8Uv', - 'MgQ/rtBxBJJOaF+1AjCd123hLgzIkkfdTh8loV9hDXMKeJgmiEkEGBECAAkFAlER', - 'nrMCGwwACgkQESeUA8sWnvhBswCfdXjznvHCc73/6/MhWcv3dbeTT/wAoLyiZg8+', - 'iY3UT9QkV9d0sMgyLkug', - '=GQsY', - '-----END PGP PRIVATE KEY BLOCK-----', - ].join("\n")); - priv_key_gnupg_ext[0].subKeys[0].decryptSecretMPIs("abcd"); - var ret2 = msg[0].decryptAndVerifySignature( - { key: priv_key_gnupg_ext[0], keymaterial: priv_key_gnupg_ext[0].subKeys[0]}, - msg[0].sessionKeys[0], - [{obj:pub_key[0], keyId: pub_key[0].getKeyId()}]); - result[1] = new test_result("Testing GnuPG stripped-key extensions", - priv_key_gnupg_ext[0].privateKeyPacket.s2k.type == 1001 && - ret.validSignatures[0] == true); - - // Exercises the ability of openpgp_keyring.getPublicKeysForKeyId to return subkeys - var test_keyring = new openpgp_keyring(); - test_keyring.init(); - test_keyring.importPublicKey([ - '-----BEGIN PGP PUBLIC KEY BLOCK-----', - 'Version: GnuPG v1.4.11 (GNU/Linux)', - '', - 'mQGiBFERvI4RBAD0M/HGglCtVNXPF72ehT8riAXrl0rSec4RJC61Bh+UAOhxn5+U', - 'fDgos5p1SpIzYmn+M87JoSSVLAjfakFk0gHgR9I3bu7SIwq3Bikk1Vw3gO+yDSO6', - 'TKpLUFGYDiBSSE1MGdxBadWLE1hlRf5B2x62gnGmjSpSVbly33PFkoDmrwCg9rAp', - 'RmncnF9GhWjOLFkEoQw9Yx8EAOsxvq8Ig5Z1gk+ZKfDZeftpHRe3FdrRtbnhxvYY', - '7z+w9uz1EpoZUwDR5G4X3hTwJQ7lXmIOskg/+eRMLEAqEY7b/7tW6RaUJ2d6Ehsi', - 'dOS89fIxElwjAOnVOM5S24f0FDQTTto7QBOoxcNTfkEJCHXSlpoOUmGAP85fXh3l', - 'yPTGBACJfKc76Un3UWC1sWIRDxYiyh3ZpZyNEskoV6ESW8jEI1RnMnv5TrfGJH5K', - 'E8jWX7TTnoFyPJtBTjlucAtkQaS4Bb7dg1LLja17zAqKNGOJK2b9fb2Z+lnTjPiY', - 'i7DPH1XHnfaEexjlh/U7mYa5RrwIphRxNi8gCuxv874ZMmhEn7QWVGVzdDMgPHRl', - 'c3QzQHRlc3QuY29tPohiBBMRAgAiBQJREbyOAhsDBgsJCAcDAgYVCAIJCgsEFgID', - 'AQIeAQIXgAAKCRC0u8O0Moa2JYxyAJ9Oi2UlcUT0VJNgwjyl/VF9Xcjf9gCeJPvy', - 'g/fp4EAU8MJIaN2yMI8pLFS5AaIEURG8nhEEAKVgeNDuYDPufLuJ0GrJV/CbXEjj', - 'aEPA0iTUqV0nTCPdAfQ/nmE3gh5UlNMr/zSHJ+c4FQhYdLrzRGDOSzV+mfPHH3t+', - 'YVx+wat0BYwABpHAtsIuLIVo2RQqYZYH85tatwBkm71HHT3jmlEAvr6NFH38+v3s', - '3w4Wl0/sdHyaeiSXAKCxJ4X1eOdN7L1rrbJozQ/gDCFuVQP/dcV6Ksss8Aw443jG', - 'AYBLHWh6o4GhAY6/h1kijF0xD+uc+tNmTQnQi1tEOoTeIZMXnSRwtk8XEuJkkbAP', - '+uyvMgyV3wrk9zkaTAin7nrjAERxezFOdBEOtnB1CovJxtMn+RRxaMEGpC4GnETy', - 'N5+6FkLuLcNXiCQP75ajzOAN1aID/juNjUNpBbNpfqBV7j1K+Kn0n9HYTyQl9ghy', - '026+/4c8ag2HV+bg3BD7c2VTVu9xBODHsfu0q8Ql/QB9W8tmYugU6DeXMHaeWPUH', - 'ph98guM9kF2yHIiRBvAd5i7wOjwn+I/Ir6nBR2yxJ3p31CDUnUlbjTPYg7mtQvHW', - 'EY2Cp4SWiJEEGBECAAkFAlERvJ4CGwIAUgkQtLvDtDKGtiVHIAQZEQIABgUCURG8', - 'ngAKCRAMiMeR296Y2SjyAJ9V3wRJJ2Szazqal4khWGfLu5R6/wCfQQIRD24yVdz8', - '2a+2eCrwyALT2GAihACfS0nWM3a0gtITqngpJsRws+Ep+eIAn15qD2itutxNb8NI', - 'bR2gBB5QmVJ3', - '=pGA6', - '-----END PGP PUBLIC KEY BLOCK-----' - ].join("\n")); - - var msg2 = openpgp.read_message([ - '-----BEGIN PGP MESSAGE-----', - 'Version: GnuPG v1.4.11 (GNU/Linux)', - '', - 'kA0DAAIRDIjHkdvemNkBrB1iB2Zvby50eHRREbz3VEVTVCBEQVRBIDEyMzQ1NohG', - 'BAARAgAGBQJREbz3AAoJEAyIx5Hb3pjZ2TcAn32LpDEuHe9QrSRlyvSuREKNOFwz', - 'AJ9zh4zsK4GIPuEu81YPNmHsju7DYg==', - '=WaSx', - '-----END PGP MESSAGE-----' - ].join("\n")); - var pubKey = test_keyring.getPublicKeysForKeyId(msg2[1].signature.issuerKeyId); - result[2] = new test_result("Testing keyring public subkey support", - pubKey != null && - pubKey.length == 1 && - msg2[1].signature.verify(msg2[0].data, pubKey[0])); - return result; -}) - diff --git a/test/ciphers/symmetric/aes.js b/test/ciphers/symmetric/aes.js deleted file mode 100644 index f36e711d..00000000 --- a/test/ciphers/symmetric/aes.js +++ /dev/null @@ -1,111 +0,0 @@ - -unittests.register("AES Rijndael cipher test with test vectors from ecb_tbl.txt", function() { - var result = new Array(); - function test_aes(input, key, output) { - return (util.hexstrdump(util.bin2str(AESencrypt(input,keyExpansion(util.bin2str(key))))) == util.hexstrdump(util.bin2str(output))); - }; - var testvectors128 = [[[0x00,0x01,0x02,0x03,0x05,0x06,0x07,0x08,0x0A,0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x12],[0x50,0x68,0x12,0xA4,0x5F,0x08,0xC8,0x89,0xB9,0x7F,0x59,0x80,0x03,0x8B,0x83,0x59],[0xD8,0xF5,0x32,0x53,0x82,0x89,0xEF,0x7D,0x06,0xB5,0x06,0xA4,0xFD,0x5B,0xE9,0xC9]], - [[0x14,0x15,0x16,0x17,0x19,0x1A,0x1B,0x1C,0x1E,0x1F,0x20,0x21,0x23,0x24,0x25,0x26],[0x5C,0x6D,0x71,0xCA,0x30,0xDE,0x8B,0x8B,0x00,0x54,0x99,0x84,0xD2,0xEC,0x7D,0x4B],[0x59,0xAB,0x30,0xF4,0xD4,0xEE,0x6E,0x4F,0xF9,0x90,0x7E,0xF6,0x5B,0x1F,0xB6,0x8C]], - [[0x28,0x29,0x2A,0x2B,0x2D,0x2E,0x2F,0x30,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3A],[0x53,0xF3,0xF4,0xC6,0x4F,0x86,0x16,0xE4,0xE7,0xC5,0x61,0x99,0xF4,0x8F,0x21,0xF6],[0xBF,0x1E,0xD2,0xFC,0xB2,0xAF,0x3F,0xD4,0x14,0x43,0xB5,0x6D,0x85,0x02,0x5C,0xB1]], - [[0x3C,0x3D,0x3E,0x3F,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0x49,0x4B,0x4C,0x4D,0x4E],[0xA1,0xEB,0x65,0xA3,0x48,0x71,0x65,0xFB,0x0F,0x1C,0x27,0xFF,0x99,0x59,0xF7,0x03],[0x73,0x16,0x63,0x2D,0x5C,0x32,0x23,0x3E,0xDC,0xB0,0x78,0x05,0x60,0xEA,0xE8,0xB2]], - [[0x50,0x51,0x52,0x53,0x55,0x56,0x57,0x58,0x5A,0x5B,0x5C,0x5D,0x5F,0x60,0x61,0x62],[0x35,0x53,0xEC,0xF0,0xB1,0x73,0x95,0x58,0xB0,0x8E,0x35,0x0A,0x98,0xA3,0x9B,0xFA],[0x40,0x8C,0x07,0x3E,0x3E,0x25,0x38,0x07,0x2B,0x72,0x62,0x5E,0x68,0xB8,0x36,0x4B]], - [[0x64,0x65,0x66,0x67,0x69,0x6A,0x6B,0x6C,0x6E,0x6F,0x70,0x71,0x73,0x74,0x75,0x76],[0x67,0x42,0x99,0x69,0x49,0x0B,0x97,0x11,0xAE,0x2B,0x01,0xDC,0x49,0x7A,0xFD,0xE8],[0xE1,0xF9,0x4D,0xFA,0x77,0x65,0x97,0xBE,0xAC,0xA2,0x62,0xF2,0xF6,0x36,0x6F,0xEA]], - [[0x78,0x79,0x7A,0x7B,0x7D,0x7E,0x7F,0x80,0x82,0x83,0x84,0x85,0x87,0x88,0x89,0x8A],[0x93,0x38,0x5C,0x1F,0x2A,0xEC,0x8B,0xED,0x19,0x2F,0x5A,0x8E,0x16,0x1D,0xD5,0x08],[0xF2,0x9E,0x98,0x6C,0x6A,0x1C,0x27,0xD7,0xB2,0x9F,0xFD,0x7E,0xE9,0x2B,0x75,0xF1]], - [[0x8C,0x8D,0x8E,0x8F,0x91,0x92,0x93,0x94,0x96,0x97,0x98,0x99,0x9B,0x9C,0x9D,0x9E],[0xB5,0xBF,0x94,0x6B,0xE1,0x9B,0xEB,0x8D,0xB3,0x98,0x3B,0x5F,0x4C,0x6E,0x8D,0xDB],[0x13,0x1C,0x88,0x6A,0x57,0xF8,0xC2,0xE7,0x13,0xAB,0xA6,0x95,0x5E,0x2B,0x55,0xB5]], - [[0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAF,0xB0,0xB1,0xB2],[0x41,0x32,0x1E,0xE1,0x0E,0x21,0xBD,0x90,0x72,0x27,0xC4,0x45,0x0F,0xF4,0x23,0x24],[0xD2,0xAB,0x76,0x62,0xDF,0x9B,0x8C,0x74,0x02,0x10,0xE5,0xEE,0xB6,0x1C,0x19,0x9D]], - [[0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,0xC5,0xC6],[0x00,0xA8,0x2F,0x59,0xC9,0x1C,0x84,0x86,0xD1,0x2C,0x0A,0x80,0x12,0x4F,0x60,0x89],[0x14,0xC1,0x05,0x54,0xB2,0x85,0x9C,0x48,0x4C,0xAB,0x58,0x69,0xBB,0xE7,0xC4,0x70]], - [[0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,0xCF,0xD0,0xD2,0xD3,0xD4,0xD5,0xD7,0xD8,0xD9,0xDA],[0x7C,0xE0,0xFD,0x07,0x67,0x54,0x69,0x1B,0x4B,0xBD,0x9F,0xAF,0x8A,0x13,0x72,0xFE],[0xDB,0x4D,0x49,0x8F,0x0A,0x49,0xCF,0x55,0x44,0x5D,0x50,0x2C,0x1F,0x9A,0xB3,0xB5]], - [[0xDC,0xDD,0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEB,0xEC,0xED,0xEE],[0x23,0x60,0x5A,0x82,0x43,0xD0,0x77,0x64,0x54,0x1B,0xC5,0xAD,0x35,0x5B,0x31,0x29],[0x6D,0x96,0xFE,0xF7,0xD6,0x65,0x90,0xA7,0x7A,0x77,0xBB,0x20,0x56,0x66,0x7F,0x7F]], - [[0xF0,0xF1,0xF2,0xF3,0xF5,0xF6,0xF7,0xF8,0xFA,0xFB,0xFC,0xFD,0xFE,0x01,0x00,0x02],[0x12,0xA8,0xCF,0xA2,0x3E,0xA7,0x64,0xFD,0x87,0x62,0x32,0xB4,0xE8,0x42,0xBC,0x44],[0x31,0x6F,0xB6,0x8E,0xDB,0xA7,0x36,0xC5,0x3E,0x78,0x47,0x7B,0xF9,0x13,0x72,0x5C]], - [[0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16],[0xBC,0xAF,0x32,0x41,0x5E,0x83,0x08,0xB3,0x72,0x3E,0x5F,0xDD,0x85,0x3C,0xCC,0x80],[0x69,0x36,0xF2,0xB9,0x3A,0xF8,0x39,0x7F,0xD3,0xA7,0x71,0xFC,0x01,0x1C,0x8C,0x37]], - [[0x2C,0x2D,0x2E,0x2F,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3B,0x3C,0x3D,0x3E],[0x89,0xAF,0xAE,0x68,0x5D,0x80,0x1A,0xD7,0x47,0xAC,0xE9,0x1F,0xC4,0x9A,0xDD,0xE0],[0xF3,0xF9,0x2F,0x7A,0x9C,0x59,0x17,0x9C,0x1F,0xCC,0x2C,0x2B,0xA0,0xB0,0x82,0xCD]]]; - - var testvectors192 = [[[0x00,0x01,0x02,0x03,0x05,0x06,0x07,0x08,0x0A,0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x12,0x14,0x15,0x16,0x17,0x19,0x1A,0x1B,0x1C],[0x2D,0x33,0xEE,0xF2,0xC0,0x43,0x0A,0x8A,0x9E,0xBF,0x45,0xE8,0x09,0xC4,0x0B,0xB6],[0xDF,0xF4,0x94,0x5E,0x03,0x36,0xDF,0x4C,0x1C,0x56,0xBC,0x70,0x0E,0xFF,0x83,0x7F]], - [[0x1E,0x1F,0x20,0x21,0x23,0x24,0x25,0x26,0x28,0x29,0x2A,0x2B,0x2D,0x2E,0x2F,0x30,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3A],[0x6A,0xA3,0x75,0xD1,0xFA,0x15,0x5A,0x61,0xFB,0x72,0x35,0x3E,0x0A,0x5A,0x87,0x56],[0xB6,0xFD,0xDE,0xF4,0x75,0x27,0x65,0xE3,0x47,0xD5,0xD2,0xDC,0x19,0x6D,0x12,0x52]], - [[0x3C,0x3D,0x3E,0x3F,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0x49,0x4B,0x4C,0x4D,0x4E,0x50,0x51,0x52,0x53,0x55,0x56,0x57,0x58],[0xBC,0x37,0x36,0x51,0x8B,0x94,0x90,0xDC,0xB8,0xED,0x60,0xEB,0x26,0x75,0x8E,0xD4],[0xD2,0x36,0x84,0xE3,0xD9,0x63,0xB3,0xAF,0xCF,0x1A,0x11,0x4A,0xCA,0x90,0xCB,0xD6]], - [[0x5A,0x5B,0x5C,0x5D,0x5F,0x60,0x61,0x62,0x64,0x65,0x66,0x67,0x69,0x6A,0x6B,0x6C,0x6E,0x6F,0x70,0x71,0x73,0x74,0x75,0x76],[0xAA,0x21,0x44,0x02,0xB4,0x6C,0xFF,0xB9,0xF7,0x61,0xEC,0x11,0x26,0x3A,0x31,0x1E],[0x3A,0x7A,0xC0,0x27,0x75,0x3E,0x2A,0x18,0xC2,0xCE,0xAB,0x9E,0x17,0xC1,0x1F,0xD0]], - [[0x78,0x79,0x7A,0x7B,0x7D,0x7E,0x7F,0x80,0x82,0x83,0x84,0x85,0x87,0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x8F,0x91,0x92,0x93,0x94],[0x02,0xAE,0xA8,0x6E,0x57,0x2E,0xEA,0xB6,0x6B,0x2C,0x3A,0xF5,0xE9,0xA4,0x6F,0xD6],[0x8F,0x67,0x86,0xBD,0x00,0x75,0x28,0xBA,0x26,0x60,0x3C,0x16,0x01,0xCD,0xD0,0xD8]], - [[0x96,0x97,0x98,0x99,0x9B,0x9C,0x9D,0x9E,0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAF,0xB0,0xB1,0xB2],[0xE2,0xAE,0xF6,0xAC,0xC3,0x3B,0x96,0x5C,0x4F,0xA1,0xF9,0x1C,0x75,0xFF,0x6F,0x36],[0xD1,0x7D,0x07,0x3B,0x01,0xE7,0x15,0x02,0xE2,0x8B,0x47,0xAB,0x55,0x11,0x68,0xB3]], - [[0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,0xC5,0xC6,0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,0xCF,0xD0],[0x06,0x59,0xDF,0x46,0x42,0x71,0x62,0xB9,0x43,0x48,0x65,0xDD,0x94,0x99,0xF9,0x1D],[0xA4,0x69,0xDA,0x51,0x71,0x19,0xFA,0xB9,0x58,0x76,0xF4,0x1D,0x06,0xD4,0x0F,0xFA]], - [[0xD2,0xD3,0xD4,0xD5,0xD7,0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEB,0xEC,0xED,0xEE],[0x49,0xA4,0x42,0x39,0xC7,0x48,0xFE,0xB4,0x56,0xF5,0x9C,0x27,0x6A,0x56,0x58,0xDF],[0x60,0x91,0xAA,0x3B,0x69,0x5C,0x11,0xF5,0xC0,0xB6,0xAD,0x26,0xD3,0xD8,0x62,0xFF]], - [[0xF0,0xF1,0xF2,0xF3,0xF5,0xF6,0xF7,0xF8,0xFA,0xFB,0xFC,0xFD,0xFE,0x01,0x00,0x02,0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C],[0x66,0x20,0x8F,0x6E,0x9D,0x04,0x52,0x5B,0xDE,0xDB,0x27,0x33,0xB6,0xA6,0xBE,0x37],[0x70,0xF9,0xE6,0x7F,0x9F,0x8D,0xF1,0x29,0x41,0x31,0x66,0x2D,0xC6,0xE6,0x93,0x64]], - [[0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16,0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20,0x22,0x23,0x24,0x25,0x27,0x28,0x29,0x2A],[0x33,0x93,0xF8,0xDF,0xC7,0x29,0xC9,0x7F,0x54,0x80,0xB9,0x50,0xBC,0x96,0x66,0xB0],[0xD1,0x54,0xDC,0xAF,0xAD,0x8B,0x20,0x7F,0xA5,0xCB,0xC9,0x5E,0x99,0x96,0xB5,0x59]], - [[0x2C,0x2D,0x2E,0x2F,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3B,0x3C,0x3D,0x3E,0x40,0x41,0x42,0x43,0x45,0x46,0x47,0x48],[0x60,0x68,0x34,0xC8,0xCE,0x06,0x3F,0x32,0x34,0xCF,0x11,0x45,0x32,0x5D,0xBD,0x71],[0x49,0x34,0xD5,0x41,0xE8,0xB4,0x6F,0xA3,0x39,0xC8,0x05,0xA7,0xAE,0xB9,0xE5,0xDA]], - [[0x4A,0x4B,0x4C,0x4D,0x4F,0x50,0x51,0x52,0x54,0x55,0x56,0x57,0x59,0x5A,0x5B,0x5C,0x5E,0x5F,0x60,0x61,0x63,0x64,0x65,0x66],[0xFE,0xC1,0xC0,0x4F,0x52,0x9B,0xBD,0x17,0xD8,0xCE,0xCF,0xCC,0x47,0x18,0xB1,0x7F],[0x62,0x56,0x4C,0x73,0x8F,0x3E,0xFE,0x18,0x6E,0x1A,0x12,0x7A,0x0C,0x4D,0x3C,0x61]], - [[0x68,0x69,0x6A,0x6B,0x6D,0x6E,0x6F,0x70,0x72,0x73,0x74,0x75,0x77,0x78,0x79,0x7A,0x7C,0x7D,0x7E,0x7F,0x81,0x82,0x83,0x84],[0x32,0xDF,0x99,0xB4,0x31,0xED,0x5D,0xC5,0xAC,0xF8,0xCA,0xF6,0xDC,0x6C,0xE4,0x75],[0x07,0x80,0x5A,0xA0,0x43,0x98,0x6E,0xB2,0x36,0x93,0xE2,0x3B,0xEF,0x8F,0x34,0x38]], - [[0x86,0x87,0x88,0x89,0x8B,0x8C,0x8D,0x8E,0x90,0x91,0x92,0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,0x9D,0x9F,0xA0,0xA1,0xA2],[0x7F,0xDC,0x2B,0x74,0x6F,0x3F,0x66,0x52,0x96,0x94,0x3B,0x83,0x71,0x0D,0x1F,0x82],[0xDF,0x0B,0x49,0x31,0x03,0x8B,0xAD,0xE8,0x48,0xDE,0xE3,0xB4,0xB8,0x5A,0xA4,0x4B]], - [[0xA4,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,0xB1,0xB3,0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0],[0x8F,0xBA,0x15,0x10,0xA3,0xC5,0xB8,0x7E,0x2E,0xAA,0x3F,0x7A,0x91,0x45,0x5C,0xA2],[0x59,0x2D,0x5F,0xDE,0xD7,0x65,0x82,0xE4,0x14,0x3C,0x65,0x09,0x93,0x09,0x47,0x7C]]]; - - var testvectors256 = [[[0x00,0x01,0x02,0x03,0x05,0x06,0x07,0x08,0x0A,0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x12,0x14,0x15,0x16,0x17,0x19,0x1A,0x1B,0x1C,0x1E,0x1F,0x20,0x21,0x23,0x24,0x25,0x26],[0x83,0x4E,0xAD,0xFC,0xCA,0xC7,0xE1,0xB3,0x06,0x64,0xB1,0xAB,0xA4,0x48,0x15,0xAB],[0x19,0x46,0xDA,0xBF,0x6A,0x03,0xA2,0xA2,0xC3,0xD0,0xB0,0x50,0x80,0xAE,0xD6,0xFC]], - [[0x28,0x29,0x2A,0x2B,0x2D,0x2E,0x2F,0x30,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3A,0x3C,0x3D,0x3E,0x3F,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0x49,0x4B,0x4C,0x4D,0x4E],[0xD9,0xDC,0x4D,0xBA,0x30,0x21,0xB0,0x5D,0x67,0xC0,0x51,0x8F,0x72,0xB6,0x2B,0xF1],[0x5E,0xD3,0x01,0xD7,0x47,0xD3,0xCC,0x71,0x54,0x45,0xEB,0xDE,0xC6,0x2F,0x2F,0xB4]], - [[0x50,0x51,0x52,0x53,0x55,0x56,0x57,0x58,0x5A,0x5B,0x5C,0x5D,0x5F,0x60,0x61,0x62,0x64,0x65,0x66,0x67,0x69,0x6A,0x6B,0x6C,0x6E,0x6F,0x70,0x71,0x73,0x74,0x75,0x76],[0xA2,0x91,0xD8,0x63,0x01,0xA4,0xA7,0x39,0xF7,0x39,0x21,0x73,0xAA,0x3C,0x60,0x4C],[0x65,0x85,0xC8,0xF4,0x3D,0x13,0xA6,0xBE,0xAB,0x64,0x19,0xFC,0x59,0x35,0xB9,0xD0]], - [[0x78,0x79,0x7A,0x7B,0x7D,0x7E,0x7F,0x80,0x82,0x83,0x84,0x85,0x87,0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x8F,0x91,0x92,0x93,0x94,0x96,0x97,0x98,0x99,0x9B,0x9C,0x9D,0x9E],[0x42,0x64,0xB2,0x69,0x64,0x98,0xDE,0x4D,0xF7,0x97,0x88,0xA9,0xF8,0x3E,0x93,0x90],[0x2A,0x5B,0x56,0xA5,0x96,0x68,0x0F,0xCC,0x0E,0x05,0xF5,0xE0,0xF1,0x51,0xEC,0xAE]], - [[0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAF,0xB0,0xB1,0xB2,0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,0xC5,0xC6],[0xEE,0x99,0x32,0xB3,0x72,0x18,0x04,0xD5,0xA8,0x3E,0xF5,0x94,0x92,0x45,0xB6,0xF6],[0xF5,0xD6,0xFF,0x41,0x4F,0xD2,0xC6,0x18,0x14,0x94,0xD2,0x0C,0x37,0xF2,0xB8,0xC4]], - [[0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,0xCF,0xD0,0xD2,0xD3,0xD4,0xD5,0xD7,0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEB,0xEC,0xED,0xEE],[0xE6,0x24,0x8F,0x55,0xC5,0xFD,0xCB,0xCA,0x9C,0xBB,0xB0,0x1C,0x88,0xA2,0xEA,0x77],[0x85,0x39,0x9C,0x01,0xF5,0x9F,0xFF,0xB5,0x20,0x4F,0x19,0xF8,0x48,0x2F,0x00,0xB8]], - [[0xF0,0xF1,0xF2,0xF3,0xF5,0xF6,0xF7,0xF8,0xFA,0xFB,0xFC,0xFD,0xFE,0x01,0x00,0x02,0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16],[0xB8,0x35,0x8E,0x41,0xB9,0xDF,0xF6,0x5F,0xD4,0x61,0xD5,0x5A,0x99,0x26,0x62,0x47],[0x92,0x09,0x7B,0x4C,0x88,0xA0,0x41,0xDD,0xF9,0x81,0x44,0xBC,0x8D,0x22,0xE8,0xE7]], - [[0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20,0x22,0x23,0x24,0x25,0x27,0x28,0x29,0x2A,0x2C,0x2D,0x2E,0x2F,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3B,0x3C,0x3D,0x3E],[0xF0,0xE2,0xD7,0x22,0x60,0xAF,0x58,0xE2,0x1E,0x01,0x5A,0xB3,0xA4,0xC0,0xD9,0x06],[0x89,0xBD,0x5B,0x73,0xB3,0x56,0xAB,0x41,0x2A,0xEF,0x9F,0x76,0xCE,0xA2,0xD6,0x5C]], - [[0x40,0x41,0x42,0x43,0x45,0x46,0x47,0x48,0x4A,0x4B,0x4C,0x4D,0x4F,0x50,0x51,0x52,0x54,0x55,0x56,0x57,0x59,0x5A,0x5B,0x5C,0x5E,0x5F,0x60,0x61,0x63,0x64,0x65,0x66],[0x47,0x5B,0x8B,0x82,0x3C,0xE8,0x89,0x3D,0xB3,0xC4,0x4A,0x9F,0x2A,0x37,0x9F,0xF7],[0x25,0x36,0x96,0x90,0x93,0xC5,0x5F,0xF9,0x45,0x46,0x92,0xF2,0xFA,0xC2,0xF5,0x30]], - [[0x68,0x69,0x6A,0x6B,0x6D,0x6E,0x6F,0x70,0x72,0x73,0x74,0x75,0x77,0x78,0x79,0x7A,0x7C,0x7D,0x7E,0x7F,0x81,0x82,0x83,0x84,0x86,0x87,0x88,0x89,0x8B,0x8C,0x8D,0x8E],[0x68,0x8F,0x52,0x81,0x94,0x58,0x12,0x86,0x2F,0x5F,0x30,0x76,0xCF,0x80,0x41,0x2F],[0x07,0xFC,0x76,0xA8,0x72,0x84,0x3F,0x3F,0x6E,0x00,0x81,0xEE,0x93,0x96,0xD6,0x37]], - [[0x90,0x91,0x92,0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,0x9D,0x9F,0xA0,0xA1,0xA2,0xA4,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,0xB1,0xB3,0xB4,0xB5,0xB6],[0x08,0xD1,0xD2,0xBC,0x75,0x0A,0xF5,0x53,0x36,0x5D,0x35,0xE7,0x5A,0xFA,0xCE,0xAA],[0xE3,0x8B,0xA8,0xEC,0x2A,0xA7,0x41,0x35,0x8D,0xCC,0x93,0xE8,0xF1,0x41,0xC4,0x91]], - [[0xB8,0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,0xC5,0xC7,0xC8,0xC9,0xCA,0xCC,0xCD,0xCE,0xCF,0xD1,0xD2,0xD3,0xD4,0xD6,0xD7,0xD8,0xD9,0xDB,0xDC,0xDD,0xDE],[0x87,0x07,0x12,0x1F,0x47,0xCC,0x3E,0xFC,0xEC,0xA5,0xF9,0xA8,0x47,0x49,0x50,0xA1],[0xD0,0x28,0xEE,0x23,0xE4,0xA8,0x90,0x75,0xD0,0xB0,0x3E,0x86,0x8D,0x7D,0x3A,0x42]], - [[0xE0,0xE1,0xE2,0xE3,0xE5,0xE6,0xE7,0xE8,0xEA,0xEB,0xEC,0xED,0xEF,0xF0,0xF1,0xF2,0xF4,0xF5,0xF6,0xF7,0xF9,0xFA,0xFB,0xFC,0xFE,0xFE,0x01,0x01,0x03,0x04,0x05,0x06],[0xE5,0x1A,0xA0,0xB1,0x35,0xDB,0xA5,0x66,0x93,0x9C,0x3B,0x63,0x59,0xA9,0x80,0xC5],[0x8C,0xD9,0x42,0x3D,0xFC,0x45,0x9E,0x54,0x71,0x55,0xC5,0xD1,0xD5,0x22,0xE5,0x40]], - [[0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A,0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E],[0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21],[0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71,0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3]], - [[0x30,0x31,0x32,0x33,0x35,0x36,0x37,0x38,0x3A,0x3B,0x3C,0x3D,0x3F,0x40,0x41,0x42,0x44,0x45,0x46,0x47,0x49,0x4A,0x4B,0x4C,0x4E,0x4F,0x50,0x51,0x53,0x54,0x55,0x56],[0x72,0x61,0x65,0xC1,0x72,0x3F,0xBC,0xF6,0xC0,0x26,0xD7,0xD0,0x0B,0x09,0x10,0x27],[0x7C,0x17,0x00,0x21,0x1A,0x39,0x91,0xFC,0x0E,0xCD,0xED,0x0A,0xB3,0xE5,0x76,0xB0]]]; - - var res = true; - var j = 0; - for (var i = 0; i < testvectors128.length; i++) { - var res2 = test_aes(testvectors128[i][1],testvectors128[i][0],testvectors128[i][2]); - res &= res2; - if (!res2) { - result[j] = new test_result("Testing 128 bit key vector with block "+ - util.hexidump(testvectors128[i][1])+ - " and key "+util.hexidump(testvectors128[i][0])+ - " should be "+util.hexidump(testvectors128[i][2]), - false); - j++; - } - } - if (res) { - result[j] = new test_result("128 bit key test vectors completed.",true) - j++; - } - - res = true; - for (var i = 0; i < testvectors192.length; i++) { - var res2 = test_aes(testvectors192[i][1],testvectors192[i][0],testvectors192[i][2]); - res &= res2; - if (!res2) { - result[j] = new test_result("Testing 192 bit key vector with block "+ - util.hexidump(testvectors192[i][1])+ - " and key "+util.hexidump(testvectors192[i][0])+ - " should be "+util.hexidump(testvectors192[i][2]), - false); - j++; - } - } - if (res) { - result[j] = new test_result("192 bit key test vectors completed.",true) - j++; - } - - res = true; - for (var i = 0; i < testvectors256.length; i++) { - var res2 = test_aes(testvectors256[i][1],testvectors256[i][0],testvectors256[i][2]); - res &= res2; - if (!res2) { - result[j] = new test_result("Testing 256 bit key vector with block "+ - util.hexidump(testvectors256[i][1])+ - " and key "+util.hexidump(testvectors256[i][0])+ - " should be "+util.hexidump(testvectors256[i][2]), - false); - j++; - } - } - if (res) { - result[j] = new test_result("256 bit key test vectors completed.", true) - j++; - } - - return result; -}); diff --git a/test/ciphers/symmetric/blowfish.js b/test/ciphers/symmetric/blowfish.js deleted file mode 100644 index c7e89b26..00000000 --- a/test/ciphers/symmetric/blowfish.js +++ /dev/null @@ -1,59 +0,0 @@ - -unittests.register("Blowfish cipher test with test vectors from http://www.schneier.com/code/vectors.txt", function() { - var result = new Array(); - function test_bf(input, key, output) { - return (util.hexstrdump(util.bin2str(BFencrypt(input,util.bin2str(key)))) == util.hexstrdump(util.bin2str(output))); - }; - var testvectors = [[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x4E,0xF9,0x97,0x45,0x61,0x98,0xDD,0x78]], - [[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x51,0x86,0x6F,0xD5,0xB8,0x5E,0xCB,0x8A]], - [[0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01],[0x7D,0x85,0x6F,0x9A,0x61,0x30,0x63,0xF2]], - [[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x24,0x66,0xDD,0x87,0x8B,0x96,0x3C,0x9D]], - [[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x61,0xF9,0xC3,0x80,0x22,0x81,0xB0,0x96]], - [[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x7D,0x0C,0xC6,0x30,0xAF,0xDA,0x1E,0xC7]], - [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x4E,0xF9,0x97,0x45,0x61,0x98,0xDD,0x78]], - [[0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x0A,0xCE,0xAB,0x0F,0xC6,0xA0,0xA2,0x8D]], - [[0x7C,0xA1,0x10,0x45,0x4A,0x1A,0x6E,0x57],[0x01,0xA1,0xD6,0xD0,0x39,0x77,0x67,0x42],[0x59,0xC6,0x82,0x45,0xEB,0x05,0x28,0x2B]], - [[0x01,0x31,0xD9,0x61,0x9D,0xC1,0x37,0x6E],[0x5C,0xD5,0x4C,0xA8,0x3D,0xEF,0x57,0xDA],[0xB1,0xB8,0xCC,0x0B,0x25,0x0F,0x09,0xA0]], - [[0x07,0xA1,0x13,0x3E,0x4A,0x0B,0x26,0x86],[0x02,0x48,0xD4,0x38,0x06,0xF6,0x71,0x72],[0x17,0x30,0xE5,0x77,0x8B,0xEA,0x1D,0xA4]], - [[0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E],[0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A],[0xA2,0x5E,0x78,0x56,0xCF,0x26,0x51,0xEB]], - [[0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6],[0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2],[0x35,0x38,0x82,0xB1,0x09,0xCE,0x8F,0x1A]], - [[0x01,0x13,0xB9,0x70,0xFD,0x34,0xF2,0xCE],[0x05,0x9B,0x5E,0x08,0x51,0xCF,0x14,0x3A],[0x48,0xF4,0xD0,0x88,0x4C,0x37,0x99,0x18]], - [[0x01,0x70,0xF1,0x75,0x46,0x8F,0xB5,0xE6],[0x07,0x56,0xD8,0xE0,0x77,0x47,0x61,0xD2],[0x43,0x21,0x93,0xB7,0x89,0x51,0xFC,0x98]], - [[0x43,0x29,0x7F,0xAD,0x38,0xE3,0x73,0xFE],[0x76,0x25,0x14,0xB8,0x29,0xBF,0x48,0x6A],[0x13,0xF0,0x41,0x54,0xD6,0x9D,0x1A,0xE5]], - [[0x07,0xA7,0x13,0x70,0x45,0xDA,0x2A,0x16],[0x3B,0xDD,0x11,0x90,0x49,0x37,0x28,0x02],[0x2E,0xED,0xDA,0x93,0xFF,0xD3,0x9C,0x79]], - [[0x04,0x68,0x91,0x04,0xC2,0xFD,0x3B,0x2F],[0x26,0x95,0x5F,0x68,0x35,0xAF,0x60,0x9A],[0xD8,0x87,0xE0,0x39,0x3C,0x2D,0xA6,0xE3]], - [[0x37,0xD0,0x6B,0xB5,0x16,0xCB,0x75,0x46],[0x16,0x4D,0x5E,0x40,0x4F,0x27,0x52,0x32],[0x5F,0x99,0xD0,0x4F,0x5B,0x16,0x39,0x69]], - [[0x1F,0x08,0x26,0x0D,0x1A,0xC2,0x46,0x5E],[0x6B,0x05,0x6E,0x18,0x75,0x9F,0x5C,0xCA],[0x4A,0x05,0x7A,0x3B,0x24,0xD3,0x97,0x7B]], - [[0x58,0x40,0x23,0x64,0x1A,0xBA,0x61,0x76],[0x00,0x4B,0xD6,0xEF,0x09,0x17,0x60,0x62],[0x45,0x20,0x31,0xC1,0xE4,0xFA,0xDA,0x8E]], - [[0x02,0x58,0x16,0x16,0x46,0x29,0xB0,0x07],[0x48,0x0D,0x39,0x00,0x6E,0xE7,0x62,0xF2],[0x75,0x55,0xAE,0x39,0xF5,0x9B,0x87,0xBD]], - [[0x49,0x79,0x3E,0xBC,0x79,0xB3,0x25,0x8F],[0x43,0x75,0x40,0xC8,0x69,0x8F,0x3C,0xFA],[0x53,0xC5,0x5F,0x9C,0xB4,0x9F,0xC0,0x19]], - [[0x4F,0xB0,0x5E,0x15,0x15,0xAB,0x73,0xA7],[0x07,0x2D,0x43,0xA0,0x77,0x07,0x52,0x92],[0x7A,0x8E,0x7B,0xFA,0x93,0x7E,0x89,0xA3]], - [[0x49,0xE9,0x5D,0x6D,0x4C,0xA2,0x29,0xBF],[0x02,0xFE,0x55,0x77,0x81,0x17,0xF1,0x2A],[0xCF,0x9C,0x5D,0x7A,0x49,0x86,0xAD,0xB5]], - [[0x01,0x83,0x10,0xDC,0x40,0x9B,0x26,0xD6],[0x1D,0x9D,0x5C,0x50,0x18,0xF7,0x28,0xC2],[0xD1,0xAB,0xB2,0x90,0x65,0x8B,0xC7,0x78]], - [[0x1C,0x58,0x7F,0x1C,0x13,0x92,0x4F,0xEF],[0x30,0x55,0x32,0x28,0x6D,0x6F,0x29,0x5A],[0x55,0xCB,0x37,0x74,0xD1,0x3E,0xF2,0x01]], - [[0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0xFA,0x34,0xEC,0x48,0x47,0xB2,0x68,0xB2]], - [[0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0xA7,0x90,0x79,0x51,0x08,0xEA,0x3C,0xAE]], - [[0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0xC3,0x9E,0x07,0x2D,0x9F,0xAC,0x63,0x1D]], - [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x01,0x49,0x33,0xE0,0xCD,0xAF,0xF6,0xE4]], - [[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xF2,0x1E,0x9A,0x77,0xB7,0x1C,0x49,0xBC]], - [[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x24,0x59,0x46,0x88,0x57,0x54,0x36,0x9A]], - [[0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10],[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x6B,0x5C,0x5A,0x9C,0x5D,0x9E,0x0A,0x5A]]]; - - var res = true; - var j = 0; - for (var i = 0; i < testvectors.length; i++) { - var res2 = test_bf(testvectors[i][1],testvectors[i][0],testvectors[i][2]); - res &= res2; - if (!res2) { - result[j] = new test_result("Testing vector "+i+" with block "+ - util.hexidump(testvectors[i][0])+ - " and key "+util.hexidump(testvectors[i][1])+ - " should be "+util.hexidump(testvectors[i][2]), false); - j++; - } - } - if (res) { - result[j] = new test_result("34 test vectors completed ", true); - } - return result; -}); diff --git a/test/ciphers/symmetric/twofish.js b/test/ciphers/symmetric/twofish.js deleted file mode 100644 index f1468a90..00000000 --- a/test/ciphers/symmetric/twofish.js +++ /dev/null @@ -1,57 +0,0 @@ - -unittests.register("Twofish test with test vectors from http://www.schneier.com/code/ecb_ival.txt", function() { - var result = new Array(); - var start = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; - var start_short = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; - var testvectors = [[0x57,0xFF,0x73,0x9D,0x4D,0xC9,0x2C,0x1B,0xD7,0xFC,0x01,0x70,0x0C,0xC8,0x21,0x6F], - [0xD4,0x3B,0xB7,0x55,0x6E,0xA3,0x2E,0x46,0xF2,0xA2,0x82,0xB7,0xD4,0x5B,0x4E,0x0D], - [0x90,0xAF,0xE9,0x1B,0xB2,0x88,0x54,0x4F,0x2C,0x32,0xDC,0x23,0x9B,0x26,0x35,0xE6], - [0x6C,0xB4,0x56,0x1C,0x40,0xBF,0x0A,0x97,0x05,0x93,0x1C,0xB6,0xD4,0x08,0xE7,0xFA], - [0x30,0x59,0xD6,0xD6,0x17,0x53,0xB9,0x58,0xD9,0x2F,0x47,0x81,0xC8,0x64,0x0E,0x58], - [0xE6,0x94,0x65,0x77,0x05,0x05,0xD7,0xF8,0x0E,0xF6,0x8C,0xA3,0x8A,0xB3,0xA3,0xD6], - [0x5A,0xB6,0x7A,0x5F,0x85,0x39,0xA4,0xA5,0xFD,0x9F,0x03,0x73,0xBA,0x46,0x34,0x66], - [0xDC,0x09,0x6B,0xCD,0x99,0xFC,0x72,0xF7,0x99,0x36,0xD4,0xC7,0x48,0xE7,0x5A,0xF7], - [0xC5,0xA3,0xE7,0xCE,0xE0,0xF1,0xB7,0x26,0x05,0x28,0xA6,0x8F,0xB4,0xEA,0x05,0xF2], - [0x43,0xD5,0xCE,0xC3,0x27,0xB2,0x4A,0xB9,0x0A,0xD3,0x4A,0x79,0xD0,0x46,0x91,0x51]]; - testvectors[47] = [0x43,0x10,0x58,0xF4,0xDB,0xC7,0xF7,0x34,0xDA,0x4F,0x02,0xF0,0x4C,0xC4,0xF4,0x59]; - testvectors[48] = [0x37,0xFE,0x26,0xFF,0x1C,0xF6,0x61,0x75,0xF5,0xDD,0xF4,0xC3,0x3B,0x97,0xA2,0x05]; - var res = true; - var j = 0; - for (var i = 0; i < 49; i++) { - var res2 = false; - var blk, key, ct; - if (i == 0) { - blk = start_short; - key = util.bin2str(start); - ct = testvectors[0]; - res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); - } else if (i == 1) { - blk = testvectors[0]; - key = util.bin2str(start); - ct = testvectors[1]; - res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); - } else if (i == 2) { - blk = testvectors[i-1]; - key = util.bin2str(testvectors[i-2].concat(start_short)); - ct = testvectors[i]; - res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); - } else if (i < 10 || i > 46) { - blk = testvectors[i-1]; - key = util.bin2str(testvectors[i-2].concat(testvectors[i-3])); - ct = testvectors[i]; - res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); - } else { - testvectors[i] = TFencrypt(testvectors[i-1],util.bin2str(testvectors[i-2].concat(testvectors[i-3]))); - res2 = true; - } - res &= res2; - if (!res2) { - result[j] = new test_result("Testing vector with block "+util.hexidump(blk)+" with key "+ util.hexstrdump(key) +" should be "+util.hexidump(ct)+" but is "+util.hexidump(TFencrypt(blk,key)), false); - j++; - } - } - if (res) { - result[j] = new test_result("49 test vectors completed", true); - } - return result; -}); diff --git a/test/coverage.html b/test/coverage.html deleted file mode 100644 index 092c28f1..00000000 --- a/test/coverage.html +++ /dev/null @@ -1,696 +0,0 @@ - - - - -OpenPGP.js testpage - - - - - -Unit Tests | Parser | Encryption / Decryption | Coverage - -
      -
      -

      JSCoverage (just a preview)

      - - - -
      - -
      -

      -Recent web browsers tend to place significant security restrictions on the use -of file: URLs. These restrictions can prevent JSCoverage from -working properly. To avoid problems, it is recommended that you do either of the -following: -

      -
        -
      • If you are using the jscoverage program to instrument your -JavaScript code, install the instrumented files on a web server.
      • -
      • Use the jscoverage-server program (which itself acts as a web -server).
      • -
      -

      -See the -manual -for further details. -

      - -
      - -
      -

      -Recent web browsers tend to place significant security restrictions on the use -of file: URLs. These restrictions can prevent JSCoverage from -working properly. To avoid problems, it is recommended that you view coverage -reports stored to the filesystem by serving them from a web server. -

      -

      -See the -manual -for further details. -

      - -
      - -
      -
      Browser
      -
      Summary
      -
      Source
      - -
      About
      -
      -
      -
      -
      - URL: - - -
      -
      - -
      -
      -
      - -
      -
      - - - - - - - - - - - - - - - - - -
      FileStatementsExecutedCoverage
      - Total: - 53 - 52092489 -
      -
      -
      - 47% -
      resources/jquery.min.js33
      100%
      src/ciphers/asymmetric/dsa.js3823
      60%
      src/ciphers/asymmetric/elgamal.js1616
      100%
      src/ciphers/asymmetric/jsbn.js375316
      84%
      src/ciphers/asymmetric/jsbn2.js452264
      58%
      src/ciphers/asymmetric/rsa.js2219
      86%
      src/ciphers/hash/md5.js259256
      98%
      src/ciphers/hash/ripe-md.js134121
      90%
      src/ciphers/hash/sha.js312226
      72%
      src/ciphers/openpgp.cfb.js10156
      55%
      src/ciphers/openpgp.crypto.js191120
      62%
      src/ciphers/symmetric/aes.js110108
      98%
      src/ciphers/symmetric/blowfish.js10087
      87%
      src/ciphers/symmetric/cast5.js179146
      81%
      src/ciphers/symmetric/dessrc.js107103
      96%
      src/ciphers/symmetric/twofish.js182161
      88%
      src/config/openpgp.config.js1514
      93%
      src/encoding/base64.js493
      6%
      src/encoding/openpgp.encoding.asciiarmor.js1016
      5%
      src/encoding/openpgp.encoding.js6053
      88%
      src/openpgp.js16321
      12%
      src/openpgp.keyring.js10036
      36%
      src/openpgp.msg.message.js731
      1%
      src/openpgp.msg.privatekey.js801
      1%
      src/openpgp.msg.publickey.js1501
      0%
      src/packet/openpgp.packet.compressed.js572
      3%
      src/packet/openpgp.packet.encrypteddata.js262
      7%
      src/packet/openpgp.packet.encryptedintegrityprotecteddata.js442
      4%
      src/packet/openpgp.packet.encryptedsessionkey.js812
      2%
      src/packet/openpgp.packet.js21510
      4%
      src/packet/openpgp.packet.keymaterial.js3331
      0%
      src/packet/openpgp.packet.literaldata.js301
      3%
      src/packet/openpgp.packet.marker.js111
      9%
      src/packet/openpgp.packet.modificationdetectioncode.js152
      13%
      src/packet/openpgp.packet.onepasssignature.js382
      5%
      src/packet/openpgp.packet.signature.js3501
      0%
      src/packet/openpgp.packet.userattribute.js712
      2%
      src/packet/openpgp.packet.userid.js1581
      0%
      src/type/openpgp.type.keyid.js92
      22%
      src/type/openpgp.type.mpi.js4336
      83%
      src/type/openpgp.type.s2k.js391
      2%
      src/util/util.js9246
      50%
      test/ciphers/hash/md5.js99
      100%
      test/ciphers/hash/ripe-md.js77
      100%
      test/ciphers/hash/sha.js1313
      100%
      test/ciphers/openpgp.crypto.js6060
      100%
      test/ciphers/symmetric/aes.js4034
      85%
      test/ciphers/symmetric/blowfish.js1715
      88%
      test/ciphers/symmetric/cast5.js99
      100%
      test/ciphers/symmetric/des.js1514
      93%
      test/ciphers/symmetric/twofish.js4139
      95%
      test/example-test.js55
      100%
      test/unittest.js99
      100%
      -
      -
      -
      -
      src/openpgp.keyring.js
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      1
      // GPG4Browsers - An OpenPGP implementation in javascript
      2
      // Copyright (C) 2011 Recurity Labs GmbH
      3
      // 
      4
      // This library is free software; you can redistribute it and/or
      5
      // modify it under the terms of the GNU Lesser General Public
      6
      // License as published by the Free Software Foundation; either
      7
      // version 2.1 of the License, or (at your option) any later version.
      8
      // 
      9
      // This library is distributed in the hope that it will be useful,
      10
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12
      // Lesser General Public License for more details.
      13
      // 
      14
      // You should have received a copy of the GNU Lesser General Public
      15
      // License along with this library; if not, write to the Free Software
      16
      // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      17
      181
      function openpgp_keyring() {
      19
      		
      20
      	/**
      21
      	 * Initialization routine for the keyring. This method reads the 
      22
      	 * keyring from HTML5 local storage and initializes this instance.
      23
      	 * This method is called by openpgp.init().
      24
      	 * @return [null] undefined
      25
      	 */
      261
      	function init() {
      271
      		var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys"));
      281
      		var spublickeys = JSON.parse(window.localStorage.getItem("publickeys"));
      291
      		if (sprivatekeys == null || sprivatekeys.length == 0) {
      301
      			sprivatekeys = new Array();
      31
      		}
      32
      331
      		if (spublickeys == null || spublickeys.length == 0) {
      341
      			spublickeys = new Array();
      35
      		}
      361
      		this.publicKeys = new Array();
      371
      		this.privateKeys = new Array();
      381
      		var k = 0;
      391
      		for (var i =0; i < sprivatekeys.length; i++) {
      400
      			var r = openpgp.read_privateKey(sprivatekeys[i]);
      410
      			this.privateKeys[k] = { armored: sprivatekeys[i], obj: r[0], keyId: r[0].getKeyId()};
      420
      			k++;
      43
      		}
      441
      		k = 0;
      451
      		for (var i =0; i < spublickeys.length; i++) {
      460
      			var r = openpgp.read_publicKey(spublickeys[i]);
      470
      			if (r[0] != null) {
      480
      				this.publicKeys[k] = { armored: spublickeys[i], obj: r[0], keyId: r[0].getKeyId()};
      490
      				k++;
      50
      			}
      51
      		}
      52
      	}
      531
      	this.init = init;
      54
      55
      	/**
      56
      	 * Checks if at least one private key is in the keyring
      57
      	 * @return
      58
      	 */
      591
      	function hasPrivateKey() {
      600
      		return this.privateKeys.length > 0;
      61
      	}
      621
      	this.hasPrivateKey = hasPrivateKey;
      63
      64
      	/**
      65
      	 * Saves the current state of the keyring to HTML5 local storage.
      66
      	 * The privateKeys array and publicKeys array gets Stringified using JSON
      67
      	 * @return [null] undefined
      68
      	 */
      691
      	function store() { 
      700
      		var priv = new Array();
      710
      		for (var i = 0; i < this.privateKeys.length; i++) {
      720
      			priv[i] = this.privateKeys[i].armored;
      73
      		}
      740
      		var pub = new Array();
      750
      		for (var i = 0; i < this.publicKeys.length; i++) {
      760
      			pub[i] = this.publicKeys[i].armored;
      77
      		}
      780
      		window.localStorage.setItem("privatekeys",JSON.stringify(priv));
      790
      		window.localStorage.setItem("publickeys",JSON.stringify(pub));
      80
      	}
      811
      	this.store = store;
      82
      	/**
      83
      	 * searches all public keys in the keyring matching the address or address part of the user ids
      84
      	 * @param email_address
      85
      	 * @return
      86
      	 */
      871
      	function getPublicKeyForAddress(email_address) {
      880
      		var results = new Array();
      890
      		var spl = string.split("<");
      900
      		var email = "";
      910
      		if (spl.length > 0) {
      920
      			email = spl[1].split(">")[0];
      93
      		} else {
      940
      			email = string.trim();
      95
      		}
      960
      		for (var i =0; i < this.publicKeys.length; i++) {
      97
      			
      980
      			for (var j = 0; j < this.publicKeys[i].userIds; j++) {
      990
      				if (this.publicKeys[i].userIds[j].indexOf(email) >= 0)
      1000
      					results[results.length] = this.publicKeys[i];
      101
      			}
      102
      		}
      1030
      		return result;
      104
      	}
      105
      106
      	/**
      107
      	 * Searches the keyring for a private key containing the specified email address
      108
      	 * @param email_address [String] email address to search for
      109
      	 * @return [Array[openpgp_msg_privatekey] private keys found
      110
      	 */
      1111
      	function getPrivateKeyForAddress(email_address) {
      1120
      		var results = new Array();
      1130
      		var spl = email_address.split("<");
      1140
      		var email = "";
      1150
      		if (spl.length > 1) {
      1160
      			email = spl[1].split(">")[0];
      117
      		} else {
      1180
      			email = email_address.trim();
      119
      		}
      1200
      		for (var i =0; i < this.privateKeys.length; i++) {
      121
      			
      1220
      			for (var j = 0; j < this.privateKeys[i].obj.userIds.length; j++) {
      1230
      				if (this.privateKeys[i].obj.userIds[j].text.indexOf(email) >= 0)
      1240
      					results[results.length] = this.privateKeys[i];
      125
      			}
      126
      		}
      1270
      		return results;
      128
      	}
      129
      1301
      	this.getPrivateKeyForAddress = getPrivateKeyForAddress;
      131
      	/**
      132
      	 * Searches the keyring for public keys having the specified key id
      133
      	 * @param keyId provided as string of hex number (lowercase)
      134
      	 * @return Array[openpgp_msg_privatekey] public keys found
      135
      	 */
      1361
      	function getPublicKeysForKeyId(keyId) {
      1370
      		var result = new Array();
      1380
      		for (var i=0; i < this.publicKeys.length; i++)
      1390
      			if (keyId == this.publicKeys[i].obj.getKeyId())
      1400
      				result[result.length] = this.publicKeys[i];
      1410
      		return result;
      142
      	}
      1431
      	this.getPublicKeysForKeyId = getPublicKeysForKeyId;
      144
      	
      145
      	/**
      146
      	 * Searches the keyring for private keys having the specified key id
      147
      	 * @param keyId [String] 8 bytes as string containing the key id to look for
      148
      	 * @return Array[openpgp_msg_privatekey] private keys found
      149
      	 */
      1501
      	function getPrivateKeyForKeyId(keyId) {
      1510
      		var result = new Array();
      1520
      		for (var i=0; i < this.privateKeys.length; i++) {
      1530
      			if (keyId == util.hexstrdump(this.privateKeys[i].obj.getKeyId())) {
      1540
      				result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.privateKeyPacket};
      155
      			}
      1560
      			if (this.privateKeys[i].obj.subKeys != null) {
      1570
      				var subkeyids = this.privateKeys[i].obj.getSubKeyIds();
      1580
      				for (var j=0; j < subkeyids.length; j++)
      1590
      					if (keyId == util.hexstrdump(subkeyids[j])) {
      1600
      						result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.subKeys[j]};
      161
      					}
      162
      			}
      163
      		}
      1640
      		return result;
      165
      	}
      1661
      	this.getPrivateKeyForKeyId = getPrivateKeyForKeyId;
      167
      	
      168
      	/**
      169
      	 * Imports a public key from an exported ascii armored message 
      170
      	 * @param armored_text [String] PUBLIC KEY BLOCK message to read the public key from
      171
      	 * @return [null] nothing
      172
      	 */
      1731
      	function importPublicKey (armored_text) {
      1740
      		var result = openpgp.read_publicKey(armored_text);
      1750
      		for (var i = 0; i < result.length; i++) {
      1760
      			this.publicKeys[this.publicKeys.length] = {armored: armored_text, obj: result[i]};
      177
      		}
      178
      	}
      179
      180
      	/**
      181
      	 * Imports a private key from an exported ascii armored message 
      182
      	 * @param armored_text [String] PRIVATE KEY BLOCK message to read the private key from
      183
      	 * @return [null] nothing
      184
      	 */
      1851
      	function importPrivateKey (armored_text) {
      1860
      		var result = openpgp.read_privateKey(armored_text);
      1870
      		for (var i = 0; i < result.length; i++) {
      1880
      			this.privateKeys[this.privateKeys.length] = {armored: armored_text, obj: result[i]};
      189
      		}
      190
      	}
      191
      1921
      	this.importPublicKey = importPublicKey;
      1931
      	this.importPrivateKey = importPrivateKey;
      194
      	
      195
      	/**
      196
      	 * returns the PUBLIC KEY BLOCK message representation of the public key at public key ring index  
      197
      	 * @param index [Integer] the index of the public key within the publicKeys array
      198
      	 * @return [String] the PUBLIC KEY BLOCK message
      199
      	 */
      2001
      	function exportPublicKey(index) {
      2010
      		return this.publicKey[index];
      202
      	}
      2031
      	this.exportPublicKey = exportPublicKey;
      204
      		
      205
      	
      206
      	/**
      207
      	 * Removes a public key from the public key keyring at the specified index 
      208
      	 * @param index [Integer] the index of the public key within the publicKeys array
      209
      	 * @return [String The public key object which has been removed
      210
      	 */
      2111
      	function removePublicKey(index) {
      2120
      		var removed = this.publicKeys.splice(index,1);
      2130
      		this.store();
      2140
      		return removed;
      215
      	}
      2161
      	this.removePublicKey = removePublicKey;
      217
      218
      	/**
      219
      	 * returns the PRIVATE KEY BLOCK message representation of the private key at private key ring index  
      220
      	 * @param index [Integer] the index of the private key within the privateKeys array
      221
      	 * @return [String] the PRIVATE KEY BLOCK message
      222
      	 */	
      2231
      	function exportPrivateKey(index) {
      2240
      		return this.privateKeys[index];
      225
      	}
      2261
      	this.exportPrivateKey = exportPrivateKey;
      227
      }
      -
      - -
      -

      - This is version 0.5.1 of JSCoverage, a program that calculates code - coverage statistics for JavaScript. -

      -

      - See http://siliconforks.com/jscoverage/ for more information. -

      -

      - Copyright © 2007, 2008, 2009, 2010 siliconforks.com -

      -
      -
      -
      - - diff --git a/test/crypto/cipher/aes.js b/test/crypto/cipher/aes.js new file mode 100644 index 00000000..f1089fe7 --- /dev/null +++ b/test/crypto/cipher/aes.js @@ -0,0 +1,121 @@ +var unit = require('../../unit.js'); + +unit.register("AES Rijndael cipher test with test vectors from ecb_tbl.txt", function() { + var openpgp = require('openpgp'); + var util = openpgp.util; + + var result = new Array(); + + function test_aes(input, key, output) { + var aes = new openpgp.crypto.cipher.aes128(util.bin2str(key)); + + var result = util.bin2str(aes.encrypt(input)); + + return util.hexstrdump(result) == util.hexstrdump(util.bin2str(output)); + }; + + var testvectors128 = [[[0x00,0x01,0x02,0x03,0x05,0x06,0x07,0x08,0x0A,0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x12],[0x50,0x68,0x12,0xA4,0x5F,0x08,0xC8,0x89,0xB9,0x7F,0x59,0x80,0x03,0x8B,0x83,0x59],[0xD8,0xF5,0x32,0x53,0x82,0x89,0xEF,0x7D,0x06,0xB5,0x06,0xA4,0xFD,0x5B,0xE9,0xC9]], + [[0x14,0x15,0x16,0x17,0x19,0x1A,0x1B,0x1C,0x1E,0x1F,0x20,0x21,0x23,0x24,0x25,0x26],[0x5C,0x6D,0x71,0xCA,0x30,0xDE,0x8B,0x8B,0x00,0x54,0x99,0x84,0xD2,0xEC,0x7D,0x4B],[0x59,0xAB,0x30,0xF4,0xD4,0xEE,0x6E,0x4F,0xF9,0x90,0x7E,0xF6,0x5B,0x1F,0xB6,0x8C]], + [[0x28,0x29,0x2A,0x2B,0x2D,0x2E,0x2F,0x30,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3A],[0x53,0xF3,0xF4,0xC6,0x4F,0x86,0x16,0xE4,0xE7,0xC5,0x61,0x99,0xF4,0x8F,0x21,0xF6],[0xBF,0x1E,0xD2,0xFC,0xB2,0xAF,0x3F,0xD4,0x14,0x43,0xB5,0x6D,0x85,0x02,0x5C,0xB1]], + [[0x3C,0x3D,0x3E,0x3F,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0x49,0x4B,0x4C,0x4D,0x4E],[0xA1,0xEB,0x65,0xA3,0x48,0x71,0x65,0xFB,0x0F,0x1C,0x27,0xFF,0x99,0x59,0xF7,0x03],[0x73,0x16,0x63,0x2D,0x5C,0x32,0x23,0x3E,0xDC,0xB0,0x78,0x05,0x60,0xEA,0xE8,0xB2]], + [[0x50,0x51,0x52,0x53,0x55,0x56,0x57,0x58,0x5A,0x5B,0x5C,0x5D,0x5F,0x60,0x61,0x62],[0x35,0x53,0xEC,0xF0,0xB1,0x73,0x95,0x58,0xB0,0x8E,0x35,0x0A,0x98,0xA3,0x9B,0xFA],[0x40,0x8C,0x07,0x3E,0x3E,0x25,0x38,0x07,0x2B,0x72,0x62,0x5E,0x68,0xB8,0x36,0x4B]], + [[0x64,0x65,0x66,0x67,0x69,0x6A,0x6B,0x6C,0x6E,0x6F,0x70,0x71,0x73,0x74,0x75,0x76],[0x67,0x42,0x99,0x69,0x49,0x0B,0x97,0x11,0xAE,0x2B,0x01,0xDC,0x49,0x7A,0xFD,0xE8],[0xE1,0xF9,0x4D,0xFA,0x77,0x65,0x97,0xBE,0xAC,0xA2,0x62,0xF2,0xF6,0x36,0x6F,0xEA]], + [[0x78,0x79,0x7A,0x7B,0x7D,0x7E,0x7F,0x80,0x82,0x83,0x84,0x85,0x87,0x88,0x89,0x8A],[0x93,0x38,0x5C,0x1F,0x2A,0xEC,0x8B,0xED,0x19,0x2F,0x5A,0x8E,0x16,0x1D,0xD5,0x08],[0xF2,0x9E,0x98,0x6C,0x6A,0x1C,0x27,0xD7,0xB2,0x9F,0xFD,0x7E,0xE9,0x2B,0x75,0xF1]], + [[0x8C,0x8D,0x8E,0x8F,0x91,0x92,0x93,0x94,0x96,0x97,0x98,0x99,0x9B,0x9C,0x9D,0x9E],[0xB5,0xBF,0x94,0x6B,0xE1,0x9B,0xEB,0x8D,0xB3,0x98,0x3B,0x5F,0x4C,0x6E,0x8D,0xDB],[0x13,0x1C,0x88,0x6A,0x57,0xF8,0xC2,0xE7,0x13,0xAB,0xA6,0x95,0x5E,0x2B,0x55,0xB5]], + [[0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAF,0xB0,0xB1,0xB2],[0x41,0x32,0x1E,0xE1,0x0E,0x21,0xBD,0x90,0x72,0x27,0xC4,0x45,0x0F,0xF4,0x23,0x24],[0xD2,0xAB,0x76,0x62,0xDF,0x9B,0x8C,0x74,0x02,0x10,0xE5,0xEE,0xB6,0x1C,0x19,0x9D]], + [[0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,0xC5,0xC6],[0x00,0xA8,0x2F,0x59,0xC9,0x1C,0x84,0x86,0xD1,0x2C,0x0A,0x80,0x12,0x4F,0x60,0x89],[0x14,0xC1,0x05,0x54,0xB2,0x85,0x9C,0x48,0x4C,0xAB,0x58,0x69,0xBB,0xE7,0xC4,0x70]], + [[0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,0xCF,0xD0,0xD2,0xD3,0xD4,0xD5,0xD7,0xD8,0xD9,0xDA],[0x7C,0xE0,0xFD,0x07,0x67,0x54,0x69,0x1B,0x4B,0xBD,0x9F,0xAF,0x8A,0x13,0x72,0xFE],[0xDB,0x4D,0x49,0x8F,0x0A,0x49,0xCF,0x55,0x44,0x5D,0x50,0x2C,0x1F,0x9A,0xB3,0xB5]], + [[0xDC,0xDD,0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEB,0xEC,0xED,0xEE],[0x23,0x60,0x5A,0x82,0x43,0xD0,0x77,0x64,0x54,0x1B,0xC5,0xAD,0x35,0x5B,0x31,0x29],[0x6D,0x96,0xFE,0xF7,0xD6,0x65,0x90,0xA7,0x7A,0x77,0xBB,0x20,0x56,0x66,0x7F,0x7F]], + [[0xF0,0xF1,0xF2,0xF3,0xF5,0xF6,0xF7,0xF8,0xFA,0xFB,0xFC,0xFD,0xFE,0x01,0x00,0x02],[0x12,0xA8,0xCF,0xA2,0x3E,0xA7,0x64,0xFD,0x87,0x62,0x32,0xB4,0xE8,0x42,0xBC,0x44],[0x31,0x6F,0xB6,0x8E,0xDB,0xA7,0x36,0xC5,0x3E,0x78,0x47,0x7B,0xF9,0x13,0x72,0x5C]], + [[0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16],[0xBC,0xAF,0x32,0x41,0x5E,0x83,0x08,0xB3,0x72,0x3E,0x5F,0xDD,0x85,0x3C,0xCC,0x80],[0x69,0x36,0xF2,0xB9,0x3A,0xF8,0x39,0x7F,0xD3,0xA7,0x71,0xFC,0x01,0x1C,0x8C,0x37]], + [[0x2C,0x2D,0x2E,0x2F,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3B,0x3C,0x3D,0x3E],[0x89,0xAF,0xAE,0x68,0x5D,0x80,0x1A,0xD7,0x47,0xAC,0xE9,0x1F,0xC4,0x9A,0xDD,0xE0],[0xF3,0xF9,0x2F,0x7A,0x9C,0x59,0x17,0x9C,0x1F,0xCC,0x2C,0x2B,0xA0,0xB0,0x82,0xCD]]]; + + var testvectors192 = [[[0x00,0x01,0x02,0x03,0x05,0x06,0x07,0x08,0x0A,0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x12,0x14,0x15,0x16,0x17,0x19,0x1A,0x1B,0x1C],[0x2D,0x33,0xEE,0xF2,0xC0,0x43,0x0A,0x8A,0x9E,0xBF,0x45,0xE8,0x09,0xC4,0x0B,0xB6],[0xDF,0xF4,0x94,0x5E,0x03,0x36,0xDF,0x4C,0x1C,0x56,0xBC,0x70,0x0E,0xFF,0x83,0x7F]], + [[0x1E,0x1F,0x20,0x21,0x23,0x24,0x25,0x26,0x28,0x29,0x2A,0x2B,0x2D,0x2E,0x2F,0x30,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3A],[0x6A,0xA3,0x75,0xD1,0xFA,0x15,0x5A,0x61,0xFB,0x72,0x35,0x3E,0x0A,0x5A,0x87,0x56],[0xB6,0xFD,0xDE,0xF4,0x75,0x27,0x65,0xE3,0x47,0xD5,0xD2,0xDC,0x19,0x6D,0x12,0x52]], + [[0x3C,0x3D,0x3E,0x3F,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0x49,0x4B,0x4C,0x4D,0x4E,0x50,0x51,0x52,0x53,0x55,0x56,0x57,0x58],[0xBC,0x37,0x36,0x51,0x8B,0x94,0x90,0xDC,0xB8,0xED,0x60,0xEB,0x26,0x75,0x8E,0xD4],[0xD2,0x36,0x84,0xE3,0xD9,0x63,0xB3,0xAF,0xCF,0x1A,0x11,0x4A,0xCA,0x90,0xCB,0xD6]], + [[0x5A,0x5B,0x5C,0x5D,0x5F,0x60,0x61,0x62,0x64,0x65,0x66,0x67,0x69,0x6A,0x6B,0x6C,0x6E,0x6F,0x70,0x71,0x73,0x74,0x75,0x76],[0xAA,0x21,0x44,0x02,0xB4,0x6C,0xFF,0xB9,0xF7,0x61,0xEC,0x11,0x26,0x3A,0x31,0x1E],[0x3A,0x7A,0xC0,0x27,0x75,0x3E,0x2A,0x18,0xC2,0xCE,0xAB,0x9E,0x17,0xC1,0x1F,0xD0]], + [[0x78,0x79,0x7A,0x7B,0x7D,0x7E,0x7F,0x80,0x82,0x83,0x84,0x85,0x87,0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x8F,0x91,0x92,0x93,0x94],[0x02,0xAE,0xA8,0x6E,0x57,0x2E,0xEA,0xB6,0x6B,0x2C,0x3A,0xF5,0xE9,0xA4,0x6F,0xD6],[0x8F,0x67,0x86,0xBD,0x00,0x75,0x28,0xBA,0x26,0x60,0x3C,0x16,0x01,0xCD,0xD0,0xD8]], + [[0x96,0x97,0x98,0x99,0x9B,0x9C,0x9D,0x9E,0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAF,0xB0,0xB1,0xB2],[0xE2,0xAE,0xF6,0xAC,0xC3,0x3B,0x96,0x5C,0x4F,0xA1,0xF9,0x1C,0x75,0xFF,0x6F,0x36],[0xD1,0x7D,0x07,0x3B,0x01,0xE7,0x15,0x02,0xE2,0x8B,0x47,0xAB,0x55,0x11,0x68,0xB3]], + [[0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,0xC5,0xC6,0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,0xCF,0xD0],[0x06,0x59,0xDF,0x46,0x42,0x71,0x62,0xB9,0x43,0x48,0x65,0xDD,0x94,0x99,0xF9,0x1D],[0xA4,0x69,0xDA,0x51,0x71,0x19,0xFA,0xB9,0x58,0x76,0xF4,0x1D,0x06,0xD4,0x0F,0xFA]], + [[0xD2,0xD3,0xD4,0xD5,0xD7,0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEB,0xEC,0xED,0xEE],[0x49,0xA4,0x42,0x39,0xC7,0x48,0xFE,0xB4,0x56,0xF5,0x9C,0x27,0x6A,0x56,0x58,0xDF],[0x60,0x91,0xAA,0x3B,0x69,0x5C,0x11,0xF5,0xC0,0xB6,0xAD,0x26,0xD3,0xD8,0x62,0xFF]], + [[0xF0,0xF1,0xF2,0xF3,0xF5,0xF6,0xF7,0xF8,0xFA,0xFB,0xFC,0xFD,0xFE,0x01,0x00,0x02,0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C],[0x66,0x20,0x8F,0x6E,0x9D,0x04,0x52,0x5B,0xDE,0xDB,0x27,0x33,0xB6,0xA6,0xBE,0x37],[0x70,0xF9,0xE6,0x7F,0x9F,0x8D,0xF1,0x29,0x41,0x31,0x66,0x2D,0xC6,0xE6,0x93,0x64]], + [[0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16,0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20,0x22,0x23,0x24,0x25,0x27,0x28,0x29,0x2A],[0x33,0x93,0xF8,0xDF,0xC7,0x29,0xC9,0x7F,0x54,0x80,0xB9,0x50,0xBC,0x96,0x66,0xB0],[0xD1,0x54,0xDC,0xAF,0xAD,0x8B,0x20,0x7F,0xA5,0xCB,0xC9,0x5E,0x99,0x96,0xB5,0x59]], + [[0x2C,0x2D,0x2E,0x2F,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3B,0x3C,0x3D,0x3E,0x40,0x41,0x42,0x43,0x45,0x46,0x47,0x48],[0x60,0x68,0x34,0xC8,0xCE,0x06,0x3F,0x32,0x34,0xCF,0x11,0x45,0x32,0x5D,0xBD,0x71],[0x49,0x34,0xD5,0x41,0xE8,0xB4,0x6F,0xA3,0x39,0xC8,0x05,0xA7,0xAE,0xB9,0xE5,0xDA]], + [[0x4A,0x4B,0x4C,0x4D,0x4F,0x50,0x51,0x52,0x54,0x55,0x56,0x57,0x59,0x5A,0x5B,0x5C,0x5E,0x5F,0x60,0x61,0x63,0x64,0x65,0x66],[0xFE,0xC1,0xC0,0x4F,0x52,0x9B,0xBD,0x17,0xD8,0xCE,0xCF,0xCC,0x47,0x18,0xB1,0x7F],[0x62,0x56,0x4C,0x73,0x8F,0x3E,0xFE,0x18,0x6E,0x1A,0x12,0x7A,0x0C,0x4D,0x3C,0x61]], + [[0x68,0x69,0x6A,0x6B,0x6D,0x6E,0x6F,0x70,0x72,0x73,0x74,0x75,0x77,0x78,0x79,0x7A,0x7C,0x7D,0x7E,0x7F,0x81,0x82,0x83,0x84],[0x32,0xDF,0x99,0xB4,0x31,0xED,0x5D,0xC5,0xAC,0xF8,0xCA,0xF6,0xDC,0x6C,0xE4,0x75],[0x07,0x80,0x5A,0xA0,0x43,0x98,0x6E,0xB2,0x36,0x93,0xE2,0x3B,0xEF,0x8F,0x34,0x38]], + [[0x86,0x87,0x88,0x89,0x8B,0x8C,0x8D,0x8E,0x90,0x91,0x92,0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,0x9D,0x9F,0xA0,0xA1,0xA2],[0x7F,0xDC,0x2B,0x74,0x6F,0x3F,0x66,0x52,0x96,0x94,0x3B,0x83,0x71,0x0D,0x1F,0x82],[0xDF,0x0B,0x49,0x31,0x03,0x8B,0xAD,0xE8,0x48,0xDE,0xE3,0xB4,0xB8,0x5A,0xA4,0x4B]], + [[0xA4,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,0xB1,0xB3,0xB4,0xB5,0xB6,0xB8,0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0],[0x8F,0xBA,0x15,0x10,0xA3,0xC5,0xB8,0x7E,0x2E,0xAA,0x3F,0x7A,0x91,0x45,0x5C,0xA2],[0x59,0x2D,0x5F,0xDE,0xD7,0x65,0x82,0xE4,0x14,0x3C,0x65,0x09,0x93,0x09,0x47,0x7C]]]; + + var testvectors256 = [[[0x00,0x01,0x02,0x03,0x05,0x06,0x07,0x08,0x0A,0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x12,0x14,0x15,0x16,0x17,0x19,0x1A,0x1B,0x1C,0x1E,0x1F,0x20,0x21,0x23,0x24,0x25,0x26],[0x83,0x4E,0xAD,0xFC,0xCA,0xC7,0xE1,0xB3,0x06,0x64,0xB1,0xAB,0xA4,0x48,0x15,0xAB],[0x19,0x46,0xDA,0xBF,0x6A,0x03,0xA2,0xA2,0xC3,0xD0,0xB0,0x50,0x80,0xAE,0xD6,0xFC]], + [[0x28,0x29,0x2A,0x2B,0x2D,0x2E,0x2F,0x30,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3A,0x3C,0x3D,0x3E,0x3F,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0x49,0x4B,0x4C,0x4D,0x4E],[0xD9,0xDC,0x4D,0xBA,0x30,0x21,0xB0,0x5D,0x67,0xC0,0x51,0x8F,0x72,0xB6,0x2B,0xF1],[0x5E,0xD3,0x01,0xD7,0x47,0xD3,0xCC,0x71,0x54,0x45,0xEB,0xDE,0xC6,0x2F,0x2F,0xB4]], + [[0x50,0x51,0x52,0x53,0x55,0x56,0x57,0x58,0x5A,0x5B,0x5C,0x5D,0x5F,0x60,0x61,0x62,0x64,0x65,0x66,0x67,0x69,0x6A,0x6B,0x6C,0x6E,0x6F,0x70,0x71,0x73,0x74,0x75,0x76],[0xA2,0x91,0xD8,0x63,0x01,0xA4,0xA7,0x39,0xF7,0x39,0x21,0x73,0xAA,0x3C,0x60,0x4C],[0x65,0x85,0xC8,0xF4,0x3D,0x13,0xA6,0xBE,0xAB,0x64,0x19,0xFC,0x59,0x35,0xB9,0xD0]], + [[0x78,0x79,0x7A,0x7B,0x7D,0x7E,0x7F,0x80,0x82,0x83,0x84,0x85,0x87,0x88,0x89,0x8A,0x8C,0x8D,0x8E,0x8F,0x91,0x92,0x93,0x94,0x96,0x97,0x98,0x99,0x9B,0x9C,0x9D,0x9E],[0x42,0x64,0xB2,0x69,0x64,0x98,0xDE,0x4D,0xF7,0x97,0x88,0xA9,0xF8,0x3E,0x93,0x90],[0x2A,0x5B,0x56,0xA5,0x96,0x68,0x0F,0xCC,0x0E,0x05,0xF5,0xE0,0xF1,0x51,0xEC,0xAE]], + [[0xA0,0xA1,0xA2,0xA3,0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAF,0xB0,0xB1,0xB2,0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,0xBE,0xBF,0xC0,0xC1,0xC3,0xC4,0xC5,0xC6],[0xEE,0x99,0x32,0xB3,0x72,0x18,0x04,0xD5,0xA8,0x3E,0xF5,0x94,0x92,0x45,0xB6,0xF6],[0xF5,0xD6,0xFF,0x41,0x4F,0xD2,0xC6,0x18,0x14,0x94,0xD2,0x0C,0x37,0xF2,0xB8,0xC4]], + [[0xC8,0xC9,0xCA,0xCB,0xCD,0xCE,0xCF,0xD0,0xD2,0xD3,0xD4,0xD5,0xD7,0xD8,0xD9,0xDA,0xDC,0xDD,0xDE,0xDF,0xE1,0xE2,0xE3,0xE4,0xE6,0xE7,0xE8,0xE9,0xEB,0xEC,0xED,0xEE],[0xE6,0x24,0x8F,0x55,0xC5,0xFD,0xCB,0xCA,0x9C,0xBB,0xB0,0x1C,0x88,0xA2,0xEA,0x77],[0x85,0x39,0x9C,0x01,0xF5,0x9F,0xFF,0xB5,0x20,0x4F,0x19,0xF8,0x48,0x2F,0x00,0xB8]], + [[0xF0,0xF1,0xF2,0xF3,0xF5,0xF6,0xF7,0xF8,0xFA,0xFB,0xFC,0xFD,0xFE,0x01,0x00,0x02,0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16],[0xB8,0x35,0x8E,0x41,0xB9,0xDF,0xF6,0x5F,0xD4,0x61,0xD5,0x5A,0x99,0x26,0x62,0x47],[0x92,0x09,0x7B,0x4C,0x88,0xA0,0x41,0xDD,0xF9,0x81,0x44,0xBC,0x8D,0x22,0xE8,0xE7]], + [[0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20,0x22,0x23,0x24,0x25,0x27,0x28,0x29,0x2A,0x2C,0x2D,0x2E,0x2F,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3B,0x3C,0x3D,0x3E],[0xF0,0xE2,0xD7,0x22,0x60,0xAF,0x58,0xE2,0x1E,0x01,0x5A,0xB3,0xA4,0xC0,0xD9,0x06],[0x89,0xBD,0x5B,0x73,0xB3,0x56,0xAB,0x41,0x2A,0xEF,0x9F,0x76,0xCE,0xA2,0xD6,0x5C]], + [[0x40,0x41,0x42,0x43,0x45,0x46,0x47,0x48,0x4A,0x4B,0x4C,0x4D,0x4F,0x50,0x51,0x52,0x54,0x55,0x56,0x57,0x59,0x5A,0x5B,0x5C,0x5E,0x5F,0x60,0x61,0x63,0x64,0x65,0x66],[0x47,0x5B,0x8B,0x82,0x3C,0xE8,0x89,0x3D,0xB3,0xC4,0x4A,0x9F,0x2A,0x37,0x9F,0xF7],[0x25,0x36,0x96,0x90,0x93,0xC5,0x5F,0xF9,0x45,0x46,0x92,0xF2,0xFA,0xC2,0xF5,0x30]], + [[0x68,0x69,0x6A,0x6B,0x6D,0x6E,0x6F,0x70,0x72,0x73,0x74,0x75,0x77,0x78,0x79,0x7A,0x7C,0x7D,0x7E,0x7F,0x81,0x82,0x83,0x84,0x86,0x87,0x88,0x89,0x8B,0x8C,0x8D,0x8E],[0x68,0x8F,0x52,0x81,0x94,0x58,0x12,0x86,0x2F,0x5F,0x30,0x76,0xCF,0x80,0x41,0x2F],[0x07,0xFC,0x76,0xA8,0x72,0x84,0x3F,0x3F,0x6E,0x00,0x81,0xEE,0x93,0x96,0xD6,0x37]], + [[0x90,0x91,0x92,0x93,0x95,0x96,0x97,0x98,0x9A,0x9B,0x9C,0x9D,0x9F,0xA0,0xA1,0xA2,0xA4,0xA5,0xA6,0xA7,0xA9,0xAA,0xAB,0xAC,0xAE,0xAF,0xB0,0xB1,0xB3,0xB4,0xB5,0xB6],[0x08,0xD1,0xD2,0xBC,0x75,0x0A,0xF5,0x53,0x36,0x5D,0x35,0xE7,0x5A,0xFA,0xCE,0xAA],[0xE3,0x8B,0xA8,0xEC,0x2A,0xA7,0x41,0x35,0x8D,0xCC,0x93,0xE8,0xF1,0x41,0xC4,0x91]], + [[0xB8,0xB9,0xBA,0xBB,0xBD,0xBE,0xBF,0xC0,0xC2,0xC3,0xC4,0xC5,0xC7,0xC8,0xC9,0xCA,0xCC,0xCD,0xCE,0xCF,0xD1,0xD2,0xD3,0xD4,0xD6,0xD7,0xD8,0xD9,0xDB,0xDC,0xDD,0xDE],[0x87,0x07,0x12,0x1F,0x47,0xCC,0x3E,0xFC,0xEC,0xA5,0xF9,0xA8,0x47,0x49,0x50,0xA1],[0xD0,0x28,0xEE,0x23,0xE4,0xA8,0x90,0x75,0xD0,0xB0,0x3E,0x86,0x8D,0x7D,0x3A,0x42]], + [[0xE0,0xE1,0xE2,0xE3,0xE5,0xE6,0xE7,0xE8,0xEA,0xEB,0xEC,0xED,0xEF,0xF0,0xF1,0xF2,0xF4,0xF5,0xF6,0xF7,0xF9,0xFA,0xFB,0xFC,0xFE,0xFE,0x01,0x01,0x03,0x04,0x05,0x06],[0xE5,0x1A,0xA0,0xB1,0x35,0xDB,0xA5,0x66,0x93,0x9C,0x3B,0x63,0x59,0xA9,0x80,0xC5],[0x8C,0xD9,0x42,0x3D,0xFC,0x45,0x9E,0x54,0x71,0x55,0xC5,0xD1,0xD5,0x22,0xE5,0x40]], + [[0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A,0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E],[0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21],[0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71,0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3]], + [[0x30,0x31,0x32,0x33,0x35,0x36,0x37,0x38,0x3A,0x3B,0x3C,0x3D,0x3F,0x40,0x41,0x42,0x44,0x45,0x46,0x47,0x49,0x4A,0x4B,0x4C,0x4E,0x4F,0x50,0x51,0x53,0x54,0x55,0x56],[0x72,0x61,0x65,0xC1,0x72,0x3F,0xBC,0xF6,0xC0,0x26,0xD7,0xD0,0x0B,0x09,0x10,0x27],[0x7C,0x17,0x00,0x21,0x1A,0x39,0x91,0xFC,0x0E,0xCD,0xED,0x0A,0xB3,0xE5,0x76,0xB0]]]; + + var res = true; + var j = 0; + for (var i = 0; i < testvectors128.length; i++) { + var res2 = test_aes(testvectors128[i][1],testvectors128[i][0],testvectors128[i][2]); + res &= res2; + if (!res2) { + result[j] = new unit.result("Testing 128 bit key vector with block "+ + util.hexidump(testvectors128[i][1])+ + " and key "+util.hexidump(testvectors128[i][0])+ + " should be "+util.hexidump(testvectors128[i][2]), + false); + j++; + } + } + if (res) { + result[j] = new unit.result("128 bit key test vectors completed.",true) + j++; + } + + res = true; + for (var i = 0; i < testvectors192.length; i++) { + var res2 = test_aes(testvectors192[i][1],testvectors192[i][0],testvectors192[i][2]); + res &= res2; + if (!res2) { + result[j] = new unit.result("Testing 192 bit key vector with block "+ + util.hexidump(testvectors192[i][1])+ + " and key "+util.hexidump(testvectors192[i][0])+ + " should be "+util.hexidump(testvectors192[i][2]), + false); + j++; + } + } + if (res) { + result[j] = new unit.result("192 bit key test vectors completed.",true) + j++; + } + + res = true; + for (var i = 0; i < testvectors256.length; i++) { + var res2 = test_aes(testvectors256[i][1],testvectors256[i][0],testvectors256[i][2]); + res &= res2; + if (!res2) { + result[j] = new unit.result("Testing 256 bit key vector with block "+ + util.hexidump(testvectors256[i][1])+ + " and key "+util.hexidump(testvectors256[i][0])+ + " should be "+util.hexidump(testvectors256[i][2]), + false); + j++; + } + } + if (res) { + result[j] = new unit.result("256 bit key test vectors completed.", true) + j++; + } + + return result; +}); diff --git a/test/crypto/cipher/blowfish.js b/test/crypto/cipher/blowfish.js new file mode 100644 index 00000000..93621767 --- /dev/null +++ b/test/crypto/cipher/blowfish.js @@ -0,0 +1,67 @@ +var unit = require('../../unit.js'); + +unit.register("Blowfish cipher test with test vectors from http://www.schneier.com/code/vectors.txt", function() { + var openpgp = require('openpgp'), + util = openpgp.util, + BFencrypt = openpgp.crypto.cipher.blowfish; + + var result = []; + function test_bf(input, key, output) { + var blowfish = new openpgp.crypto.cipher.blowfish(util.bin2str(key)); + var result = util.bin2str(blowfish.encrypt(input)); + + return (util.hexstrdump(result) == util.hexstrdump(util.bin2str(output))); + } + var testvectors = [[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x4E,0xF9,0x97,0x45,0x61,0x98,0xDD,0x78]], + [[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x51,0x86,0x6F,0xD5,0xB8,0x5E,0xCB,0x8A]], + [[0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01],[0x7D,0x85,0x6F,0x9A,0x61,0x30,0x63,0xF2]], + [[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x24,0x66,0xDD,0x87,0x8B,0x96,0x3C,0x9D]], + [[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x61,0xF9,0xC3,0x80,0x22,0x81,0xB0,0x96]], + [[0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x7D,0x0C,0xC6,0x30,0xAF,0xDA,0x1E,0xC7]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x4E,0xF9,0x97,0x45,0x61,0x98,0xDD,0x78]], + [[0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x0A,0xCE,0xAB,0x0F,0xC6,0xA0,0xA2,0x8D]], + [[0x7C,0xA1,0x10,0x45,0x4A,0x1A,0x6E,0x57],[0x01,0xA1,0xD6,0xD0,0x39,0x77,0x67,0x42],[0x59,0xC6,0x82,0x45,0xEB,0x05,0x28,0x2B]], + [[0x01,0x31,0xD9,0x61,0x9D,0xC1,0x37,0x6E],[0x5C,0xD5,0x4C,0xA8,0x3D,0xEF,0x57,0xDA],[0xB1,0xB8,0xCC,0x0B,0x25,0x0F,0x09,0xA0]], + [[0x07,0xA1,0x13,0x3E,0x4A,0x0B,0x26,0x86],[0x02,0x48,0xD4,0x38,0x06,0xF6,0x71,0x72],[0x17,0x30,0xE5,0x77,0x8B,0xEA,0x1D,0xA4]], + [[0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E],[0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A],[0xA2,0x5E,0x78,0x56,0xCF,0x26,0x51,0xEB]], + [[0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6],[0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2],[0x35,0x38,0x82,0xB1,0x09,0xCE,0x8F,0x1A]], + [[0x01,0x13,0xB9,0x70,0xFD,0x34,0xF2,0xCE],[0x05,0x9B,0x5E,0x08,0x51,0xCF,0x14,0x3A],[0x48,0xF4,0xD0,0x88,0x4C,0x37,0x99,0x18]], + [[0x01,0x70,0xF1,0x75,0x46,0x8F,0xB5,0xE6],[0x07,0x56,0xD8,0xE0,0x77,0x47,0x61,0xD2],[0x43,0x21,0x93,0xB7,0x89,0x51,0xFC,0x98]], + [[0x43,0x29,0x7F,0xAD,0x38,0xE3,0x73,0xFE],[0x76,0x25,0x14,0xB8,0x29,0xBF,0x48,0x6A],[0x13,0xF0,0x41,0x54,0xD6,0x9D,0x1A,0xE5]], + [[0x07,0xA7,0x13,0x70,0x45,0xDA,0x2A,0x16],[0x3B,0xDD,0x11,0x90,0x49,0x37,0x28,0x02],[0x2E,0xED,0xDA,0x93,0xFF,0xD3,0x9C,0x79]], + [[0x04,0x68,0x91,0x04,0xC2,0xFD,0x3B,0x2F],[0x26,0x95,0x5F,0x68,0x35,0xAF,0x60,0x9A],[0xD8,0x87,0xE0,0x39,0x3C,0x2D,0xA6,0xE3]], + [[0x37,0xD0,0x6B,0xB5,0x16,0xCB,0x75,0x46],[0x16,0x4D,0x5E,0x40,0x4F,0x27,0x52,0x32],[0x5F,0x99,0xD0,0x4F,0x5B,0x16,0x39,0x69]], + [[0x1F,0x08,0x26,0x0D,0x1A,0xC2,0x46,0x5E],[0x6B,0x05,0x6E,0x18,0x75,0x9F,0x5C,0xCA],[0x4A,0x05,0x7A,0x3B,0x24,0xD3,0x97,0x7B]], + [[0x58,0x40,0x23,0x64,0x1A,0xBA,0x61,0x76],[0x00,0x4B,0xD6,0xEF,0x09,0x17,0x60,0x62],[0x45,0x20,0x31,0xC1,0xE4,0xFA,0xDA,0x8E]], + [[0x02,0x58,0x16,0x16,0x46,0x29,0xB0,0x07],[0x48,0x0D,0x39,0x00,0x6E,0xE7,0x62,0xF2],[0x75,0x55,0xAE,0x39,0xF5,0x9B,0x87,0xBD]], + [[0x49,0x79,0x3E,0xBC,0x79,0xB3,0x25,0x8F],[0x43,0x75,0x40,0xC8,0x69,0x8F,0x3C,0xFA],[0x53,0xC5,0x5F,0x9C,0xB4,0x9F,0xC0,0x19]], + [[0x4F,0xB0,0x5E,0x15,0x15,0xAB,0x73,0xA7],[0x07,0x2D,0x43,0xA0,0x77,0x07,0x52,0x92],[0x7A,0x8E,0x7B,0xFA,0x93,0x7E,0x89,0xA3]], + [[0x49,0xE9,0x5D,0x6D,0x4C,0xA2,0x29,0xBF],[0x02,0xFE,0x55,0x77,0x81,0x17,0xF1,0x2A],[0xCF,0x9C,0x5D,0x7A,0x49,0x86,0xAD,0xB5]], + [[0x01,0x83,0x10,0xDC,0x40,0x9B,0x26,0xD6],[0x1D,0x9D,0x5C,0x50,0x18,0xF7,0x28,0xC2],[0xD1,0xAB,0xB2,0x90,0x65,0x8B,0xC7,0x78]], + [[0x1C,0x58,0x7F,0x1C,0x13,0x92,0x4F,0xEF],[0x30,0x55,0x32,0x28,0x6D,0x6F,0x29,0x5A],[0x55,0xCB,0x37,0x74,0xD1,0x3E,0xF2,0x01]], + [[0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0xFA,0x34,0xEC,0x48,0x47,0xB2,0x68,0xB2]], + [[0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0xA7,0x90,0x79,0x51,0x08,0xEA,0x3C,0xAE]], + [[0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0xC3,0x9E,0x07,0x2D,0x9F,0xAC,0x63,0x1D]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x01,0x49,0x33,0xE0,0xCD,0xAF,0xF6,0xE4]], + [[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xF2,0x1E,0x9A,0x77,0xB7,0x1C,0x49,0xBC]], + [[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x24,0x59,0x46,0x88,0x57,0x54,0x36,0x9A]], + [[0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10],[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF],[0x6B,0x5C,0x5A,0x9C,0x5D,0x9E,0x0A,0x5A]]]; + + var res = true; + var j = 0; + for (var i = 0; i < testvectors.length; i++) { + var res2 = test_bf(testvectors[i][1],testvectors[i][0],testvectors[i][2]); + res &= res2; + if (!res2) { + result[j] = new unit.result("Testing vector "+i+" with block "+ + util.hexidump(testvectors[i][0])+ + " and key "+util.hexidump(testvectors[i][1])+ + " should be "+util.hexidump(testvectors[i][2]), false); + j++; + } + } + if (res) { + result[j] = new unit.result("34 test vectors completed ", true); + } + return result; +}); diff --git a/test/ciphers/symmetric/cast5.js b/test/crypto/cipher/cast5.js similarity index 53% rename from test/ciphers/symmetric/cast5.js rename to test/crypto/cipher/cast5.js index aaac7373..98828d7a 100644 --- a/test/ciphers/symmetric/cast5.js +++ b/test/crypto/cipher/cast5.js @@ -1,14 +1,21 @@ +var unit = require('../../unit.js'); -unittests.register("CAST-128 cipher test with test vectors from RFC2144", function() { - var result = new Array(); +unit.register("CAST-128 cipher test with test vectors from RFC2144", function() { + var openpgp = require('openpgp'), + util = openpgp.util; + + var result = []; function test_cast(input, key, output) { - return (util.hexstrdump(util.bin2str(cast5_encrypt(input,util.bin2str(key)))) == util.hexstrdump(util.bin2str(output))); - }; + var cast5 = new openpgp.crypto.cipher.cast5(util.bin2str(key)); + var result = util.bin2str(cast5.encrypt(input)); + + return util.hexstrdump(result) == util.hexstrdump(util.bin2str(output)); + } var testvectors = [[[0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78,0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A],[0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF],[0x23,0x8B,0x4F,0xE5,0x84,0x7E,0x44,0xB2]]]; for (var i = 0; i < testvectors.length; i++) { - result[i] = new test_result("Testing vector with block "+ + result[i] = new unit.result("Testing vector with block "+ util.hexidump(testvectors[i][0])+ " and key "+util.hexidump(testvectors[i][1])+ " should be "+util.hexidump(testvectors[i][2]), diff --git a/test/crypto/cipher/des.js b/test/crypto/cipher/des.js new file mode 100644 index 00000000..5a3ea465 --- /dev/null +++ b/test/crypto/cipher/des.js @@ -0,0 +1,165 @@ +var unit = require('../../unit.js'); + +unit.register("TripleDES (EDE) cipher test with test vectors from http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf", function() { + var openpgp = require('openpgp'), + util = openpgp.util; + + var result = []; + var key = util.bin2str([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]); + var testvectors = [[[0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00]], + [[0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xDD,0x7F,0x12,0x1C,0xA5,0x01,0x56,0x19]], + [[0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x2E,0x86,0x53,0x10,0x4F,0x38,0x34,0xEA]], + [[0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x4B,0xD3,0x88,0xFF,0x6C,0xD8,0x1D,0x4F]], + [[0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x20,0xB9,0xE7,0x67,0xB2,0xFB,0x14,0x56]], + [[0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x55,0x57,0x93,0x80,0xD7,0x71,0x38,0xEF]], + [[0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x6C,0xC5,0xDE,0xFA,0xAF,0x04,0x51,0x2F]], + [[0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x0D,0x9F,0x27,0x9B,0xA5,0xD8,0x72,0x60]], + [[0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00],[0xD9,0x03,0x1B,0x02,0x71,0xBD,0x5A,0x0A]], + [[0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00],[0x42,0x42,0x50,0xB3,0x7C,0x3D,0xD9,0x51]], + [[0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00],[0xB8,0x06,0x1B,0x7E,0xCD,0x9A,0x21,0xE5]], + [[0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00],[0xF1,0x5D,0x0F,0x28,0x6B,0x65,0xBD,0x28]], + [[0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00],[0xAD,0xD0,0xCC,0x8D,0x6E,0x5D,0xEB,0xA1]], + [[0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00],[0xE6,0xD5,0xF8,0x27,0x52,0xAD,0x63,0xD1]], + [[0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00],[0xEC,0xBF,0xE3,0xBD,0x3F,0x59,0x1A,0x5E]], + [[0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00],[0xF3,0x56,0x83,0x43,0x79,0xD1,0x65,0xCD]], + [[0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00],[0x2B,0x9F,0x98,0x2F,0x20,0x03,0x7F,0xA9]], + [[0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00],[0x88,0x9D,0xE0,0x68,0xA1,0x6F,0x0B,0xE6]], + [[0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00],[0xE1,0x9E,0x27,0x5D,0x84,0x6A,0x12,0x98]], + [[0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00],[0x32,0x9A,0x8E,0xD5,0x23,0xD7,0x1A,0xEC]], + [[0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00],[0xE7,0xFC,0xE2,0x25,0x57,0xD2,0x3C,0x97]], + [[0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00],[0x12,0xA9,0xF5,0x81,0x7F,0xF2,0xD6,0x5D]], + [[0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00],[0xA4,0x84,0xC3,0xAD,0x38,0xDC,0x9C,0x19]], + [[0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00],[0xFB,0xE0,0x0A,0x8A,0x1E,0xF8,0xAD,0x72]], + [[0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00],[0x75,0x0D,0x07,0x94,0x07,0x52,0x13,0x63]], + [[0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00],[0x64,0xFE,0xED,0x9C,0x72,0x4C,0x2F,0xAF]], + [[0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00],[0xF0,0x2B,0x26,0x3B,0x32,0x8E,0x2B,0x60]], + [[0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00],[0x9D,0x64,0x55,0x5A,0x9A,0x10,0xB8,0x52]], + [[0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00],[0xD1,0x06,0xFF,0x0B,0xED,0x52,0x55,0xD7]], + [[0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00],[0xE1,0x65,0x2C,0x6B,0x13,0x8C,0x64,0xA5]], + [[0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00],[0xE4,0x28,0x58,0x11,0x86,0xEC,0x8F,0x46]], + [[0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00],[0xAE,0xB5,0xF5,0xED,0xE2,0x2D,0x1A,0x36]], + [[0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00],[0xE9,0x43,0xD7,0x56,0x8A,0xEC,0x0C,0x5C]], + [[0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00],[0xDF,0x98,0xC8,0x27,0x6F,0x54,0xB0,0x4B]], + [[0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00],[0xB1,0x60,0xE4,0x68,0x0F,0x6C,0x69,0x6F]], + [[0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00],[0xFA,0x07,0x52,0xB0,0x7D,0x9C,0x4A,0xB8]], + [[0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00],[0xCA,0x3A,0x2B,0x03,0x6D,0xBC,0x85,0x02]], + [[0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00],[0x5E,0x09,0x05,0x51,0x7B,0xB5,0x9B,0xCF]], + [[0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00],[0x81,0x4E,0xEB,0x3B,0x91,0xD9,0x07,0x26]], + [[0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00],[0x4D,0x49,0xDB,0x15,0x32,0x91,0x9C,0x9F]], + [[0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00],[0x25,0xEB,0x5F,0xC3,0xF8,0xCF,0x06,0x21]], + [[0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00],[0xAB,0x6A,0x20,0xC0,0x62,0x0D,0x1C,0x6F]], + [[0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00],[0x79,0xE9,0x0D,0xBC,0x98,0xF9,0x2C,0xCA]], + [[0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00],[0x86,0x6E,0xCE,0xDD,0x80,0x72,0xBB,0x0E]], + [[0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00],[0x8B,0x54,0x53,0x6F,0x2F,0x3E,0x64,0xA8]], + [[0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00],[0xEA,0x51,0xD3,0x97,0x55,0x95,0xB8,0x6B]], + [[0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00],[0xCA,0xFF,0xC6,0xAC,0x45,0x42,0xDE,0x31]], + [[0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00],[0x8D,0xD4,0x5A,0x2D,0xDF,0x90,0x79,0x6C]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00],[0x10,0x29,0xD5,0x5E,0x88,0x0E,0xC2,0xD0]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00],[0x5D,0x86,0xCB,0x23,0x63,0x9D,0xBE,0xA9]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00],[0x1D,0x1C,0xA8,0x53,0xAE,0x7C,0x0C,0x5F]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00],[0xCE,0x33,0x23,0x29,0x24,0x8F,0x32,0x28]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00],[0x84,0x05,0xD1,0xAB,0xE2,0x4F,0xB9,0x42]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00],[0xE6,0x43,0xD7,0x80,0x90,0xCA,0x42,0x07]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00],[0x48,0x22,0x1B,0x99,0x37,0x74,0x8A,0x23]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00],[0xDD,0x7C,0x0B,0xBD,0x61,0xFA,0xFD,0x54]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80],[0x2F,0xBC,0x29,0x1A,0x57,0x0D,0xB5,0xC4]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40],[0xE0,0x7C,0x30,0xD7,0xE4,0xE2,0x6E,0x12]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20],[0x09,0x53,0xE2,0x25,0x8E,0x8E,0x90,0xA1]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10],[0x5B,0x71,0x1B,0xC4,0xCE,0xEB,0xF2,0xEE]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08],[0xCC,0x08,0x3F,0x1E,0x6D,0x9E,0x85,0xF6]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04],[0xD2,0xFD,0x88,0x67,0xD5,0x0D,0x2D,0xFE]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02],[0x06,0xE7,0xEA,0x22,0xCE,0x92,0x70,0x8F]], + [[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01],[0x16,0x6B,0x40,0xB4,0x4A,0xBA,0x4B,0xD6]]]; + + var res = true; + var j = 0; + for (var i = 0; i < testvectors.length; i++) { + var des = new openpgp.crypto.cipher.des(key); + + var encr = util.bin2str(des.encrypt(testvectors[i][0], key)); + var res2 = encr == util.bin2str(testvectors[i][1]); + + res &= res2; + + if (!res2) { + result[j] = new unit.result("Testing vector with block " + + util.hexidump(testvectors[i][0]) + + " and key " + util.hexstrdump(key) + + " should be " + util.hexidump(testvectors[i][1]) + " != " + + util.hexidump(encr), + false); + j++; + } + } + if (res) { + result[j] = new unit.result("All 3DES EDE test vectors completed", true); + } + return result; +}); + + +unit.register("DES encrypt/decrypt padding tests", function () { + var openpgp = require('openpgp'), + util = openpgp.util; + + var result = []; + var key = util.bin2str([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]); + var testvectors = new Array(); + testvectors[0] = [[[0x01], [0x24, 0xC7, 0x4A, 0x9A, 0x79, 0x75, 0x4B, 0xC7]], + [[0x02, 0x03], [0xA7, 0x7A, 0x9A, 0x59, 0x8A, 0x86, 0x85, 0xC5]], + [[0x03, 0x04, 0x05], [0x01, 0xCF, 0xEB, 0x6A, 0x74, 0x60, 0xF5, 0x02]], + [[0x04, 0x05, 0x06, 0x07], [0xA8, 0xF0, 0x3D, 0x59, 0xBA, 0x6B, 0x0E, 0x76]], + [[0x05, 0x06, 0x07, 0x08, 0x09], [0x86, 0x40, 0x33, 0x61, 0x3F, 0x55, 0x73, 0x49]], + [[0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B], [0x13, 0x21, 0x3E, 0x0E, 0xCE, 0x2C, 0x94, 0x01]], + [[0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D], [0x30, 0x49, 0x97, 0xC1, 0xDA, 0xD5, 0x59, 0xA5]], + [[0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F], [0x83, 0x25, 0x79, 0x06, 0x54, 0xA4, 0x44, 0xD9]]]; + testvectors[1] = [[[0x01], [0xF2, 0xAB, 0x1C, 0x9E, 0x70, 0x7D, 0xCC, 0x92]], + [[0x02, 0x03], [0x6B, 0x4C, 0x67, 0x24, 0x9F, 0xB7, 0x4D, 0xAC]], + [[0x03, 0x04, 0x05], [0x68, 0x95, 0xAB, 0xA8, 0xEA, 0x53, 0x13, 0x23]], + [[0x04, 0x05, 0x06, 0x07], [0xC8, 0xDE, 0x60, 0x8F, 0xF6, 0x09, 0x90, 0xB5]], + [[0x05, 0x06, 0x07, 0x08, 0x09], [0x19, 0x13, 0x50, 0x20, 0x70, 0x40, 0x2E, 0x09]], + [[0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B], [0xA8, 0x23, 0x40, 0xC6, 0x17, 0xA6, 0x31, 0x4A]], + [[0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D], [0x36, 0x62, 0xF2, 0x99, 0x68, 0xD4, 0xBF, 0x7C]], + [[0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F], [0x83, 0x25, 0x79, 0x06, 0x54, 0xA4, 0x44, 0xD9, 0x08, 0x6F, 0x9A, 0x1D, 0x74, 0xC9, 0x4D, 0x4E]]]; + testvectors[2] = [[[0x01], [0x83, 0x68, 0xE4, 0x9C, 0x84, 0xCC, 0xCB, 0xF0]], + [[0x02, 0x03], [0xBB, 0xA8, 0x0B, 0x66, 0x1B, 0x62, 0xC4, 0xC8]], + [[0x03, 0x04, 0x05], [0x9A, 0xD7, 0x5A, 0x24, 0xFD, 0x3F, 0xBF, 0x22]], + [[0x04, 0x05, 0x06, 0x07], [0x14, 0x4E, 0x68, 0x6D, 0x2E, 0xC1, 0xB7, 0x52]], + [[0x05, 0x06, 0x07, 0x08, 0x09], [0x12, 0x0A, 0x51, 0x08, 0xF9, 0xA3, 0x03, 0x74]], + [[0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B], [0xB2, 0x07, 0xD1, 0x05, 0xF6, 0x67, 0xAF, 0xBA]], + [[0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D], [0xCA, 0x59, 0x61, 0x3A, 0x83, 0x23, 0x26, 0xDD]], + [[0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F], [0x83, 0x25, 0x79, 0x06, 0x54, 0xA4, 0x44, 0xD9]]]; + + var des = new openpgp.crypto.cipher.originalDes(key); + + var res = true; + var j = 0; + + for (var padding = 0; padding < 3; padding++) { + var thisVectorSet = testvectors[padding]; + + for (var i = 0; i < thisVectorSet.length; i++) { + var encrypted = des.encrypt(thisVectorSet[i][0], padding); + var decrypted = des.decrypt(encrypted, padding); + + var res2 = (util.bin2str(encrypted) == util.bin2str(thisVectorSet[i][1])); + var res3 = (util.bin2str(decrypted) == util.bin2str(thisVectorSet[i][0])); + res &= res2; + res &= res3; + if (!res2 || !res3) { + result[j] = new unit.result( + "Testing vector with block [" + + util.hexidump(thisVectorSet[i][0]) + + "] and key [" + util.hexstrdump(key) + + "] and padding [" + padding + + "] should be " + util.hexidump(thisVectorSet[i][1]) + " - Actually [ENC:" + util.hexidump(encrypted) + ", DEC:" + util.hexidump(decrypted) + "]", + false); + j++; + } + } + } + if (res) { + result[j] = new unit.result("All DES test vectors completed", true); + } + return result; +}); diff --git a/test/crypto/cipher/twofish.js b/test/crypto/cipher/twofish.js new file mode 100644 index 00000000..ccbad52b --- /dev/null +++ b/test/crypto/cipher/twofish.js @@ -0,0 +1,68 @@ +var unit = require('../../unit.js'); + +unit.register("Twofish test with test vectors from http://www.schneier.com/code/ecb_ival.txt", function() { + var openpgp = require('openpgp'), + util = openpgp.util; + + function TFencrypt(block, key) { + var tf = new openpgp.crypto.cipher.twofish(key); + + return tf.encrypt(block); + } + + + var result = []; + var start = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + var start_short = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + var testvectors = [[0x57,0xFF,0x73,0x9D,0x4D,0xC9,0x2C,0x1B,0xD7,0xFC,0x01,0x70,0x0C,0xC8,0x21,0x6F], + [0xD4,0x3B,0xB7,0x55,0x6E,0xA3,0x2E,0x46,0xF2,0xA2,0x82,0xB7,0xD4,0x5B,0x4E,0x0D], + [0x90,0xAF,0xE9,0x1B,0xB2,0x88,0x54,0x4F,0x2C,0x32,0xDC,0x23,0x9B,0x26,0x35,0xE6], + [0x6C,0xB4,0x56,0x1C,0x40,0xBF,0x0A,0x97,0x05,0x93,0x1C,0xB6,0xD4,0x08,0xE7,0xFA], + [0x30,0x59,0xD6,0xD6,0x17,0x53,0xB9,0x58,0xD9,0x2F,0x47,0x81,0xC8,0x64,0x0E,0x58], + [0xE6,0x94,0x65,0x77,0x05,0x05,0xD7,0xF8,0x0E,0xF6,0x8C,0xA3,0x8A,0xB3,0xA3,0xD6], + [0x5A,0xB6,0x7A,0x5F,0x85,0x39,0xA4,0xA5,0xFD,0x9F,0x03,0x73,0xBA,0x46,0x34,0x66], + [0xDC,0x09,0x6B,0xCD,0x99,0xFC,0x72,0xF7,0x99,0x36,0xD4,0xC7,0x48,0xE7,0x5A,0xF7], + [0xC5,0xA3,0xE7,0xCE,0xE0,0xF1,0xB7,0x26,0x05,0x28,0xA6,0x8F,0xB4,0xEA,0x05,0xF2], + [0x43,0xD5,0xCE,0xC3,0x27,0xB2,0x4A,0xB9,0x0A,0xD3,0x4A,0x79,0xD0,0x46,0x91,0x51]]; + testvectors[47] = [0x43,0x10,0x58,0xF4,0xDB,0xC7,0xF7,0x34,0xDA,0x4F,0x02,0xF0,0x4C,0xC4,0xF4,0x59]; + testvectors[48] = [0x37,0xFE,0x26,0xFF,0x1C,0xF6,0x61,0x75,0xF5,0xDD,0xF4,0xC3,0x3B,0x97,0xA2,0x05]; + var res = true; + var j = 0; + for (var i = 0; i < 49; i++) { + var res2 = false; + var blk, key, ct; + if (i === 0) { + blk = start_short; + key = util.bin2str(start); + ct = testvectors[0]; + res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); + } else if (i === 1) { + blk = testvectors[0]; + key = util.bin2str(start); + ct = testvectors[1]; + res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); + } else if (i === 2) { + blk = testvectors[i-1]; + key = util.bin2str(testvectors[i-2].concat(start_short)); + ct = testvectors[i]; + res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); + } else if (i < 10 || i > 46) { + blk = testvectors[i-1]; + key = util.bin2str(testvectors[i-2].concat(testvectors[i-3])); + ct = testvectors[i]; + res2 = (util.bin2str(TFencrypt(blk,key)) == util.bin2str(ct)); + } else { + testvectors[i] = TFencrypt(testvectors[i-1],util.bin2str(testvectors[i-2].concat(testvectors[i-3]))); + res2 = true; + } + res &= res2; + if (!res2) { + result[j] = new unit.result("Testing vector with block "+util.hexidump(blk)+" with key "+ util.hexstrdump(key) +" should be "+util.hexidump(ct)+" but is "+util.hexidump(TFencrypt(blk,key)), false); + j++; + } + } + if (res) { + result[j] = new unit.result("49 test vectors completed", true); + } + return result; +}); diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js new file mode 100644 index 00000000..9d65e5e7 --- /dev/null +++ b/test/crypto/crypto.js @@ -0,0 +1,270 @@ +var unit = require('../unit.js'); + +unit.register("Functional testing of openpgp.crypto.* methods", function() { + var openpgp = require('openpgp'); + var util = openpgp.util; + var result = []; + var RSApubMPIstrs = [ + util.bin2str([0x08,0x00,0xac,0x15,0xb3,0xd6,0xd2,0x0f,0xf0,0x7a,0xdd,0x21,0xb7, + 0xbf,0x61,0xfa,0xca,0x93,0x86,0xc8,0x55,0x5a,0x4b,0xa6,0xa4,0x1a, + 0x60,0xa2,0x3a,0x37,0x06,0x08,0xd8,0x15,0x8e,0x85,0x45,0xaa,0xb7, + 0x1d,0x7b,0x0b,0x73,0x94,0x55,0x0c,0x5c,0xec,0xc0,0x22,0x4b,0xa1, + 0x64,0x20,0x7d,0x4d,0xa8,0x96,0x1a,0x64,0x38,0x93,0xcd,0xec,0x73, + 0x5d,0xf9,0x89,0x88,0x24,0x3d,0x48,0xff,0x3b,0x87,0x62,0xd0,0x84, + 0xea,0xff,0x39,0xb5,0x27,0x70,0xea,0x4a,0xb2,0x2e,0x9d,0xf1,0x7c, + 0x23,0xec,0xf4,0x5e,0xea,0x61,0x3d,0xe5,0xd8,0x0d,0xf9,0x59,0x6d, + 0x28,0x00,0xeb,0xcb,0xc9,0x55,0x00,0x72,0x30,0x1f,0x65,0x9d,0xd6, + 0x17,0x58,0x5f,0xa6,0x4a,0xa0,0xdd,0xe1,0x76,0xf2,0xef,0x21,0x9f, + 0x84,0xfc,0xaa,0x5b,0x52,0x6e,0xc1,0xa2,0xb9,0xbd,0xb9,0xf4,0x9e, + 0x49,0x92,0xf2,0xaf,0x57,0x86,0xf2,0xef,0x70,0xbf,0x51,0x40,0xfd, + 0xbf,0x56,0x51,0xe8,0x2c,0xa2,0x4f,0xf8,0xa4,0xd7,0x36,0x18,0x85, + 0xce,0x09,0x0d,0xbc,0x8d,0x65,0x5e,0x8a,0x1d,0x98,0xb0,0x4d,0x9d, + 0xc1,0xcf,0x82,0xe1,0xb7,0x43,0x5d,0x5a,0x72,0xcd,0x55,0xd2,0xff, + 0xb1,0xb4,0x78,0xbf,0xa1,0x7d,0xac,0xd9,0x1b,0xc4,0xfa,0x39,0x34, + 0x92,0x09,0xf9,0x08,0x2a,0x6b,0x9d,0x14,0x56,0x12,0x4c,0xe9,0xa6, + 0x29,0xc1,0xf3,0xa9,0x0b,0xfc,0x31,0x75,0x58,0x74,0x2a,0x88,0xaf, + 0xee,0xc9,0xa4,0xcd,0x15,0xdc,0x1b,0x8d,0x64,0xc1,0x36,0x17,0xc4, + 0x8d,0x5e,0x99,0x7a,0x5b,0x9f,0x39,0xd0,0x00,0x6e,0xf9]), + util.bin2str([0x00,0x11,0x01,0x00,0x01])]; + var RSAsecMPIstrs = [ + util.bin2str([0x07,0xfe,0x23,0xff,0xce,0x45,0x6c,0x60,0x65,0x40,0x6e,0xae,0x35, + 0x10,0x56,0x60,0xee,0xab,0xfa,0x10,0x42,0xba,0xc7,0x04,0xaf,0x63, + 0xcd,0x3f,0x62,0xca,0x4b,0xfa,0xe1,0xa9,0x70,0xcd,0x34,0x8b,0xc8, + 0x0e,0xe4,0xc4,0xba,0x83,0x17,0x5f,0xa4,0xb8,0xea,0x60,0xc2,0x4d, + 0x9a,0xf2,0xa9,0x03,0xeb,0xf6,0xaa,0xc2,0xb8,0x8b,0x43,0x12,0xe9, + 0xf7,0x88,0xd2,0x5a,0xa6,0xaa,0x23,0x71,0x31,0x74,0xdb,0x19,0x20, + 0x15,0x41,0x1b,0x43,0x68,0x62,0xd8,0xc0,0x93,0x91,0xe8,0xfc,0xb1, + 0xa9,0x9a,0x52,0x6c,0xe0,0xbf,0x43,0x01,0xa8,0x37,0x14,0x28,0xbf, + 0x0b,0x15,0x56,0x3e,0xa5,0x79,0xa0,0xc4,0x42,0x88,0xee,0xeb,0x1b, + 0xf4,0x7a,0x4a,0x58,0x31,0x58,0x81,0xd2,0x3e,0xde,0x07,0x64,0x92, + 0xf0,0x60,0xd3,0x9a,0x29,0xca,0xc6,0x67,0x75,0x07,0xca,0x92,0x39, + 0x56,0xf6,0x11,0x84,0xba,0x6d,0x4b,0xe6,0x6f,0x66,0xc2,0x17,0xeb, + 0x46,0x69,0x1c,0xbb,0xdf,0xc0,0x38,0x00,0xd6,0x01,0xe6,0x70,0x9d, + 0x4b,0x9b,0x70,0xed,0x5c,0xb8,0xcf,0xe8,0x68,0x71,0xbe,0x24,0x6d, + 0xb1,0xa3,0x13,0xcc,0xf1,0xbc,0x67,0xdc,0xe0,0x69,0x09,0x82,0x3c, + 0x3b,0x0f,0x14,0x98,0x48,0x30,0xb2,0x70,0xc6,0x9e,0xfa,0x46,0x8f, + 0xf1,0xc0,0x65,0x8e,0xc6,0xae,0xdc,0x47,0x91,0x13,0x1e,0xd6,0x4a, + 0xf2,0xad,0xda,0xc2,0xc7,0x39,0x78,0x99,0xde,0x57,0x14,0x45,0x7f, + 0x32,0x38,0xa3,0x44,0x0f,0xe7,0x39,0x4c,0x6f,0x0f,0x32,0x7e,0xf1, + 0x5c,0x84,0x97,0xdd,0xa0,0x0c,0x87,0x66,0x7d,0x75,0x79]), + util.bin2str([0x04,0x00,0xc2,0xbc,0x71,0xf7,0x41,0x4a,0x09,0x66,0x70,0x02,0x68, + 0x8b,0xeb,0xe2,0x34,0xd1,0x12,0x83,0x93,0x75,0xe9,0x71,0x32,0xe2, + 0xed,0x18,0x6f,0x8e,0x3a,0xff,0x22,0x70,0x28,0x01,0xbf,0x4a,0x39, + 0x41,0xbb,0x3c,0x4a,0xbc,0xb8,0x13,0xfc,0x14,0xf6,0x71,0xa1,0x44, + 0x1c,0x02,0xa1,0x73,0x81,0xcc,0xa0,0x35,0x02,0x3e,0x97,0xb5,0xc4, + 0x94,0x33,0xf1,0xd1,0xdf,0x14,0x3f,0xfb,0x8f,0xb9,0x75,0x70,0xdc, + 0x74,0x3f,0x07,0x35,0x8f,0x53,0xaa,0xb2,0xd6,0x88,0x51,0x71,0x4e, + 0x01,0x24,0xec,0x7d,0xca,0xf6,0xa2,0xb3,0xbb,0xad,0x2e,0x60,0xfb, + 0x1c,0xee,0x49,0xd0,0x4e,0x5c,0xe3,0x1f,0x88,0x48,0xe4,0x68,0x14, + 0x3d,0x71,0xba,0xd7,0x4d,0x35,0x10,0x86,0x37,0x62,0xe0,0xa5,0x0b]), + util.bin2str([0x04,0x00,0xe2,0x38,0xf9,0xc8,0x3c,0xd1,0xcf,0x62,0x93,0xc3,0x77, + 0x76,0x97,0x44,0xe8,0xc8,0xca,0x93,0x9a,0xef,0xf0,0x63,0x76,0x25, + 0x3b,0x1c,0x46,0xff,0x90,0x13,0x91,0x15,0x97,0x7e,0x88,0x95,0xd4, + 0x7f,0x2f,0x52,0x6e,0x0d,0x55,0x55,0x2e,0xf1,0x58,0x5c,0x7e,0x56, + 0xd4,0x48,0xaa,0xdb,0x8c,0x44,0x4d,0x84,0x69,0x33,0x87,0x07,0xb2, + 0x7e,0xf5,0xa0,0x60,0xfb,0x73,0x59,0x46,0x29,0xcb,0x1e,0x3f,0x7c, + 0x2f,0xa6,0x53,0xe3,0x8c,0xef,0xd5,0xeb,0xbb,0xc8,0x9a,0x8e,0x66, + 0x4a,0x47,0x2f,0xe1,0xba,0x5e,0x32,0xd4,0x52,0x04,0x88,0x9d,0x63, + 0x3e,0xba,0x71,0x2d,0xf7,0x61,0xd5,0xfc,0x26,0xbf,0xd8,0x60,0x92, + 0x7b,0x94,0xf8,0x6f,0x3d,0x97,0x0b,0x0c,0x52,0x8c,0xb3,0xb6,0x8b]), + util.bin2str([0x04,0x00,0xb7,0xc5,0x4d,0x6e,0x2f,0xdd,0xef,0xec,0x07,0x70,0xa2, + 0x7c,0x1c,0x9d,0x8e,0x66,0x60,0x7c,0x61,0x1e,0x45,0xe9,0xdc,0x82, + 0x2f,0xc5,0x7e,0x1a,0xc6,0xd0,0x92,0xc5,0x22,0x9b,0x9a,0xfb,0x73, + 0x95,0x99,0xf2,0x7c,0xdb,0x2a,0x93,0x7b,0x5a,0x29,0x73,0x24,0x16, + 0x41,0x49,0xb5,0xf2,0x5f,0xbe,0xe7,0x64,0x4d,0xda,0x52,0x9e,0xc1, + 0x41,0x40,0x5e,0x03,0x92,0x8d,0x39,0x95,0x1f,0x68,0x9f,0x00,0x2e, + 0x0c,0x6f,0xcf,0xd9,0x6d,0x68,0xf7,0x00,0x4f,0x0e,0xc8,0x0b,0xfa, + 0x51,0xe0,0x22,0xf0,0xff,0xa7,0x42,0xd4,0xde,0x0b,0x47,0x8f,0x2b, + 0xf5,0x4d,0x04,0x32,0x91,0x89,0x4b,0x0e,0x05,0x8d,0x70,0xf9,0xbb, + 0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])]; + + var DSApubMPIstrs = [ + util.bin2str([0x08,0x00,0xa8,0x85,0x5c,0x28,0x05,0x94,0x03,0xbe,0x07,0x6c,0x13,0x3e,0x65, + 0xfb,0xb5,0xe1,0x99,0x7c,0xfa,0x84,0xe3,0xac,0x47,0xa5,0xc4,0x46,0xd8,0x5f, + 0x44,0xe9,0xc1,0x6b,0x69,0xf7,0x10,0x76,0x49,0xa7,0x25,0x85,0xf4,0x1b,0xed, + 0xc6,0x60,0xc4,0x5b,0xaa,0xd4,0x87,0xd6,0x8f,0x92,0x56,0x7d,0x55,0x3f,0x45, + 0xae,0x12,0x73,0xda,0x29,0x8c,0xba,0x32,0xcc,0xd7,0xa4,0xd0,0x24,0xb0,0x7c, + 0xd8,0x0c,0x3a,0x91,0x6f,0x98,0x40,0x9c,0x9a,0xa8,0xcc,0x28,0x27,0x95,0x0b, + 0xe1,0x5b,0xb9,0x3b,0x1c,0x1c,0xd2,0xec,0xab,0x07,0x25,0x8d,0x7a,0x2a,0x2b, + 0x16,0x14,0xe8,0xda,0x71,0xd2,0xab,0xba,0x85,0x14,0x0d,0xc5,0xe0,0x88,0xeb, + 0xa5,0xe2,0xd5,0x48,0x3d,0x74,0x0c,0x41,0xeb,0xfd,0xb6,0x4e,0xf9,0x2c,0x82, + 0x17,0xdd,0x64,0x1e,0x19,0x39,0xa3,0x7f,0xf9,0x00,0xcd,0x9b,0xda,0x2e,0xbd, + 0x71,0x12,0xdf,0x0d,0x7c,0x0a,0x6b,0x2d,0x21,0x3b,0x9c,0x66,0x93,0x4a,0x1e, + 0x90,0x79,0xd3,0x5a,0x5b,0xe5,0xb9,0x94,0x1b,0xe6,0x47,0x99,0x06,0x98,0xd8, + 0x2a,0xe5,0xe2,0xa6,0x95,0x6a,0x07,0xc8,0xac,0x7c,0xe9,0xfc,0xa2,0x6a,0x16, + 0x2c,0x94,0x98,0xbd,0x91,0x0a,0x7c,0x7c,0x2c,0xb9,0x7e,0xa2,0x51,0x8b,0x45, + 0x1d,0x46,0x34,0xa8,0x52,0x2b,0xdd,0xd9,0xa8,0xbc,0x46,0x78,0x66,0xe1,0x72, + 0x11,0xf1,0xcb,0x1a,0xb6,0x4e,0x05,0x54,0xf7,0xe9,0xbe,0x4c,0x25,0x59,0x08, + 0x9f,0xf8,0xea,0x25,0x97,0x33,0xd6,0xc9,0x0f,0x59,0x0e,0xfd,0x9f,0xdc,0xe2, + 0xc0,0xcf,0x2f]), + util.bin2str([0x01,0x00,0xe1,0x72,0x2c,0xd0,0xbb,0x1a,0x4f,0xb6,0xb6,0x95,0x77,0x71,0x2e, + 0x01,0x48,0x3e,0x35,0x54,0x64,0x2b,0xed,0x40,0x5f,0x65,0x0c,0x57,0x28,0x5f, + 0xfd,0xfd,0xff,0xd7]), + util.bin2str([0x07,0xff,0x5d,0x9f,0xc4,0xb5,0x63,0x25,0x9d,0x72,0x88,0xe5,0x53,0x46,0x98, + 0xe3,0xe9,0x62,0xcb,0x0c,0xa1,0xb7,0x75,0x9f,0x18,0x41,0x94,0x32,0x28,0x29, + 0x6d,0x69,0xe0,0x3f,0x7d,0x7b,0x2b,0x06,0x5a,0x33,0x5c,0xd4,0x36,0x31,0x09, + 0x54,0x85,0x9d,0xb8,0x20,0xfe,0xda,0xfc,0xcd,0x1f,0xb1,0x2c,0x15,0x08,0x9d, + 0x32,0x53,0x2f,0xc1,0x42,0x22,0x69,0xff,0x67,0x2e,0x39,0x97,0x50,0x66,0x39, + 0xda,0xcf,0xfd,0x64,0x6f,0x91,0x05,0x64,0x37,0xc5,0x07,0x24,0xaa,0x40,0xa0, + 0x75,0x82,0x1d,0x97,0x96,0x12,0xf1,0xbd,0x9e,0x09,0x26,0x3c,0x97,0x5d,0x57, + 0xb8,0x5c,0x7d,0x89,0x03,0x82,0xcd,0x40,0xe5,0x03,0xe6,0x4a,0xfb,0xbc,0xd2, + 0xef,0x7a,0x89,0x02,0x08,0xc8,0x52,0xfa,0x97,0x74,0x66,0x32,0xae,0xa6,0x52, + 0x4b,0xef,0x5f,0xce,0x91,0x23,0x3f,0xab,0x9d,0x62,0x21,0xef,0x48,0x6d,0x07, + 0x5a,0xba,0xdf,0x00,0x91,0x54,0xea,0x5c,0xfa,0x4b,0x16,0x28,0x1a,0xce,0x48, + 0xb7,0x5c,0x50,0xa5,0x59,0xa4,0xb4,0xaf,0x1f,0xeb,0x8d,0x58,0x3f,0x0a,0xa5, + 0x97,0x2b,0x51,0x56,0xe8,0x88,0xf6,0x07,0xbc,0xdf,0xfa,0x2b,0x7b,0x88,0xe0, + 0x46,0xc8,0x7a,0x3e,0xd8,0x80,0xdb,0x4d,0x87,0x61,0x4f,0x64,0xcd,0xeb,0xe8, + 0x0d,0x86,0x16,0xcc,0xdd,0x6c,0x76,0x66,0xc1,0x73,0xb7,0x08,0x98,0x89,0x2f, + 0x67,0x69,0xd1,0xfc,0x97,0x4d,0xa2,0xce,0xad,0xbb,0x6f,0xab,0xa5,0xd6,0x18, + 0xb3,0x1a,0x96,0x02,0xbc,0x31,0x42,0xa2,0xad,0x77,0xe8,0xe2,0x4c,0x99,0xf9, + 0xdd,0xbe,0xcd]), + util.bin2str([0x07,0xff,0x5d,0xfe,0x9c,0x98,0xef,0x3a,0xa6,0x49,0xf0,0x10,0x67,0x79,0x2a, + 0x9d,0x79,0x43,0x06,0xa4,0xa8,0x6b,0x1a,0x6d,0x1f,0x77,0x6e,0x00,0x31,0xb9, + 0xed,0xc9,0x66,0xff,0xf1,0x21,0x32,0xfa,0x62,0x43,0xcd,0x97,0xd3,0x3d,0xaf, + 0xb4,0x29,0x29,0x26,0x4e,0x1c,0xa0,0xad,0x1c,0x07,0x28,0x3f,0xe5,0x43,0x10, + 0xba,0xb4,0x08,0xe0,0xdc,0xa2,0xc3,0x5b,0x1f,0xbd,0x94,0xc7,0x43,0xe5,0xf2, + 0x17,0x30,0x54,0x7f,0x14,0xbe,0xf4,0xbd,0x91,0x3b,0xe4,0x36,0xa4,0x50,0x5b, + 0x37,0x89,0x5e,0xcc,0xc7,0x74,0x54,0x32,0x20,0x09,0x63,0x98,0xb7,0xd9,0xaf, + 0x7f,0xb0,0x6c,0x27,0x43,0xfe,0x52,0xe6,0x1a,0x88,0x59,0x25,0xfc,0xeb,0x43, + 0x50,0xc7,0x65,0x43,0xc1,0x86,0x73,0x58,0x53,0x3a,0xcf,0x7a,0xa3,0x1d,0x56, + 0xc8,0x4a,0x80,0x70,0xb7,0xbf,0xf2,0xa3,0xec,0xe8,0x77,0x05,0x33,0x09,0x9d, + 0xaa,0xca,0xa0,0xe1,0x64,0x64,0x6f,0x76,0x99,0x41,0x75,0x78,0x90,0xf6,0xe7, + 0x23,0xe6,0xec,0x50,0xe5,0x99,0xa8,0x3e,0x1a,0x4b,0xc9,0x88,0x58,0x66,0xae, + 0x1a,0x53,0x5e,0xe4,0xb7,0x86,0xcf,0xa6,0xe5,0xad,0xb4,0x80,0xa0,0xf1,0x0d, + 0x96,0xb8,0x41,0xd0,0x07,0x9a,0x21,0x8d,0x50,0x7f,0x4f,0x73,0x13,0xa2,0xe2, + 0x02,0x07,0xc3,0xa3,0x0f,0x09,0x18,0x7f,0xf7,0x6b,0x90,0x70,0xc0,0xf9,0x0c, + 0x67,0x8d,0x9d,0x14,0xb6,0x9d,0x32,0x82,0xd0,0xb5,0xc6,0x57,0xf0,0x91,0xd9, + 0xc3,0x26,0xae,0x9f,0xa9,0x67,0x49,0x96,0x5c,0x07,0x3e,0x47,0x5c,0xed,0x60, + 0x07,0xac,0x6a])]; + var DSAsecMPIstrs = [util.bin2str([0x01,0x00,0x9b,0x58,0xa8,0xf4,0x04,0xb1,0xd5,0x14,0x09,0xe1, + 0xe1,0xa1,0x8a,0x0b,0xa3,0xc3,0xa3,0x66,0xaa,0x27,0x99,0x50, + 0x1c,0x4d,0xba,0x24,0xee,0xdf,0xdf,0xb8,0x8e,0x8e])]; + + var ElgamalpubMPIstrs = + [util.bin2str([0x08,0x00,0xea,0xcc,0xbe,0xe2,0xe4,0x5a,0x51,0x18,0x93,0xa1,0x12,0x2f, + 0x00,0x99,0x42,0xd8,0x5c,0x1c,0x2f,0xb6,0x3c,0xd9,0x94,0x61,0xb4,0x55, + 0x8d,0x4e,0x73,0xe6,0x69,0xbc,0x1d,0x33,0xe3,0x2d,0x91,0x23,0x69,0x95, + 0x98,0xd7,0x18,0x5a,0xaf,0xa7,0x93,0xc6,0x05,0x93,0x3a,0xc7,0xea,0xd0, + 0xb1,0xa9,0xc7,0xab,0x41,0x89,0xc8,0x38,0x99,0xdc,0x1a,0x57,0x35,0x1a, + 0x27,0x62,0x40,0x71,0x9f,0x36,0x1c,0x6d,0x18,0x1c,0x93,0xf7,0xba,0x35, + 0x06,0xed,0x30,0xb8,0xd9,0x8a,0x7c,0x03,0xaf,0xba,0x40,0x1f,0x62,0xf1, + 0x6d,0x87,0x2c,0xa6,0x2e,0x46,0xb0,0xaa,0xbc,0xbc,0x93,0xfa,0x9b,0x47, + 0x3f,0x70,0x1f,0x2a,0xc2,0x66,0x9c,0x7c,0x69,0xe0,0x2b,0x05,0xee,0xb7, + 0xa7,0x7f,0xf3,0x21,0x48,0x85,0xc2,0x95,0x5f,0x6f,0x1e,0xb3,0x9b,0x97, + 0xf8,0x14,0xc3,0xff,0x4d,0x97,0x25,0x29,0x94,0x41,0x4b,0x90,0xd8,0xba, + 0x71,0x45,0x4b,0x1e,0x2f,0xca,0x82,0x5f,0x56,0x77,0xe9,0xd3,0x88,0x5d, + 0x8b,0xec,0x92,0x8b,0x8a,0x23,0x88,0x05,0xf8,0x2c,0xa8,0xf1,0x70,0x76, + 0xe7,0xbf,0x75,0xa8,0x31,0x14,0x8e,0x76,0xc8,0x01,0xa6,0x25,0x27,0x49, + 0xaf,0xdc,0xf4,0xf6,0xf4,0xce,0x90,0x84,0x15,0x2b,0x4d,0xb3,0xcc,0x77, + 0xdb,0x65,0x71,0x75,0xd3,0x00,0x1d,0x22,0xc5,0x42,0x2f,0x51,0xfa,0x7b, + 0xeb,0x6e,0x03,0xd9,0x41,0xdd,0x2d,0x1a,0xdd,0x07,0x74,0x8b,0xb7,0xa2, + 0xfa,0xb2,0x59,0x0e,0x0e,0x94,0x7c,0x00,0xad,0x95,0x23,0x42,0x91,0x18, + 0x4c,0x97,0xf1,0x27,0x62,0x77]), + util.bin2str([0x00,0x03,0x05]), + util.bin2str([0x07,0xff,0x57,0x19,0x76,0xfc,0x09,0x6a,0x7a,0xf7,0xba,0xb2,0x42,0xbf, + 0xcd,0x2b,0xc1,0x1a,0x79,0x25,0x8c,0xad,0xf4,0x3a,0x0a,0x7a,0x9b,0x4c, + 0x46,0x3c,0xe0,0x4f,0xcc,0x6e,0xe5,0x7a,0x33,0x3a,0x4e,0x80,0xcb,0xd3, + 0x62,0xd7,0x8f,0xe2,0xc8,0xb0,0xd0,0xcb,0x49,0xc9,0x9e,0x2d,0x97,0x16, + 0x3a,0x7d,0xb1,0xe1,0xd3,0xd9,0xd7,0x3f,0x20,0x60,0xe3,0x3e,0x77,0xea, + 0x0c,0xe4,0x7b,0xf0,0x39,0x1a,0x0d,0xd9,0x8f,0x73,0xd2,0x51,0xb8,0x0c, + 0x0e,0x15,0x1e,0xad,0x7c,0xd8,0x9d,0x74,0x6e,0xa2,0x17,0x6b,0x58,0x14, + 0x2b,0xb7,0xad,0x8a,0xd7,0x66,0xc0,0xdf,0xea,0x2d,0xfc,0xc4,0x6e,0x68, + 0xb6,0x4c,0x9a,0x16,0xa4,0x3d,0xc2,0x26,0x0c,0xb7,0xd4,0x13,0x7b,0x22, + 0xfd,0x84,0xd7,0x0f,0xdc,0x42,0x75,0x05,0x85,0x29,0x00,0x31,0x1d,0xec, + 0x4e,0x22,0x8b,0xf6,0x37,0x83,0x45,0xe5,0xb3,0x31,0x61,0x2c,0x02,0xa1, + 0xc6,0x9d,0xea,0xba,0x3d,0x8a,0xab,0x0f,0x61,0x5e,0x14,0x64,0x69,0x1e, + 0xa0,0x15,0x48,0x86,0xe5,0x11,0x06,0xe8,0xde,0x34,0xc7,0xa7,0x3d,0x35, + 0xd1,0x76,0xc2,0xbe,0x01,0x82,0x61,0x8d,0xe7,0x7e,0x28,0x1d,0x4e,0x8c, + 0xb9,0xe8,0x7e,0xa4,0x5f,0xa6,0x3a,0x9e,0x5d,0xac,0xf3,0x60,0x22,0x14, + 0xd5,0xd5,0xbe,0x1f,0xf0,0x19,0xe6,0x81,0xfd,0x5d,0xe1,0xf8,0x76,0x5f, + 0xe3,0xda,0xba,0x19,0xf3,0xcb,0x10,0xa0,0x6b,0xd0,0x2d,0xbe,0x40,0x42, + 0x7b,0x9b,0x15,0xa4,0x2d,0xec,0xcf,0x09,0xd6,0xe3,0x92,0xc3,0x8d,0x65, + 0x6b,0x60,0x97,0xda,0x6b,0xca])]; + + var ElgamalsecMPIstrs = [ + util.bin2str([0x01,0x52,0x02,0x80,0x87,0xf6,0xe4,0x49,0xd7,0x2e,0x3e,0xfe,0x60,0xb9, + 0xa3,0x2a,0xf0,0x67,0x58,0xe9,0xf6,0x47,0x83,0xde,0x7e,0xfb,0xbb,0xbd, + 0xdf,0x48,0x12,0x1b,0x06,0x7d,0x13,0xbc,0x3b,0x49,0xf9,0x86,0xd4,0x53, + 0xed,0x2d,0x68])]; + + var RSApubMPIs = []; + var i; + for (i = 0; i < 2; i++) { + RSApubMPIs[i] = new openpgp.mpi(); + RSApubMPIs[i].read(RSApubMPIstrs[i]); + } + + var RSAsecMPIs = []; + for (i = 0; i < 4; i++) { + RSAsecMPIs[i] = new openpgp.mpi(); + RSAsecMPIs[i].read(RSAsecMPIstrs[i]); + } + + var DSAsecMPIs = []; + for (i = 0; i < 1; i++) { + DSAsecMPIs[i] = new openpgp.mpi(); + DSAsecMPIs[i].read(DSAsecMPIstrs[i]); + } + + var DSApubMPIs = []; + for (i = 0; i < 4; i++) { + DSApubMPIs[i] = new openpgp.mpi(); + DSApubMPIs[i].read(DSApubMPIstrs[i]); + } + var ElgamalsecMPIs = []; + for (i = 0; i < 1; i++) { + ElgamalsecMPIs[i] = new openpgp.mpi(); + ElgamalsecMPIs[i].read(ElgamalsecMPIstrs[i]); + } + + var ElgamalpubMPIs = []; + for (i = 0; i < 3; i++) { + ElgamalpubMPIs[i] = new openpgp.mpi(); + ElgamalpubMPIs[i].read(ElgamalpubMPIstrs[i]); + } + + //Originally we passed public and secret MPI separately, now they are joined. Is this what we want to do long term? + // RSA + var RSAsignedData = openpgp.crypto.signature.sign(2, 1, RSApubMPIs.concat(RSAsecMPIs), "foobar"); + var RSAsignedDataMPI = new openpgp.mpi(); + RSAsignedDataMPI.read(RSAsignedData); + result[0] = new unit.result("Testing RSA Sign and Verify", + openpgp.crypto.signature.verify(1, 2, [RSAsignedDataMPI], RSApubMPIs, "foobar")); + + // DSA + var DSAsignedData = openpgp.crypto.signature.sign(2, 17, DSApubMPIs.concat(DSAsecMPIs), "foobar"); + + var DSAmsgMPIs = []; + DSAmsgMPIs[0] = new openpgp.mpi(); + DSAmsgMPIs[1] = new openpgp.mpi(); + DSAmsgMPIs[0].read(DSAsignedData.substring(0,34)); + DSAmsgMPIs[1].read(DSAsignedData.substring(34,68)); + result[1] = new unit.result("Testing DSA Sign and Verify", + openpgp.crypto.signature.verify(17, 2, DSAmsgMPIs, DSApubMPIs, "foobar")); + + var symmAlgo = "aes256"; // AES256 + var symmKey = openpgp.crypto.generateSessionKey(symmAlgo); + var symmencDataOCFB = openpgp.crypto.cfb.encrypt(openpgp.crypto.getPrefixRandom(symmAlgo), symmAlgo, "foobarfoobar1234567890", symmKey, true); + var symmencDataCFB = openpgp.crypto.cfb.encrypt(openpgp.crypto.getPrefixRandom(symmAlgo), symmAlgo, "foobarfoobar1234567890", symmKey, false); + + result[2] = new unit.result("Testing symmetric encrypt and decrypt with OpenPGP CFB resync", + openpgp.crypto.cfb.decrypt(symmAlgo,symmKey,symmencDataOCFB,true) == "foobarfoobar1234567890"); + result[3] = new unit.result("Testing symmetric encrypt and decrypt without OpenPGP CFB resync (used in modification detection code \"MDC\" packets)", + openpgp.crypto.cfb.decrypt(symmAlgo,symmKey,symmencDataCFB,false) == "foobarfoobar1234567890"); + + var RSAUnencryptedData = new openpgp.mpi(); + RSAUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength())); + var RSAEncryptedData = openpgp.crypto.publicKeyEncrypt("rsa_encrypt_sign", RSApubMPIs, RSAUnencryptedData); + + result[4] = new unit.result("Testing asymmetric encrypt and decrypt using RSA with eme_pkcs1 padding", + openpgp.crypto.pkcs1.eme.decode(openpgp.crypto.publicKeyDecrypt("rsa_encrypt_sign", RSApubMPIs.concat(RSAsecMPIs), RSAEncryptedData).write().substring(2), RSApubMPIs[0].byteLength()) == symmKey); + + var ElgamalUnencryptedData = new openpgp.mpi(); + ElgamalUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength())); + var ElgamalEncryptedData = openpgp.crypto.publicKeyEncrypt("elgamal", ElgamalpubMPIs, ElgamalUnencryptedData); + + result[5] = new unit.result("Testing asymmetric encrypt and decrypt using Elgamal with eme_pkcs1 padding", + openpgp.crypto.pkcs1.eme.decode(openpgp.crypto.publicKeyDecrypt("elgamal", ElgamalpubMPIs.concat(ElgamalsecMPIs), ElgamalEncryptedData).write().substring(2), ElgamalpubMPIs[0].byteLength()) == symmKey); + + return result; +}); diff --git a/test/ciphers/hash/md5.js b/test/crypto/hash/md5.js similarity index 60% rename from test/ciphers/hash/md5.js rename to test/crypto/hash/md5.js index 4fd6c254..c5d2a318 100644 --- a/test/ciphers/hash/md5.js +++ b/test/crypto/hash/md5.js @@ -1,17 +1,22 @@ +var unit = require('../../unit.js'); + +unit.register("MD5 test with test vectors from RFC 1321", function() { + var openpgp = require('openpgp'), + util = openpgp.util, + MD5 = openpgp.crypto.hash.md5; -unittests.register("MD5 test with test vectors from RFC 1321", function() { var result = new Array(); - result[0] = new test_result("MD5 (\"\") = d41d8cd98f00b204e9800998ecf8427e", + result[0] = new unit.result("MD5 (\"\") = d41d8cd98f00b204e9800998ecf8427e", util.hexstrdump(MD5("")) == "d41d8cd98f00b204e9800998ecf8427e"); - result[1] = new test_result("MD5 (\"a\") = 0cc175b9c0f1b6a831c399e269772661", + result[1] = new unit.result("MD5 (\"a\") = 0cc175b9c0f1b6a831c399e269772661", util.hexstrdump(MD5 ("abc")) == "900150983cd24fb0d6963f7d28e17f72"); - result[2] = new test_result("MD5 (\"message digest\") = f96b697d7cb7938d525a2f31aaf161d0", + result[2] = new unit.result("MD5 (\"message digest\") = f96b697d7cb7938d525a2f31aaf161d0", util.hexstrdump(MD5 ("message digest")) == "f96b697d7cb7938d525a2f31aaf161d0"); - result[3] = new test_result("MD5 (\"abcdefghijklmnopqrstuvwxyz\") = c3fcd3d76192e4007dfb496cca67e13b", + result[3] = new unit.result("MD5 (\"abcdefghijklmnopqrstuvwxyz\") = c3fcd3d76192e4007dfb496cca67e13b", util.hexstrdump(MD5 ("abcdefghijklmnopqrstuvwxyz")) == "c3fcd3d76192e4007dfb496cca67e13b"); - result[4] = new test_result("MD5 (\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\") = d174ab98d277d9f5a5611c2c9f419d9f", + result[4] = new unit.result("MD5 (\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\") = d174ab98d277d9f5a5611c2c9f419d9f", util.hexstrdump(MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")) == "d174ab98d277d9f5a5611c2c9f419d9f"); - result[5] = new test_result("MD5 (\"12345678901234567890123456789012345678901234567890123456789012345678901234567890\") = 57edf4a22be3c955ac49da2e2107b67a", + result[5] = new unit.result("MD5 (\"12345678901234567890123456789012345678901234567890123456789012345678901234567890\") = 57edf4a22be3c955ac49da2e2107b67a", util.hexstrdump(MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890")) == "57edf4a22be3c955ac49da2e2107b67a"); return result; }); diff --git a/test/crypto/hash/ripemd.js b/test/crypto/hash/ripemd.js new file mode 100644 index 00000000..25c3970c --- /dev/null +++ b/test/crypto/hash/ripemd.js @@ -0,0 +1,19 @@ +var unit = require('../../unit.js'); + +unit.register("RIPE-MD 160 bits test with test vectors from http://homes.esat.kuleuven.be/~bosselae/ripemd160.html", function() { + + var openpgp = require('openpgp'), + util = openpgp.util, + RMDstring = openpgp.crypto.hash.ripemd; + + var result = new Array(); + result[0] = new unit.result("RMDstring (\"\") = 9c1185a5c5e9fc54612808977ee8f548b2258d31", + util.hexstrdump(RMDstring("")) == "9c1185a5c5e9fc54612808977ee8f548b2258d31"); + result[1] = new unit.result("RMDstring (\"a\") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", + util.hexstrdump(RMDstring("a")) == "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); + result[2] = new unit.result("RMDstring (\"abc\") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", + util.hexstrdump(RMDstring("abc")) == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); + result[3] = new unit.result("RMDstring (\"message digest\") = 5d0689ef49d2fae572b881b123a85ffa21595f36", + util.hexstrdump(RMDstring("message digest")) == "5d0689ef49d2fae572b881b123a85ffa21595f36"); + return result; +}); diff --git a/test/crypto/hash/sha.js b/test/crypto/hash/sha.js new file mode 100644 index 00000000..52f0d304 --- /dev/null +++ b/test/crypto/hash/sha.js @@ -0,0 +1,32 @@ +var unit = require('../../unit.js'); + + +unit.register("SHA* test with test vectors from NIST FIPS 180-2", function() { + var openpgp = require('openpgp'), + util = openpgp.util, + hash = openpgp.crypto.hash; + + var result = new Array(); + + result[0] = new unit.result("SHA1 - a9993e364706816aba3e25717850c26c9cd0d89d = hash.sha1(\"abc\") ", + "a9993e364706816aba3e25717850c26c9cd0d89d" == util.hexstrdump(hash.sha1("abc"))); + result[1] = new unit.result("SHA1 - 84983e441c3bd26ebaae4aa1f95129e5e54670f1 = hash.sha1(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1" == util.hexstrdump(hash.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); + result[2] = new unit.result("SHA224 - 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 = hash.sha224(\"abc\") ", + "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" == util.hexstrdump(hash.sha224("abc"))); + result[3] = new unit.result("SHA224 - 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525 = hash.sha224(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", + "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" == util.hexstrdump(hash.sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); + result[4] = new unit.result("SHA256 - ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad = hash.sha256(\"abc\") ", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" == util.hexstrdump(hash.sha256("abc"))); + result[5] = new unit.result("SHA256 - 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 = hash.sha256(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" == util.hexstrdump(hash.sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); + result[6] = new unit.result("SHA384 - cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 = hash.sha384(\"abc\") ", + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" == util.hexstrdump(hash.sha384("abc"))); + result[7] = new unit.result("SHA384 - 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b = str384(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", + "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b" == util.hexstrdump(hash.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); + result[8] = new unit.result("SHA512 - ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f = hash.sha512(\"abc\") ", + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" == util.hexstrdump(hash.sha512("abc"))); + result[9] = new unit.result("SHA512 - 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 = hash.sha512(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ", + "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" == util.hexstrdump(hash.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); + return result; +}); diff --git a/test/general/basic.js b/test/general/basic.js new file mode 100644 index 00000000..e6b3d97b --- /dev/null +++ b/test/general/basic.js @@ -0,0 +1,148 @@ +var unit = require('../unit.js'); + +unit.register("Key generation/encryption/decryption", function() { + var openpgp = require('openpgp'); + var result = []; + var testHelper = function(passphrase, userid, message) { + var key = openpgp.generateKeyPair(openpgp.enums.publicKey.rsa_encrypt_sign, 512, + userid, passphrase); + + var info = '\npassphrase: ' + passphrase + '\n' + + 'userid: ' + userid + '\n' + + 'message: ' + message; + + var privKey = openpgp.key.readArmored(key.privateKeyArmored).keys[0]; + + var encrypted = openpgp.encryptMessage([privKey], message); + + var msg = openpgp.message.readArmored(encrypted); + + var keyids = msg.getEncryptionKeyIds(); + + privKey.decryptKeyPacket(keyids, passphrase); + + try { + var decrypted = openpgp.decryptMessage(privKey, msg); + return new unit.result(message + ' == ' + decrypted + info, message == decrypted); + } catch (e) { + return new unit.result("Exception on decrypt of private key packet!" + info, false); + } + + }; + + result.push(testHelper('password', 'Test McTestington ', 'hello world')); + result.push(testHelper('●●●●', '♔♔♔♔ ', 'łäóć')); + + return result; +}); + +unit.register("Message encryption/decryption", function() { + var openpgp = require('openpgp'); + + var result = []; + + var pub_key = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + 'Type: RSA/RSA', + '', + 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', + 'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5', + 'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0', + 'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS', + 'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6', + 'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki', + 'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf', + '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa', + 'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag', + 'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr', + 'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb', + 'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA', + 'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP', + 'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2', + 'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X', + 'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD', + 'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY', + 'hz3tYjKhoFTKEIq3y3Pp', + '=h/aX', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + + var priv_key = + ['-----BEGIN PGP PRIVATE KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + 'Type: RSA/RSA', + 'Pwd: hello world', + '', + 'lQH+BFJhL04BBADclrUEDDsm0PSZbQ6pml9FpzTyXiyCyDN+rMOsy9J300Oc10kt', + '/nyBej9vZSRcaW5VpNNj0iA+c1/w2FPf84zNsTzvDmuMaNHFUzky4/vkYuZra//3', + '+Ri7CF8RawSYQ/4IRbC9zqdBlzniyfQOW7Dp/LYe8eibnDSrmkQem0G0jwARAQAB', + '/gMDAu7L//czBpE40p1ZqO8K3k7UejemjsQqc7kOqnlDYd1Z6/3NEA/UM30Siipr', + 'KjdIFY5+hp0hcs6EiiNq0PDfm/W2j+7HfrZ5kpeQVxDek4irezYZrl7JS2xezaLv', + 'k0Fv/6fxasnFtjOM6Qbstu67s5Gpl9y06ZxbP3VpT62+Xeibn/swWrfiJjuGEEhM', + 'bgnsMpHtzAz/L8y6KSzViG/05hBaqrvk3/GeEA6nE+o0+0a6r0LYLTemmq6FbaA1', + 'PHo+x7k7oFcBFUUeSzgx78GckuPwqr2mNfeF+IuSRnrlpZl3kcbHASPAOfEkyMXS', + 'sWGE7grCAjbyQyM3OEXTSyqnehvGS/1RdB6kDDxGwgE/QFbwNyEh6K4eaaAThW2j', + 'IEEI0WEnRkPi9fXyxhFsCLSI1XhqTaq7iDNqJTxE+AX2b9ZuZXAxI3Tc/7++vEyL', + '3p18N/MB2kt1Wb1azmXWL2EKlT1BZ5yDaJuBQ8BhphM3tCRUZXN0IE1jVGVzdGlu', + 'Z3RvbiA8dGVzdEBleGFtcGxlLmNvbT6IuQQTAQIAIwUCUmEvTgIbLwcLCQgHAwIB', + 'BhUIAgkKCwQWAgMBAh4BAheAAAoJEEpjYTpNbkCUMAwD+gIK08qpEZSVas9qW+Ok', + '32wzNkwxe6PQgZwcyBqMQYZUcKagC8+89pMQQ5sKUGvpIgat42Tf1KLGPcvG4cDA', + 'JZ6w2PYz9YHQqPh9LA+PAnV8m25TcGmKcKgvFUqQ3U53X/Y9sBP8HooRqfwwHcv9', + 'pMgQmojmNbI4VHydRqIBePawnQH+BFJhL04BBADpH8+0EVolpPiOrXTKoBKTiyrB', + 'UyxzodyJ8zmVJ3HMTEU/vidpQwzISwoc/ndDFMXQauq6xqBCD9m2BPQI3UdQzXnb', + 'LsAI52nWCIqOkzM5NAKWoKhyXK9Y4UH4v9LAYQgl/stIISvCgG4mJ8lzzEBWvRdf', + 'Qm2Ghb64/3V5NDdemwARAQAB/gMDAu7L//czBpE40iPcpLzL7GwBbWFhSWgSLy53', + 'Md99Kxw3cApWCok2E8R9/4VS0490xKZIa5y2I/K8thVhqk96Z8Kbt7MRMC1WLHgC', + 'qJvkeQCI6PrFM0PUIPLHAQtDJYKtaLXxYuexcAdKzZj3FHdtLNWCooK6n3vJlL1c', + 'WjZcHJ1PH7USlj1jup4XfxsbziuysRUSyXkjn92GZLm+64vCIiwhqAYoizF2NHHG', + 'hRTN4gQzxrxgkeVchl+ag7DkQUDANIIVI+A63JeLJgWJiH1fbYlwESByHW+zBFNt', + 'qStjfIOhjrfNIc3RvsggbDdWQLcbxmLZj4sB0ydPSgRKoaUdRHJY0S4vp9ouKOtl', + '2au/P1BP3bhD0fDXl91oeheYth+MSmsJFDg/vZJzCJhFaQ9dp+2EnjN5auNCNbaI', + 'beFJRHFf9cha8p3hh+AK54NRCT++B2MXYf+TPwqX88jYMBv8kk8vYUgo8128r1zQ', + 'EzjviQE9BBgBAgAJBQJSYS9OAhsuAKgJEEpjYTpNbkCUnSAEGQECAAYFAlJhL04A', + 'CgkQ4IT3RGwgLJe6ogQA2aaJEIBIXtgrs+8WSJ4k3DN4rRXcXaUZf667pjdD9nF2', + '3BzjFH6Z78JIGaxRHJdM7b05aE8YuzM8f3NIlT0F0OLq/TI2muYU9f/U2DQBuf+w', + 'KTB62+PELVgi9MsXC1Qv/u/o1LZtmmxTFFOD35xKsxZZI2OJj2pQpqObW27M8Nlc', + 'BQQAw2YA3fFc38qPK+PY4rZyTRdbvjyyX+1zeqIo8wn7QCQwXs+OGaH2fGoT35AI', + 'SXuqKcWqoEuO7OBSEFThCXBfUYMC01OrqKEswPm/V3zZkLu01q12UMwZach28QwK', + '/YZly4ioND2tdazj17u2rU2dwtiHPe1iMqGgVMoQirfLc+k=', + '=lw5e', + '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); + + var plaintext = 'short message\nnext line\n한국어/조선말'; + + var key = openpgp.key.readArmored(pub_key).keys[0]; + + var encrypted = openpgp.encryptMessage([key], plaintext); + + var message = openpgp.message.readArmored(encrypted); + + var privKey = openpgp.key.readArmored(priv_key).keys[0]; + + // get key IDs the message is encrypted for + var keyids = message.getEncryptionKeyIds(); + + // decrypt only required key packets + var success = privKey.decryptKeyPacket(keyids, 'hello what?') + + result.push(new unit.result('Decrypting key packet with wrong password returns false', !success)); + + var decrypted, error; + try { + decrypted = openpgp.decryptMessage(privKey, message); + } catch (e) { + error = e; + } + result.push(new unit.result('Calling decryptMessage with not decrypted key packet leads to exception: \'' + (error || '') + '\'', error)); + + success = privKey.decryptKeyPacket(keyids, 'hello world'); + + result.push(new unit.result('Decrypting key packet with correct password returns true', success)); + + decrypted = openpgp.decryptMessage(privKey, message); + + result.push(new unit.result('Encrypt plain text and afterwards decrypt leads to same result', plaintext == decrypted)); + + return result; + +}); diff --git a/test/general/key.js b/test/general/key.js new file mode 100644 index 00000000..c3e8181d --- /dev/null +++ b/test/general/key.js @@ -0,0 +1,266 @@ +var unit = require('../unit.js'); + +unit.register("Key testing", function() { + var openpgp = require('openpgp'); + + var twoKeys = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', + 'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5', + 'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0', + 'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS', + 'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6', + 'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki', + 'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf', + '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa', + 'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag', + 'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr', + 'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb', + 'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA', + 'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP', + 'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2', + 'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X', + 'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD', + 'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY', + 'hz3tYjKhoFTKEIq3y3PpmQENBFKV0FUBCACtZliApy01KBGbGNB36YGH4lpr+5Ko', + 'qF1I8A5IT0YeNjyGisOkWsDsUzOqaNvgzQ82I3MY/jQV5rLBhH/6LiRmCA16WkKc', + 'qBrHfNGIxJ+Q+ofVBHUbaS9ClXYI88j747QgWzirnLuEA0GfilRZcewII1pDA/G7', + '+m1HwV4qHsPataYLeboqhPA3h1EVVQFMAcwlqjOuS8+weHQRfNVRGQdRMm6H7166', + 'PseDVRUHdkJpVaKFhptgrDoNI0lO+UujdqeF1o5tVZ0j/s7RbyBvdLTXNuBbcpq9', + '3ceSWuJPZmi1XztQXKYey0f+ltgVtZDEc7TGV5WDX9erRECCcA3+s7J3ABEBAAG0', + 'G0pTIENyeXB0byA8ZGlmZmllQGhvbWUub3JnPokBPwQTAQIAKQUCUpXQVQIbAwUJ', + 'CWYBgAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJENvyI+hwU030yRAIAKX/', + 'mGEgi/miqasbbQoyK/CSa7sRxgZwOWQLdi2xxpE5V4W4HJIDNLJs5vGpRN4mmcNK', + '2fmJAh74w0PskmVgJEhPdFJ14UC3fFPq5nbqkBl7hU0tDP5jZxo9ruQZfDOWpHKx', + 'OCz5guYJ0CW97bz4fChZNFDyfU7VsJQwRIoViVcMCipP0fVZQkIhhwpzQpmVmN8E', + '0a6jWezTZv1YpMdlzbEfH79l3StaOh9/Un9CkIyqEWdYiKvIYms9nENyehN7r/OK', + 'YN3SW+qlt5GaL+ws+N1w6kEZjPFwnsr+Y4A3oHcAwXq7nfOz71USojSmmo8pgdN8', + 'je16CP98vw3/k6TncLS5AQ0EUpXQVQEIAMEjHMeqg7B04FliUFWr/8C6sJDb492M', + 'lGAWgghIbnuJfXAnUGdNoAzn0S+n93Y/qHbW6YcjHD4/G+kK3MuxthAFqcVjdHZQ', + 'XK0rkhXO/u1co7v1cdtkOTEcyOpyLXolM/1S2UYImhrml7YulTHMnWVja7xu6QIR', + 'so+7HBFT/u9D47L/xXrXMzXFVZfBtVY+yoeTrOY3OX9cBMOAu0kuN9eT18Yv2yi6', + 'XMzP3iONVHtl6HfFrAA7kAtx4ne0jgAPWZ+a8hMy59on2ZFs/AvSpJtSc1kw/vMT', + 'WkyVP1Ky20vAPHQ6Ej5q1NGJ/JbcFgolvEeI/3uDueLjj4SdSIbLOXMAEQEAAYkB', + 'JQQYAQIADwUCUpXQVQIbDAUJCWYBgAAKCRDb8iPocFNN9NLkB/wO4iRxia0zf4Kw', + '2RLVZG8qcuo3Bw9UTXYYlI0AutoLNnSURMLLCq6rcJ0BCXGj/2iZ0NBxZq3t5vbR', + 'h6uUv+hpiSxK1nF7AheN4aAAzhbWx0UDTF04ebG/neE4uDklRIJLhif6+Bwu+EUe', + 'TlGbDj7fqGSsNe8g92w71e41rF/9CMoOswrKgIjXAou3aexogWcHvKY2D+1q9exO', + 'Re1rIa1+sUGl5PG2wsEsznN6qtN5gMlGY1ofWDY+I02gO4qzaZ/FxRZfittCw7v5', + 'dmQYKot9qRi2Kx3Fvw+hivFBpC4TWgppFBnJJnAsFXZJQcejMW4nEmOViRQXY8N8', + 'PepQmgsu', + '=w6wd', + '-----END PGP PUBLIC KEY BLOCK-----'].join("\n"); + + var pub_revoked = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'mQENBFKpincBCADhZjIihK15f3l+j87JgeLp9eUTSbn+g3gOFSR73TOMyBHMPt8O', + 'KwuA+TN2sM86AooOR/2B2MjHBUZqrgeJe+sk5411yXezyYdQGZ8vlq/FeLeNF70D', + 'JrvIC6tsEe2F9F7ICO7o7G+k5yveLaYQNU/okiP8Gj79XW3wN77+yAMwpQzBsrwa', + 'UO/X4mDV59h1DdrTuN4g8SZhAmY/JfT7YCZuQ8ivOs9n7xPdbGpIQWGWjJLVWziC', + '7uvxN4eFOlCqvc6JwmS/xyYGKL2B3RcQuY+OlvQ3wxKFEGDfG73HtWBd2soB7/7p', + 'w53mVcz5sLhkOWjMTj+VDDZ3jas+7VznaAbVABEBAAGJAToEIAECACQFAlKpj3od', + 'HQNUZXN0aW5nIHJldm9rZSBjb21wbGV0ZSBrZXkACgkQO+K1SH0WBbOtJgf/XqJF', + 'dfWJjXBPEdfDbnXW+OZcvVgUMEEKEKsS1MiB21BEQpsTiuOLLgDOnEKRDjT1Z9H/', + '6owkb1+iLOZRGcJIdXxxAi2W0hNwx3qSiYkJIaYIm6dhoTy77lAmrPGwjoBETflU', + 'CdWWgYFUGQVNPnpCi0AizoHXX2S4zaVlLnDthss+/FtIiuiYAIbMzB902nhF0oKH', + 'v5PTrm1IpbstchjHITtrRi4tdbyvpAmZFC6a+ydylijNyKkMeoMy0S+6tIAyaTym', + 'V5UthMH/Kk2n3bWNY4YnjDcQpIPlPF1cEnqq2c47nYxHuYdGJsw9l1F88J0enL72', + '56LWk5waecsz6XOYXrQTVjMgS2V5IDx2M0BrZXkuY29tPokBMQQwAQIAGwUCUqmP', + 'BRQdIFRlc3RpbmcgcmV2b2RlIHVpZAAKCRA74rVIfRYFszHUB/oCAV+IMzZF6uad', + 'v0Gi+Z2qCY1Eqshdxv4i7J2G3174YGF9+0hMrHwsxBkVQ/oLZKBFjfP7Z1RZXxso', + 'ts0dBho3XWZr3mrEk6Au6Ss+pbGNqq2XytV+CB3xY0DKX1Q0BJOEhgcSNn187jqd', + 'XoKLuK/hy0Bk6YkXe1lv6HqkFxYGNB2MW0wSPjrfnjjHkM29bM0Q/JNVY4o/osmY', + 'zoY/hc59fKBm5uBBL7kEtSkMO0KPVzqhvMCi5qW9/V9+vNn//WWOY+fAXYKa1cBo', + 'aMykBfE2gGf/alIV9dFpHl+TkIT8lD8sY5dBmiKHN4D38PhuLdFWHXLe4ww7kqXt', + 'JrD0bchKiQE/BBMBAgApBQJSqYp3AhsDBQkJZgGABwsJCAcDAgEGFQgCCQoLBBYC', + 'AwECHgECF4AACgkQO+K1SH0WBbOOAwgAx9Qr6UciDbN2Bn1254YH6j5HZbVXGTA/', + 'uQhZZGAYE/wDuZ5u8Z2U4giEZ3dwtblqRZ6WROmtELXn+3bGGbYjczHEFOKt4D/y', + 'HtrjCtQX04eS+FfL453n7aaQbpmHou22UvV0hik+iagMbIrYnB6nqaui9k8HrGzE', + '1HE1AeC5UTlopEHb/KQRGLUmAlr8oJEhDVXLEq41exNTArJWa9QlimFZeaG+vcbz', + '2QarcmIXmZ3o+1ARwZKTK/20oCpF6/gUGnY3KMvpLYdW88Qznsp+7yWhpC1nchfW', + '7frQmuQa94yb5PN7kBJ83yF/SZiDggZ8YfcCf1DNcbw8bjPYyFNW3bkBDQRSqYp3', + 'AQgA1Jgpmxwr2kmP2qj8FW9sQceylHJr4gUfSQ/4KPZbGFZhzK+xdEluBJOzxNbf', + 'LQXhQOHbWFmlNrGpoVDawZbA5FL7w5WHYMmNY1AADmmP0uHbHqdOvOyz/boo3fU0', + 'dcl0wOjo06vsUqLf8/3skQstUFjwLzjI2ebXWHXj5OSqZsoFvj+/P/NaOeVuAwFx', + '50vfUK19o40wsRoprgxmZOIL4uMioQ/V/QUr++ziahwqFwDQmqmj0bAzV/bIklSJ', + 'jrLfs7amX8qiGPn8K5UyWzYMa2q9r0Srt/9wx+FoSRbqRvsqLFYoU3d745zX1W7o', + 'dFcDddGMv5LMPnvNR+Qm7PUlowARAQABiQE0BCgBAgAeBQJSqY5XFx0DVGVzdGlu', + 'ZyBzdWJrZXkgcmV2b2tlAAoJEDvitUh9FgWzsUoH/1MrYYo7aQErScnhbIVQ5qpB', + 'qnqBTiyVGa3cqSPKUkT552dRs6TwsjFKnOs68MIZQ6qfliZE/ApKPQhxaHgmfWKI', + 'Q09Qv04SKHqo9njX6E3q257DnvmQiv6c9PRA3G/p2doBrj3joaOVm/ZioiCZdf2W', + 'l6akAf7j5DbcVRh8BQigM4EUhsVjBvGPYxqVNIM4aWHMTG62CaREa9g1PWOobASU', + 'jX47B7/FFP4zCLkeb+znDMwc8jKWeUBp5sUGhWo74wFiD5Dp2Zz50qRi1u05nJXg', + 'bIib7pwmH2CeDwmPRi/HRUrKBcqFzSYG5QVggQ5KMIU9M7zmvd8mDYE8MQbTLbaJ', + 'ASUEGAECAA8FAlKpincCGwwFCQlmAYAACgkQO+K1SH0WBbPbnQgAxcYAS3YplyBI', + 'ddNJQNvyrWnnuGXoGGKgkE8+LUR3rX3NK/c4pF7EFgrNxKIPrWZoIu7m1XNqoK3g', + 'PwRXJfPPQWalVrhhOajtYipXumQVAe+q8DyxAZ5YJGrUvR9b96GRel9G+HsRlR1M', + 'NV62ZXFdXVgg9FZJHDR8fa1Zy93xC0JSKu4ZoCrH5ybw+DPCngogDl4KwgdV5y4e', + 'EAZpGDSq7PrdsgZTiSuepwVw116GWJm1zecmh6FdpZL/ZrE6EfYcCGJqJiVfDiCR', + 'jgvGbcTzxnvrRmDevmJUdXBSAE11OYQuDGlhgFCU0o9cdX+k+QqP5wNycXhoJ+yk', + 'pMiJM+NJAQ==', + '=ok+o', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + + var pub_v3 = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: SKS 1.1.3', + '', + 'mQENAy9J/w4AAAEIALBDDD4vWqG/Jg59ghhMYAa+E7ECCTv2At8hxsM5cMP8P9sMLjs+GMfD', + 'IdQSOqlQXbunYADvM1l/h2fOuUMoYFIIGaUsO5Daxvd9uWceM4DVzhXMeJZb9wc5jEJEF21+', + 'qidKj5OGsMyTrg++mn4Gh/aFXvvy3N3KWaQpPfNi3NRZUpNLz0IlfbXVBQGD6reLoxPptJun', + 'NqpClyRiesgq8HCscmB2oQo+b9KzSSgzU9qQJA4SljMYVmJ2sDE/sjREI8iKL8lIgUMhJG9q', + 'NggWjuxFTpVcGKkuQFJIvdL+UhTVvEBuqw6n4cmFAzfZ/AInJM032qLtsaIf5begFKI3up0A', + 'BRGJARUDBSAxm7HC5begFKI3up0BAbdDB/0TOcI0ec+OPxC5RTZAltgIgyUc0yOjHoTD/yBh', + 'WjZdQ9YVrLGMWTW4fjhm4rFnppVZKS/N71bwI76SnN9zO4pPfx86aQPR7StmSLJxB+cfh2GL', + 'gudJoG9ifhJWdNYMUD/yhA0TpJkdHMD5yTDE5Ce/PqKLviiX9C5MPW0AT1MDvafQlzeUXfb5', + '1a71vQNPw7W1NBAVZRwztm7TNUaxWMFuOmUtOJpq4F/qDQTIHW2zGPJvl47rpf6JSiyIyU70', + 'l0deiQcZOXPC80tgInhNoBrz3zbEXhXRJo1fHkr2YSLclpJaoUOHsPxoyrNB28ASL5ZknPwI', + 'Zx3+cFxaGpRprfSdtCFKb2huIEEuIFBlcnJ5IDxwZXJyeUBwaG9lbml4Lm5ldD6JARUDBRAv', + 'Sf8k5begFKI3up0BAcbGB/0eLod2qrQxoE2/RUWQtqklOPUj/p/ZTmvZm8BgsdIflb0AMeey', + '9o8AbxyAgA3pcrcCjcye79M1Ma2trEvRksvs8hViuq3BXXjDbjPZi3wTtKSvbAC022OV52Sb', + '8/sgiTGp7xC8QMqS8w4ZeKoxJGh1TVMYrevUA8a2Rr5aDqrR3EA4rifSHwkVjJWOPF69xiKt', + 'IVA0LcYJvGsPOQCf2ag+nOcnDrF4dvcmg6XZ/RyLepve+1qkhXsA/oq+yHoaqWfe+bwgssk/', + 'qw1aEUk7Di8x7vY+cfjvWaazcYGw8kkIwSSqqIq0pkKFz2xDDfSaDJl6OW/2GUK0wDpJmYZo', + 'PN40iJUDBRAvSgDsU5OkROGu2G8BAeUqBACbC45t4+wYxWCxxp81pkFRb8RWBvEvbXI+Spwd', + '4NcKs8jc5OVC8V02yiq4KbKFDRxdw2OWpUCSRAJe1gjsfFrZ+2RivpKk06kbAYthES03MjXg', + 'cfcV3z2d7IWanJzdcOlzsHzPe1+RoUAaqBjvcqPRCGRlk0ogkYHyWYxElc6574iVAwUQL9iL', + 'CXr7ES8bepftAQGPywP/d9GSpEmS7LLIqazl4rgN1nkXN5KqduiH8Whu3xcBrdOAn7IYnGTp', + 'O+Ag4qwKKH+y/ke9CeZL6AnrU9c0pux150dHsDeHtpTPyInkjgKI7BofprydvpiFNd0nlAi4', + 'J4SAEYr3q92Qn/IiKpnLgo6Ls/GFb7q6y1O/2LL8PC2zrYU=', + '=eoGb', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + + var pub_sig_test = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'mQENBFKgqXUBCADC4c6sSBnBU+15Y32/a8IXqO2WxKxSHj7I5hv1OdSTmSZes7nZ', + '5V96qsk0k5/ka3C2In+GfTKfuAJ0oVkTZVi5tHP9D+PcZngrIFX56OZ2P5PtTU7U', + 'jh0C78JwCVnv6Eg57JnIMwdbL3ZLqmogLhw5q15Hie5btCIQnuuKfrwxnsox4i3q', + 'dYCHYB1HBGzpvflS07r3Y3IRFJaP8hUhx7PsvpD1s+9DU8AuMNZTXAqRI/bms5hC', + 'BpVejXLj/vlNeQil99MoI7s14L+dHogYuUOUbsXim5EyIFfF/1v+o5l0wmueWrE8', + 'mYQfj5ZvURlGVFah9ECaW9/ResCyJ1Yh975xABEBAAG0I1NpZ25hdHVyZSBUZXN0', + 'IDxzaWduYXR1cmVAdGVzdC5jb20+iQE8BBMBAgAmAhsDBwsJCAcDAgEGFQgCCQoL', + 'BBYCAwECHgECF4AFAlKgq80CGQEACgkQwHbmNNMrSY3KKQf/UGnuc6LbVyhkFQKo', + 'USTVDFg/42CVmIGOG+aZBo0VZuzNYARwDKyoZ5okKqZi5VSfdDaBXuW4VIYepvux', + 'AV8eJV6GIsLRv/wJcKPABIXDIK1tdNetiYbd+2/Fb2/YqAX5wOKIxd3Ggzyx5X4F', + 'WhA6fIBIXyShUWoadkX7S87z5hryhII9281rW2mOsLC5fy/SUQUWM1YmsZ1owvY9', + 'q6W8xRnHDmY+Ko91xex7fikDLBofsWbTUc0/O/1o9miIZfp2nXLKQus2H1WdZVOe', + 'H9zFiy54x7+zTov94SJE3xXppoQnIpeOTlFjTP2mjxm0VW1Dn9lGE3IFgWolpNPy', + 'Rv6dnLQdU2Vjb25kIFVzZXIgPHNlY29uZEB1c2VyLmNvbT6IowQwAQIADQUCUrF1', + 'hwYdIEh1cnoACgkQSmNhOk1uQJRVeQP9GQoLvan5FMYcPPY4a9dNlkvtheRXcoif', + 'oYdQoEyy9zAFCqmg2pC6RrHaMwNINw534JDh2vgWQ0MU3ktMJjSvGBBHayQc6ov8', + 'i4I6rUPBlYoSDKyFnhCCXWF56bHMGyEGJhcQLv1hrGPVv6PTKj3hyR+2n50Impwo', + 'UrlFIwYZNyWJAS8EMAECABkFAlKgqqYSHSBUZXN0aW5nIHB1cnBvc2VzAAoJEMB2', + '5jTTK0mNvKAH/Rgu+I12Fb7S8axNwzp5m/jl1iscYbjgOrdUEI7bc2yo0KhGwYOV', + 'U3Zj68Ogj6gkLkVwfhvJYZJgfYBG7nTxkC5/MTABQrAI5ZX89Hh9y0tLh2wKr5iK', + 'MH6Mi9xxJmVJ+IiAKx/02f+sKWh4tv3TFNNxnp24LPHWz7RMd/o4m8itmzQxFmaZ', + 'yEPd/CD6hYqSMP5Y7zMN4gTB+tHsawB9PWkrF/dW8bk3PtZanDlBMUSVrPH15bIZ', + 'lFO1NKEN39WagmNe5wezKxWmHBcuISQHxCIX3Hf4dYyexndX25fMphF93YgQnNE+', + 'zQeBJyNBKRpMXzGndELo5KFaA1YyC07GKKyJATkEEwECACMFAlKgqeYCGwMHCwkI', + 'BwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRDAduY00ytJjagNCACGQMQPl6foIVcz', + 'OzLf8npGihIjiIYARQz4+yg6ze9TG2hjIpWLiwGNJ0uEG22cFiN7OeFnUADFi131', + 'oEtZzIXcBd0A1S87ooH+86YjpvLj5PMlviVKGsGmdqtWpQN5fII8brydNLwSHlLV', + '+JolvyMlA2Ao/sePopR0aSKIPfD108YIIiZztE4pHgDzE5G66zAw3zWn/dzLuGln', + 'Mp4nrY8Rxb68MaZFhVq0A5QFzlOjQ/iDJWrPM6vy/U8TQxmaYGMjcEyEEil+3+OJ', + 'OFqfB4byISOIxL9LqFVRndbgOw7ICi+qE2e7+9G2koCtEkjpPg3ZCF4mfZiaLT9p', + 'QhoFS4yxiJwEEAECAAYFAlKgqhYACgkQSmNhOk1uQJSJ0gP9F5RRwGBbXD4Mg4gq', + 'wcQYrzw9ZAapLKZ2vuco6gHknQAM1YuaOpKQu1rd6eFzKE4M11CLmoS/CalDhg9f', + 'aN6fvTZG7lbUnSZKl/tgvG7qeneA919/b1RtMNDkHmRxvHysiyDYmkJYlmZlwXZB', + '5FBoRvv5b2oXfWLLEcNvUvbetuC5AQ0EUqCpdQEIAOMvycVLkIKm9EMbxFqGc019', + 'yjCB3xiK+hF0PwdfWBXF8KskJ4hfybd19LdO6EGnKfAVGaeVEt6RtUJMsgfhqAhE', + 'BwaeHLLfjXjd7PetBdzybh0u2kfaGDBQshdEuLcfqTqp4+R+ha1epdXAPDP+lb9E', + '5OXIOU2EWLSY+62fyGw3kvUSYNQKufDoKuq5vzltW1uYVq3aeA7e/yTqEoWSoRGo', + '25f/xaY6u6sYIyLpkZ6IX1n1BzLirfJSkJ8svNX+hNihCDshKJUDoMwAPcRdICkr', + 'vFbrO3k24OylQA6dpQqHUWD9kVu8sEZH/eiHZ5YBo/hgwNH7UMaFSBAYQZrSZjcA', + 'EQEAAYkBHwQoAQIACQUCUqCrcgIdAwAKCRDAduY00ytJjeO9B/9O/A6idEMy6cEG', + 'PAYv0U/SJW0RcM54/Ptryg3jiros+qkLQD+Hp2q/xxpXKFPByGWkkGZnNIIxaA1j', + 'SPvOJXrK728b/OXKB3IaMknKTB7gLGH4oA9/dmzHgbeqNWXYok5GSwPxLSUoeIrZ', + 'j+6DkUz2ebDx1FO797eibeL1Dn15iyWh/l3QMT+1fLjJyVDnEtNhZibMlDPohVuS', + 'suJfoKbQJkT6mRy4nDWsPLzFOt3VreJKXo9MMrrHV44XeOKo5nqCK3KsfCoeoqft', + 'G7e/NP4DgcfkgNrU/XnBmR9ZVn9/o3EbDENniOVlNH2JaSQskspv5fv7k6dRWn4Q', + 'NRhN5uMWiQEfBBgBAgAJBQJSoKl1AhsMAAoJEMB25jTTK0mNgaEIAKBkMGTSexox', + 'zy6EWtSR+XfA+LxXjhwOgJWrRKvLUqssGbhQNRfY3gy7dEGiSKdnIV+d/xSLgm7i', + 'zAyE4SjmDDOFRfxpyEsxhw2738OyEenEvO70A2J6RLj91Rfg9+vhT7WWyxBKdU1b', + 'zM2ZORHCBUmbqjYAiLUbz0E589YwJR3a7osjCC8Lstf2C62ttAAAcKks2+wt4kUQ', + 'Zm7WAUi1kG26VvOXVg9Tnj00mnBWmWlLPG7Qjudf2RBMJ/S8gg9OZWpBN29NEl6X', + 'SU+DbbDHw3G97gRNE7QcHZPGyRtjbKv3nV2mJ8DMKrTzLuPUUcFqd7AlpdrFeDx/', + '8YM3DBS79eW5Ay4EUqCq0hEIAMIgqJsi3uTPzJw4b4c1Oue+O98jWaacrk7M57+y', + 'Ol209yRUDyLgojs8ZmEZWdvjBG1hr15FIYI4BmusVXHCokVDGv8KNP4pvbf5wljM', + '2KG1FAxvxZ38/VXTDVH8dOERTf8JPLKlSLbF6rNqfePIL/1wto47b6oRCdawIC25', + 'ft6XX18WlE+dgIefbYcmc0BOgHTHf8YY04IIg67904/RRE6yAWS42Ibx4h1J/haP', + '95SdthKg5J4HQ2lhudC2NJS3p+QBEieavSFuYTXgJwEeLs6gobwpZ7B0IWqAFCYH', + 'rUOxA35MIg39TfZ4VAC+QZRjoDlp+NAM6tP9HfzsiTi5IecBAOEsOESNYr4ifBkw', + 'StjpU6GuGydZf8MP/Ab/EHDAgYTlB/9VLpplMKMVCJLfYIOxEPkhYCfu30kxzsAL', + 'dLmatluP33Zxv0YMnin6lY4Wii0G56ZovbuKDnGR1JcJT4Rr6ZUdd5dZzGqaP7Aj', + 'J/thLQbIJdC1cGntd2V4lyMSly03ENXxYklzWm7S7xgS+uYsE36s1nctytBqxJYl', + '8e/7y+Zg4DxgrA2RM9+5R5neciiPGJIx16tBjOq/CM+R2d2+998YN7rKLxZ3w12t', + 'RXHdGt2DZBVkH7bWxy8/2nTxwRmMiEcmeHfOsMz8BiEdgAU+E8YvuIYb2hL2Vdly', + 'ie9boAnoy0fvVMOpcexw/DQHQcPba5OlfTQJwhTxnfaVd8jaxxJmCAC3PljfH9+/', + 'MZrI2ApzC/xTP64t1ERJ7KP50eu53D+w2IpBOLJwnxMIxjtePRSdbF/0EEEL/0jF', + 'GPSGNEw95/QZAyvbhkCTHuo2Sz3f0M2hCCzReo+t+et13h/7nQhEeNEJtOFFu/t+', + 'nX9BrqNLCjH/6TCpQOkiZC3JQGzJxLU15P0LT+/20Rd8ysym0kPg2SrJCnyOrWwZ', + 'wj+1hEHR9pfNtPIZx2LodtRF//Qo9KMSv9G6Tw3a60x7+18siHxTO9wzOxJxRnqN', + 'LgguiQYq//N6LxF1MeQSxxmNr6kNalafp+pwRwNV4G2L7QWPYn3Axe5oEbjKfnoF', + 'pwhalEs4PCnNiQGFBBgBAgAPBQJSoKrSAhsCBQkAAVGAAGoJEMB25jTTK0mNXyAE', + 'GREIAAYFAlKgqtIACgkQqxSB4x5Bj2igHQD+JYra3ESBrVwurLq4n8mm4bq5Wujm', + 'Da5k6Vf7F7ytbDAA/jb47AhgcDXQRcMw0ElTap5AP/JgtuglW/fO4cJxJfa8Yf0H', + '/i95k6w/MOn5CIwgpZyHc/F4bAVyaZmZ8gAT4lhn03ZDehFNrGJ0IhQH/QfqqNSp', + 'NqG8h7GQIH6ovJlLIcolszIL3khI7LhMsIS6Yi8xpPPB9QcqNmjYkuYAtPE2KyL+', + '2yBt+f4AJ/VFnBygcUf+AC6YxBS3cYclGKUAE9j6StRGj3kPNJPF7M5dZi+1+1Tu', + 'yJ5ucX3iq+3GKLq98Lv7SPUxIqkxuZbkZIoX99Wqz8of9BUV2wTDvVXB7TEPC5Ho', + '1y9Mb82aDrqPCq3DXvw5nz3EwxYqIXoKvLW5zsScBg9N3gmMeukXr2FCREKP5oht', + 'yeSTTh8ZnzRiwuUH1t90E7w=', + '=e8xo', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + + + + var tests = [function() { + var pubKey = openpgp.key.readArmored(twoKeys); + var verified = !pubKey.err && pubKey.keys.length == 2 && + pubKey.keys[0].getKeyPacket().getKeyId().toHex() == '4a63613a4d6e4094' && + pubKey.keys[1].getKeyPacket().getKeyId().toHex() == 'dbf223e870534df4'; + return new unit.result("Parsing armored text with two keys", verified); + + },function() { + var pubKeyV4 = openpgp.key.readArmored(twoKeys).keys[0]; + var pubKeyV3 = openpgp.key.readArmored(pub_v3).keys[0]; + var verified = pubKeyV4.getKeyPacket().getKeyId().toHex() == '4a63613a4d6e4094' && + openpgp.util.hexstrdump(pubKeyV4.getKeyPacket().getFingerprint()) == 'f470e50dcb1ad5f1e64e08644a63613a4d6e4094' && + pubKeyV3.getKeyPacket().getKeyId().toHex() == 'e5b7a014a237ba9d' && + openpgp.util.hexstrdump(pubKeyV3.getKeyPacket().getFingerprint()) == 'a44fcee620436a443bc4913640ab3e49'; + + return new unit.result("Testing key ID and fingerprint for V3 and V4 keys", verified); + + },function() { + var pubKey = openpgp.key.readArmored(pub_sig_test).keys[0]; + var packetlist = new openpgp.packet.list(); + packetlist.read(openpgp.armor.decode(pub_sig_test).data); + var subkeys = pubKey.getSubkeyPackets(); + var verified = subkeys.length == 2 && + subkeys[0].getKeyId().equals(packetlist[8].getKeyId()) && + subkeys[1].getKeyId().equals(packetlist[11].getKeyId()); + return new unit.result("Testing key method getSubkeyPackets", verified); + + },function() { + var pubKey = openpgp.key.readArmored(pub_sig_test).keys[0]; + var status = pubKey.subKeys[0].verify(pubKey.primaryKey); + return new unit.result("Verify status of revoked subkey", status == openpgp.enums.keyStatus.revoked); + + }]; + + var results = []; + + for(var i in tests) { + results.push(tests[i]()); + } + + return results; + +}); + diff --git a/test/general/keyring.js b/test/general/keyring.js new file mode 100644 index 00000000..a328f160 --- /dev/null +++ b/test/general/keyring.js @@ -0,0 +1,61 @@ +var unit = require('../unit.js'); + +unit.register("Keyring testing", function() { + var openpgp = require('openpgp'); + var keyringClass = new require('keyring'); + var keyring = new keyringClass(); + var result = []; + + keyring.importKey([ + '-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v1.4.11 (GNU/Linux)', + '', + 'mQGiBFERvI4RBAD0M/HGglCtVNXPF72ehT8riAXrl0rSec4RJC61Bh+UAOhxn5+U', + 'fDgos5p1SpIzYmn+M87JoSSVLAjfakFk0gHgR9I3bu7SIwq3Bikk1Vw3gO+yDSO6', + 'TKpLUFGYDiBSSE1MGdxBadWLE1hlRf5B2x62gnGmjSpSVbly33PFkoDmrwCg9rAp', + 'RmncnF9GhWjOLFkEoQw9Yx8EAOsxvq8Ig5Z1gk+ZKfDZeftpHRe3FdrRtbnhxvYY', + '7z+w9uz1EpoZUwDR5G4X3hTwJQ7lXmIOskg/+eRMLEAqEY7b/7tW6RaUJ2d6Ehsi', + 'dOS89fIxElwjAOnVOM5S24f0FDQTTto7QBOoxcNTfkEJCHXSlpoOUmGAP85fXh3l', + 'yPTGBACJfKc76Un3UWC1sWIRDxYiyh3ZpZyNEskoV6ESW8jEI1RnMnv5TrfGJH5K', + 'E8jWX7TTnoFyPJtBTjlucAtkQaS4Bb7dg1LLja17zAqKNGOJK2b9fb2Z+lnTjPiY', + 'i7DPH1XHnfaEexjlh/U7mYa5RrwIphRxNi8gCuxv874ZMmhEn7QWVGVzdDMgPHRl', + 'c3QzQHRlc3QuY29tPohiBBMRAgAiBQJREbyOAhsDBgsJCAcDAgYVCAIJCgsEFgID', + 'AQIeAQIXgAAKCRC0u8O0Moa2JYxyAJ9Oi2UlcUT0VJNgwjyl/VF9Xcjf9gCeJPvy', + 'g/fp4EAU8MJIaN2yMI8pLFS5AaIEURG8nhEEAKVgeNDuYDPufLuJ0GrJV/CbXEjj', + 'aEPA0iTUqV0nTCPdAfQ/nmE3gh5UlNMr/zSHJ+c4FQhYdLrzRGDOSzV+mfPHH3t+', + 'YVx+wat0BYwABpHAtsIuLIVo2RQqYZYH85tatwBkm71HHT3jmlEAvr6NFH38+v3s', + '3w4Wl0/sdHyaeiSXAKCxJ4X1eOdN7L1rrbJozQ/gDCFuVQP/dcV6Ksss8Aw443jG', + 'AYBLHWh6o4GhAY6/h1kijF0xD+uc+tNmTQnQi1tEOoTeIZMXnSRwtk8XEuJkkbAP', + '+uyvMgyV3wrk9zkaTAin7nrjAERxezFOdBEOtnB1CovJxtMn+RRxaMEGpC4GnETy', + 'N5+6FkLuLcNXiCQP75ajzOAN1aID/juNjUNpBbNpfqBV7j1K+Kn0n9HYTyQl9ghy', + '026+/4c8ag2HV+bg3BD7c2VTVu9xBODHsfu0q8Ql/QB9W8tmYugU6DeXMHaeWPUH', + 'ph98guM9kF2yHIiRBvAd5i7wOjwn+I/Ir6nBR2yxJ3p31CDUnUlbjTPYg7mtQvHW', + 'EY2Cp4SWiJEEGBECAAkFAlERvJ4CGwIAUgkQtLvDtDKGtiVHIAQZEQIABgUCURG8', + 'ngAKCRAMiMeR296Y2SjyAJ9V3wRJJ2Szazqal4khWGfLu5R6/wCfQQIRD24yVdz8', + '2a+2eCrwyALT2GAihACfS0nWM3a0gtITqngpJsRws+Ep+eIAn15qD2itutxNb8NI', + 'bR2gBB5QmVJ3', + '=pGA6', + '-----END PGP PUBLIC KEY BLOCK-----' + ].join("\n")); + + var msg2 = openpgp.message.readArmored([ + '-----BEGIN PGP MESSAGE-----', + 'Version: GnuPG v1.4.11 (GNU/Linux)', + '', + 'kA0DAAIRDIjHkdvemNkBrB1iB2Zvby50eHRREbz3VEVTVCBEQVRBIDEyMzQ1NohG', + 'BAARAgAGBQJREbz3AAoJEAyIx5Hb3pjZ2TcAn32LpDEuHe9QrSRlyvSuREKNOFwz', + 'AJ9zh4zsK4GIPuEu81YPNmHsju7DYg==', + '=WaSx', + '-----END PGP MESSAGE-----' + ].join("\n")); + var signingKeyIds = msg2.getSigningKeyIds(); + var key = keyring.getKeysForKeyId(signingKeyIds[0].toHex()); + var verified = msg2.verify(key); + result[2] = new unit.result("Testing keyring getKeysForKeyId method", + key !== null && + key.length == 1 && + verified[0].valid); + return result; +}); + + diff --git a/test/general/openpgp.basic.js b/test/general/openpgp.basic.js deleted file mode 100644 index 3d2e27ef..00000000 --- a/test/general/openpgp.basic.js +++ /dev/null @@ -1,69 +0,0 @@ - -unittests.register("Encryption/decryption", function() { - -openpgp.init(); - - - -function test(passphrase, userid, message) { - var key = openpgp.generate_key_pair(1, 512, userid, passphrase), - priv_key = key.privateKey, - pub_key = openpgp.read_publicKey(key.publicKeyArmored); - - var info = '\npassphrase: ' + passphrase + '\n' - + 'userid: ' + userid + '\n' - + 'message: ' + message; - - if(!priv_key.decryptSecretMPIs(passphrase)) { - return new test_result('Generating a decryptable private key failed' - + info, - false); - } - - var encrypted = openpgp.write_signed_and_encrypted_message(priv_key, - pub_key, message); - - openpgp.keyring.importPublicKey(key.publicKeyArmored) - - - var msg = openpgp.read_message(encrypted); - var keymat = null; - var sesskey = null; - - // Find the private (sub)key for the session key of the message - for (var i = 0; i< msg[0].sessionKeys.length; i++) { - if (priv_key.privateKeyPacket.publicKey.getKeyId() == msg[0].sessionKeys[i].keyId.bytes) { - keymat = { key: priv_key, keymaterial: priv_key.privateKeyPacket}; - sesskey = msg[0].sessionKeys[i]; - break; - } - for (var j = 0; j < priv_key.subKeys.length; j++) { - if (priv_key.subKeys[j].publicKey.getKeyId() == msg[0].sessionKeys[i].keyId.bytes) { - keymat = { key: priv_key, keymaterial: priv_key.subKeys[j]}; - sesskey = msg[0].sessionKeys[i]; - break; - } - } - } - - var decrypted = '' - if (keymat != null) { - if (!keymat.keymaterial.decryptSecretMPIs(passphrase)) { - return new test_result("Password for secrect key was incorrect!", - + info, false) - } - - decrypted = msg[0].decrypt(keymat, sesskey); - } else { - return new test_result("No private key found!" + info, false); - } - - return new test_result(message + ' == ' + decrypted + info, message == decrypted); -} - -var result = [] -result.push(test('password', 'Test McTestington ', 'hello world')); -result.push(test('●●●●', '♔♔♔♔ ', 'łäóć')); - -return result -}); diff --git a/test/general/packet.js b/test/general/packet.js new file mode 100644 index 00000000..e0d12509 --- /dev/null +++ b/test/general/packet.js @@ -0,0 +1,470 @@ +var unit = require('../unit.js'); + +unit.register("Packet testing", function() { + + var openpgp = require('openpgp'); + + var armored_key = + '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' + + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' + + '\n' + + 'lQH+BFF79J8BBADDhRUOMUSGdYM1Kq9J/vVS3qLfaZHweycAKm9SnpLGLJE+Qbki\n' + + 'JRXLAhxZ+HgVThR9VXs8wbPR2UXnDhMJGe+VcMA0jiwIOEAF0y9M3ZQsPFWguej2\n' + + '1ZycgOwxYHehbKdPqRK+nFgFbhvg6f6x2Gt+a0ZbvivGL1BqSSGsL+dchQARAQAB\n' + + '/gMDAijatUNeUFZSyfg16x343/1Jo6u07LVTdH6Bcbx4yBQjEHvlgb6m1eqEIbZ1\n' + + 'holVzt0fSKTzmlxltDaOwFLf7i42lqNoWyfaqFrOblJ5Ays7Q+6xiJTBROG9po+j\n' + + 'Z2AE+hkBIwKghB645OikchR4sn9Ej3ipea5v9+a7YimHlVmIiqgLDygQvXkzXVaf\n' + + 'Zi1P2wB7eU6If2xeeX5GSR8rWo+I7ujns0W8S9PxBHlH3n1oXUmFWsWLZCY/qpkD\n' + + 'I/FroBhXxBVRpQhQmdsWPUdcgmQTEj8jnP++lwSQexfgk2QboAW7ODUA8Cl9oy87\n' + + 'Uor5schwwdD3oRoLGcJZfR6Dyu9dCYdQSDWj+IQs95hJQfHNcfj7XFtTyOi7Kxx0\n' + + 'Jxio9De84QnxNAoNYuLtwkaRgkUVKVph2nYWJfAJunuMMosM2WdcidHJ5d6RIdxB\n' + + 'U6o3T+d8BPXuRQEZH9+FkDkb4ihakKO3+Zcon85e1ZUUtB1QYXRyaWNrIDxwYXRy\n' + + 'aWNrQGV4YW1wbGUuY29tPoi5BBMBAgAjBQJRe/SfAhsDBwsJCAcDAgEGFQgCCQoL\n' + + 'BBYCAwECHgECF4AACgkQObliSdM/GEJbjgP/ffei4lU6fXp8Qu0ubNHh4A6swkTO\n' + + 'b3suuBELE4A2/pK5YnW5yByFFSi4kq8bJp5O6p9ydXpOA38t3aQ8wrbo0yDvGekr\n' + + '1S1HWOLgCaY7rEDQubuCOHd2R81/VQOJyG3zgX4KFIgkVyV9BZXUpz4PXuhMORmv\n' + + '81uzej9r7BYkJ6GdAf4EUXv0nwEEAKbO02jtGEHet2fQfkAYyO+789sTxyfrUy5y\n' + + 'SAf5n3GgkuiHz8dFevhgqYyMK0OYEOCZqdd1lRBjL6Us7PxTljHc2jtGhoAgE4aZ\n' + + 'LKarI3j+5Oofcaq0+S0bhqiQ5hl6C4SkdYOEeJ0Hlq2008n0pJIlU4E5yIu0oNvb\n' + + '4+4owTpRABEBAAH+AwMCKNq1Q15QVlLJyeuGBEA+7nXS3aSy6mE4lR5f3Ml5NRqt\n' + + 'jm6Q+UUI69DzhLGX4jHRxna6NMP74S3CghOz9eChMndkfWLC/c11h1npzLci+AwJ\n' + + '45xMbw/OW5PLlaxdtkg/SnsHpFGCAuTUWY87kuWoG0HSVMn9Clm+67rdicOW6L5a\n' + + 'ChfyWcVZ+Hvwjx8YM0/j11If7oUkCZEstSUeJYOI10JQLhNLpDdkB89vXhAMaCuU\n' + + 'Ijhdq0vvJi6JruKQGPK+jajJ4MMannpQtKAvt8aifqpdovYy8w4yh2pGkadFvrsZ\n' + + 'mxpjqmmawab6zlOW5WrLxQVL1cQRdrIQ7jYtuLApGWkPfytSCBZ20pSyWnmkxd4X\n' + + 'OIms6BjqrP9LxBEXsPBwdUA5Iranr+UBIPDxQrTp5k0DJhXBCpJ1k3ZT+2dxiRS2\n' + + 'sk83w2VUBnXdYWZx0YlMqr3bDT6J5fO+8V8pbgY5BkHRCFMacFx45km/fvmInwQY\n' + + 'AQIACQUCUXv0nwIbDAAKCRA5uWJJ0z8YQqb3A/97njLl33OQYXVp9OTk/VgE6O+w\n' + + 'oSYa+6xMOzsk7tluLIRQtnIprga/e8vEZXGTomV2a77HBksg+YjlTh/l8oMuaoxG\n' + + 'QNkMpoRJKPip29RTW4gLdnoJVekZ/awkBN2S3NMArOZGca8U+M1IuV7OyVchSVSl\n' + + 'YRlci72GHhlyos8YHA==\n' + + '=KXkj\n' + + '-----END PGP PRIVATE KEY BLOCK-----'; + + + var tests = [function() { + var message = new openpgp.packet.list(); + + var literal = new openpgp.packet.literal(); + literal.setText('Hello world'); + + var enc = new openpgp.packet.symmetrically_encrypted(); + message.push(enc); + enc.packets.push(literal); + + var key = '12345678901234567890123456789012', + algo = 'aes256'; + + enc.encrypt(algo, key); + + + + var msg2 = new openpgp.packet.list(); + msg2.read(message.write()); + + msg2[0].decrypt(algo, key); + + return new unit.result('Symmetrically encrypted packet', + msg2[0].packets[0].data == literal.data); + + }, function() { + var key = '12345678901234567890123456789012', + algo = 'aes256'; + + var literal = new openpgp.packet.literal(), + enc = new openpgp.packet.sym_encrypted_integrity_protected(), + msg = new openpgp.packet.list(); + + msg.push(enc); + literal.setText('Hello world!'); + enc.packets.push(literal); + enc.encrypt(algo, key); + + + + var msg2 = new openpgp.packet.list(); + msg2.read(msg.write()); + + msg2[0].decrypt(algo, key); + + return new unit.result('Sym. encrypted integrity protected packet', + msg2[0].packets[0].data == literal.data); + + }, function() { + + var msg = + '-----BEGIN PGP MESSAGE-----\n' + + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' + + '\n' + + 'jA0ECQMCpo7I8WqsebTJ0koBmm6/oqdHXJU9aPe+Po+nk/k4/PZrLmlXwz2lhqBg\n' + + 'GAlY9rxVStLBrg0Hn+5gkhyHI9B85rM1BEYXQ8pP5CSFuTwbJ3O2s67dzQ==\n' + + '=VZ0/\n' + + '-----END PGP MESSAGE-----'; + + + + var msgbytes = openpgp.armor.decode(msg).data; + + var parsed = new openpgp.packet.list(); + parsed.read(msgbytes); + + parsed[0].decrypt('test'); + + var key = parsed[0].sessionKey; + parsed[1].decrypt(parsed[0].sessionKeyAlgorithm, key); + var compressed = parsed[1].packets[0]; + + var result = compressed.packets[0].data; + + return new unit.result('Sym encrypted session key with a compressed packet', + result == 'Hello world!\n'); + + }, function() { + + var rsa = new openpgp.crypto.publicKey.rsa(), + mpi = rsa.generate(512, "10001") + + var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u]; + + mpi = mpi.map(function(k) { + var mpi = new openpgp.mpi(); + mpi.fromBigInteger(k); + return mpi; + }); + + var enc = new openpgp.packet.public_key_encrypted_session_key(), + msg = new openpgp.packet.list(), + msg2 = new openpgp.packet.list(); + + enc.sessionKey = '12345678901234567890123456789012'; + enc.publicKeyAlgorithm = 'rsa_encrypt'; + enc.sessionKeyAlgorithm = 'aes256'; + enc.publicKeyId.bytes = '12345678'; + enc.encrypt({ mpi: mpi }); + + msg.push(enc); + + msg2.read(msg.write()); + + msg2[0].decrypt({ mpi: mpi }); + + return new unit.result('Public key encrypted symmetric key packet', + msg2[0].sessionKey == enc.sessionKey && + msg2[0].sessionKeyAlgorithm == enc.sessionKeyAlgorithm); + }, function() { + var armored_key = + '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' + + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' + + '\n' + + 'lQHYBFF33iMBBAC9YfOYahJlWrVj2J1TjQiZLunWljI4G9e6ARTyD99nfOkV3swh\n' + + '0WaOse4Utj7BfTqdYcoezhCaQpuExUupKWZqmduBcwSmEBfNu1XyKcxlDQuuk0Vk\n' + + 'viGC3kFRce/cJaKVFSRU8V5zPgt6KQNv/wNz7ydEisaSoNbk51vQt5oGfwARAQAB\n' + + 'AAP5AVL8xWMuKgLj9g7/wftMH+jO7vhAxje2W3Y+8r8TnOSn0536lQvzl/eQyeLC\n' + + 'VK2k3+7+trgO7I4KuXCXZqgAbEi3niDYXDaCJ+8gdR9qvPM2gi9NM71TGXZvGE0w\n' + + 'X8gIZfqLTQWKm9TIS/3tdrth4nwhiye0ASychOboIiN6VIECAMbCQ4/noxGV6yTK\n' + + 'VezsGSz+iCMxz2lV270/Ac2C5WPk+OlxXloxUXeEkGIr6Xkmhhpceed2KL41UC8Y\n' + + 'w5ttGIECAPPsahniKGyqp9CHy6W0B83yhhcIbmLlaVG2ftKyUEDxIggzOlXuVrue\n' + + 'z9XRd6wFqwDd1QMFW0uUyHPDCIFPnv8CAJaDFSZutuWdWMt15NZXjfgRgfJuDrtv\n' + + 'E7yFY/p0el8lCihOT8WoHbTn1PbCYMzNBc0IhHaZKAtA2pjkE+wzz9ClP7QbR2Vv\n' + + 'cmdlIDxnZW9yZ2VAZXhhbXBsZS5jb20+iLkEEwECACMFAlF33iMCGwMHCwkIBwMC\n' + + 'AQYVCAIJCgsEFgIDAQIeAQIXgAAKCRBcqs36fwJCXRbvA/9LPiK6WFKcFoNBnLEJ\n' + + 'mS/CNkL8yTpkslpCP6+TwJMc8uXqwYl9/PW2+CwmzZjs6JsvTzMcR/ZbfZJuSW6Y\n' + + 'EsLNejsSpgcY9aiewGtE+53e5oKYnlmVMTWOPywciIgMvXlzdGhxcwqJ8u0hT+ug\n' + + '9CjcAfuX9yw85LwXtdGwNh7J8Q==\n' + + '=lKiS\n' + + '-----END PGP PRIVATE KEY BLOCK-----'; + + key = new openpgp.packet.list(); + key.read(openpgp.armor.decode(armored_key).data); + key = key[0]; + + var enc = new openpgp.packet.public_key_encrypted_session_key(), + secret = '12345678901234567890123456789012'; + + enc.sessionKey = secret; + enc.publicKeyAlgorithm = 'rsa_encrypt'; + enc.sessionKeyAlgorithm = 'aes256'; + enc.publicKeyId.bytes = '12345678'; + + enc.encrypt(key); + + enc.decrypt(key); + + return new unit.result('Secret key packet (reading, unencrpted)', + enc.sessionKey == secret); + }, function() { + + var armored_key = + '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' + + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' + + '\n' + + 'lQHYBFF6gtkBBADKUOWZK6/V75MNwBS+hLYicoS0Sojbo3qWXXpS7eM+uhiDm4bP\n' + + 'DNjdNVA0R+TCjvhWbc3W6cvdHYTmHRMhTIOefncZRt3OwF7AvVk53fKKPiNNv5C9\n' + + 'IK8bcDhAknSOg1TXRSpXLHtYy36A6iDgffNSjoCOVaeKpuRDMA37PvJWFQARAQAB\n' + + 'AAP+KxHbOwcrnPPuXppCYEew3Xb7LMWESpvMFFgsmxx1COzFnLjek1P1E+yOWT7n\n' + + '4opcsEuaazLk+TrYSMOuR6O6DgGg5c+ctVPU+NGNNCiiTkOzuD+8ow8NgsoINOxi\n' + + '481qLK0NYpc5sEg394J3fRuzpfEi6DTS/RzCN7YDiGFccNECAM71NuaAzH5LrZ+B\n' + + '4Okwy9CQQbgoYrdaia24CjEaUODaROnyNsvOb0ydEebVAbGzrsBr6LrisTidyZsG\n' + + 't2T+L7ECAPpCFzZIwwk6giZ10HmXEhXZLXYmdhQD/1fwegpTrEciMA6MCcdkcCyO\n' + + '2/J+S+NXM62ykMGDhg2cjhU1rj/uaaUCAJfCjkwpxMsDKHYDFDXyjJFy2vEmA3s8\n' + + 'cnmAUDF1caPyEcPEZmYJRE+KdroOD6IGhzp7oA34Ef3D6HOCovH9YaCgbbQbSm9o\n' + + 'bm55IDxqb2hubnlAZXhhbXBsZS5jb20+iLkEEwECACMFAlF6gtkCGwMHCwkIBwMC\n' + + 'AQYVCAIJCgsEFgIDAQIeAQIXgAAKCRA6HTM8yP08keZgA/4vL273zrqnmOrqmo/K\n' + + 'UxQgD0vMhM58d25UjGYI6LAZkAls/k4FvFt5GUHVWJR3HBRuuNlB7UndH/uYlU7j\n' + + 'm/bQLiP4uvFQuRGuG76f0O5t/KyeUdzrpNiJpe8tYDAnoPxUzENYsIv0fm2ZISo1\n' + + 'QnnXX2WuVZGMZH1YhQoakZxbnp0B2ARReoLZAQQAvQvPp2MLu9vnRvZ3Py559kQf\n' + + '0Z5AnEXVokALTn5A2m51dLekQ9T3Rhz8p9I6C/XjVQwBkp1USOaDUz+L7lsbNdY4\n' + + 'YbUi3eIA5RImVXeTIrD1hE4CllDNKmqT5wFN07eEu7QhDEuYioO+4gtjjhUDYeIA\n' + + 'dCVtVO//q8rP8ukZEc8AEQEAAQAD/RHlttyNe3RnDr/AoKx6HXDLpUmGlm5VDDMm\n' + + 'pgth14j2cSdCJYqIdHqOTvsiY31zY3jPQKzdOTgHnsI4X2qK9InbwXepSBkaOJzY\n' + + 'iNhifPSUs9qoNawDqbFJ8PMXd4QQGgM93w+tudKC650Zuq7M7eWSdQg0u9aoLY97\n' + + 'MpKx3DUFAgDA/RgoO8xYMgkKN1tuKWa61qesLdJRAZI/3cnvtsmmEBt9tdbcDoBz\n' + + 'gOIAAvUFgipuP6dBWLyf2NRNRVVQdNTlAgD6xS7S87g3kTa3GLcEI2cveaP1WWNK\n' + + 'rKFnVWsjBKArKFzMQ5N6FMnFD4T96i3sYlACE5UjH90SpOgBKOpdKzSjAf9nghrw\n' + + 'kbFbF708ZIpVEwxvp/JoSutYUQ4v01MImnCGqzDVuSef3eutLLu4ZG7kLekxNauV\n' + + '8tGFwxsdtv30RL/3nW+InwQYAQIACQUCUXqC2QIbDAAKCRA6HTM8yP08kRXjBACu\n' + + 'RtEwjU+p6qqm3pmh7xz1CzhQN1F7VOj9dFUeECJJ1iv8J71w5UINH0otIceeBeWy\n' + + 'NLA/QvK8+4/b9QW+S8aDZyeZpYg37gBwdTNGNT7TsEAxz9SUbx9uRja0wNmtb5xW\n' + + 'mG+VE8CBXNkp8JTWx05AHwtK3baWlHWwpwnRlbU94Q==\n' + + '=FSwA\n' + + '-----END PGP PRIVATE KEY BLOCK-----'; + + var armored_msg = + '-----BEGIN PGP MESSAGE-----\n' + + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' + + '\n' + + 'hIwDFYET+7bfx/ABA/95Uc9942Tg8oqpO0vEu2eSKwPALM3a0DrVdAiFOIK/dJmZ\n' + + 'YrtPRw3EEwHZjl6CO9RD+95iE27tPbsICw1K43gofSV/wWsPO6vvs3eftQYHSxxa\n' + + 'IQbTPImiRaJ73Mf7iM3CNtQM4iUBsx1HnUGl+rtD0nz3fLm6i3CjwiNQWW42I9JH\n' + + 'AWv8EvvpxZ8X2ClFfSW3UVBoROHe9CAWHM/40nGutAZK8MIgmUI4xqkLFBbqqTyx\n' + + '/cDSC4Q+sv65UX4urbfc7uJuk1Cpj54=\n' + + '=iSaK\n' + + '-----END PGP MESSAGE-----'; + + + var key = new openpgp.packet.list(); + key.read(openpgp.armor.decode(armored_key).data); + key = key[3]; + + var msg = new openpgp.packet.list(); + msg.read(openpgp.armor.decode(armored_msg).data); + + msg[0].decrypt(key); + msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey); + + var text = msg[1].packets[0].packets[0].data; + + + return new unit.result('Public key encrypted packet (reading, GPG)', + text == 'Hello world!'); + }, function() { + + var passphrase = 'hello', + algo = 'aes256'; + + var literal = new openpgp.packet.literal(), + key_enc = new openpgp.packet.sym_encrypted_session_key(), + enc = new openpgp.packet.sym_encrypted_integrity_protected(), + msg = new openpgp.packet.list(); + + msg.push(key_enc); + msg.push(enc); + + key_enc.sessionKeyAlgorithm = algo; + key_enc.decrypt(passphrase); + + var key = key_enc.sessionKey; + + literal.setText('Hello world!'); + enc.packets.push(literal); + enc.encrypt(algo, key); + + + var msg2 = new openpgp.packet.list(); + msg2.read(msg.write()); + + msg2[0].decrypt(passphrase); + var key2 = msg2[0].sessionKey; + msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2); + + + return new unit.result('Sym encrypted session key reading/writing', + msg2[1].packets[0].data == literal.data); + + }, function() { + var armored_msg = + '-----BEGIN PGP MESSAGE-----\n' + + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' + + '\n' + + 'hIwD95D9aHS5fxEBA/98CwH54XZmwobOmHUcvWcDDQysBEC4uf7wASiGcRbejDaO\n' + + 'aJqcrK/3k8sBQMO7yOhvrCRqqpGDqnmx7IaaKLnZS7nYAZoHEsK9UyG0hDa8Cfbo\n' + + 'CP4xZVcgIvIfAW/in1LeT2td0QcQNbeewBmPea+vQEEvRgIP10tlE7MK8Ay48dJH\n' + + 'AagMgNYg7MBUjpuOCVrjM1pWja8uzbULfYhTq3IJ8H3QhbdT+k9khY9f0aJPEeYi\n' + + 'dVv6DK9uviMGc/DsVCw5K8lQRLlkcHc=\n' + + '=pR+C\n' + + '-----END PGP MESSAGE-----'; + + var key = new openpgp.packet.list(); + key.read(openpgp.armor.decode(armored_key).data); + key = key[3]; + key.decrypt('test'); + + var msg = new openpgp.packet.list(); + msg.read(openpgp.armor.decode(armored_msg).data); + + msg[0].decrypt(key); + msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey); + + var text = msg[1].packets[0].packets[0].data; + + + + return new unit.result('Secret key encryption/decryption test', + text == 'Hello world!'); + }, function() { + + + var key = new openpgp.packet.list(); + key.read(openpgp.armor.decode(armored_key).data); + + + var verified = key[2].verify(key[0], + { + userid: key[1], + key: key[0] + }); + + verified = verified && key[4].verify(key[0], + { + key: key[0], + bind: key[3], + }) + + + return new unit.result('Secret key reading with signature verification.', + verified == true); + }, function() { + + var armored_msg = + '-----BEGIN PGP MESSAGE-----\n' + + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' + + '\n' + + 'hIwD95D9aHS5fxEBA/4/X4myvH+jB1HYNeZvdK+WsBNDMfLsBGOf205Rxr3vSob/\n' + + 'A09boj8/9lFaipqu+AEdQKEjCB8sZ+OY0WiQPEPpuhG+mVqDqEiPFkdpcqNtS0VV\n' + + 'pwqplHo6QnH2MHfxprZHYuwcEC9ynJCxJ6kSCD8Xs99h+PjxNNw7NhMjkF+N69LA\n' + + 'NwGPtbLx2/r2nR4gO8gV92A2RQCOwPP7ZV+6fXgWIs+mhyCHFP3xUP5DaFCNM8mo\n' + + 'PN97i659ucxF6IbOoK56FEaUbOPTD6xdyhWamxKfMsIb0UJgVUNhGaq+VlvOJxaB\n' + + 'iRcnY5UxsypKgtqfcKIseb21MIo4vcNdogyxBIDlAO472Zfxn0udzr6W2aQ77+NK\n' + + 'FE1O0kCXS+DTFOYYVD7X8rXGSglQsdXJmHd89sdYFQkO7D7bOLdRJuXgdgH2czCs\n' + + 'UBGuHZzsGbTdyKvpVBuS3rnyHHBk6oCnsm1Nl7eLs64VkZUxjEUbq5pb4dlr1pw2\n' + + 'ztpmpAnRcmM=\n' + + '=htrB\n' + + '-----END PGP MESSAGE-----' + + var key = new openpgp.packet.list(); + key.read(openpgp.armor.decode(armored_key).data); + key[3].decrypt('test') + + var msg = new openpgp.packet.list(); + msg.read(openpgp.armor.decode(armored_msg).data); + + + msg[0].decrypt(key[3]); + msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey); + + var payload = msg[1].packets[0].packets + + + + var verified = payload[2].verify(key[0], payload[1]); + + + + return new unit.result('Reading a signed, encrypted message.', + verified == true); + }, function() { + var key = new openpgp.packet.list(); + key.push(new openpgp.packet.secret_key); + + var rsa = new openpgp.crypto.publicKey.rsa(), + mpi = rsa.generate(512, "10001") + + + var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u]; + + mpi = mpi.map(function(k) { + var mpi = new openpgp.mpi(); + mpi.fromBigInteger(k); + return mpi; + }); + + key[0].mpi = mpi; + + key[0].encrypt('hello'); + + var raw = key.write(); + + var key2 = new openpgp.packet.list(); + key2.read(raw); + key2[0].decrypt('hello'); + + + return new unit.result('Writing and encryptio of a secret key packet.', + key[0].mpi.toString() == key2[0].mpi.toString()); + }, function() { + + var key = new openpgp.packet.secret_key(); + + var rsa = new openpgp.crypto.publicKey.rsa, + mpi = rsa.generate(512, "10001") + + var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u]; + + mpi = mpi.map(function(k) { + var mpi = new openpgp.mpi(); + mpi.fromBigInteger(k); + return mpi; + }); + + key.mpi = mpi; + + var signed = new openpgp.packet.list(), + literal = new openpgp.packet.literal(), + signature = new openpgp.packet.signature(); + + literal.setText('Hello world'); + + signature.hashAlgorithm = 'sha256'; + signature.publicKeyAlgorithm = 'rsa_sign'; + signature.signatureType = 'binary'; + + signature.sign(key, literal); + + signed.push(literal); + signed.push(signature); + + var raw = signed.write(); + + var signed2 = new openpgp.packet.list(); + signed2.read(raw); + + var verified = signed2[1].verify(key, signed2[0]); + + + return new unit.result('Writing and verification of a signature packet.', + verified == true); + }]; + + + + tests.reverse(); + + var results = []; + + for(var i in tests) { + results.push(tests[i]()); + } + + + return results; +}); diff --git a/test/general/signature.js b/test/general/signature.js new file mode 100644 index 00000000..429c88eb --- /dev/null +++ b/test/general/signature.js @@ -0,0 +1,536 @@ +var unit = require('../unit.js'); + +unit.register("Signature testing", function() { + var openpgp = require('openpgp'); + + var priv_key_arm1 = + [ '-----BEGIN PGP PRIVATE KEY BLOCK-----', + 'Version: GnuPG v1.4.11 (GNU/Linux)', + '', + 'lQHhBFERnrMRBADmM0hIfkI3yosjgbWo9v0Lnr3CCE+8KsMszgVS+hBu0XfGraKm', + 'ivcA2aaJimHqVYOP7gEnwFAxHBBpeTJcu5wzCFyJwEYqVeS3nnaIhBPplSF14Duf', + 'i6bB9RV7KxVAg6aunmM2tAutqC+a0y2rDaf7jkJoZ9gWJe2zI+vraD6fiwCgxvHo', + '3IgULB9RqIqpLoMgXfcjC+cD/1jeJlKRm+n71ryYwT/ECKsspFz7S36z6q3XyS8Q', + 'QfrsUz2p1fbFicvJwIOJ8B20J/N2/nit4P0gBUTUxv3QEa7XCM/56/xrGkyBzscW', + 'AzBoy/AK9K7GN6z13RozuAS60F1xO7MQc6Yi2VU3eASDQEKiyL/Ubf/s/rkZ+sGj', + 'yJizBACtwCbQzA+z9XBZNUat5NPgcZz5Qeh1nwF9Nxnr6pyBv7tkrLh/3gxRGHqG', + '063dMbUk8pmUcJzBUyRsNiIPDoEUsLjY5zmZZmp/waAhpREsnK29WLCbqLdpUors', + 'c1JJBsObkA1IM8TZY8YUmvsMEvBLCCanuKpclZZXqeRAeOHJ0v4DAwK8WfuTe5B+', + 'M2BOOeZbN8BpfiA1l//fMMHLRS3UvbLBv4P1+4SyvhyYTR7M76Q0xPc03MFOWHL+', + 'S9VumbQWVGVzdDIgPHRlc3QyQHRlc3QuY29tPohiBBMRAgAiBQJREZ6zAhsDBgsJ', + 'CAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRARJ5QDyxae+MXNAKCzWSDR3tMrTrDb', + 'TAri73N1Xb3j1ACfSl9y+SAah2q7GvmiR1+6+/ekqJGdAVgEURGesxAEANlpMZjW', + '33jMxlKHDdyRFXtKOq8RreXhq00plorHbgz9zFEWm4VF53+E/KGnmHGyY5Cy8TKy', + 'ZjaueZZ9XuG0huZg5If68irFfNZtxdA26jv8//PdZ0Uj+X6J3RVa2peMLDDswTYL', + 'OL1ZO1fxdtDD40fdAiIZ1QyjwEG0APtz41EfAAMFBAC5/dtgBBPtHe8UjDBaUe4n', + 'NzHuUBBp6XE+H7eqHNFCuZAJ7yqJLGVHNIaQR419cNy08/OO/+YUQ7rg78LxjFiv', + 'CH7IzhfU+6yvELSbgRMicY6EnAP2GT+b1+MtFNa3lBGtBHcJla52c2rTAHthYZWk', + 'fT5R5DnJuQ2cJHBMS9HWyP4DAwK8WfuTe5B+M2C7a/YJSUv6SexdGCaiaTcAm6g/', + 'PvA6hw/FLzIEP67QcQSSTmhftQIwnddt4S4MyJJH3U4fJaFfYQ1zCniYJohJBBgR', + 'AgAJBQJREZ6zAhsMAAoJEBEnlAPLFp74QbMAn3V4857xwnO9/+vzIVnL93W3k0/8', + 'AKC8omYPPomN1E/UJFfXdLDIMi5LoA==', + '=LSrW', + '-----END PGP PRIVATE KEY BLOCK-----' + ].join("\n"); + var pub_key_arm1 = + [ '-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v1.4.11 (GNU/Linux)', + '', + 'mQGiBFERlw4RBAD6Bmcf2w1dtUmtCLkdxeqZLArk3vYoQAjdibxA3gXVyur7fsWb', + 'ro0jVbBHqOCtC6jDxE2l52NP9+tTlWeVMaqqNvUE47LSaPq2DGI8Wx1Rj6bF3mTs', + 'obYEwhGbGh/MhJnME9AHODarvk8AZbzo0+k1EwrBWF6dTUBPfqO7rGU2ewCg80WV', + 'x5pt3evj8rRK3jQ8SMKTNRsD/1PhTdxdZTdXARAFzcW1VaaruWW0Rr1+XHKKwDCz', + 'i7HE76SO9qjnQfZCZG75CdQxI0h8GFeN3zsDqmhob2iSz2aJ1krtjM+iZ1FBFd57', + 'OqCV6wmk5IT0RBN12ZzMS19YvzN/ONXHrmTZlKExd9Mh9RKLeVNw+bf6JsKQEzcY', + 'JzFkBACX9X+hDYchO/2hiTwx4iOO9Fhsuh7eIWumB3gt+aUpm1jrSbas/QLTymmk', + 'uZuQVXI4NtnlvzlNgWv4L5s5RU5WqNGG7WSaKNdcrvJZRC2dgbUJt04J5CKrWp6R', + 'aIYal/81Ut1778lU01PEt563TcQnUBlnjU5OR25KhfSeN5CZY7QUVGVzdCA8dGVz', + 'dEB0ZXN0LmNvbT6IYgQTEQIAIgUCURGXDgIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC', + 'HgECF4AACgkQikDlZK/UvLSspgCfcNaOpTg1W2ucR1JwBbBGvaERfuMAnRgt3/rs', + 'EplqEakMckCtikEnpxYe', + '=b2Ln', + '-----END PGP PUBLIC KEY BLOCK-----' + ].join("\n"); + var msg_arm1 = + [ '-----BEGIN PGP MESSAGE-----', + 'Version: GnuPG v1.4.11 (GNU/Linux)', + '', + 'hQEOA1N4OCSSjECBEAP/diDJCQn4e88193PgqhbfAkohk9RQ0v0MPnXpJbCRTHKO', + '8r9nxiAr/TQv4ZOingXdAp2JZEoE9pXxZ3r1UWew04czxmgJ8FP1ztZYWVFAWFVi', + 'Tj930TBD7L1fY/MD4fK6xjEG7z5GT8k4tn4mLm/PpWMbarIglfMopTy1M/py2cID', + '/2Sj7Ikh3UFiG+zm4sViYc5roNbMy8ixeoKixxi99Mx8INa2cxNfqbabjblFyc0Z', + 'BwmbIc+ZiY2meRNI5y/tk0gRD7hT84IXGGl6/mH00bsX/kkWdKGeTvz8s5G8RDHa', + 'Za4HgLbXItkX/QarvRS9kvkD01ujHfj+1ZvgmOBttNfP0p8BQLIICqvg1eYD9aPB', + '+GtOZ2F3+k5VyBL5yIn/s65SBjNO8Fqs3aL0x+p7s1cfUzx8J8a8nWpqq/qIQIqg', + 'ZJH6MZRKuQwscwH6NWgsSVwcnVCAXnYOpbHxFQ+j7RbF/+uiuqU+DFH/Rd5pik8b', + '0Dqnp0yfefrkjQ0nuvubgB6Rv89mHpnvuJfFJRInpg4lrHwLvRwdpN2HDozFHcKK', + 'aOU=', + '=4iGt', + '-----END PGP MESSAGE-----' + ].join("\n"); + + var priv_key_arm2 = + ['-----BEGIN PGP PRIVATE KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + 'Type: RSA/RSA', + 'Pwd: hello world', + '', + 'lQH+BFJhL04BBADclrUEDDsm0PSZbQ6pml9FpzTyXiyCyDN+rMOsy9J300Oc10kt', + '/nyBej9vZSRcaW5VpNNj0iA+c1/w2FPf84zNsTzvDmuMaNHFUzky4/vkYuZra//3', + '+Ri7CF8RawSYQ/4IRbC9zqdBlzniyfQOW7Dp/LYe8eibnDSrmkQem0G0jwARAQAB', + '/gMDAu7L//czBpE40p1ZqO8K3k7UejemjsQqc7kOqnlDYd1Z6/3NEA/UM30Siipr', + 'KjdIFY5+hp0hcs6EiiNq0PDfm/W2j+7HfrZ5kpeQVxDek4irezYZrl7JS2xezaLv', + 'k0Fv/6fxasnFtjOM6Qbstu67s5Gpl9y06ZxbP3VpT62+Xeibn/swWrfiJjuGEEhM', + 'bgnsMpHtzAz/L8y6KSzViG/05hBaqrvk3/GeEA6nE+o0+0a6r0LYLTemmq6FbaA1', + 'PHo+x7k7oFcBFUUeSzgx78GckuPwqr2mNfeF+IuSRnrlpZl3kcbHASPAOfEkyMXS', + 'sWGE7grCAjbyQyM3OEXTSyqnehvGS/1RdB6kDDxGwgE/QFbwNyEh6K4eaaAThW2j', + 'IEEI0WEnRkPi9fXyxhFsCLSI1XhqTaq7iDNqJTxE+AX2b9ZuZXAxI3Tc/7++vEyL', + '3p18N/MB2kt1Wb1azmXWL2EKlT1BZ5yDaJuBQ8BhphM3tCRUZXN0IE1jVGVzdGlu', + 'Z3RvbiA8dGVzdEBleGFtcGxlLmNvbT6IuQQTAQIAIwUCUmEvTgIbLwcLCQgHAwIB', + 'BhUIAgkKCwQWAgMBAh4BAheAAAoJEEpjYTpNbkCUMAwD+gIK08qpEZSVas9qW+Ok', + '32wzNkwxe6PQgZwcyBqMQYZUcKagC8+89pMQQ5sKUGvpIgat42Tf1KLGPcvG4cDA', + 'JZ6w2PYz9YHQqPh9LA+PAnV8m25TcGmKcKgvFUqQ3U53X/Y9sBP8HooRqfwwHcv9', + 'pMgQmojmNbI4VHydRqIBePawnQH+BFJhL04BBADpH8+0EVolpPiOrXTKoBKTiyrB', + 'UyxzodyJ8zmVJ3HMTEU/vidpQwzISwoc/ndDFMXQauq6xqBCD9m2BPQI3UdQzXnb', + 'LsAI52nWCIqOkzM5NAKWoKhyXK9Y4UH4v9LAYQgl/stIISvCgG4mJ8lzzEBWvRdf', + 'Qm2Ghb64/3V5NDdemwARAQAB/gMDAu7L//czBpE40iPcpLzL7GwBbWFhSWgSLy53', + 'Md99Kxw3cApWCok2E8R9/4VS0490xKZIa5y2I/K8thVhqk96Z8Kbt7MRMC1WLHgC', + 'qJvkeQCI6PrFM0PUIPLHAQtDJYKtaLXxYuexcAdKzZj3FHdtLNWCooK6n3vJlL1c', + 'WjZcHJ1PH7USlj1jup4XfxsbziuysRUSyXkjn92GZLm+64vCIiwhqAYoizF2NHHG', + 'hRTN4gQzxrxgkeVchl+ag7DkQUDANIIVI+A63JeLJgWJiH1fbYlwESByHW+zBFNt', + 'qStjfIOhjrfNIc3RvsggbDdWQLcbxmLZj4sB0ydPSgRKoaUdRHJY0S4vp9ouKOtl', + '2au/P1BP3bhD0fDXl91oeheYth+MSmsJFDg/vZJzCJhFaQ9dp+2EnjN5auNCNbaI', + 'beFJRHFf9cha8p3hh+AK54NRCT++B2MXYf+TPwqX88jYMBv8kk8vYUgo8128r1zQ', + 'EzjviQE9BBgBAgAJBQJSYS9OAhsuAKgJEEpjYTpNbkCUnSAEGQECAAYFAlJhL04A', + 'CgkQ4IT3RGwgLJe6ogQA2aaJEIBIXtgrs+8WSJ4k3DN4rRXcXaUZf667pjdD9nF2', + '3BzjFH6Z78JIGaxRHJdM7b05aE8YuzM8f3NIlT0F0OLq/TI2muYU9f/U2DQBuf+w', + 'KTB62+PELVgi9MsXC1Qv/u/o1LZtmmxTFFOD35xKsxZZI2OJj2pQpqObW27M8Nlc', + 'BQQAw2YA3fFc38qPK+PY4rZyTRdbvjyyX+1zeqIo8wn7QCQwXs+OGaH2fGoT35AI', + 'SXuqKcWqoEuO7OBSEFThCXBfUYMC01OrqKEswPm/V3zZkLu01q12UMwZach28QwK', + '/YZly4ioND2tdazj17u2rU2dwtiHPe1iMqGgVMoQirfLc+k=', + '=lw5e', + '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); + + var pub_key_arm2 = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + 'Type: RSA/RSA', + '', + 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', + 'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5', + 'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0', + 'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS', + 'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6', + 'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki', + 'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf', + '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa', + 'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag', + 'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr', + 'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb', + 'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA', + 'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP', + 'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2', + 'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X', + 'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD', + 'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY', + 'hz3tYjKhoFTKEIq3y3Pp', + '=h/aX', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + +var pub_key_arm3 = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'mQENBFKV0FUBCACtZliApy01KBGbGNB36YGH4lpr+5KoqF1I8A5IT0YeNjyGisOk', + 'WsDsUzOqaNvgzQ82I3MY/jQV5rLBhH/6LiRmCA16WkKcqBrHfNGIxJ+Q+ofVBHUb', + 'aS9ClXYI88j747QgWzirnLuEA0GfilRZcewII1pDA/G7+m1HwV4qHsPataYLeboq', + 'hPA3h1EVVQFMAcwlqjOuS8+weHQRfNVRGQdRMm6H7166PseDVRUHdkJpVaKFhptg', + 'rDoNI0lO+UujdqeF1o5tVZ0j/s7RbyBvdLTXNuBbcpq93ceSWuJPZmi1XztQXKYe', + 'y0f+ltgVtZDEc7TGV5WDX9erRECCcA3+s7J3ABEBAAG0G0pTIENyeXB0byA8ZGlm', + 'ZmllQGhvbWUub3JnPokBPwQTAQIAKQUCUpXQVQIbAwUJCWYBgAcLCQgHAwIBBhUI', + 'AgkKCwQWAgMBAh4BAheAAAoJENvyI+hwU030yRAIAKX/mGEgi/miqasbbQoyK/CS', + 'a7sRxgZwOWQLdi2xxpE5V4W4HJIDNLJs5vGpRN4mmcNK2fmJAh74w0PskmVgJEhP', + 'dFJ14UC3fFPq5nbqkBl7hU0tDP5jZxo9ruQZfDOWpHKxOCz5guYJ0CW97bz4fChZ', + 'NFDyfU7VsJQwRIoViVcMCipP0fVZQkIhhwpzQpmVmN8E0a6jWezTZv1YpMdlzbEf', + 'H79l3StaOh9/Un9CkIyqEWdYiKvIYms9nENyehN7r/OKYN3SW+qlt5GaL+ws+N1w', + '6kEZjPFwnsr+Y4A3oHcAwXq7nfOz71USojSmmo8pgdN8je16CP98vw3/k6TncLS5', + 'AQ0EUpXQVQEIAMEjHMeqg7B04FliUFWr/8C6sJDb492MlGAWgghIbnuJfXAnUGdN', + 'oAzn0S+n93Y/qHbW6YcjHD4/G+kK3MuxthAFqcVjdHZQXK0rkhXO/u1co7v1cdtk', + 'OTEcyOpyLXolM/1S2UYImhrml7YulTHMnWVja7xu6QIRso+7HBFT/u9D47L/xXrX', + 'MzXFVZfBtVY+yoeTrOY3OX9cBMOAu0kuN9eT18Yv2yi6XMzP3iONVHtl6HfFrAA7', + 'kAtx4ne0jgAPWZ+a8hMy59on2ZFs/AvSpJtSc1kw/vMTWkyVP1Ky20vAPHQ6Ej5q', + '1NGJ/JbcFgolvEeI/3uDueLjj4SdSIbLOXMAEQEAAYkBJQQYAQIADwUCUpXQVQIb', + 'DAUJCWYBgAAKCRDb8iPocFNN9NLkB/wO4iRxia0zf4Kw2RLVZG8qcuo3Bw9UTXYY', + 'lI0AutoLNnSURMLLCq6rcJ0BCXGj/2iZ0NBxZq3t5vbRh6uUv+hpiSxK1nF7AheN', + '4aAAzhbWx0UDTF04ebG/neE4uDklRIJLhif6+Bwu+EUeTlGbDj7fqGSsNe8g92w7', + '1e41rF/9CMoOswrKgIjXAou3aexogWcHvKY2D+1q9exORe1rIa1+sUGl5PG2wsEs', + 'znN6qtN5gMlGY1ofWDY+I02gO4qzaZ/FxRZfittCw7v5dmQYKot9qRi2Kx3Fvw+h', + 'ivFBpC4TWgppFBnJJnAsFXZJQcejMW4nEmOViRQXY8N8PepQmgsu', + '=ummy', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + +var pub_revoked = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'mQENBFKpincBCADhZjIihK15f3l+j87JgeLp9eUTSbn+g3gOFSR73TOMyBHMPt8O', + 'KwuA+TN2sM86AooOR/2B2MjHBUZqrgeJe+sk5411yXezyYdQGZ8vlq/FeLeNF70D', + 'JrvIC6tsEe2F9F7ICO7o7G+k5yveLaYQNU/okiP8Gj79XW3wN77+yAMwpQzBsrwa', + 'UO/X4mDV59h1DdrTuN4g8SZhAmY/JfT7YCZuQ8ivOs9n7xPdbGpIQWGWjJLVWziC', + '7uvxN4eFOlCqvc6JwmS/xyYGKL2B3RcQuY+OlvQ3wxKFEGDfG73HtWBd2soB7/7p', + 'w53mVcz5sLhkOWjMTj+VDDZ3jas+7VznaAbVABEBAAGJAToEIAECACQFAlKpj3od', + 'HQNUZXN0aW5nIHJldm9rZSBjb21wbGV0ZSBrZXkACgkQO+K1SH0WBbOtJgf/XqJF', + 'dfWJjXBPEdfDbnXW+OZcvVgUMEEKEKsS1MiB21BEQpsTiuOLLgDOnEKRDjT1Z9H/', + '6owkb1+iLOZRGcJIdXxxAi2W0hNwx3qSiYkJIaYIm6dhoTy77lAmrPGwjoBETflU', + 'CdWWgYFUGQVNPnpCi0AizoHXX2S4zaVlLnDthss+/FtIiuiYAIbMzB902nhF0oKH', + 'v5PTrm1IpbstchjHITtrRi4tdbyvpAmZFC6a+ydylijNyKkMeoMy0S+6tIAyaTym', + 'V5UthMH/Kk2n3bWNY4YnjDcQpIPlPF1cEnqq2c47nYxHuYdGJsw9l1F88J0enL72', + '56LWk5waecsz6XOYXrQTVjMgS2V5IDx2M0BrZXkuY29tPokBMQQwAQIAGwUCUqmP', + 'BRQdIFRlc3RpbmcgcmV2b2RlIHVpZAAKCRA74rVIfRYFszHUB/oCAV+IMzZF6uad', + 'v0Gi+Z2qCY1Eqshdxv4i7J2G3174YGF9+0hMrHwsxBkVQ/oLZKBFjfP7Z1RZXxso', + 'ts0dBho3XWZr3mrEk6Au6Ss+pbGNqq2XytV+CB3xY0DKX1Q0BJOEhgcSNn187jqd', + 'XoKLuK/hy0Bk6YkXe1lv6HqkFxYGNB2MW0wSPjrfnjjHkM29bM0Q/JNVY4o/osmY', + 'zoY/hc59fKBm5uBBL7kEtSkMO0KPVzqhvMCi5qW9/V9+vNn//WWOY+fAXYKa1cBo', + 'aMykBfE2gGf/alIV9dFpHl+TkIT8lD8sY5dBmiKHN4D38PhuLdFWHXLe4ww7kqXt', + 'JrD0bchKiQE/BBMBAgApBQJSqYp3AhsDBQkJZgGABwsJCAcDAgEGFQgCCQoLBBYC', + 'AwECHgECF4AACgkQO+K1SH0WBbOOAwgAx9Qr6UciDbN2Bn1254YH6j5HZbVXGTA/', + 'uQhZZGAYE/wDuZ5u8Z2U4giEZ3dwtblqRZ6WROmtELXn+3bGGbYjczHEFOKt4D/y', + 'HtrjCtQX04eS+FfL453n7aaQbpmHou22UvV0hik+iagMbIrYnB6nqaui9k8HrGzE', + '1HE1AeC5UTlopEHb/KQRGLUmAlr8oJEhDVXLEq41exNTArJWa9QlimFZeaG+vcbz', + '2QarcmIXmZ3o+1ARwZKTK/20oCpF6/gUGnY3KMvpLYdW88Qznsp+7yWhpC1nchfW', + '7frQmuQa94yb5PN7kBJ83yF/SZiDggZ8YfcCf1DNcbw8bjPYyFNW3bkBDQRSqYp3', + 'AQgA1Jgpmxwr2kmP2qj8FW9sQceylHJr4gUfSQ/4KPZbGFZhzK+xdEluBJOzxNbf', + 'LQXhQOHbWFmlNrGpoVDawZbA5FL7w5WHYMmNY1AADmmP0uHbHqdOvOyz/boo3fU0', + 'dcl0wOjo06vsUqLf8/3skQstUFjwLzjI2ebXWHXj5OSqZsoFvj+/P/NaOeVuAwFx', + '50vfUK19o40wsRoprgxmZOIL4uMioQ/V/QUr++ziahwqFwDQmqmj0bAzV/bIklSJ', + 'jrLfs7amX8qiGPn8K5UyWzYMa2q9r0Srt/9wx+FoSRbqRvsqLFYoU3d745zX1W7o', + 'dFcDddGMv5LMPnvNR+Qm7PUlowARAQABiQE0BCgBAgAeBQJSqY5XFx0DVGVzdGlu', + 'ZyBzdWJrZXkgcmV2b2tlAAoJEDvitUh9FgWzsUoH/1MrYYo7aQErScnhbIVQ5qpB', + 'qnqBTiyVGa3cqSPKUkT552dRs6TwsjFKnOs68MIZQ6qfliZE/ApKPQhxaHgmfWKI', + 'Q09Qv04SKHqo9njX6E3q257DnvmQiv6c9PRA3G/p2doBrj3joaOVm/ZioiCZdf2W', + 'l6akAf7j5DbcVRh8BQigM4EUhsVjBvGPYxqVNIM4aWHMTG62CaREa9g1PWOobASU', + 'jX47B7/FFP4zCLkeb+znDMwc8jKWeUBp5sUGhWo74wFiD5Dp2Zz50qRi1u05nJXg', + 'bIib7pwmH2CeDwmPRi/HRUrKBcqFzSYG5QVggQ5KMIU9M7zmvd8mDYE8MQbTLbaJ', + 'ASUEGAECAA8FAlKpincCGwwFCQlmAYAACgkQO+K1SH0WBbPbnQgAxcYAS3YplyBI', + 'ddNJQNvyrWnnuGXoGGKgkE8+LUR3rX3NK/c4pF7EFgrNxKIPrWZoIu7m1XNqoK3g', + 'PwRXJfPPQWalVrhhOajtYipXumQVAe+q8DyxAZ5YJGrUvR9b96GRel9G+HsRlR1M', + 'NV62ZXFdXVgg9FZJHDR8fa1Zy93xC0JSKu4ZoCrH5ybw+DPCngogDl4KwgdV5y4e', + 'EAZpGDSq7PrdsgZTiSuepwVw116GWJm1zecmh6FdpZL/ZrE6EfYcCGJqJiVfDiCR', + 'jgvGbcTzxnvrRmDevmJUdXBSAE11OYQuDGlhgFCU0o9cdX+k+QqP5wNycXhoJ+yk', + 'pMiJM+NJAQ==', + '=ok+o', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + +var pub_v3 = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: SKS 1.1.3', + '', + 'mQENAy9J/w4AAAEIALBDDD4vWqG/Jg59ghhMYAa+E7ECCTv2At8hxsM5cMP8P9sMLjs+GMfD', + 'IdQSOqlQXbunYADvM1l/h2fOuUMoYFIIGaUsO5Daxvd9uWceM4DVzhXMeJZb9wc5jEJEF21+', + 'qidKj5OGsMyTrg++mn4Gh/aFXvvy3N3KWaQpPfNi3NRZUpNLz0IlfbXVBQGD6reLoxPptJun', + 'NqpClyRiesgq8HCscmB2oQo+b9KzSSgzU9qQJA4SljMYVmJ2sDE/sjREI8iKL8lIgUMhJG9q', + 'NggWjuxFTpVcGKkuQFJIvdL+UhTVvEBuqw6n4cmFAzfZ/AInJM032qLtsaIf5begFKI3up0A', + 'BRGJARUDBSAxm7HC5begFKI3up0BAbdDB/0TOcI0ec+OPxC5RTZAltgIgyUc0yOjHoTD/yBh', + 'WjZdQ9YVrLGMWTW4fjhm4rFnppVZKS/N71bwI76SnN9zO4pPfx86aQPR7StmSLJxB+cfh2GL', + 'gudJoG9ifhJWdNYMUD/yhA0TpJkdHMD5yTDE5Ce/PqKLviiX9C5MPW0AT1MDvafQlzeUXfb5', + '1a71vQNPw7W1NBAVZRwztm7TNUaxWMFuOmUtOJpq4F/qDQTIHW2zGPJvl47rpf6JSiyIyU70', + 'l0deiQcZOXPC80tgInhNoBrz3zbEXhXRJo1fHkr2YSLclpJaoUOHsPxoyrNB28ASL5ZknPwI', + 'Zx3+cFxaGpRprfSdtCFKb2huIEEuIFBlcnJ5IDxwZXJyeUBwaG9lbml4Lm5ldD6JARUDBRAv', + 'Sf8k5begFKI3up0BAcbGB/0eLod2qrQxoE2/RUWQtqklOPUj/p/ZTmvZm8BgsdIflb0AMeey', + '9o8AbxyAgA3pcrcCjcye79M1Ma2trEvRksvs8hViuq3BXXjDbjPZi3wTtKSvbAC022OV52Sb', + '8/sgiTGp7xC8QMqS8w4ZeKoxJGh1TVMYrevUA8a2Rr5aDqrR3EA4rifSHwkVjJWOPF69xiKt', + 'IVA0LcYJvGsPOQCf2ag+nOcnDrF4dvcmg6XZ/RyLepve+1qkhXsA/oq+yHoaqWfe+bwgssk/', + 'qw1aEUk7Di8x7vY+cfjvWaazcYGw8kkIwSSqqIq0pkKFz2xDDfSaDJl6OW/2GUK0wDpJmYZo', + 'PN40iJUDBRAvSgDsU5OkROGu2G8BAeUqBACbC45t4+wYxWCxxp81pkFRb8RWBvEvbXI+Spwd', + '4NcKs8jc5OVC8V02yiq4KbKFDRxdw2OWpUCSRAJe1gjsfFrZ+2RivpKk06kbAYthES03MjXg', + 'cfcV3z2d7IWanJzdcOlzsHzPe1+RoUAaqBjvcqPRCGRlk0ogkYHyWYxElc6574iVAwUQL9iL', + 'CXr7ES8bepftAQGPywP/d9GSpEmS7LLIqazl4rgN1nkXN5KqduiH8Whu3xcBrdOAn7IYnGTp', + 'O+Ag4qwKKH+y/ke9CeZL6AnrU9c0pux150dHsDeHtpTPyInkjgKI7BofprydvpiFNd0nlAi4', + 'J4SAEYr3q92Qn/IiKpnLgo6Ls/GFb7q6y1O/2LL8PC2zrYU=', + '=eoGb', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + + + var tests = [function() { + var priv_key = openpgp.key.readArmored(priv_key_arm1).keys[0]; + var pub_key = openpgp.key.readArmored(pub_key_arm1).keys[0]; + var msg = openpgp.message.readArmored(msg_arm1); + priv_key.decrypt("abcd"); + var decrypted = openpgp.decryptAndVerifyMessage(priv_key, [pub_key], msg); + var verified = decrypted && decrypted.signatures[0].valid; + return new unit.result("Testing signature checking on CAST5-enciphered message", + verified); + + }, function() { + + // exercises the GnuPG s2k type 1001 extension: + // the secrets on the primary key have been stripped. + var priv_key_gnupg_ext = openpgp.key.readArmored([ + '-----BEGIN PGP PRIVATE KEY BLOCK-----', + 'Version: GnuPG v1.4.11 (GNU/Linux)', + '', + 'lQGqBFERnrMRBADmM0hIfkI3yosjgbWo9v0Lnr3CCE+8KsMszgVS+hBu0XfGraKm', + 'ivcA2aaJimHqVYOP7gEnwFAxHBBpeTJcu5wzCFyJwEYqVeS3nnaIhBPplSF14Duf', + 'i6bB9RV7KxVAg6aunmM2tAutqC+a0y2rDaf7jkJoZ9gWJe2zI+vraD6fiwCgxvHo', + '3IgULB9RqIqpLoMgXfcjC+cD/1jeJlKRm+n71ryYwT/ECKsspFz7S36z6q3XyS8Q', + 'QfrsUz2p1fbFicvJwIOJ8B20J/N2/nit4P0gBUTUxv3QEa7XCM/56/xrGkyBzscW', + 'AzBoy/AK9K7GN6z13RozuAS60F1xO7MQc6Yi2VU3eASDQEKiyL/Ubf/s/rkZ+sGj', + 'yJizBACtwCbQzA+z9XBZNUat5NPgcZz5Qeh1nwF9Nxnr6pyBv7tkrLh/3gxRGHqG', + '063dMbUk8pmUcJzBUyRsNiIPDoEUsLjY5zmZZmp/waAhpREsnK29WLCbqLdpUors', + 'c1JJBsObkA1IM8TZY8YUmvsMEvBLCCanuKpclZZXqeRAeOHJ0v4DZQJHTlUBtBZU', + 'ZXN0MiA8dGVzdDJAdGVzdC5jb20+iGIEExECACIFAlERnrMCGwMGCwkIBwMCBhUI', + 'AgkKCwQWAgMBAh4BAheAAAoJEBEnlAPLFp74xc0AoLNZINHe0ytOsNtMCuLvc3Vd', + 'vePUAJ9KX3L5IBqHarsa+aJHX7r796SokZ0BWARREZ6zEAQA2WkxmNbfeMzGUocN', + '3JEVe0o6rxGt5eGrTSmWisduDP3MURabhUXnf4T8oaeYcbJjkLLxMrJmNq55ln1e', + '4bSG5mDkh/ryKsV81m3F0DbqO/z/891nRSP5fondFVral4wsMOzBNgs4vVk7V/F2', + '0MPjR90CIhnVDKPAQbQA+3PjUR8AAwUEALn922AEE+0d7xSMMFpR7ic3Me5QEGnp', + 'cT4ft6oc0UK5kAnvKoksZUc0hpBHjX1w3LTz847/5hRDuuDvwvGMWK8IfsjOF9T7', + 'rK8QtJuBEyJxjoScA/YZP5vX4y0U1reUEa0EdwmVrnZzatMAe2FhlaR9PlHkOcm5', + 'DZwkcExL0dbI/gMDArxZ+5N7kH4zYLtr9glJS/pJ7F0YJqJpNwCbqD8+8DqHD8Uv', + 'MgQ/rtBxBJJOaF+1AjCd123hLgzIkkfdTh8loV9hDXMKeJgmiEkEGBECAAkFAlER', + 'nrMCGwwACgkQESeUA8sWnvhBswCfdXjznvHCc73/6/MhWcv3dbeTT/wAoLyiZg8+', + 'iY3UT9QkV9d0sMgyLkug', + '=GQsY', + '-----END PGP PRIVATE KEY BLOCK-----', + ].join("\n")).keys[0]; + var pub_key = openpgp.key.readArmored(pub_key_arm1).keys[0]; + var msg = openpgp.message.readArmored(msg_arm1); + + priv_key_gnupg_ext.subKeys[0].subKey.decrypt("abcd"); + msg = msg.decrypt(priv_key_gnupg_ext); + var verified = msg.verify([pub_key]); + return new unit.result("Testing GnuPG stripped-key extensions", + verified[0].valid); + + }, function() { + + var signedArmor = + ['-----BEGIN PGP MESSAGE-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'owGbwMvMwMT4oOW7S46CznTGNeZJLCWpFSVBU3ZGF2fkF5Uo5KYWFyemp3LlAUUV', + 'cjLzUrneTp3zauvaN9O26L9ZuOFNy4LXyydwcXXMYWFgZGJgY2UCaWXg4hSAmblK', + 'nPmfsXYxd58Ka9eVrEnSpzilr520fXBrJsf2P/oTqzTj3hzyLG0o3TTzxFfrtOXf', + 'cw6U57n3/Z4X0pEZ68C5/o/6NpPICD7fuEOz3936raZ6wXGzueY8pfPnVjY0ajAc', + 'PtJzvvqj+ubYaT1sK9wWhd9lL3/V+9Zuua9QjOWC22buchsCroh8fLoZAA==', + '=VH8F', + '-----END PGP MESSAGE-----'].join('\n'); + + var sMsg = openpgp.message.readArmored(signedArmor); + var pub_key = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var verified = sMsg.verify([pub_key]); + return new unit.result("Verify V4 signature. Hash: SHA1. PK: RSA. Signature Type: 0x00 (binary document)", verified[0].valid); + }, function() { + + var signedArmor = + ['-----BEGIN PGP MESSAGE-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'owGbwMvMyMj4oOW7S46CznTG09YlLCWpFSVBU47xFGfkF5Uo5KYWFyemp/Jy5QGF', + 'FXIy84DMt1PnvNq69s20LfpvFm5407Lg9fIJvFy8XJ0MU5lZGUFa4eYxxiQz/6+/', + 'aFt4/6+e76O6s1afLi65emmK9xsdh7Mr60UnT2UN0LwocWnT7t/nOMJubnypvzTu', + 'aPJyvm9TTpobW/O+P1n2THLS4UCvWt12Oa2lJ04GLwk/bDF1u+8ZpfPCpsxLVzcs', + 'ZGtbq/f23XxV/jkL47hr3s3Ic4yoZTW4oZO27GYf37TPp9L3VboCAA==', + '=pa6B', + '-----END PGP MESSAGE-----'].join('\n'); + + var sMsg = openpgp.message.readArmored(signedArmor); + var pub_key = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var verified = sMsg.verify([pub_key]); + return new unit.result("Verify V3 signature. Hash: MD5. PK: RSA. Signature Type: 0x01 (text document)", verified[0].valid); + }, function() { + + var msg_armor = + ['-----BEGIN PGP MESSAGE-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'hIwD4IT3RGwgLJcBBADEBdm+GEW7IV1K/Bykg0nB0WYO08ai7/8/+Y/O9xu6RiU0', + 'q7/jWuKms7kSjw9gxMCjf2dGnAuT4Cg505Kj5WfeBuHh618ovO8qo4h0qHyp1/y3', + 'o1P0IXPAb+LGJOeO7DyM9Xp2AOBiIKOVWzFTg+MBZOc+XZEVx3FioHfm9SSDudLA', + 'WAEkDakCG6MRFj/7SmOiV8mQKH+YPMKT69eDZW7hjINabrpM2pdRU7c9lC7CMUBx', + 'Vj7wZsQBMASSC8f2rhpGA2iKvYMsmW3g9R1xkvj1MXWftSPUS4jeNTAgEwvvF6Af', + 'cP+OYSXKlTbwfEr73ES2O3/IFE9sHRjPqWaxWuv4DDQ5YfIxE54C1aE8Aq5/QaIH', + 'v38TUSia0yEMCc/tJd58DikkT07AF162tcx9Ro0ZjhudyuvUyXIfPfxA+XWR2pdz', + 'ifxyV4zia9RvaCUY8vXGM+gQJ3NNXx2LkZA3kWUEyxFVL1Vl/XUQY0M6U+uccSk4', + 'eMXm6eyEWDcj0lBRckqKoKo1w/uan11jPuHsnRz6jO9DsuKEz79UDgI=', + '=cFi7', + '-----END PGP MESSAGE-----'].join('\n'); + + var plaintext = 'short message\nnext line\n한국어/조선말'; + var esMsg = openpgp.message.readArmored(msg_armor); + var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0]; + + var keyids = esMsg.getEncryptionKeyIds(); + privKey.decryptKeyPacket(keyids, 'hello world'); + + var decrypted = openpgp.decryptAndVerifyMessage(privKey, [pubKey], esMsg); + var verified = decrypted.text == plaintext && decrypted.signatures[0].valid; + + return new unit.result("Verify signature of signed and encrypted message from GPG2 with openpgp.decryptAndVerifyMessage", verified); + }, function() { + + var msg_armor = + ['-----BEGIN PGP MESSAGE-----', + 'Version: Encryption Desktop 10.3.0 (Build 9307)', + 'Charset: utf-8', + '', + 'qANQR1DBjAPghPdEbCAslwED/2S4oNvCjO5TdLUMMUuVOQc8fi6c5XIBu7Y09fEX', + 'Jm/UrkDHVgmPojLGBDF0CYENNZOVrNfpahY7A3r4HPzGucBzCO1uxuUIKjhtNAAM', + 'mjD939ernjooOZrM6xDuRaX8adG0LSxpNaVJGxXd/EdlmKDJbYDI6aJ5INrUxzAR', + 'DAqw0sBSAXgRWgiH6IIiAo5y5WFEDEN9sGStaEQT2wd32kX73M4iZuMt/GM2agiB', + 'sWb7yLcNHiJ/3OnTfDg9+T543kFq9FlwFbwqygO/wm9e/kgMBq0ZsFOfV+GRtXep', + '3qNbJsmzGvdqiUHb/+hkdE191jaSVcO/zaMW4N0Vc1IwIEhZ8I9+9bKwusdVhHT5', + 'MySnhIogv+0Ilag/aY+UiCt+Zcie69T7Eix48fC/VVW5w3INf1T2CMmDm5ZLZFRN', + 'oyqzb9Vsgu1gS7SCb6qTbnbV9PlSyU4wJB6siX8hz/U0urokT5se3uYRjiV0KbkA', + 'zl1/r/wCrmwX4Gl9VN9+33cQgYZAlJLsRw8N82GhbVweZS8qwv24GQ==', + '=nx90', + '-----END PGP MESSAGE-----'].join('\n'); + + var plaintext = 'short message\nnext line\n한국어/조선말\n\n'; + var esMsg = openpgp.message.readArmored(msg_armor); + var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0]; + + var keyids = esMsg.getEncryptionKeyIds(); + privKey.decryptKeyPacket(keyids, 'hello world'); + + var decrypted = openpgp.decryptAndVerifyMessage(privKey, [pubKey], esMsg); + var verified = decrypted.text == plaintext && decrypted.signatures[0].valid; + + return new unit.result("Verify signature of signed and encrypted message from PGP 10.3.0 with openpgp.decryptAndVerifyMessage", verified); + }, function() { + + var msg_armor = + ['-----BEGIN PGP MESSAGE-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'owGbwMvMwMF4+5Pyi4Jg3y8ME8DcBy3fXXIUdKYzrjFNYilJrSgJmsXDXJyRX1Si', + 'kJtaXJyYnsqVBxRVyMnMS+V6O3XOq61r30zbov9m4YY3LQteL5/QMYeFgZGDgY2V', + 'CaSRgYtTAGZiYxYLwySbQk07ptZel6gmjrKyBWsyWdkOG3oscLBdIpXXfDdb6fNv', + '8ULN5L1ed+xNo79P2dBotWud6vn7e9dtLJ7o12PunnvEz8gyyvP4/As/los0xsnZ', + 'H+8ublrhvGtLxJUZuUKZO6QdHq2Nepuw8OrfiMXPBDQXXpV2q11Ze+rD3lndgv/C', + 'bJQNOhll0J0H839jFvt/16m20h/ZmDoWqJywapnypjdIjcXr+7rJFess40yenV7Q', + '2LSu/EX6Aq29x+dv+GPUMfuhTNE3viWWUR4PD6T7XfmdViUwmSf8fkRNUn/t3a2n', + 'cq46Xr36seCor/OLp0atSZwHrjx2SU5zPLheZn+zw/0d1/YZnD7AEeP9s/Cuycyv', + 'CZ5HZNKufvB8fsh+dfdSXW0GfqkPfxk36Vw8ufpjaoZDyt2nxxg/6D4KS3UvZzv3', + 'axdLZ9yd0OJNZv4P501If24W4vTGz6nI7Ser8Yd2PiOvE5MWMT0wLZQ+zPX1sv0/', + 's8PvkyWmVM0O0fB/ZSHovHNNPffDg/rWhzOmXQ9/7vTn477F+aWm5sYzJ75/BQA=', + '=+L0S', + '-----END PGP MESSAGE-----'].join('\n'); + + var plaintext = 'short message\nnext line\n한국어/조선말'; + var sMsg = openpgp.message.readArmored(msg_armor); + var pubKey2 = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var pubKey3 = openpgp.key.readArmored(pub_key_arm3).keys[0]; + + var keyids = sMsg.getSigningKeyIds(); + + var verified = pubKey2.getPublicKeyPacket(keyids) !== null && pubKey3.getPublicKeyPacket(keyids) !== null; + + verified = verified && sMsg.getText() == plaintext; + + var verifiedSig = sMsg.verify([pubKey2, pubKey3]); + + verified = verified && verifiedSig[0].valid && verifiedSig[1].valid; + + return new unit.result("Verify signed message with two one pass signatures", verified); + }, function() { + + var msg_armor = + ['-----BEGIN PGP SIGNED MESSAGE-----', + 'Hash: SHA256', + '', + 'short message', + 'next line', + '한국어/조선말', + '-----BEGIN PGP SIGNATURE-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'iJwEAQEIAAYFAlKcju8ACgkQ4IT3RGwgLJci6gP/dCmIraUa6AGpJxzGfK+jYpjl', + 'G0KunFyGmyPxeJVnPi2bBp3EPIbiayQ71CcDe9DKpF046tora07AA9eo+/YbvJ9P', + 'PWeScw3oj/ejsmKQoDBGzyDMFUphevnhgc5lENjovJqmiu6FKjNmADTxcZ/qFTOq', + '44EWTgdW3IqXFkNpKjeJARwEAQEIAAYFAlKcju8ACgkQ2/Ij6HBTTfQi6gf9HxhE', + 'ycLDhQ8iyC090TaYwsDytScU2vOMiI5rJCy2tfDV0pfn+UekYGMnKxZTpwtmno1j', + 'mVOlieENszz5IcehS5TYwk4lmRFjoba+Z8qwPEYhYxP29GMbmRIsH811sQHFTigo', + 'LI2t4pSSSUpAiXd9y6KtvkWcGGn8IfkNHCEHPh1ov28QvH0+ByIiKYK5N6ZB8hEo', + '0uMYhKQPVJdPCvMkAxQCRPw84EvmxuJ0HMCeSB9tHQXpz5un2m8D9yiGpBQPnqlW', + 'vCCq7fgaUz8ksxvQ9bSwv0iIIbbBdTP7Z8y2c1Oof6NDl7irH+QCeNT7IIGs8Smn', + 'BEzv/FqkQAhjy3Krxg==', + '=3Pkl', + '-----END PGP SIGNATURE-----'].join('\n'); + + var plaintext = 'short message\nnext line\n한국어/조선말'; + var csMsg = openpgp.cleartext.readArmored(msg_armor); + var pubKey2 = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var pubKey3 = openpgp.key.readArmored(pub_key_arm3).keys[0]; + + var keyids = csMsg.getSigningKeyIds(); + + var verified = pubKey2.getPublicKeyPacket(keyids) !== null && pubKey3.getPublicKeyPacket(keyids) !== null; + + var cleartextSig = openpgp.verifyClearSignedMessage([pubKey2, pubKey3], csMsg); + + verified = verified && cleartextSig.text == plaintext; + + verified = verified && cleartextSig.signatures[0].valid && cleartextSig.signatures[1].valid; + + return new unit.result("Verify cleartext signed message with two signatures with openpgp.verifyClearSignedMessage", verified); + }, function() { + + var plaintext = 'short message\nnext line\n한국어/조선말'; + var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0]; + privKey.getSigningKeyPacket().decrypt('hello world'); + + var clearSignedArmor = openpgp.signClearMessage([privKey], plaintext); + + var csMsg = openpgp.cleartext.readArmored(clearSignedArmor); + + var cleartextSig = openpgp.verifyClearSignedMessage([pubKey], csMsg); + + var verified = cleartextSig.text == plaintext.replace(/\r/g,''); + + verified = verified && cleartextSig.signatures[0].valid; + + return new unit.result("Sign text with openpgp.signClearMessage and verify with openpgp.verifyClearSignedMessage leads to same cleartext and valid signatures", verified); + }, function() { + + var pubKey = openpgp.key.readArmored(pub_revoked).keys[0]; + + var verified = pubKey.revocationSignature.verify(pubKey.primaryKey, {key: pubKey.primaryKey}); + + return new unit.result("Verify primary key revocation signature", verified); + }, function() { + + var pubKey = openpgp.key.readArmored(pub_revoked).keys[0]; + + var verified = pubKey.subKeys[0].revocationSignature.verify(pubKey.primaryKey, {key: pubKey.subKeys[0].subKey}); + + return new unit.result("Verify subkey revocation signature", verified); + }, function() { + + var pubKey = openpgp.key.readArmored(pub_revoked).keys[0]; + + var verified = !pubKey.users[0].selfCertifications[0].keyNeverExpires && + pubKey.users[0].selfCertifications[0].keyExpirationTime == 5*365*24*60*60; + + return new unit.result("Verify key expiration date", verified); + }, function() { + + var pubKey = openpgp.key.readArmored(pub_v3).keys[0]; + + var verified = pubKey.users[0].selfCertifications[0].verify(pubKey.primaryKey, {key: pubKey.primaryKey, userid: pubKey.users[0].userId}); + + return new unit.result("Verify V3 certification signature", verified); + }]; + + var results = []; + + for(var i in tests) { + results.push(tests[i]()); + } + + return results; + +}); diff --git a/test/index.html b/test/index.html index 1c4e0f14..1fedc06a 100644 --- a/test/index.html +++ b/test/index.html @@ -1,82 +1,9 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - OpenPGP.js testpage + + + @@ -160,7 +100,6 @@ function unit_tests() { Encryption / Decryption | Coverage -

      Print Debug Messages

      Unit tests

      @@ -169,7 +108,10 @@ function unit_tests() { -

      + TestDescriptionResult + + +
      diff --git a/test/test-all.js b/test/test-all.js new file mode 100644 index 00000000..7b22068a --- /dev/null +++ b/test/test-all.js @@ -0,0 +1,20 @@ + +module.exports = require('./unit.js'); + +require('./crypto/hash/sha.js'); +require('./crypto/hash/md5.js'); +require('./crypto/hash/ripemd.js'); + +require('./crypto/cipher/aes.js'); +require('./crypto/cipher/blowfish.js'); +require('./crypto/cipher/cast5.js'); +require('./crypto/cipher/des.js'); +require('./crypto/cipher/twofish.js'); + +require('./crypto/crypto.js'); + +require('./general/basic.js'); +require('./general/key.js'); +require('./general/keyring.js'); +require('./general/packet.js'); +require('./general/signature.js'); diff --git a/test/test.js b/test/test.js new file mode 100644 index 00000000..9c937381 --- /dev/null +++ b/test/test.js @@ -0,0 +1,6 @@ + +module.exports = require('./unit.js'); + +require('./test-all.js'); + +module.exports.run_all(); diff --git a/test/unit.js b/test/unit.js new file mode 100644 index 00000000..081a3fc5 --- /dev/null +++ b/test/unit.js @@ -0,0 +1,48 @@ + +module.exports = { + tests: [], + register: function(str_title, func_runtest) { + this.tests.push({ title: str_title, run: func_runtest }); + }, + + run: function() { + var test = this.tests.shift(); + + var result = { + title: test.title + }; + + + result.tests = test.run(); + + return result; + }, + + run_all: function() { + var passed = true; + + while(this.tests.length > 0) { + var result = this.run(); + + console.log('Test: ' + result.title); + + for(var i in result.tests) { + + var res = result.tests[i].result ? + 'SUCCESS' : 'FAILED'; + + console.log(result.tests[i].description + ' ' + res); + + passed = passed && result.tests[i].result; + } + } + + if(!passed) process.exit(1); + }, + + result: function(str_description, boolean_result) { + this.description = str_description; + this.result = boolean_result; + } +} + diff --git a/test/unittest.js b/test/unittest.js deleted file mode 100644 index 3a8e3b22..00000000 --- a/test/unittest.js +++ /dev/null @@ -1,21 +0,0 @@ - -var unittests = { - tests: Array(), - register: function(str_title, func_runtest) { - this.tests[this.tests.length] = {title: str_title, run: func_runtest}; - - }, - - runAll: function() { - var result = new Array(); - for (var i = 0; i < this.tests.length; i++) { - result[i] = {tests: this.tests[i].run(), title: this.tests[i].title }; - } - return result; - } -} - -function test_result(str_description, boolean_result) { - this.description = str_description; - this.result = boolean_result; -} \ No newline at end of file