--- /dev/null
+s3
+test/node_modules
+support/test-runner/node_modules
+node_modules
--- /dev/null
+test/node_modules
+support
--- /dev/null
+
+0.7.4 / 2011-07-12
+==================
+
+ * Added `SocketNamespace#of` shortcut. [3rd-Eden]
+ * Fixed a IE payload decoding bug. [3rd-Eden]
+ * Honor document protocol, unless overriden. [dvv]
+ * Fixed new builder dependencies. [3rd-Eden]
+
+0.7.3 / 2011-06-30
+==================
+
+ * Fixed; acks don't depend on arity. They're automatic for `.send` and
+ callback based for `.emit`. [dvv]
+ * Added support for sub-sockets authorization. [3rd-Eden]
+ * Added BC support for `new io.connect`. [fat]
+ * Fixed double `connect` events. [3rd-Eden]
+ * Fixed reconnection with jsonp-polling maintaining old sessionid. [franck34]
+
+0.7.2 / 2011-06-22
+==================
+
+ * Added `noop` message type.
+
+0.7.1 / 2011-06-21
+==================
+
+ * Bumped socket.io dependency version for acceptance tests.
+
+0.7.0 / 2011-06-21
+==================
+
+ * http://socket.io/announcement.html
+
--- /dev/null
+
+ALL_TESTS = $(shell find test/ -name '*.test.js')
+
+run-tests:
+ @npm link --local > /dev/null
+ @./node_modules/.bin/expresso \
+ -I lib \
+ -I support \
+ --serial \
+ $(TESTS)
+
+test:
+ @$(MAKE) TESTS="$(ALL_TESTS)" run-tests
+
+test-acceptance:
+ @npm link --local > /dev/null
+ @node support/test-runner/app
+
+build:
+ @node ./bin/builder.js
+
+.PHONY: test
--- /dev/null
+socket.io
+=========
+
+#### Sockets for the rest of us
+
+The `socket.io` client is basically a simple HTTP Socket interface implementation.
+It looks similar to WebSocket while providing additional features and
+leveraging other transports when WebSocket is not supported by the user's
+browser.
+
+```js
+var socket = io.connect('http://domain.com');
+socket.on('connect', function () {
+ // socket connected
+});
+socket.on('custom event', function () {
+ // server emitted a custom event
+});
+socket.on('disconnect', function () {
+ // socket disconnected
+});
+socket.send('hi there');
+```
+
+### Recipes
+
+#### Utilizing namespaces (ie: multiple sockets)
+
+If you want to namespace all the messages and events emitted to a particular
+endpoint, simply specify it as part of the `connect` uri:
+
+```js
+var chat = io.connect('http://localhost/chat');
+chat.on('connect', function () {
+ // chat socket connected
+});
+
+var news = io.connect('/news'); // io.connect auto-detects host
+news.on('connect', function () {
+ // news socket connected
+});
+```
+
+#### Emitting custom events
+
+To ease with the creation of applications, you can emit custom events outside
+of the global `message` event.
+
+```js
+var socket = io.connect();
+socket.emit('server custom event', { my: 'data' });
+```
+
+#### Forcing disconnection
+
+```js
+var socket = io.connect();
+socket.on('connect', function () {
+ socket.disconnect();
+});
+```
+
+### Documentation
+
+#### io#connect
+
+```js
+io.connect(uri, [options]);
+```
+
+##### Options:
+
+- *resource*
+
+ socket.io
+
+ The resource is what allows the `socket.io` server to identify incoming connections by `socket.io` clients. In other words, any HTTP server can implement socket.io and still serve other normal, non-realtime HTTP requests.
+
+- *transports*
+
+```js
+['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling']
+```
+
+ A list of the transports to attempt to utilize (in order of preference).
+
+- *'connect timeout'*
+
+```js
+5000
+```
+
+ The amount of milliseconds a transport has to create a connection before we consider it timed out.
+
+- *'try multiple transports'*
+
+```js
+true
+```
+
+ A boolean indicating if we should try other transports when the connectTimeout occurs.
+
+- *reconnect*
+
+```js
+true
+```
+
+ A boolean indicating if we should automatically reconnect if a connection is disconnected.
+
+- *'reconnection delay'*
+
+```js
+500
+```
+
+ The amount of milliseconds before we try to connect to the server again. We are using a exponential back off algorithm for the following reconnections, on each reconnect attempt this value will get multiplied (500 > 1000 > 2000 > 4000 > 8000).
+
+
+- *'max reconnection attempts'*
+
+```js
+10
+```
+
+ The amount of attempts should we make using the current transport to connect to the server? After this we will do one final attempt, and re-try with all enabled transport methods before we give up.
+
+##### Properties:
+
+- *options*
+
+ The passed in options combined with the defaults.
+
+- *connected*
+
+ Whether the socket is connected or not.
+
+- *connecting*
+
+ Whether the socket is connecting or not.
+
+- *reconnecting*
+
+ Whether we are reconnecting or not.
+
+- *transport*
+
+ The transport instance.
+
+##### Methods:
+
+- *connect(λ)*
+
+ Establishes a connection. If λ is supplied as argument, it will be called once the connection is established.
+
+- *send(message)*
+
+ A string of data to send.
+
+- *disconnect*
+
+ Closes the connection.
+
+- *on(event, λ)*
+
+ Adds a listener for the event *event*.
+
+- *once(event, λ)*
+
+ Adds a one time listener for the event *event*. The listener is removed after the first time the event is fired.
+
+- *removeEvent(event, λ)*
+
+ Removes the listener λ for the event *event*.
+
+##### Events:
+
+- *connect*
+
+ Fired when the connection is established and the handshake successful.
+
+- *connecting(transport_type)*
+
+ Fired when a connection is attempted, passing the transport name.
+
+- *connect_failed*
+
+ Fired when the connection timeout occurs after the last connection attempt.
+ This only fires if the `connectTimeout` option is set.
+ If the `tryTransportsOnConnectTimeout` option is set, this only fires once all
+ possible transports have been tried.
+
+- *message(message)*
+
+ Fired when a message arrives from the server
+
+- *close*
+
+ Fired when the connection is closed. Be careful with using this event, as some transports will fire it even under temporary, expected disconnections (such as XHR-Polling).
+
+- *disconnect*
+
+ Fired when the connection is considered disconnected.
+
+- *reconnect(transport_type,reconnectionAttempts)*
+
+ Fired when the connection has been re-established. This only fires if the `reconnect` option is set.
+
+- *reconnecting(reconnectionDelay,reconnectionAttempts)*
+
+ Fired when a reconnection is attempted, passing the next delay for the next reconnection.
+
+- *reconnect_failed*
+
+ Fired when all reconnection attempts have failed and we where unsuccessful in reconnecting to the server.
+
+### Contributors
+
+Guillermo Rauch <guillermo@learnboost.com>
+
+Arnout Kazemier <info@3rd-eden.com>
+
+### License
+
+(The MIT License)
+
+Copyright (c) 2010 LearnBoost <dev@learnboost.com>
+
+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', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs')
+ , socket = require('../lib/io')
+ , uglify = require('uglify-js');
+
+/**
+ * License headers.
+ * @api private
+ */
+
+var template = '/*! Socket.IO.%ext% build:' + socket.version + ', %type%. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */\n'
+ , development = template.replace('%type%', 'development').replace('%ext%', 'js')
+ , production = template.replace('%type%', 'production').replace('%ext%', 'min.js');
+
+/**
+ * If statements, these allows you to create serveride & client side compatible code
+ * using specially designed `if` statements that remove serverside designed code from
+ * the source files
+ *
+ * @api private
+ */
+var starttagIF = '// if node'
+ , endtagIF = '// end node';
+
+/**
+ * The modules that are required to create a base build of Socket.IO.
+ *
+ * @const
+ * @type {Array}
+ * @api private
+ */
+
+var base = [
+ 'io.js'
+ , 'util.js'
+ , 'events.js'
+ , 'json.js'
+ , 'parser.js'
+ , 'transport.js'
+ , 'socket.js'
+ , 'namespace.js'
+ ];
+
+/**
+ * The available transports for Socket.IO. These are mapped as:
+ *
+ * - `key` the name of the transport
+ * - `value` the dependencies for the transport
+ *
+ * @const
+ * @type {Object}
+ * @api public
+ */
+
+ var baseTransports = {
+ 'websocket': ['transports/websocket.js']
+ , 'flashsocket': [
+ 'transports/websocket.js'
+ , 'transports/flashsocket.js'
+ , 'vendor/web-socket-js/swfobject.js'
+ , 'vendor/web-socket-js/web_socket.js'
+ ]
+ , 'htmlfile': ['transports/xhr.js', 'transports/htmlfile.js']
+ /* FIXME: re-enable me once we have multi-part support
+ , 'xhr-multipart': ['transports/xhr.js', 'transports/xhr-multipart.js'] */
+ , 'xhr-polling': ['transports/xhr.js', 'transports/xhr-polling.js']
+ , 'jsonp-polling': ['transports/xhr.js', 'transports/jsonp-polling.js']
+ };
+
+/**
+ * Builds a custom Socket.IO distribution based on the transports that you need. You
+ * can configure the build to create development build or production build (minified).
+ *
+ * @param {Array} transports The transports that needs to be bundled.
+ * @param {Object} [options] Options to configure the building process.
+ * @param {Function} callback The argument is always the callback, because the options are.. optional:D.
+ * @callback {String|Boolean} err An optional argument, if it exists than an error occurred during the build process.
+ * @callback {String} result The result of the build process.
+ * @api public
+ */
+
+var builder = module.exports = function(){
+ var transports, options, callback, error = null
+ , args = Array.prototype.slice.call(arguments,0)
+ , settings = {
+ minify: true
+ , node: false
+ , custom: []
+ };
+
+ // Fancy pancy argument support
+ // this makes any pattern possible mainly because we require only one of each type
+ args.forEach(function(arg){
+ switch(Object.prototype.toString.call(arg).replace(/\[object\s(\w+)\]/gi , '$1' ).toLowerCase()){
+ case 'array':
+ return transports = arg;
+ case 'object':
+ return options = arg;
+ case 'function':
+ return callback = arg;
+ }
+ });
+
+ // Add defaults
+ options = options || {};
+ transports = transports || Object.keys(baseTransports);
+
+ // Merge the data
+ for(var option in options) settings[option] = options[option];
+
+ // Start creating a dependencies chain with all the required files for the custom Socket.IO bundle.
+ var files = [];
+ base.forEach(function(file){
+ files.push(__dirname + '/../lib/' + file);
+ });
+
+ transports.forEach(function(transport){
+ var dependencies = baseTransports[transport];
+ if (!dependencies) return error = 'Unsupported transport `' + transport + '` supplied as argument.';
+
+ // Add the files to the files list, but only if they are not added before
+ dependencies.forEach(function(file){
+ var path = __dirname + '/../lib/' + file;
+ if (!~files.indexOf(path)) files.push(path);
+ })
+ });
+
+ // check to see if the files tree compilation generated any errors.
+ if (error) return callback(error);
+
+ var results = {};
+ files.forEach(function(file){
+ fs.readFile(file, function(err, content){
+ if (err) error = err;
+ results[file] = content;
+
+ // check if we are done yet, or not.. Just by checking the size of the result
+ // object.
+ if (Object.keys(results).length !== files.length) return;
+
+ // we are done, did we error?
+ if (error) return callback(error);
+
+ // concatinate the file contents in order
+ var code = development
+ , ignore = 0;
+
+ files.forEach(function(file){
+ code += results[file];
+ });
+
+ // check if we need to add custom code
+ if (settings.custom.length){
+ settings.custom.forEach(function(content){
+ code += content;
+ })
+ }
+
+ // Search for conditional code blocks that need to be removed as they where designed for
+ // a server side env. but only if we don't want to make this build node compatible
+ if (!settings.node){
+ code = code.split('\n').filter(function(line){
+ // check if there are tags in here
+ var start = line.indexOf(starttagIF) >= 0
+ , end = line.indexOf(endtagIF) >= 0
+ , ret = ignore;
+
+ // ignore the current line
+ if (start) ignore++,ret = ignore;
+
+ // stop ignoring the next line
+ if (end) ignore--;
+
+ return ret == 0;
+ }).join('\n')
+ }
+
+ // check if we need to process it any further
+ if (settings.minify){
+ var ast = uglify.parser.parse(code);
+ ast = uglify.uglify.ast_mangle(ast);
+ ast = uglify.uglify.ast_squeeze(ast);
+
+ code = production + uglify.uglify.gen_code(ast);
+ }
+
+ callback(error, code);
+ })
+ })
+};
+
+/**
+ * Builder version is also the current client version
+ * this way we don't have to do another include for the
+ * clients version number and we can just include the builder.
+ *
+ * @type {String}
+ * @api public
+ */
+
+builder.version = socket.version;
+
+/**
+ * A list of all build in transport types.
+ *
+ * @type {Object}
+ * @api public
+ */
+
+builder.transports = baseTransports;
+
+/**
+ * Command line support, this allows us to generate builds without having
+ * to load it as module.
+ */
+
+if (!module.parent){
+ var args = process.argv.slice(2); // the first 2 are `node` and the path to this file, we don't need them
+
+ // build a development build
+ builder(args.length ? args : false, {minify:false},function(err, content){
+ if (err) return console.error(err);
+
+ fs.write(fs.openSync(__dirname + '/../dist/socket.io.js', 'w'), content, 0, 'utf8');
+ console.log('Successfully generated the development build: socket.io.js');
+ });
+
+ // and build a production build
+ builder(args.length ? args : false, function(err, content){
+ if (err) return console.error(err);
+
+ fs.write(fs.openSync(__dirname + '/../dist/socket.io.min.js', 'w'), content, 0, 'utf8');
+ console.log('Successfully generated the production build: socket.io.min.js');
+ });
+}
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports.EventEmitter = EventEmitter;
+
+ /**
+ * Event emitter constructor.
+ *
+ * @api public.
+ */
+
+ function EventEmitter () {};
+
+ /**
+ * Adds a listener
+ *
+ * @api public
+ */
+
+ EventEmitter.prototype.on = function (name, fn) {
+ if (!this.$events) {
+ this.$events = {};
+ }
+
+ if (!this.$events[name]) {
+ this.$events[name] = fn;
+ } else if (io.util.isArray(this.$events[name])) {
+ this.$events[name].push(fn);
+ } else {
+ this.$events[name] = [this.$events[name], fn];
+ }
+
+ return this;
+ };
+
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+
+ /**
+ * Adds a volatile listener.
+ *
+ * @api public
+ */
+
+ EventEmitter.prototype.once = function (name, fn) {
+ var self = this;
+
+ function on () {
+ self.removeListener(name, on);
+ fn.apply(this, arguments);
+ };
+
+ on.listener = fn;
+ this.on(name, on);
+
+ return this;
+ };
+
+ /**
+ * Removes a listener.
+ *
+ * @api public
+ */
+
+ EventEmitter.prototype.removeListener = function (name, fn) {
+ if (this.$events && this.$events[name]) {
+ var list = this.$events[name];
+
+ if (io.util.isArray(list)) {
+ var pos = -1;
+
+ for (var i = 0, l = list.length; i < l; i++) {
+ if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
+ pos = i;
+ break;
+ }
+ }
+
+ if (pos < 0) {
+ return this;
+ }
+
+ list.splice(pos, 1);
+
+ if (!list.length) {
+ delete this.$events[name];
+ }
+ } else if (list === fn || (list.listener && list.listener === fn)) {
+ delete this.$events[name];
+ }
+ }
+
+ return this;
+ };
+
+ /**
+ * Removes all listeners for an event.
+ *
+ * @api public
+ */
+
+ EventEmitter.prototype.removeAllListeners = function (name) {
+ // TODO: enable this when node 0.5 is stable
+ //if (name === undefined) {
+ //this.$events = {};
+ //return this;
+ //}
+
+ if (this.$events && this.$events[name]) {
+ this.$events[name] = null;
+ }
+
+ return this;
+ };
+
+ /**
+ * Gets all listeners for a certain event.
+ *
+ * @api publci
+ */
+
+ EventEmitter.prototype.listeners = function (name) {
+ if (!this.$events) {
+ this.$events = {};
+ }
+
+ if (!this.$events[name]) {
+ this.$events[name] = [];
+ }
+
+ if (!io.util.isArray(this.$events[name])) {
+ this.$events[name] = [this.$events[name]];
+ }
+
+ return this.$events[name];
+ };
+
+ /**
+ * Emits an event.
+ *
+ * @api public
+ */
+
+ EventEmitter.prototype.emit = function (name) {
+ if (!this.$events) {
+ return false;
+ }
+
+ var handler = this.$events[name];
+
+ if (!handler) {
+ return false;
+ }
+
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ if ('function' == typeof handler) {
+ handler.apply(this, args);
+ } else if (io.util.isArray(handler)) {
+ var listeners = handler.slice();
+
+ for (var i = 0, l = listeners.length; i < l; i++) {
+ listeners[i].apply(this, args);
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+ };
+
+})(
+ 'undefined' != typeof io ? io : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports) {
+
+ /**
+ * IO namespace.
+ *
+ * @namespace
+ */
+
+ var io = exports;
+
+ /**
+ * Socket.IO version
+ *
+ * @api public
+ */
+
+ io.version = '0.7.4';
+
+ /**
+ * Protocol implemented.
+ *
+ * @api public
+ */
+
+ io.protocol = 1;
+
+ /**
+ * Available transports, these will be populated with the available transports
+ *
+ * @api public
+ */
+
+ io.transports = [];
+
+ /**
+ * Keep track of jsonp callbacks.
+ *
+ * @api private
+ */
+
+ io.j = [];
+
+ /**
+ * Keep track of our io.Sockets
+ *
+ * @api private
+ */
+ io.sockets = {};
+
+ // if node
+
+ /**
+ * Expose constructors if in Node
+ */
+
+ if ('object' === typeof module && 'function' === typeof require) {
+
+ /**
+ * Expose utils
+ *
+ * @api private
+ */
+
+ io.util = require('./util').util;
+
+ /**
+ * Expose JSON.
+ *
+ * @api private
+ */
+
+ io.JSON = require('./json').JSON;
+
+ /**
+ * Expose parser.
+ *
+ * @api private
+ */
+
+ io.parser = require('./parser').parser;
+
+ /**
+ * Expose EventEmitter
+ *
+ * @api private
+ */
+
+ io.EventEmitter = process.EventEmitter;
+
+ /**
+ * Expose Transport
+ *
+ * @api public
+ */
+
+ io.Transport = require('./transport').Transport;
+
+ /**
+ * Expose all transports
+ */
+
+ io.transports.forEach(function (t) {
+ //io.Transport[t] = require('./transports/node/' + t);
+ });
+
+ /**
+ * Expose Socket
+ *
+ * @api public
+ */
+
+ io.Socket = require('./socket').Socket;
+
+ /**
+ * Location of `dist/` directory.
+ *
+ * @api private
+ */
+
+ io.dist = __dirname + '/../dist';
+
+ /**
+ * Expose our build system which can generate
+ * socket.io files on the fly with different transports
+ *
+ * @api private
+ */
+
+ io.builder = require('../bin/builder');
+
+ }
+ // end node
+
+ /**
+ * Manages connections to hosts.
+ *
+ * @param {String} uri
+ * @Param {Boolean} force creation of new socket (defaults to false)
+ * @api public
+ */
+
+ io.connect = function (host, details) {
+ var uri = io.util.parseUri(host)
+ , uuri
+ , socket;
+
+ if ('undefined' != typeof document) {
+ uri.protocol = uri.protocol || document.location.protocol.slice(0, -1);
+ uri.host = uri.host || document.domain;
+ uri.port = uri.port || document.location.port;
+ }
+
+ uuri = io.util.uniqueUri(uri);
+
+ var options = {
+ host: uri.host
+ , secure: uri.protocol == 'https'
+ , port: uri.port || 80
+ };
+ io.util.merge(options, details);
+
+ if (options['force new connection'] || !io.sockets[uuri]) {
+ socket = new io.Socket(options);
+ }
+
+ if (!options['force new connection'] && socket) {
+ io.sockets[uuri] = socket;
+ }
+
+ socket = socket || io.sockets[uuri];
+
+ // if path is different from '' or /
+ return socket.of(uri.path.length > 1 ? uri.path : '');
+ };
+
+})('object' === typeof module ? module.exports : (window.io = {}));
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Based on JSON2 (http://www.JSON.org/js.html).
+ */
+
+(function (exports, nativeJSON) {
+ "use strict";
+
+ // use native JSON if it's available
+ if (nativeJSON && nativeJSON.parse){
+ return exports.JSON = {
+ parse: nativeJSON.parse
+ , stringify: nativeJSON.stringify
+ }
+ }
+
+ var JSON = exports.JSON = {};
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ function date(d, key) {
+ return isFinite(d.valueOf()) ?
+ d.getUTCFullYear() + '-' +
+ f(d.getUTCMonth() + 1) + '-' +
+ f(d.getUTCDate()) + 'T' +
+ f(d.getUTCHours()) + ':' +
+ f(d.getUTCMinutes()) + ':' +
+ f(d.getUTCSeconds()) + 'Z' : null;
+ };
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' : '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value instanceof Date) {
+ value = date(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' : gap ?
+ '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ if (typeof rep[i] === 'string') {
+ k = rep[i];
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' : gap ?
+ '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
+ '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ JSON.parse = function (text, reviver) {
+ // The parse method takes a text and an optional reviver function, and returns
+ // a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+ // The walk method is used to recursively walk the resulting structure so
+ // that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+ // Parsing happens in four stages. In the first stage, we replace certain
+ // Unicode characters with escape sequences. JavaScript handles many characters
+ // incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+ // In the second stage, we run the text against regular expressions that look
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
+ // because they can cause invocation, and '=' because it can cause mutation.
+ // But just to be safe, we want to reject all unexpected forms.
+
+ // We split the second stage into 4 regexp operations in order to work around
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+ // replace all simple value tokens with ']' characters. Third, we delete all
+ // open brackets that follow a colon or comma or that begin the text. Finally,
+ // we look to see that the remaining characters are only whitespace or ']' or
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+ // In the third stage we use the eval function to compile the text into a
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
+ // in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+ // In the optional fourth stage, we recursively walk the new structure, passing
+ // each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+
+})(
+ 'undefined' != typeof io ? io : module.exports
+ , typeof JSON !== 'undefined' ? JSON : undefined
+);
--- /dev/null
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports.SocketNamespace = SocketNamespace;
+
+ /**
+ * Socket namespace constructor.
+ *
+ * @constructor
+ * @api public
+ */
+
+ function SocketNamespace (socket, name) {
+ this.socket = socket;
+ this.name = name || '';
+ this.flags = {};
+ this.json = new Flag(this, 'json');
+ this.ackPackets = 0;
+ this.acks = {};
+ };
+
+ /**
+ * Apply EventEmitter mixin.
+ */
+
+ io.util.mixin(SocketNamespace, io.EventEmitter);
+
+ /**
+ * Copies emit since we override it
+ *
+ * @api private
+ */
+
+ SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
+
+ /**
+ * Creates a new namespace, by proxying the request to the socket. This
+ * allows us to use the synax as we do on the server.
+ *
+ * @api public
+ */
+
+ SocketNamespace.prototype.of = function () {
+ return this.socket.of.apply(this.socket, arguments);
+ };
+
+ /**
+ * Sends a packet.
+ *
+ * @api private
+ */
+
+ SocketNamespace.prototype.packet = function (packet) {
+ packet.endpoint = this.name;
+ this.socket.packet(packet);
+ this.flags = {};
+ return this;
+ };
+
+ /**
+ * Sends a message
+ *
+ * @api public
+ */
+
+ SocketNamespace.prototype.send = function (data, fn) {
+ var packet = {
+ type: this.flags.json ? 'json' : 'message'
+ , data: data
+ };
+
+ if ('function' == typeof fn) {
+ packet.id = ++this.ackPackets;
+ packet.ack = true;
+ this.acks[packet.id] = fn;
+ }
+
+ return this.packet(packet);
+ };
+
+ /**
+ * Emits an event
+ *
+ * @api public
+ */
+
+ SocketNamespace.prototype.emit = function (name) {
+ var args = Array.prototype.slice.call(arguments, 1)
+ , lastArg = args[args.length - 1]
+ , packet = {
+ type: 'event'
+ , name: name
+ };
+
+ if ('function' == typeof lastArg) {
+ packet.id = ++this.ackPackets;
+ packet.ack = 'data';
+ this.acks[packet.id] = lastArg;
+ args = args.slice(0, args.length - 1);
+ }
+
+ packet.args = args;
+
+ return this.packet(packet);
+ };
+
+ /**
+ * Disconnects the namespace
+ *
+ * @api private
+ */
+
+ SocketNamespace.prototype.disconnect = function () {
+ if (this.name === '') {
+ this.socket.disconnect();
+ } else {
+ this.packet({ type: 'disconnect' });
+ this.$emit('disconnect');
+ }
+
+ return this;
+ };
+
+ /**
+ * Handles a packet
+ *
+ * @api private
+ */
+
+ SocketNamespace.prototype.onPacket = function (packet) {
+ var self = this;
+
+ function ack () {
+ self.packet({
+ type: 'ack'
+ , args: io.util.toArray(arguments)
+ , ackId: packet.id
+ });
+ };
+
+ switch (packet.type) {
+ case 'connect':
+ this.$emit('connect');
+ break;
+
+ case 'disconnect':
+ if (this.name === '') {
+ this.socket.onDisconnect(packet.reason || 'booted');
+ } else {
+ this.$emit('disconnect', packet.reason);
+ }
+ break;
+
+ case 'message':
+ case 'json':
+ var params = ['message', packet.data];
+
+ if (packet.ack == 'data') {
+ params.push(ack);
+ } else if (packet.ack) {
+ this.packet({ type: 'ack', ackId: packet.id });
+ }
+
+ this.$emit.apply(this, params);
+ break;
+
+ case 'event':
+ var params = [packet.name].concat(packet.args);
+
+ if (packet.ack == 'data')
+ params.push(ack);
+
+ this.$emit.apply(this, params);
+ break;
+
+ case 'ack':
+ if (this.acks[packet.ackId]) {
+ this.acks[packet.ackId].apply(this, packet.args);
+ delete this.acks[packet.ackId];
+ }
+ break;
+
+ case 'error':
+ if (packet.advice){
+ this.socket.onError(packet);
+ } else {
+ if (packet.reason == 'unauthorized') {
+ this.$emit('connect_failed', packet.reason);
+ } else {
+ this.$emit('error', packet.reason);
+ }
+ }
+ break;
+ }
+ };
+
+ /**
+ * Flag interface.
+ *
+ * @api private
+ */
+
+ function Flag (nsp, name) {
+ this.namespace = nsp;
+ this.name = name;
+ };
+
+ /**
+ * Send a message
+ *
+ * @api public
+ */
+
+ Flag.prototype.send = function () {
+ this.namespace.flags[this.name] = true;
+ this.namespace.send.apply(this.namespace, arguments);
+ };
+
+ /**
+ * Emit an event
+ *
+ * @api public
+ */
+
+ Flag.prototype.emit = function () {
+ this.namespace.flags[this.name] = true;
+ this.namespace.emit.apply(this.namespace, arguments);
+ };
+
+})(
+ 'undefined' != typeof io ? io : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Parser namespace.
+ *
+ * @namespace
+ */
+
+ var parser = exports.parser = {};
+
+ /**
+ * Packet types.
+ */
+
+ var packets = parser.packets = [
+ 'disconnect'
+ , 'connect'
+ , 'heartbeat'
+ , 'message'
+ , 'json'
+ , 'event'
+ , 'ack'
+ , 'error'
+ , 'noop'
+ ];
+
+ /**
+ * Errors reasons.
+ */
+
+ var reasons = parser.reasons = [
+ 'transport not supported'
+ , 'client not handshaken'
+ , 'unauthorized'
+ ];
+
+ /**
+ * Errors advice.
+ */
+
+ var advice = parser.advice = [
+ 'reconnect'
+ ];
+
+ /**
+ * Shortcuts.
+ */
+
+ var JSON = io.JSON
+ , indexOf = io.util.indexOf;
+
+ /**
+ * Encodes a packet.
+ *
+ * @api private
+ */
+
+ parser.encodePacket = function (packet) {
+ var type = indexOf(packets, packet.type)
+ , id = packet.id || ''
+ , endpoint = packet.endpoint || ''
+ , ack = packet.ack
+ , data = null;
+
+ switch (packet.type) {
+ case 'error':
+ var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
+ , adv = packet.advice ? indexOf(advice, packet.advice) : ''
+
+ if (reason !== '' || adv !== '')
+ data = reason + (adv !== '' ? ('+' + adv) : '')
+
+ break;
+
+ case 'message':
+ if (packet.data !== '')
+ data = packet.data;
+ break;
+
+ case 'event':
+ var ev = { name: packet.name };
+
+ if (packet.args && packet.args.length) {
+ ev.args = packet.args;
+ }
+
+ data = JSON.stringify(ev);
+ break;
+
+ case 'json':
+ data = JSON.stringify(packet.data);
+ break;
+
+ case 'connect':
+ if (packet.qs)
+ data = packet.qs;
+ break;
+
+ case 'ack':
+ data = packet.ackId
+ + (packet.args && packet.args.length
+ ? '+' + JSON.stringify(packet.args) : '');
+ break;
+ }
+
+ // construct packet with required fragments
+ var encoded = [
+ type
+ , id + (ack == 'data' ? '+' : '')
+ , endpoint
+ ];
+
+ // data fragment is optional
+ if (data !== null && data !== undefined)
+ encoded.push(data);
+
+ return encoded.join(':');
+ };
+
+ /**
+ * Encodes multiple messages (payload).
+ *
+ * @param {Array} messages
+ * @api private
+ */
+
+ parser.encodePayload = function (packets) {
+ var decoded = '';
+
+ if (packets.length == 1)
+ return packets[0];
+
+ for (var i = 0, l = packets.length; i < l; i++) {
+ var packet = packets[i];
+ decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
+ }
+
+ return decoded;
+ };
+
+ /**
+ * Decodes a packet
+ *
+ * @api private
+ */
+
+ var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
+
+ parser.decodePacket = function (data) {
+ var pieces = data.match(regexp);
+
+ if (!pieces) return {};
+
+ var id = pieces[2] || ''
+ , data = pieces[5] || ''
+ , packet = {
+ type: packets[pieces[1]]
+ , endpoint: pieces[4] || ''
+ };
+
+ // whether we need to acknowledge the packet
+ if (id) {
+ packet.id = id;
+ if (pieces[3])
+ packet.ack = 'data';
+ else
+ packet.ack = true;
+ }
+
+ // handle different packet types
+ switch (packet.type) {
+ case 'error':
+ var pieces = data.split('+');
+ packet.reason = reasons[pieces[0]] || '';
+ packet.advice = advice[pieces[1]] || '';
+ break;
+
+ case 'message':
+ packet.data = data || '';
+ break;
+
+ case 'event':
+ try {
+ var opts = JSON.parse(data);
+ packet.name = opts.name;
+ packet.args = opts.args;
+ } catch (e) { }
+
+ packet.args = packet.args || [];
+ break;
+
+ case 'json':
+ try {
+ packet.data = JSON.parse(data);
+ } catch (e) { }
+ break;
+
+ case 'connect':
+ packet.qs = data || '';
+ break;
+
+ case 'ack':
+ var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
+ if (pieces) {
+ packet.ackId = pieces[1];
+ packet.args = [];
+
+ if (pieces[3]) {
+ try {
+ packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
+ } catch (e) { }
+ }
+ }
+ break;
+
+ case 'disconnect':
+ case 'heartbeat':
+ break;
+ };
+
+ return packet;
+ };
+
+ /**
+ * Decodes data payload. Detects multiple messages
+ *
+ * @return {Array} messages
+ * @api public
+ */
+
+ parser.decodePayload = function (data) {
+ // IE doesn't like data[i] for unicode chars, charAt works fine
+ if (data.charAt(0) == '\ufffd') {
+ var ret = [];
+
+ for (var i = 1, length = ''; i < data.length; i++) {
+ if (data.charAt(i) == '\ufffd') {
+ ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
+ i += Number(length) + 1;
+ length = '';
+ } else {
+ length += data.charAt(i);
+ }
+ }
+
+ return ret;
+ } else {
+ return [parser.decodePacket(data)];
+ }
+ };
+
+})(
+ 'undefined' != typeof io ? io : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+io.js
\ No newline at end of file
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports.Socket = Socket;
+
+ /**
+ * Create a new `Socket.IO client` which can establish a persisent
+ * connection with a Socket.IO enabled server.
+ *
+ * @api public
+ */
+
+ function Socket (options) {
+ this.options = {
+ port: 80
+ , secure: false
+ , document: document
+ , resource: 'socket.io'
+ , transports: io.transports
+ , 'connect timeout': 10000
+ , 'try multiple transports': true
+ , 'reconnect': true
+ , 'reconnection delay': 500
+ , 'reopen delay': 3000
+ , 'max reconnection attempts': 10
+ , 'sync disconnect on unload': true
+ , 'auto connect': true
+ };
+
+ io.util.merge(this.options, options);
+
+ this.connected = false;
+ this.open = false;
+ this.connecting = false;
+ this.reconnecting = false;
+ this.namespaces = {};
+ this.buffer = [];
+ this.doBuffer = false;
+
+ if (this.options['sync disconnect on unload'] &&
+ (!this.isXDomain() || io.util.ua.hasCORS)) {
+ var self = this;
+
+ io.util.on(window, 'beforeunload', function () {
+ self.disconnectSync();
+ }, false);
+ }
+
+ if (this.options['auto connect']) {
+ this.connect();
+ }
+};
+
+ /**
+ * Apply EventEmitter mixin.
+ */
+
+ io.util.mixin(Socket, io.EventEmitter);
+
+ /**
+ * Returns a namespace listener/emitter for this socket
+ *
+ * @api public
+ */
+
+ Socket.prototype.of = function (name) {
+ if (!this.namespaces[name]) {
+ this.namespaces[name] = new io.SocketNamespace(this, name);
+
+ if (name !== '') {
+ this.namespaces[name].packet({ type: 'connect' });
+ }
+ }
+
+ return this.namespaces[name];
+ };
+
+ /**
+ * Emits the given event to the Socket and all namespaces
+ *
+ * @api private
+ */
+
+ Socket.prototype.publish = function () {
+ this.emit.apply(this, arguments);
+
+ var nsp;
+
+ for (var i in this.namespaces) {
+ if (this.namespaces.hasOwnProperty(i)) {
+ nsp = this.of(i);
+ nsp.$emit.apply(nsp, arguments);
+ }
+ }
+ };
+
+ /**
+ * Performs the handshake
+ *
+ * @api private
+ */
+
+ function empty () { };
+
+ Socket.prototype.handshake = function (fn) {
+ var self = this
+ , options = this.options;
+
+ function complete (data) {
+ if (data instanceof Error) {
+ self.onError(data.message);
+ } else {
+ fn.apply(null, data.split(':'));
+ }
+ };
+
+ var url = [
+ 'http' + (options.secure ? 's' : '') + ':/'
+ , options.host + ':' + options.port
+ , this.options.resource
+ , io.protocol
+ , '?t=' + + new Date
+ ].join('/');
+
+ if (this.isXDomain()) {
+ var insertAt = document.getElementsByTagName('script')[0]
+ , script = document.createElement('SCRIPT');
+
+ script.src = url + '&jsonp=' + io.j.length;
+ insertAt.parentNode.insertBefore(script, insertAt);
+
+ io.j.push(function (data) {
+ complete(data);
+ script.parentNode.removeChild(script);
+ });
+ } else {
+ var xhr = io.util.request();
+
+ xhr.open('GET', url);
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState == 4) {
+ xhr.onreadystatechange = empty;
+
+ if (xhr.status == 200) {
+ complete(xhr.responseText);
+ } else {
+ !self.reconnecting && self.onError(xhr.responseText);
+ }
+ }
+ };
+ xhr.send(null);
+ }
+ };
+
+ /**
+ * Find an available transport based on the options supplied in the constructor.
+ *
+ * @api private
+ */
+
+ Socket.prototype.getTransport = function (override) {
+ var transports = override || this.transports, match;
+
+ for (var i = 0, transport; transport = transports[i]; i++) {
+ if (io.Transport[transport]
+ && io.Transport[transport].check(this)
+ && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
+ return new io.Transport[transport](this, this.sessionid);
+ }
+ }
+
+ return null;
+ };
+
+ /**
+ * Connects to the server.
+ *
+ * @param {Function} [fn] Callback.
+ * @returns {io.Socket}
+ * @api public
+ */
+
+ Socket.prototype.connect = function (fn) {
+ if (this.connecting) {
+ return this;
+ }
+
+ var self = this;
+
+ this.handshake(function (sid, heartbeat, close, transports) {
+ self.sessionid = sid;
+ self.closeTimeout = close * 1000;
+ self.heartbeatTimeout = heartbeat * 1000;
+ self.transports = io.util.intersect(
+ transports.split(',')
+ , self.options.transports
+ );
+
+ function connect (transports){
+ self.transport = self.getTransport(transports);
+ if (!self.transport) return self.publish('connect_failed');
+
+ self.connecting = true;
+ self.publish('connecting', self.transport.name);
+ self.transport.open();
+
+ if (self.options['connect timeout']) {
+ self.connectTimeoutTimer = setTimeout(function () {
+ if (!self.connected) {
+ self.connecting = false;
+
+ if (self.options['try multiple transports']) {
+ if (!self.remainingTransports) {
+ self.remainingTransports = self.transports.slice(0);
+ }
+
+ var remaining = self.remainingTransports;
+
+ while (remaining.length > 0 && remaining.splice(0,1)[0] !=
+ self.transport.name) {}
+
+ if (remaining.length){
+ connect(remaining);
+ } else {
+ self.publish('connect_failed');
+ }
+ }
+ }
+ }, self.options['connect timeout']);
+ }
+ }
+
+ connect();
+
+ self.once('connect', function (){
+ clearTimeout(self.connectTimeoutTimer);
+
+ fn && typeof fn == 'function' && fn();
+ });
+ });
+
+ return this;
+ };
+
+ /**
+ * Sends a message.
+ *
+ * @param {Object} data packet.
+ * @returns {io.Socket}
+ * @api public
+ */
+
+ Socket.prototype.packet = function (data) {
+ if (this.connected && !this.doBuffer) {
+ this.transport.packet(data);
+ } else {
+ this.buffer.push(data);
+ }
+
+ return this;
+ };
+
+ /**
+ * Sets buffer state
+ *
+ * @api private
+ */
+
+ Socket.prototype.setBuffer = function (v) {
+ this.doBuffer = v;
+
+ if (!v && this.connected && this.buffer.length) {
+ this.transport.payload(this.buffer);
+ this.buffer = [];
+ }
+ };
+
+ /**
+ * Disconnect the established connect.
+ *
+ * @returns {io.Socket}
+ * @api public
+ */
+
+ Socket.prototype.disconnect = function () {
+ if (this.connected) {
+ if (this.open) {
+ this.of('').packet({ type: 'disconnect' });
+ }
+
+ // handle disconnection immediately
+ this.onDisconnect('booted');
+ }
+
+ return this;
+ };
+
+ /**
+ * Disconnects the socket with a sync XHR.
+ *
+ * @api private
+ */
+
+ Socket.prototype.disconnectSync = function () {
+ // ensure disconnection
+ var xhr = io.util.request()
+ , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;
+
+ xhr.open('GET', uri, true);
+
+ // handle disconnection immediately
+ this.onDisconnect('booted');
+ };
+
+ /**
+ * Check if we need to use cross domain enabled transports. Cross domain would
+ * be a different port or different domain name.
+ *
+ * @returns {Boolean}
+ * @api private
+ */
+
+ Socket.prototype.isXDomain = function () {
+ var locPort = window.location.port || 80;
+ return this.options.host !== document.domain || this.options.port != locPort;
+ };
+
+ /**
+ * Called upon handshake.
+ *
+ * @api private
+ */
+
+ Socket.prototype.onConnect = function () {
+ this.connected = true;
+ this.connecting = false;
+ if (!this.doBuffer) {
+ // make sure to flush the buffer
+ this.setBuffer(false);
+ }
+ this.emit('connect');
+ };
+
+ /**
+ * Called when the transport opens
+ *
+ * @api private
+ */
+
+ Socket.prototype.onOpen = function () {
+ this.open = true;
+ };
+
+ /**
+ * Called when the transport closes.
+ *
+ * @api private
+ */
+
+ Socket.prototype.onClose = function () {
+ this.open = false;
+ };
+
+ /**
+ * Called when the transport first opens a connection
+ *
+ * @param text
+ */
+
+ Socket.prototype.onPacket = function (packet) {
+ this.of(packet.endpoint).onPacket(packet);
+ };
+
+ /**
+ * Handles an error.
+ *
+ * @api private
+ */
+
+ Socket.prototype.onError = function (err) {
+ if (err && err.advice) {
+ if (err.advice === 'reconnect' && this.connected) {
+ this.disconnect();
+ this.reconnect();
+ }
+ }
+
+ this.publish('error', err && err.reason ? err.reason : err);
+ };
+
+ /**
+ * Called when the transport disconnects.
+ *
+ * @api private
+ */
+
+ Socket.prototype.onDisconnect = function (reason) {
+ var wasConnected = this.connected;
+
+ this.connected = false;
+ this.connecting = false;
+ this.open = false;
+
+ if (wasConnected) {
+ this.transport.close();
+ this.transport.clearTimeouts();
+ this.publish('disconnect', reason);
+
+ if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
+ this.reconnect();
+ }
+ }
+ };
+
+ /**
+ * Called upon reconnection.
+ *
+ * @api private
+ */
+
+ Socket.prototype.reconnect = function () {
+ this.reconnecting = true;
+ this.reconnectionAttempts = 0;
+ this.reconnectionDelay = this.options['reconnection delay'];
+
+ var self = this
+ , maxAttempts = this.options['max reconnection attempts']
+ , tryMultiple = this.options['try multiple transports']
+
+ function reset () {
+ if (self.connected) {
+ self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
+ }
+
+ self.removeListener('connect_failed', maybeReconnect);
+ self.removeListener('connect', maybeReconnect);
+
+ self.reconnecting = false;
+
+ delete self.reconnectionAttempts;
+ delete self.reconnectionDelay;
+ delete self.reconnectionTimer;
+ delete self.redoTransports;
+
+ self.options['try multiple transports'] = tryMultiple;
+ };
+
+ function maybeReconnect () {
+ if (!self.reconnecting) {
+ return;
+ }
+
+ if (self.connected) {
+ return reset();
+ };
+
+ if (self.connecting && self.reconnecting) {
+ return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
+ }
+
+ if (self.reconnectionAttempts++ >= maxAttempts) {
+ if (!self.redoTransports) {
+ self.on('connect_failed', maybeReconnect);
+ self.options['try multiple transports'] = true;
+ self.transport = self.getTransport();
+ self.redoTransports = true;
+ self.connect();
+ } else {
+ self.publish('reconnect_failed');
+ reset();
+ }
+ } else {
+ self.reconnectionDelay *= 2; // exponential back off
+ self.connect();
+ self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
+ self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
+ }
+ };
+
+ this.options['try multiple transports'] = false;
+ this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
+
+ this.on('connect', maybeReconnect);
+ };
+
+})(
+ 'undefined' != typeof io ? io : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports.Transport = Transport;
+
+ /**
+ * This is the transport template for all supported transport methods.
+ *
+ * @constructor
+ * @api public
+ */
+
+ function Transport (socket, sessid) {
+ this.socket = socket;
+ this.sessid = sessid;
+ };
+
+ /**
+ * Apply EventEmitter mixin.
+ */
+
+ io.util.mixin(Transport, io.EventEmitter);
+
+ /**
+ * Handles the response from the server. When a new response is received
+ * it will automatically update the timeout, decode the message and
+ * forwards the response to the onMessage function for further processing.
+ *
+ * @param {String} data Response from the server.
+ * @api private
+ */
+
+ Transport.prototype.onData = function (data) {
+ this.clearCloseTimeout();
+ this.setCloseTimeout();
+
+ if (data !== '') {
+ // todo: we should only do decodePayload for xhr transports
+ var msgs = io.parser.decodePayload(data);
+
+ if (msgs && msgs.length) {
+ for (var i = 0, l = msgs.length; i < l; i++) {
+ this.onPacket(msgs[i]);
+ }
+ }
+ }
+
+ return this;
+ };
+
+ /**
+ * Handles packets.
+ *
+ * @api private
+ */
+
+ Transport.prototype.onPacket = function (packet) {
+ if (packet.type == 'heartbeat') {
+ return this.onHeartbeat();
+ }
+
+ if (packet.type == 'connect' && packet.endpoint == '') {
+ this.onConnect();
+ }
+
+ this.socket.onPacket(packet);
+
+ return this;
+ };
+
+ /**
+ * Sets close timeout
+ *
+ * @api private
+ */
+
+ Transport.prototype.setCloseTimeout = function () {
+ if (!this.closeTimeout) {
+ var self = this;
+
+ this.closeTimeout = setTimeout(function () {
+ self.onDisconnect();
+ }, this.socket.closeTimeout);
+ }
+ };
+
+ /**
+ * Called when transport disconnects.
+ *
+ * @api private
+ */
+
+ Transport.prototype.onDisconnect = function () {
+ if (this.close) this.close();
+ this.clearTimeouts();
+ this.socket.onDisconnect();
+ return this;
+ };
+
+ /**
+ * Called when transport connects
+ *
+ * @api private
+ */
+
+ Transport.prototype.onConnect = function () {
+ this.socket.onConnect();
+ return this;
+ }
+
+ /**
+ * Clears close timeout
+ *
+ * @api private
+ */
+
+ Transport.prototype.clearCloseTimeout = function () {
+ if (this.closeTimeout) {
+ clearTimeout(this.closeTimeout);
+ this.closeTimeout = null;
+ }
+ };
+
+ /**
+ * Clear timeouts
+ *
+ * @api private
+ */
+
+ Transport.prototype.clearTimeouts = function () {
+ this.clearCloseTimeout();
+
+ if (this.reopenTimeout) {
+ clearTimeout(this.reopenTimeout);
+ }
+ };
+
+ /**
+ * Sends a packet
+ *
+ * @param {Object} packet object.
+ * @api private
+ */
+
+ Transport.prototype.packet = function (packet) {
+ this.send(io.parser.encodePacket(packet));
+ };
+
+ /**
+ * Send the received heartbeat message back to server. So the server
+ * knows we are still connected.
+ *
+ * @param {String} heartbeat Heartbeat response from the server.
+ * @api private
+ */
+
+ Transport.prototype.onHeartbeat = function (heartbeat) {
+ this.packet({ type: 'heartbeat' });
+ };
+
+ /**
+ * Called when the transport opens.
+ *
+ * @api private
+ */
+
+ Transport.prototype.onOpen = function () {
+ this.open = true;
+ this.clearCloseTimeout();
+ this.socket.onOpen();
+ };
+
+ /**
+ * Notifies the base when the connection with the Socket.IO server
+ * has been disconnected.
+ *
+ * @api private
+ */
+
+ Transport.prototype.onClose = function () {
+ var self = this;
+
+ /* FIXME: reopen delay causing a infinit loop
+ this.reopenTimeout = setTimeout(function () {
+ self.open();
+ }, this.socket.options['reopen delay']);*/
+
+ this.open = false;
+ this.setCloseTimeout();
+ this.socket.onClose();
+ };
+
+ /**
+ * Generates a connection url based on the Socket.IO URL Protocol.
+ * See <https://github.com/learnboost/socket.io-node/> for more details.
+ *
+ * @returns {String} Connection url
+ * @api private
+ */
+
+ Transport.prototype.prepareUrl = function () {
+ var options = this.socket.options;
+
+ return this.scheme() + '://'
+ + options.host + ':' + options.port + '/'
+ + options.resource + '/' + io.protocol
+ + '/' + this.name + '/' + this.sessid;
+ };
+})(
+ 'undefined' != typeof io ? io : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports.flashsocket = Flashsocket;
+
+ /**
+ * The Flashsocket transport. This is a API wrapper for the HTML5 WebSocket
+ * specification. It uses a .swf file to communicate with the server. If you want
+ * to serve the .swf file from a other server than where the Socket.IO script is
+ * coming from you need to use the insecure version of the .swf. More information
+ * about this can be found on the github page.
+ *
+ * @constructor
+ * @extends {io.Transport.websocket}
+ * @api public
+ */
+
+ function Flashsocket () {
+ io.Transport.websocket.apply(this, arguments);
+ };
+
+ /**
+ * Inherits from Transport.
+ */
+
+ io.util.inherit(Flashsocket, io.Transport.websocket);
+
+ /**
+ * Transport name
+ *
+ * @api public
+ */
+
+ Flashsocket.prototype.name = 'flashsocket';
+
+ /**
+ *Disconnect the established `Flashsocket` connection. This is done by adding a
+ * new task to the Flashsocket. The rest will be handled off by the `WebSocket`
+ * transport.
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ Flashsocket.prototype.open = function () {
+ var self = this, args = arguments;
+ WebSocket.__addTask(function () {
+ io.Transport.websocket.prototype.open.apply(self, args);
+ });
+ return this;
+ };
+
+ /**
+ * Sends a message to the Socket.IO server. This is done by adding a new
+ * task to the Flashsocket. The rest will be handled off by the `WebSocket`
+ * transport.
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ Flashsocket.prototype.send = function () {
+ var self = this, args = arguments;
+ WebSocket.__addTask(function () {
+ io.Transport.websocket.prototype.send.apply(self, args);
+ });
+ return this;
+ };
+
+ /**
+ * Disconnects the established `Flashsocket` connection.
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ Flashsocket.prototype.close = function () {
+ WebSocket.__tasks.length = 0;
+ io.Transport.websocket.prototype.close.call(this);
+ return this;
+ };
+
+ /**
+ * Check if the Flashsocket transport is supported as it requires that the Adobe
+ * Flash Player plugin version `10.0.0` or greater is installed. And also check if
+ * the polyfill is correctly loaded.
+ *
+ * @returns {Boolean}
+ * @api public
+ */
+
+ Flashsocket.check = function (socket) {
+ if (
+ typeof WebSocket == 'undefined'
+ || !('__initialize' in WebSocket) || !swfobject
+ ) return false;
+
+ var supported = swfobject.getFlashPlayerVersion().major >= 10
+ , options = socket.options
+ , path = [
+ 'http' + (options.secure ? 's' : '') + ':/'
+ , options.host + ':' + options.port
+ , options.resource
+ , 'static/flashsocket'
+ , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
+ ];
+
+ // Only start downloading the swf file when the checked that this browser
+ // actually supports it
+ if (supported && !Flashsocket.loaded) {
+ if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
+ // Set the correct file based on the XDomain settings
+ WEB_SOCKET_SWF_LOCATION = path.join('/');
+ }
+
+ WebSocket.__initialize();
+ Flashsocket.loaded = true;
+ }
+
+ return supported;
+ };
+
+ /**
+ * Check if the Flashsocket transport can be used as cross domain / cross origin
+ * transport. Because we can't see which type (secure or insecure) of .swf is used
+ * we will just return true.
+ *
+ * @returns {Boolean}
+ * @api public
+ */
+
+ Flashsocket.xdomainCheck = function () {
+ return true;
+ };
+
+ /**
+ * Disable AUTO_INITIALIZATION
+ */
+
+ if (typeof window != 'undefined') {
+ WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true;
+ }
+
+ /**
+ * Add the transport to your public io.transports array.
+ *
+ * @api private
+ */
+
+ io.transports.push('flashsocket');
+})(
+ 'undefined' != typeof io ? io.Transport : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports.htmlfile = HTMLFile;
+
+ /**
+ * The HTMLFile transport creates a `forever iframe` based transport
+ * for Internet Explorer. Regular forever iframe implementations will
+ * continuously trigger the browsers buzy indicators. If the forever iframe
+ * is created inside a `htmlfile` these indicators will not be trigged.
+ *
+ * @constructor
+ * @extends {io.Transport.XHR}
+ * @api public
+ */
+
+ function HTMLFile (socket) {
+ io.Transport.XHR.apply(this, arguments);
+ };
+
+ /**
+ * Inherits from XHR transport.
+ */
+
+ io.util.inherit(HTMLFile, io.Transport.XHR);
+
+ /**
+ * Transport name
+ *
+ * @api public
+ */
+
+ HTMLFile.prototype.name = 'htmlfile';
+
+ /**
+ * Creates a new ActiveX `htmlfile` with a forever loading iframe
+ * that can be used to listen to messages. Inside the generated
+ * `htmlfile` a reference will be made to the HTMLFile transport.
+ *
+ * @api private
+ */
+
+ HTMLFile.prototype.get = function () {
+ this.doc = new ActiveXObject('htmlfile');
+ this.doc.open();
+ this.doc.write('<html></html>');
+ this.doc.close();
+ this.doc.parentWindow.s = this;
+
+ var iframeC = this.doc.createElement('div');
+ iframeC.className = 'socketio';
+
+ this.doc.body.appendChild(iframeC);
+ this.iframe = this.doc.createElement('iframe');
+
+ iframeC.appendChild(this.iframe);
+
+ this.iframe.src = this.prepareUrl() + '/?t=' + (+ new Date);
+
+ var self = this;
+
+ io.util.on(window, 'unload', function () {
+ self.destroy();
+ });
+ };
+
+ /**
+ * The Socket.IO server will write script tags inside the forever
+ * iframe, this function will be used as callback for the incoming
+ * information.
+ *
+ * @param {String} data The message
+ * @param {document} doc Reference to the context
+ * @api private
+ */
+
+ HTMLFile.prototype._ = function (data, doc) {
+ this.onData(data);
+ try {
+ var script = doc.getElementsByTagName('script')[0];
+ script.parentNode.removeChild(script);
+ } catch (e) { }
+ };
+
+ /**
+ * Destroy the established connection, iframe and `htmlfile`.
+ * And calls the `CollectGarbage` function of Internet Explorer
+ * to release the memory.
+ *
+ * @api private
+ */
+
+ HTMLFile.prototype.destroy = function () {
+ if (this.iframe){
+ try {
+ this.iframe.src = 'about:blank';
+ } catch(e){}
+
+ this.doc = null;
+ this.iframe.parentNode.removeChild(this.iframe);
+ this.iframe = null;
+
+ CollectGarbage();
+ }
+ };
+
+ /**
+ * Disconnects the established connection.
+ *
+ * @returns {Transport} Chaining.
+ * @api public
+ */
+
+ HTMLFile.prototype.close = function () {
+ this.destroy();
+ return io.Transport.XHR.prototype.close.call(this);
+ };
+
+ /**
+ * Checks if the browser supports this transport. The browser
+ * must have an `ActiveXObject` implementation.
+ *
+ * @return {Boolean}
+ * @api public
+ */
+
+ HTMLFile.check = function () {
+ if ('ActiveXObject' in window){
+ try {
+ var a = new ActiveXObject('htmlfile');
+ return a && io.Transport.XHR.check();
+ } catch(e){}
+ }
+ return false;
+ };
+
+ /**
+ * Check if cross domain requests are supported.
+ *
+ * @returns {Boolean}
+ * @api public
+ */
+
+ HTMLFile.xdomainCheck = function () {
+ // we can probably do handling for sub-domains, we should
+ // test that it's cross domain but a subdomain here
+ return false;
+ };
+
+ /**
+ * Add the transport to your public io.transports array.
+ *
+ * @api private
+ */
+
+ io.transports.push('htmlfile');
+
+})(
+ 'undefined' != typeof io ? io.Transport : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports['jsonp-polling'] = JSONPPolling;
+
+ /**
+ * The JSONP transport creates an persistent connection by dynamically
+ * inserting a script tag in the page. This script tag will receive the
+ * information of the Socket.IO server. When new information is received
+ * it creates a new script tag for the new data stream.
+ *
+ * @constructor
+ * @extends {io.Transport.xhr-polling}
+ * @api public
+ */
+
+ function JSONPPolling (socket) {
+ io.Transport['xhr-polling'].apply(this, arguments);
+
+ this.index = io.j.length;
+
+ var self = this;
+
+ io.j.push(function (msg) {
+ self._(msg);
+ });
+ };
+
+ /**
+ * Inherits from XHR polling transport.
+ */
+
+ io.util.inherit(JSONPPolling, io.Transport['xhr-polling']);
+
+ /**
+ * Transport name
+ *
+ * @api public
+ */
+
+ JSONPPolling.prototype.name = 'jsonp-polling';
+
+ /**
+ * Posts a encoded message to the Socket.IO server using an iframe.
+ * The iframe is used because script tags can create POST based requests.
+ * The iframe is positioned outside of the view so the user does not
+ * notice it's existence.
+ *
+ * @param {String} data A encoded message.
+ * @api private
+ */
+
+ JSONPPolling.prototype.post = function (data) {
+ var self = this;
+
+ if (!this.form) {
+ var form = document.createElement('FORM')
+ , area = document.createElement('TEXTAREA')
+ , id = this.iframeId = 'socketio_iframe_' + this.index
+ , iframe;
+
+ form.className = 'socketio';
+ form.style.position = 'absolute';
+ form.style.top = '-1000px';
+ form.style.left = '-1000px';
+ form.target = id;
+ form.method = 'POST';
+ area.name = 'd';
+ form.appendChild(area);
+ document.body.appendChild(form);
+
+ this.form = form;
+ this.area = area;
+ }
+
+ this.form.action = this.prepareUrl() + '?t=' + (+new Date) + '&i=' + this.index;
+
+ function complete () {
+ initIframe();
+ self.socket.setBuffer(false);
+ };
+
+ function initIframe () {
+ if (self.iframe) {
+ self.form.removeChild(self.iframe);
+ }
+
+ try {
+ // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
+ iframe = document.createElement('<iframe name="'+ self.iframeId +'">');
+ } catch (e) {
+ iframe = document.createElement('iframe');
+ iframe.name = self.iframeId;
+ }
+
+ iframe.id = self.iframeId;
+
+ self.form.appendChild(iframe);
+ self.iframe = iframe;
+ };
+
+ initIframe();
+
+ this.area.value = data;
+
+ try {
+ this.form.submit();
+ } catch(e) {}
+
+ if (this.iframe.attachEvent) {
+ iframe.onreadystatechange = function () {
+ if (self.iframe.readyState == 'complete') {
+ complete();
+ }
+ };
+ } else {
+ this.iframe.onload = complete;
+ }
+ };
+
+ /**
+ * Creates a new JSONP poll that can be used to listen
+ * for messages from the Socket.IO server.
+ *
+ * @api private
+ */
+
+ JSONPPolling.prototype.get = function () {
+ var self = this
+ , script = document.createElement('SCRIPT');
+
+ if (this.script) {
+ this.script.parentNode.removeChild(this.script);
+ this.script = null;
+ }
+
+ script.async = true;
+ script.src = this.prepareUrl() + '/?t=' + (+new Date) + '&i=' + this.index;
+ script.onerror = function () {
+ self.onClose();
+ };
+
+ var insertAt = document.getElementsByTagName('script')[0]
+ insertAt.parentNode.insertBefore(script, insertAt);
+ this.script = script;
+ };
+
+ /**
+ * Callback function for the incoming message stream from the Socket.IO server.
+ *
+ * @param {String} data The message
+ * @api private
+ */
+
+ JSONPPolling.prototype._ = function (msg) {
+ this.onData(msg);
+ if (this.open) {
+ this.get();
+ }
+ return this;
+ };
+
+ /**
+ * Checks if browser supports this transport.
+ *
+ * @return {Boolean}
+ * @api public
+ */
+
+ JSONPPolling.check = function () {
+ return true;
+ };
+
+ /**
+ * Check if cross domain requests are supported
+ *
+ * @returns {Boolean}
+ * @api public
+ */
+
+ JSONPPolling.xdomainCheck = function () {
+ return true;
+ };
+
+ /**
+ * Add the transport to your public io.transports array.
+ *
+ * @api private
+ */
+
+ io.transports.push('jsonp-polling');
+
+})(
+ 'undefined' != typeof io ? io.Transport : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports.websocket = WS;
+
+ /**
+ * The WebSocket transport uses the HTML5 WebSocket API to establish an
+ * persistent connection with the Socket.IO server. This transport will also
+ * be inherited by the FlashSocket fallback as it provides a API compatible
+ * polyfill for the WebSockets.
+ *
+ * @constructor
+ * @extends {io.Transport}
+ * @api public
+ */
+
+ function WS (socket) {
+ io.Transport.apply(this, arguments);
+ };
+
+ /**
+ * Inherits from Transport.
+ */
+
+ io.util.inherit(WS, io.Transport);
+
+ /**
+ * Transport name
+ *
+ * @api public
+ */
+
+ WS.prototype.name = 'websocket';
+
+ /**
+ * Initializes a new `WebSocket` connection with the Socket.IO server. We attach
+ * all the appropriate listeners to handle the responses from the server.
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ WS.prototype.open = function () {
+ this.websocket = new WebSocket(this.prepareUrl());
+
+ var self = this;
+ this.websocket.onopen = function () {
+ self.onOpen();
+ self.socket.setBuffer(false);
+ };
+ this.websocket.onmessage = function (ev) {
+ self.onData(ev.data);
+ };
+ this.websocket.onclose = function () {
+ self.onClose();
+ self.socket.setBuffer(true);
+ };
+ this.websocket.onerror = function (e) {
+ self.onError(e);
+ };
+
+ return this;
+ };
+
+ /**
+ * Send a message to the Socket.IO server. The message will automatically be
+ * encoded in the correct message format.
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ WS.prototype.send = function (data) {
+ this.websocket.send(data);
+ return this;
+ };
+
+ /**
+ * Payload
+ *
+ * @api private
+ */
+
+ WS.prototype.payload = function (arr) {
+ for (var i = 0, l = arr.length; i < l; i++) {
+ this.packet(arr[i]);
+ }
+ return this;
+ };
+
+ /**
+ * Disconnect the established `WebSocket` connection.
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ WS.prototype.close = function () {
+ this.websocket.close();
+ return this;
+ };
+
+ /**
+ * Handle the errors that `WebSocket` might be giving when we
+ * are attempting to connect or send messages.
+ *
+ * @param {Error} e The error.
+ * @api private
+ */
+
+ WS.prototype.onError = function (e) {
+ this.socket.onError(e);
+ };
+
+ /**
+ * Returns the appropriate scheme for the URI generation.
+ *
+ * @api private
+ */
+ WS.prototype.scheme = function () {
+ return this.socket.options.secure ? 'wss' : 'ws';
+ };
+
+ /**
+ * Checks if the browser has support for native `WebSockets` and that
+ * it's not the polyfill created for the FlashSocket transport.
+ *
+ * @return {Boolean}
+ * @api public
+ */
+
+ WS.check = function () {
+ return 'WebSocket' in window && !('__addTask' in WebSocket);
+ };
+
+ /**
+ * Check if the `WebSocket` transport support cross domain communications.
+ *
+ * @returns {Boolean}
+ * @api public
+ */
+
+ WS.xdomainCheck = function () {
+ return true;
+ };
+
+ /**
+ * Add the transport to your public io.transports array.
+ *
+ * @api private
+ */
+
+ io.transports.push('websocket');
+
+})(
+ 'undefined' != typeof io ? io.Transport : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ */
+
+ exports['xhr-polling'] = XHRPolling;
+
+ /**
+ * The XHR-polling transport uses long polling XHR requests to create a
+ * "persistent" connection with the server.
+ *
+ * @constructor
+ * @api public
+ */
+
+ function XHRPolling () {
+ io.Transport.XHR.apply(this, arguments);
+ };
+
+ /**
+ * Inherits from XHR transport.
+ */
+
+ io.util.inherit(XHRPolling, io.Transport.XHR);
+
+ /**
+ * Transport name
+ *
+ * @api public
+ */
+
+ XHRPolling.prototype.name = 'xhr-polling';
+
+ /**
+ * Establish a connection, for iPhone and Android this will be done once the page
+ * is loaded.
+ *
+ * @returns {Transport} Chaining.
+ * @api public
+ */
+
+ XHRPolling.prototype.open = function () {
+ var self = this;
+
+ io.util.defer(function () {
+ io.Transport.XHR.prototype.open.call(self);
+ });
+
+ return false;
+ };
+
+ /**
+ * Starts a XHR request to wait for incoming messages.
+ *
+ * @api private
+ */
+
+ function empty () {};
+
+ XHRPolling.prototype.get = function () {
+ if (!this.open) return;
+
+ var self = this;
+
+ function stateChange () {
+ if (this.readyState == 4) {
+ this.onreadystatechange = empty;
+
+ if (this.status == 200) {
+ self.onData(this.responseText);
+ self.get();
+ } else {
+ self.onClose();
+ }
+ }
+ };
+
+ function onload () {
+ this.onload = empty;
+ self.onData(this.responseText);
+ self.get();
+ };
+
+ this.xhr = this.request();
+
+ if (window.XDomainRequest && this.xhr instanceof XDomainRequest) {
+ this.xhr.onload = this.xhr.onerror = onload;
+ } else {
+ this.xhr.onreadystatechange = stateChange;
+ }
+
+ this.xhr.send(null);
+ };
+
+ /**
+ * Handle the unclean close behavior.
+ *
+ * @api private
+ */
+
+ XHRPolling.prototype.onClose = function () {
+ io.Transport.XHR.prototype.onClose.call(this);
+
+ if (this.xhr) {
+ this.xhr.onreadystatechange = this.xhr.onload = empty;
+ try {
+ this.xhr.abort();
+ } catch(e){}
+ this.xhr = null;
+ }
+ };
+
+ /**
+ * Add the transport to your public io.transports array.
+ *
+ * @api private
+ */
+
+ io.transports.push('xhr-polling');
+
+})(
+ 'undefined' != typeof io ? io.Transport : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports, io) {
+
+ /**
+ * Expose constructor.
+ *
+ * @api public
+ */
+
+ exports.XHR = XHR;
+
+ /**
+ * XHR constructor
+ *
+ * @costructor
+ * @api public
+ */
+
+ function XHR (socket) {
+ if (!socket) return;
+
+ io.Transport.apply(this, arguments);
+ this.sendBuffer = [];
+ };
+
+ /**
+ * Inherits from Transport.
+ */
+
+ io.util.inherit(XHR, io.Transport);
+
+ /**
+ * Establish a connection
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ XHR.prototype.open = function () {
+ this.socket.setBuffer(false);
+ this.onOpen();
+ this.get();
+
+ // we need to make sure the request succeeds since we have no indication
+ // whether the request opened or not until it succeeded.
+ this.setCloseTimeout();
+
+ return this;
+ };
+
+ /**
+ * Check if we need to send data to the Socket.IO server, if we have data in our
+ * buffer we encode it and forward it to the `post` method.
+ *
+ * @api private
+ */
+
+ XHR.prototype.payload = function (payload) {
+ var msgs = [];
+
+ for (var i = 0, l = payload.length; i < l; i++) {
+ msgs.push(io.parser.encodePacket(payload[i]));
+ }
+
+ this.send(io.parser.encodePayload(msgs));
+ };
+
+ /**
+ * Send data to the Socket.IO server.
+ *
+ * @param data The message
+ * @returns {Transport}
+ * @api public
+ */
+
+ XHR.prototype.send = function (data) {
+ this.post(data);
+ return this;
+ };
+
+ /**
+ * Posts a encoded message to the Socket.IO server.
+ *
+ * @param {String} data A encoded message.
+ * @api private
+ */
+
+ function empty () { };
+
+ XHR.prototype.post = function (data) {
+ var self = this;
+ this.socket.setBuffer(true);
+
+ function stateChange () {
+ if (this.readyState == 4) {
+ this.onreadystatechange = empty;
+ self.posting = false;
+
+ if (this.status == 200){
+ self.socket.setBuffer(false);
+ } else {
+ self.onClose();
+ }
+ }
+ }
+
+ function onload () {
+ this.onload = empty;
+ self.socket.setBuffer(false);
+ };
+
+ this.sendXHR = this.request('POST');
+
+ if (window.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
+ this.sendXHR.onload = this.sendXHR.onerror = onload;
+ } else {
+ this.sendXHR.onreadystatechange = stateChange;
+ }
+
+ this.sendXHR.send(data);
+ };
+
+ /**
+ * Disconnects the established `XHR` connection.
+ *
+ * @returns {Transport}
+ * @api public
+ */
+
+ XHR.prototype.close = function () {
+ this.onClose();
+ return this;
+ };
+
+ /**
+ * Generates a configured XHR request
+ *
+ * @param {String} url The url that needs to be requested.
+ * @param {String} method The method the request should use.
+ * @returns {XMLHttpRequest}
+ * @api private
+ */
+
+ XHR.prototype.request = function (method) {
+ var req = io.util.request(this.socket.isXDomain());
+ req.open(method || 'GET', this.prepareUrl() + '?t' + (+ new Date));
+
+ if (method == 'POST') {
+ try {
+ if (req.setRequestHeader) {
+ req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
+ } else {
+ // XDomainRequest
+ req.contentType = 'text/plain';
+ }
+ } catch (e) {}
+ }
+
+ return req;
+ };
+
+ /**
+ * Returns the scheme to use for the transport URLs.
+ *
+ * @api private
+ */
+
+ XHR.prototype.scheme = function () {
+ return this.socket.options.secure ? 'https' : 'http';
+ };
+
+ /**
+ * Check if the XHR transports are supported
+ *
+ * @param {Boolean} xdomain Check if we support cross domain requests.
+ * @returns {Boolean}
+ * @api public
+ */
+
+ XHR.check = function (socket, xdomain) {
+ try {
+ if (io.util.request(xdomain)) {
+ return true;
+ }
+ } catch(e) {}
+
+ return false;
+ };
+
+ /**
+ * Check if the XHR transport supports corss domain requests.
+ *
+ * @returns {Boolean}
+ * @api public
+ */
+
+ XHR.xdomainCheck = function () {
+ return XHR.check(null, true);
+ };
+
+})(
+ 'undefined' != typeof io ? io.Transport : module.exports
+ , 'undefined' != typeof io ? io : module.parent.exports
+);
--- /dev/null
+
+/**
+ * socket.io
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (exports) {
+
+ /**
+ * Utilities namespace.
+ *
+ * @namespace
+ */
+
+ var util = exports.util = {};
+
+ /**
+ * Parses an URI
+ *
+ * @author Steven Levithan <stevenlevithan.com> (MIT license)
+ * @api public
+ */
+
+ var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
+
+ var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
+ 'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
+ 'anchor'];
+
+ util.parseUri = function (str) {
+ var m = re.exec(str || '')
+ , uri = {}
+ , i = 14;
+
+ while (i--) {
+ uri[parts[i]] = m[i] || '';
+ }
+
+ return uri;
+ };
+
+ /**
+ * Produces a unique url that identifies a Socket.IO connection.
+ *
+ * @param {Object} uri
+ * @api public
+ */
+
+ util.uniqueUri = function (uri) {
+ var protocol = uri.protocol
+ , host = uri.host
+ , port = uri.port;
+
+ if ('undefined' != typeof document) {
+ host = host || document.domain;
+ port = port || (protocol == 'https'
+ && document.location.protocol !== 'https:' ? 443 : document.location.port);
+ } else {
+ host = host || 'localhost';
+
+ if (!port && protocol == 'https') {
+ port = 443;
+ }
+ }
+
+ return (protocol || 'http') + '://' + host + ':' + (port || 80);
+ };
+
+ /**
+ * Executes the given function when the page is loaded.
+ *
+ * io.util.load(function () { console.log('page loaded'); });
+ *
+ * @param {Function} fn
+ * @api public
+ */
+
+ var pageLoaded = false;
+
+ util.load = function (fn) {
+ if (document.readyState === 'complete' || pageLoaded) {
+ return fn();
+ }
+
+ util.on(window, 'load', fn, false);
+ };
+
+ /**
+ * Adds an event.
+ *
+ * @api private
+ */
+
+ util.on = function (element, event, fn, capture) {
+ if (element.attachEvent) {
+ element.attachEvent('on' + event, fn);
+ } else {
+ element.addEventListener(event, fn, capture);
+ }
+ };
+
+ /**
+ * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
+ *
+ * @param {Boolean} [xdomain] Create a request that can be used cross domain.
+ * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
+ * @api private
+ */
+
+ util.request = function (xdomain) {
+ if ('undefined' != typeof window) {
+ if (xdomain && window.XDomainRequest) {
+ return new XDomainRequest();
+ };
+
+ if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
+ return new XMLHttpRequest();
+ };
+
+ if (!xdomain) {
+ try {
+ return new window.ActiveXObject('Microsoft.XMLHTTP');
+ } catch(e) { }
+ }
+ }
+
+ return null;
+ };
+
+ /**
+ * XHR based transport constructor.
+ *
+ * @constructor
+ * @api public
+ */
+
+ /**
+ * Change the internal pageLoaded value.
+ */
+
+ if ('undefined' != typeof window) {
+ util.load(function () {
+ pageLoaded = true;
+ });
+ }
+
+ /**
+ * Defers a function to ensure a spinner is not displayed by the browser
+ *
+ * @param {Function} fn
+ * @api public
+ */
+
+ util.defer = function (fn) {
+ if (!util.ua.webkit) {
+ return fn();
+ }
+
+ util.load(function () {
+ setTimeout(fn, 100);
+ });
+ };
+
+ /**
+ * Merges two objects.
+ *
+ * @api public
+ */
+
+ util.merge = function merge (target, additional, deep, lastseen) {
+ var seen = lastseen || []
+ , depth = typeof deep == 'undefined' ? 2 : deep
+ , prop;
+
+ for (prop in additional) {
+ if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
+ if (typeof target[prop] !== 'object' || !depth) {
+ target[prop] = additional[prop];
+ seen.push(additional[prop]);
+ } else {
+ util.merge(target[prop], additional[prop], depth - 1, seen);
+ }
+ }
+ }
+
+ return target;
+ };
+
+ /**
+ * Merges prototypes from objects
+ *
+ * @api public
+ */
+
+ util.mixin = function (ctor, ctor2) {
+ util.merge(ctor.prototype, ctor2.prototype);
+ };
+
+ /**
+ * Shortcut for prototypical and static inheritance.
+ *
+ * @api private
+ */
+
+ util.inherit = function (ctor, ctor2) {
+ ctor.prototype = new ctor2;
+ util.merge(ctor, ctor2);
+ };
+
+ /**
+ * Checks if the given object is an Array.
+ *
+ * io.util.isArray([]); // true
+ * io.util.isArray({}); // false
+ *
+ * @param Object obj
+ * @api public
+ */
+
+ util.isArray = Array.isArray || function (obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+ };
+
+ /**
+ * Intersects values of two arrays into a third
+ *
+ * @api public
+ */
+
+ util.intersect = function (arr, arr2) {
+ var ret = []
+ , longest = arr.length > arr2.length ? arr : arr2
+ , shortest = arr.length > arr2.length ? arr2 : arr
+
+ for (var i = 0, l = shortest.length; i < l; i++) {
+ if (~util.indexOf(longest, shortest[i]))
+ ret.push(shortest[i]);
+ }
+
+ return ret;
+ }
+
+ /**
+ * Array indexOf compatibility.
+ *
+ * @see bit.ly/a5Dxa2
+ * @api public
+ */
+
+ util.indexOf = function (arr, o, i) {
+ if (Array.prototype.indexOf) {
+ return Array.prototype.indexOf.call(arr, o, i);
+ }
+
+ for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
+ ; i < j && arr[i] !== o; i++);
+
+ return j <= i ? -1 : i;
+ };
+
+ /**
+ * Converts enumerables to array.
+ *
+ * @api public
+ */
+
+ util.toArray = function (enu) {
+ var arr = [];
+
+ for (var i = 0, l = enu.length; i < l; i++)
+ arr.push(enu[i]);
+
+ return arr;
+ };
+
+ /**
+ * UA / engines detection namespace.
+ *
+ * @namespace
+ */
+
+ util.ua = {};
+
+ /**
+ * Whether the UA supports CORS for XHR.
+ *
+ * @api public
+ */
+
+ util.ua.hasCORS = 'undefined' != typeof window && window.XMLHttpRequest &&
+ (function () {
+ try {
+ var a = new XMLHttpRequest();
+ } catch (e) {
+ return false;
+ }
+
+ return a.withCredentials != undefined;
+ })();
+
+ /**
+ * Detect webkit.
+ *
+ * @api public
+ */
+
+ util.ua.webkit = 'undefined' != typeof navigator
+ && /webkit/i.test(navigator.userAgent);
+
+})('undefined' != typeof window ? io : module.exports);
--- /dev/null
+## How to try the sample
+
+Assuming you have Web server (e.g. Apache) running at **http://example.com/** .
+
+1. Download [web-socket-ruby](http://github.com/gimite/web-socket-ruby/tree/master).
+2. Run sample Web Socket server (echo server) in example.com with: (#1)<br>
+```
+$ ruby web-socket-ruby/samples/echo_server.rb example.com 10081
+```
+3. If your server already provides socket policy file at port **843**, modify the file to allow access to port **10081**. Otherwise you can skip this step. See below for details.
+4. Publish the web-socket-js directory with your Web server (e.g. put it in ~/public_html).
+5. Change ws://localhost:10081 to **ws://example.com:10081** in sample.html.
+6. Open sample.html in your browser.
+7. After "onopen" is shown, input something, click [Send] and confirm echo back.
+
+\#1: First argument of echo_server.rb means that it accepts Web Socket connection from HTML pages in example.com.
+
+
+## How to use it in your application
+
+- Copy swfobject.js, web_socket.js, WebSocketMain.swf to your application directory.
+- Write JavaScript code:
+
+```html
+<!-- Import JavaScript Libraries. -->
+<script type="text/javascript" src="swfobject.js"></script>
+<script type="text/javascript" src="web_socket.js"></script>
+
+<script type="text/javascript">
+
+ // Let the library know where WebSocketMain.swf is:
+ WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";
+
+ // Write your code in the same way as for native WebSocket:
+ var ws = new WebSocket("ws://example.com:10081/");
+ ws.onopen = function() {
+ ws.send("Hello"); // Sends a message.
+ };
+ ws.onmessage = function(e) {
+ // Receives a message.
+ alert(e.data);
+ };
+ ws.onclose = function() {
+ alert("closed");
+ };
+
+</script>
+```
+
+- Put Flash socket policy file to your server unless you use web-socket-ruby or em-websocket as your WebSocket server. See "Flash socket policy file" section below for details.
+
+
+## Troubleshooting
+
+If it doesn't work, try these:
+
+1. Try Chrome and Firefox 3.x.
+
+ - It doesn't work on Chrome:<br>
+ It's likely an issue of your code or the server. Debug your code as usual e.g. using console.log.
+ - It works on Chrome but it doesn't work on Firefox:<br>
+ It's likely an issue of web-socket-js specific configuration (e.g. 3 and 4 below).
+ - It works on both Chrome and Firefox, but it doesn't work on your browser:<br>
+ Check "Supported environment" section below. Your browser may not be supported by web-socket-js.
+
+2. Add this line before your code:
+ WEB_SOCKET_DEBUG = true;
+and use Developer Tools (Chrome/Safari) or Firebug (Firefox) to see if console.log outputs any errors.
+
+3. Make sure you do NOT open your HTML page as local file e.g. file:///.../sample.html. web-socket-js doesn't work on local file. Open it via Web server e.g. http:///.../sample.html.
+
+4. If you are NOT using web-socket-ruby or em-websocket as your WebSocket server, you need to place Flash socket policy file on your server. See "Flash socket policy file" section below for details.
+
+5. Check if sample.html bundled with web-socket-js works.
+
+6. Make sure the port used for WebSocket (10081 in example above) is not blocked by your server/client's firewall.
+
+7. Install [debugger version of Flash Player](http://www.adobe.com/support/flashplayer/downloads.html) to see Flash errors.
+
+
+## Supported environments
+
+It should work on:
+
+- Google Chrome 4 or later (just uses native implementation)
+- Firefox 3.x, 4.x, Internet Explorer 8, 9 + Flash Player 10 or later
+
+It may or may not work on other browsers such as Safari, Opera or IE 6. Patch for these browsers are appreciated, but I will not work on fixing issues specific to these browsers by myself.
+
+
+## Limitations/differences compared to native WebSocket
+
+- You need some more lines in your JavaScript code. See "How to use it in your application" section above for details.
+- It requires Flash Player 10 or later unless the browser supports native WebSocket.
+- Your server must provide Flash socket policy file, unless you use web-socket-ruby or em-websocket. See "Flash socket policy file" section below for details.
+- It has limited support for Cookies on WebSocket. See "Cookie support" section below for details.
+- It doesn't use proxies specified in browser config. See "Proxy support" section below for details.
+
+
+### Flash socket policy file
+
+This implementation uses Flash's socket, which means that your server must provide Flash socket policy file to declare the server accepts connections from Flash.
+
+If you use [web-socket-ruby](http://github.com/gimite/web-socket-ruby/tree/master) or [em-websocket](https://github.com/igrigorik/em-websocket), you don't need anything special, because they handle Flash socket policy file request. But if you already provide socket policy file at port **843**, you need to modify the file to allow access to Web Socket port, because it precedes what the libraries provide.
+
+If you use other Web Socket server implementation, you need to provide socket policy file yourself. See [Setting up A Flash Socket Policy File](http://www.lightsphere.com/dev/articles/flash_socket_policy.html) for details and sample script to run socket policy file server. [node.js implementation is available here](http://github.com/LearnBoost/Socket.IO-node/blob/master/lib/socket.io/transports/flashsocket.js).
+
+Actually, it's still better to provide socket policy file at port 843 even if you use web-socket-ruby or em-websocket. Flash always try to connect to port 843 first, so providing the file at port 843 makes startup faster.
+
+
+### Cookie support
+
+web-socket-js has limited supported for Cookies on WebSocket.
+
+Cookie is sent if Web Socket host is exactly the same as the origin of JavaScript (The port can be different). Otherwise it is not sent, because I don't know way to send right Cookie (which is Cookie of the host of Web Socket, I heard). Also, HttpOnly Cookies are not sent.
+
+Note that it's technically possible that client sends arbitrary string as Cookie and any other headers (by modifying this library for example) once you place Flash socket policy file in your server. So don't trust Cookie and other headers if you allow connection from untrusted origin.
+
+
+### Proxy support
+
+[The WebSocket spec](http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol) specifies instructions for User Agents to support proxied connections by implementing the HTTP CONNECT method.
+
+The AS3 Socket class doesn't implement this mechanism, which renders it useless for the scenarios where the user trying to open a socket is behind a proxy.
+
+The class RFC2817Socket (by Christian Cantrell) effectively lets us implement this, as long as the proxy settings are known and provided by the interface that instantiates the WebSocket. As such, if you want to support proxied conncetions, you'll have to supply this information to the WebSocket constructor when Flash is being used. One way to go about it would be to ask the user for proxy settings information if the initial connection fails.
+
+
+## How to host HTML file and SWF file in different domains
+
+By default, HTML file and SWF file must be in the same domain. You can follow steps below to allow hosting them in different domain.
+
+**WARNING**: If you use the method below, HTML files in ANY domains can send arbitrary TCP data to your WebSocket server, regardless of configuration in Flash socket policy file. Arbitrary TCP data means that they can even fake request headers including Origin and Cookie.
+
+1. Unzip WebSocketMainInsecure.zip to extract WebSocketMainInsecure.swf.
+2. Put WebSocketMainInsecure.swf on your server, instead of WebSocketMain.swf.
+3. In JavaScript, set WEB_SOCKET_SWF_LOCATION to URL of your WebSocketMainInsecure.swf.
+
+
+## How to build WebSocketMain.swf
+
+Install [Flex 4 SDK](http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4).
+
+ $ cd flash-src
+ $ ./build.sh
+
+
+## WebSocket protocol versions
+
+- web-socket-js supports [Hixie 76 version](http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76) of WebSocket protocol by default i.e. in [master branch](https://github.com/gimite/web-socket-js).
+- If you want to try newer [Hybi 07 version](http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07), check out from [hybi-07 branch](https://github.com/gimite/web-socket-js/tree/hybi-07). This will become the master branch in the future, probably when Chrome switches to Hybi 07.
+- Hixie 75 or before is no longer supported.
+
+
+## License
+
+New BSD License.
--- /dev/null
+package {
+
+public interface IWebSocketLogger {
+ function log(message:String):void;
+ function error(message:String):void;
+}
+
+}
--- /dev/null
+// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
+// License: New BSD License
+// Reference: http://dev.w3.org/html5/websockets/
+// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
+
+package {
+
+import com.adobe.net.proxies.RFC2817Socket;
+import com.gsolo.encryption.MD5;
+import com.hurlant.crypto.tls.TLSConfig;
+import com.hurlant.crypto.tls.TLSEngine;
+import com.hurlant.crypto.tls.TLSSecurityParameters;
+import com.hurlant.crypto.tls.TLSSocket;
+
+import flash.display.*;
+import flash.events.*;
+import flash.external.*;
+import flash.net.*;
+import flash.system.*;
+import flash.utils.*;
+
+import mx.controls.*;
+import mx.core.*;
+import mx.events.*;
+import mx.utils.*;
+
+public class WebSocket extends EventDispatcher {
+
+ private static var CONNECTING:int = 0;
+ private static var OPEN:int = 1;
+ private static var CLOSING:int = 2;
+ private static var CLOSED:int = 3;
+
+ private var id:int;
+ private var rawSocket:Socket;
+ private var tlsSocket:TLSSocket;
+ private var tlsConfig:TLSConfig;
+ private var socket:Socket;
+ private var url:String;
+ private var scheme:String;
+ private var host:String;
+ private var port:uint;
+ private var path:String;
+ private var origin:String;
+ private var requestedProtocols:Array;
+ private var acceptedProtocol:String;
+ private var buffer:ByteArray = new ByteArray();
+ private var headerState:int = 0;
+ private var readyState:int = CONNECTING;
+ private var cookie:String;
+ private var headers:String;
+ private var noiseChars:Array;
+ private var expectedDigest:String;
+ private var logger:IWebSocketLogger;
+
+ public function WebSocket(
+ id:int, url:String, protocols:Array, origin:String,
+ proxyHost:String, proxyPort:int,
+ cookie:String, headers:String,
+ logger:IWebSocketLogger) {
+ this.logger = logger;
+ this.id = id;
+ initNoiseChars();
+ this.url = url;
+ var m:Array = url.match(/^(\w+):\/\/([^\/:]+)(:(\d+))?(\/.*)?(\?.*)?$/);
+ if (!m) fatal("SYNTAX_ERR: invalid url: " + url);
+ this.scheme = m[1];
+ this.host = m[2];
+ var defaultPort:int = scheme == "wss" ? 443 : 80;
+ this.port = parseInt(m[4]) || defaultPort;
+ this.path = (m[5] || "/") + (m[6] || "");
+ this.origin = origin;
+ this.requestedProtocols = protocols;
+ this.cookie = cookie;
+ // if present and not the empty string, headers MUST end with \r\n
+ // headers should be zero or more complete lines, for example
+ // "Header1: xxx\r\nHeader2: yyyy\r\n"
+ this.headers = headers;
+
+ if (proxyHost != null && proxyPort != 0){
+ if (scheme == "wss") {
+ fatal("wss with proxy is not supported");
+ }
+ var proxySocket:RFC2817Socket = new RFC2817Socket();
+ proxySocket.setProxyInfo(proxyHost, proxyPort);
+ proxySocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
+ rawSocket = socket = proxySocket;
+ } else {
+ rawSocket = new Socket();
+ if (scheme == "wss") {
+ tlsConfig= new TLSConfig(TLSEngine.CLIENT,
+ null, null, null, null, null,
+ TLSSecurityParameters.PROTOCOL_VERSION);
+ tlsConfig.trustAllCertificates = true;
+ tlsConfig.ignoreCommonNameMismatch = true;
+ tlsSocket = new TLSSocket();
+ tlsSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
+ socket = tlsSocket;
+ } else {
+ rawSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
+ socket = rawSocket;
+ }
+ }
+ rawSocket.addEventListener(Event.CLOSE, onSocketClose);
+ rawSocket.addEventListener(Event.CONNECT, onSocketConnect);
+ rawSocket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIoError);
+ rawSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSocketSecurityError);
+ rawSocket.connect(host, port);
+ }
+
+ /**
+ * @return This WebSocket's ID.
+ */
+ public function getId():int {
+ return this.id;
+ }
+
+ /**
+ * @return this WebSocket's readyState.
+ */
+ public function getReadyState():int {
+ return this.readyState;
+ }
+
+ public function getAcceptedProtocol():String {
+ return this.acceptedProtocol;
+ }
+
+ public function send(encData:String):int {
+ var data:String = decodeURIComponent(encData);
+ if (readyState == OPEN) {
+ socket.writeByte(0x00);
+ socket.writeUTFBytes(data);
+ socket.writeByte(0xff);
+ socket.flush();
+ logger.log("sent: " + data);
+ return -1;
+ } else if (readyState == CLOSING || readyState == CLOSED) {
+ var bytes:ByteArray = new ByteArray();
+ bytes.writeUTFBytes(data);
+ return bytes.length; // not sure whether it should include \x00 and \xff
+ } else {
+ fatal("invalid state");
+ return 0;
+ }
+ }
+
+ public function close(isError:Boolean = false):void {
+ logger.log("close");
+ try {
+ if (readyState == OPEN && !isError) {
+ socket.writeByte(0xff);
+ socket.writeByte(0x00);
+ socket.flush();
+ }
+ socket.close();
+ } catch (ex:Error) { }
+ readyState = CLOSED;
+ this.dispatchEvent(new WebSocketEvent(isError ? "error" : "close"));
+ }
+
+ private function onSocketConnect(event:Event):void {
+ logger.log("connected");
+
+ if (scheme == "wss") {
+ logger.log("starting SSL/TLS");
+ tlsSocket.startTLS(rawSocket, host, tlsConfig);
+ }
+
+ var defaultPort:int = scheme == "wss" ? 443 : 80;
+ var hostValue:String = host + (port == defaultPort ? "" : ":" + port);
+ var key1:String = generateKey();
+ var key2:String = generateKey();
+ var key3:String = generateKey3();
+ expectedDigest = getSecurityDigest(key1, key2, key3);
+ var opt:String = "";
+ if (requestedProtocols.length > 0) {
+ opt += "Sec-WebSocket-Protocol: " + requestedProtocols.join(",") + "\r\n";
+ }
+ // if caller passes additional headers they must end with "\r\n"
+ if (headers) opt += headers;
+
+ var req:String = StringUtil.substitute(
+ "GET {0} HTTP/1.1\r\n" +
+ "Upgrade: WebSocket\r\n" +
+ "Connection: Upgrade\r\n" +
+ "Host: {1}\r\n" +
+ "Origin: {2}\r\n" +
+ "Cookie: {3}\r\n" +
+ "Sec-WebSocket-Key1: {4}\r\n" +
+ "Sec-WebSocket-Key2: {5}\r\n" +
+ "{6}" +
+ "\r\n",
+ path, hostValue, origin, cookie, key1, key2, opt);
+ logger.log("request header:\n" + req);
+ socket.writeUTFBytes(req);
+ logger.log("sent key3: " + key3);
+ writeBytes(key3);
+ socket.flush();
+ }
+
+ private function onSocketClose(event:Event):void {
+ logger.log("closed");
+ readyState = CLOSED;
+ this.dispatchEvent(new WebSocketEvent("close"));
+ }
+
+ private function onSocketIoError(event:IOErrorEvent):void {
+ var message:String;
+ if (readyState == CONNECTING) {
+ message = "cannot connect to Web Socket server at " + url + " (IoError)";
+ } else {
+ message = "error communicating with Web Socket server at " + url + " (IoError)";
+ }
+ onError(message);
+ }
+
+ private function onSocketSecurityError(event:SecurityErrorEvent):void {
+ var message:String;
+ if (readyState == CONNECTING) {
+ message =
+ "cannot connect to Web Socket server at " + url + " (SecurityError)\n" +
+ "make sure the server is running and Flash socket policy file is correctly placed";
+ } else {
+ message = "error communicating with Web Socket server at " + url + " (SecurityError)";
+ }
+ onError(message);
+ }
+
+ private function onError(message:String):void {
+ if (readyState == CLOSED) return;
+ logger.error(message);
+ close(readyState != CONNECTING);
+ }
+
+ private function onSocketData(event:ProgressEvent):void {
+ var pos:int = buffer.length;
+ socket.readBytes(buffer, pos);
+ for (; pos < buffer.length; ++pos) {
+ if (headerState < 4) {
+ // try to find "\r\n\r\n"
+ if ((headerState == 0 || headerState == 2) && buffer[pos] == 0x0d) {
+ ++headerState;
+ } else if ((headerState == 1 || headerState == 3) && buffer[pos] == 0x0a) {
+ ++headerState;
+ } else {
+ headerState = 0;
+ }
+ if (headerState == 4) {
+ var headerStr:String = readUTFBytes(buffer, 0, pos + 1);
+ logger.log("response header:\n" + headerStr);
+ if (!validateHeader(headerStr)) return;
+ removeBufferBefore(pos + 1);
+ pos = -1;
+ }
+ } else if (headerState == 4) {
+ if (pos == 15) {
+ var replyDigest:String = readBytes(buffer, 0, 16);
+ logger.log("reply digest: " + replyDigest);
+ if (replyDigest != expectedDigest) {
+ onError("digest doesn't match: " + replyDigest + " != " + expectedDigest);
+ return;
+ }
+ headerState = 5;
+ removeBufferBefore(pos + 1);
+ pos = -1;
+ readyState = OPEN;
+ this.dispatchEvent(new WebSocketEvent("open"));
+ }
+ } else {
+ if (buffer[pos] == 0xff && pos > 0) {
+ if (buffer[0] != 0x00) {
+ onError("data must start with \\x00");
+ return;
+ }
+ var data:String = readUTFBytes(buffer, 1, pos - 1);
+ logger.log("received: " + data);
+ this.dispatchEvent(new WebSocketEvent("message", encodeURIComponent(data)));
+ removeBufferBefore(pos + 1);
+ pos = -1;
+ } else if (pos == 1 && buffer[0] == 0xff && buffer[1] == 0x00) { // closing
+ logger.log("received closing packet");
+ removeBufferBefore(pos + 1);
+ pos = -1;
+ close();
+ }
+ }
+ }
+ }
+
+ private function validateHeader(headerStr:String):Boolean {
+ var lines:Array = headerStr.split(/\r\n/);
+ if (!lines[0].match(/^HTTP\/1.1 101 /)) {
+ onError("bad response: " + lines[0]);
+ return false;
+ }
+ var header:Object = {};
+ var lowerHeader:Object = {};
+ for (var i:int = 1; i < lines.length; ++i) {
+ if (lines[i].length == 0) continue;
+ var m:Array = lines[i].match(/^(\S+): (.*)$/);
+ if (!m) {
+ onError("failed to parse response header line: " + lines[i]);
+ return false;
+ }
+ header[m[1].toLowerCase()] = m[2];
+ lowerHeader[m[1].toLowerCase()] = m[2].toLowerCase();
+ }
+ if (lowerHeader["upgrade"] != "websocket") {
+ onError("invalid Upgrade: " + header["Upgrade"]);
+ return false;
+ }
+ if (lowerHeader["connection"] != "upgrade") {
+ onError("invalid Connection: " + header["Connection"]);
+ return false;
+ }
+ if (!lowerHeader["sec-websocket-origin"]) {
+ if (lowerHeader["websocket-origin"]) {
+ onError(
+ "The WebSocket server speaks old WebSocket protocol, " +
+ "which is not supported by web-socket-js. " +
+ "It requires WebSocket protocol 76 or later. " +
+ "Try newer version of the server if available.");
+ } else {
+ onError("header Sec-WebSocket-Origin is missing");
+ }
+ return false;
+ }
+ var resOrigin:String = lowerHeader["sec-websocket-origin"];
+ if (resOrigin != origin) {
+ onError("origin doesn't match: '" + resOrigin + "' != '" + origin + "'");
+ return false;
+ }
+ if (requestedProtocols.length > 0) {
+ acceptedProtocol = header["sec-websocket-protocol"];
+ if (requestedProtocols.indexOf(acceptedProtocol) < 0) {
+ onError("protocol doesn't match: '" +
+ acceptedProtocol + "' not in '" + requestedProtocols.join(",") + "'");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private function removeBufferBefore(pos:int):void {
+ if (pos == 0) return;
+ var nextBuffer:ByteArray = new ByteArray();
+ buffer.position = pos;
+ buffer.readBytes(nextBuffer);
+ buffer = nextBuffer;
+ }
+
+ private function initNoiseChars():void {
+ noiseChars = new Array();
+ for (var i:int = 0x21; i <= 0x2f; ++i) {
+ noiseChars.push(String.fromCharCode(i));
+ }
+ for (var j:int = 0x3a; j <= 0x7a; ++j) {
+ noiseChars.push(String.fromCharCode(j));
+ }
+ }
+
+ private function generateKey():String {
+ var spaces:uint = randomInt(1, 12);
+ var max:uint = uint.MAX_VALUE / spaces;
+ var number:uint = randomInt(0, max);
+ var key:String = (number * spaces).toString();
+ var noises:int = randomInt(1, 12);
+ var pos:int;
+ for (var i:int = 0; i < noises; ++i) {
+ var char:String = noiseChars[randomInt(0, noiseChars.length - 1)];
+ pos = randomInt(0, key.length);
+ key = key.substr(0, pos) + char + key.substr(pos);
+ }
+ for (var j:int = 0; j < spaces; ++j) {
+ pos = randomInt(1, key.length - 1);
+ key = key.substr(0, pos) + " " + key.substr(pos);
+ }
+ return key;
+ }
+
+ private function generateKey3():String {
+ var key3:String = "";
+ for (var i:int = 0; i < 8; ++i) {
+ key3 += String.fromCharCode(randomInt(0, 255));
+ }
+ return key3;
+ }
+
+ private function getSecurityDigest(key1:String, key2:String, key3:String):String {
+ var bytes1:String = keyToBytes(key1);
+ var bytes2:String = keyToBytes(key2);
+ return MD5.rstr_md5(bytes1 + bytes2 + key3);
+ }
+
+ private function keyToBytes(key:String):String {
+ var keyNum:uint = parseInt(key.replace(/[^\d]/g, ""));
+ var spaces:uint = 0;
+ for (var i:int = 0; i < key.length; ++i) {
+ if (key.charAt(i) == " ") ++spaces;
+ }
+ var resultNum:uint = keyNum / spaces;
+ var bytes:String = "";
+ for (var j:int = 3; j >= 0; --j) {
+ bytes += String.fromCharCode((resultNum >> (j * 8)) & 0xff);
+ }
+ return bytes;
+ }
+
+ // Writes byte sequence to socket.
+ // bytes is String in special format where bytes[i] is i-th byte, not i-th character.
+ private function writeBytes(bytes:String):void {
+ for (var i:int = 0; i < bytes.length; ++i) {
+ socket.writeByte(bytes.charCodeAt(i));
+ }
+ }
+
+ // Reads specified number of bytes from buffer, and returns it as special format String
+ // where bytes[i] is i-th byte (not i-th character).
+ private function readBytes(buffer:ByteArray, start:int, numBytes:int):String {
+ buffer.position = start;
+ var bytes:String = "";
+ for (var i:int = 0; i < numBytes; ++i) {
+ // & 0xff is to make \x80-\xff positive number.
+ bytes += String.fromCharCode(buffer.readByte() & 0xff);
+ }
+ return bytes;
+ }
+
+ private function readUTFBytes(buffer:ByteArray, start:int, numBytes:int):String {
+ buffer.position = start;
+ var data:String = "";
+ for(var i:int = start; i < start + numBytes; ++i) {
+ // Workaround of a bug of ByteArray#readUTFBytes() that bytes after "\x00" is discarded.
+ if (buffer[i] == 0x00) {
+ data += buffer.readUTFBytes(i - buffer.position) + "\x00";
+ buffer.position = i + 1;
+ }
+ }
+ data += buffer.readUTFBytes(start + numBytes - buffer.position);
+ return data;
+ }
+
+ private function randomInt(min:uint, max:uint):uint {
+ return min + Math.floor(Math.random() * (Number(max) - min + 1));
+ }
+
+ private function fatal(message:String):void {
+ logger.error(message);
+ throw message;
+ }
+
+ // for debug
+ private function dumpBytes(bytes:String):void {
+ var output:String = "";
+ for (var i:int = 0; i < bytes.length; ++i) {
+ output += bytes.charCodeAt(i).toString() + ", ";
+ }
+ logger.log(output);
+ }
+
+}
+
+}
--- /dev/null
+package {
+
+import flash.events.Event;
+
+/**
+ * This class represents a generic websocket event. It contains the standard "type"
+ * parameter as well as a "message" parameter.
+ */
+public class WebSocketEvent extends Event {
+
+ public static const OPEN:String = "open";
+ public static const CLOSE:String = "close";
+ public static const MESSAGE:String = "message";
+ public static const ERROR:String = "error";
+
+ public var message:String;
+
+ public function WebSocketEvent(
+ type:String, message:String = null, bubbles:Boolean = false, cancelable:Boolean = false) {
+ super(type, bubbles, cancelable);
+ this.message = message;
+ }
+
+ public override function clone():Event {
+ return new WebSocketEvent(this.type, this.message, this.bubbles, this.cancelable);
+ }
+
+ public override function toString():String {
+ return "WebSocketEvent: " + this.type + ": " + this.message;
+ }
+}
+
+}
--- /dev/null
+// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
+// License: New BSD License
+// Reference: http://dev.w3.org/html5/websockets/
+// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
+
+package {
+
+import flash.display.Sprite;
+import flash.external.ExternalInterface;
+import flash.system.Security;
+import flash.utils.setTimeout;
+
+import mx.utils.URLUtil;
+
+/**
+ * Provides JavaScript API of WebSocket.
+ */
+public class WebSocketMain extends Sprite implements IWebSocketLogger{
+
+ private var callerUrl:String;
+ private var debug:Boolean = false;
+ private var manualPolicyFileLoaded:Boolean = false;
+ private var webSockets:Array = [];
+ private var eventQueue:Array = [];
+
+ public function WebSocketMain() {
+ ExternalInterface.addCallback("setCallerUrl", setCallerUrl);
+ ExternalInterface.addCallback("setDebug", setDebug);
+ ExternalInterface.addCallback("create", create);
+ ExternalInterface.addCallback("send", send);
+ ExternalInterface.addCallback("close", close);
+ ExternalInterface.addCallback("loadManualPolicyFile", loadManualPolicyFile);
+ ExternalInterface.addCallback("receiveEvents", receiveEvents);
+ ExternalInterface.call("WebSocket.__onFlashInitialized");
+ }
+
+ public function setCallerUrl(url:String):void {
+ callerUrl = url;
+ }
+
+ public function setDebug(val:Boolean):void {
+ debug = val;
+ }
+
+ private function loadDefaultPolicyFile(wsUrl:String):void {
+ var policyUrl:String = "xmlsocket://" + URLUtil.getServerName(wsUrl) + ":843";
+ log("policy file: " + policyUrl);
+ Security.loadPolicyFile(policyUrl);
+ }
+
+ public function loadManualPolicyFile(policyUrl:String):void {
+ log("policy file: " + policyUrl);
+ Security.loadPolicyFile(policyUrl);
+ manualPolicyFileLoaded = true;
+ }
+
+ public function log(message:String):void {
+ if (debug) {
+ ExternalInterface.call("WebSocket.__log", encodeURIComponent("[WebSocket] " + message));
+ }
+ }
+
+ public function error(message:String):void {
+ ExternalInterface.call("WebSocket.__error", encodeURIComponent("[WebSocket] " + message));
+ }
+
+ private function parseEvent(event:WebSocketEvent):Object {
+ var webSocket:WebSocket = event.target as WebSocket;
+ var eventObj:Object = {};
+ eventObj.type = event.type;
+ eventObj.webSocketId = webSocket.getId();
+ eventObj.readyState = webSocket.getReadyState();
+ eventObj.protocol = webSocket.getAcceptedProtocol();
+ if (event.message !== null) {
+ eventObj.message = event.message;
+ }
+ return eventObj;
+ }
+
+ public function create(
+ webSocketId:int,
+ url:String, protocols:Array,
+ proxyHost:String = null, proxyPort:int = 0,
+ headers:String = null):void {
+ if (!manualPolicyFileLoaded) {
+ loadDefaultPolicyFile(url);
+ }
+ var newSocket:WebSocket = new WebSocket(
+ webSocketId, url, protocols, getOrigin(), proxyHost, proxyPort,
+ getCookie(url), headers, this);
+ newSocket.addEventListener("open", onSocketEvent);
+ newSocket.addEventListener("close", onSocketEvent);
+ newSocket.addEventListener("error", onSocketEvent);
+ newSocket.addEventListener("message", onSocketEvent);
+ webSockets[webSocketId] = newSocket;
+ }
+
+ public function send(webSocketId:int, encData:String):int {
+ var webSocket:WebSocket = webSockets[webSocketId];
+ return webSocket.send(encData);
+ }
+
+ public function close(webSocketId:int):void {
+ var webSocket:WebSocket = webSockets[webSocketId];
+ webSocket.close();
+ }
+
+ public function receiveEvents():Object {
+ var result:Object = eventQueue;
+ eventQueue = [];
+ return result;
+ }
+
+ private function getOrigin():String {
+ return (URLUtil.getProtocol(this.callerUrl) + "://" +
+ URLUtil.getServerNameWithPort(this.callerUrl)).toLowerCase();
+ }
+
+ private function getCookie(url:String):String {
+ if (URLUtil.getServerName(url).toLowerCase() ==
+ URLUtil.getServerName(this.callerUrl).toLowerCase()) {
+ return ExternalInterface.call("function(){return document.cookie}");
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Socket event handler.
+ */
+ public function onSocketEvent(event:WebSocketEvent):void {
+ var eventObj:Object = parseEvent(event);
+ eventQueue.push(eventObj);
+ processEvents();
+ }
+
+ /**
+ * Process our event queue. If javascript is unresponsive, set
+ * a timeout and try again.
+ */
+ public function processEvents():void {
+ if (eventQueue.length == 0) return;
+ if (!ExternalInterface.call("WebSocket.__onFlashEvent")) {
+ setTimeout(processEvents, 500);
+ }
+ }
+
+}
+
+}
--- /dev/null
+// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
+// License: New BSD License
+// Reference: http://dev.w3.org/html5/websockets/
+// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
+
+package {
+
+import flash.system.*;
+
+public class WebSocketMainInsecure extends WebSocketMain {
+
+ public function WebSocketMainInsecure() {
+ Security.allowDomain("*");
+ super();
+ }
+
+}
+
+}
--- /dev/null
+#!/bin/sh
+
+# You need Flex 4 SDK:
+# http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4
+
+mxmlc -static-link-runtime-shared-libraries -target-player=10.0.0 -output=../WebSocketMain.swf WebSocketMain.as &&
+mxmlc -static-link-runtime-shared-libraries -output=../WebSocketMainInsecure.swf WebSocketMainInsecure.as &&
+cd .. &&
+zip WebSocketMainInsecure.zip WebSocketMainInsecure.swf &&
+rm WebSocketMainInsecure.swf
--- /dev/null
+/*
+ Adobe Systems Incorporated(r) Source Code License Agreement
+ Copyright(c) 2005 Adobe Systems Incorporated. All rights reserved.
+
+ Please read this Source Code License Agreement carefully before using
+ the source code.
+
+ Adobe Systems Incorporated 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, and
+ distribute this source code and such derivative works in source or
+ object code form without any attribution requirements.
+
+ The name "Adobe Systems Incorporated" must not be used to endorse or promote products
+ derived from the source code without prior written permission.
+
+ You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and
+ against any loss, damage, claims or lawsuits, including attorney's
+ fees that arise or result from your use or distribution of the source
+ code.
+
+ THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT
+ ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
+ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF
+ NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA
+ OR ITS SUPPLIERS 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 SOURCE CODE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package com.adobe.net.proxies
+{
+ import flash.events.Event;
+ import flash.events.IOErrorEvent;
+ import flash.events.ProgressEvent;
+ import flash.net.Socket;
+
+ /**
+ * This class allows TCP socket connections through HTTP proxies in accordance with
+ * RFC 2817:
+ *
+ * ftp://ftp.rfc-editor.org/in-notes/rfc2817.txt
+ *
+ * It can also be used to make direct connections to a destination, as well. If you
+ * pass the host and port into the constructor, no proxy will be used. You can also
+ * call connect, passing in the host and the port, and if you didn't set the proxy
+ * info, a direct connection will be made. A proxy is only used after you have called
+ * the setProxyInfo function.
+ *
+ * The connection to and negotiation with the proxy is completely hidden. All the
+ * same events are thrown whether you are using a proxy or not, and the data you
+ * receive from the target server will look exact as it would if you were connected
+ * to it directly rather than through a proxy.
+ *
+ * @author Christian Cantrell
+ *
+ **/
+ public class RFC2817Socket
+ extends Socket
+ {
+ private var proxyHost:String = null;
+ private var host:String = null;
+ private var proxyPort:int = 0;
+ private var port:int = 0;
+ private var deferredEventHandlers:Object = new Object();
+ private var buffer:String = new String();
+
+ /**
+ * Construct a new RFC2817Socket object. If you pass in the host and the port,
+ * no proxy will be used. If you want to use a proxy, instantiate with no
+ * arguments, call setProxyInfo, then call connect.
+ **/
+ public function RFC2817Socket(host:String = null, port:int = 0)
+ {
+ if (host != null && port != 0)
+ {
+ super(host, port);
+ }
+ }
+
+ /**
+ * Set the proxy host and port number. Your connection will only proxied if
+ * this function has been called.
+ **/
+ public function setProxyInfo(host:String, port:int):void
+ {
+ this.proxyHost = host;
+ this.proxyPort = port;
+
+ var deferredSocketDataHandler:Object = this.deferredEventHandlers[ProgressEvent.SOCKET_DATA];
+ var deferredConnectHandler:Object = this.deferredEventHandlers[Event.CONNECT];
+
+ if (deferredSocketDataHandler != null)
+ {
+ super.removeEventListener(ProgressEvent.SOCKET_DATA, deferredSocketDataHandler.listener, deferredSocketDataHandler.useCapture);
+ }
+
+ if (deferredConnectHandler != null)
+ {
+ super.removeEventListener(Event.CONNECT, deferredConnectHandler.listener, deferredConnectHandler.useCapture);
+ }
+ }
+
+ /**
+ * Connect to the specified host over the specified port. If you want your
+ * connection proxied, call the setProxyInfo function first.
+ **/
+ public override function connect(host:String, port:int):void
+ {
+ if (this.proxyHost == null)
+ {
+ this.redirectConnectEvent();
+ this.redirectSocketDataEvent();
+ super.connect(host, port);
+ }
+ else
+ {
+ this.host = host;
+ this.port = port;
+ super.addEventListener(Event.CONNECT, this.onConnect);
+ super.addEventListener(ProgressEvent.SOCKET_DATA, this.onSocketData);
+ super.connect(this.proxyHost, this.proxyPort);
+ }
+ }
+
+ private function onConnect(event:Event):void
+ {
+ this.writeUTFBytes("CONNECT "+this.host+":"+this.port+" HTTP/1.1\n\n");
+ this.flush();
+ this.redirectConnectEvent();
+ }
+
+ private function onSocketData(event:ProgressEvent):void
+ {
+ while (this.bytesAvailable != 0)
+ {
+ this.buffer += this.readUTFBytes(1);
+ if (this.buffer.search(/\r?\n\r?\n$/) != -1)
+ {
+ this.checkResponse(event);
+ break;
+ }
+ }
+ }
+
+ private function checkResponse(event:ProgressEvent):void
+ {
+ var responseCode:String = this.buffer.substr(this.buffer.indexOf(" ")+1, 3);
+
+ if (responseCode.search(/^2/) == -1)
+ {
+ var ioError:IOErrorEvent = new IOErrorEvent(IOErrorEvent.IO_ERROR);
+ ioError.text = "Error connecting to the proxy ["+this.proxyHost+"] on port ["+this.proxyPort+"]: " + this.buffer;
+ this.dispatchEvent(ioError);
+ }
+ else
+ {
+ this.redirectSocketDataEvent();
+ this.dispatchEvent(new Event(Event.CONNECT));
+ if (this.bytesAvailable > 0)
+ {
+ this.dispatchEvent(event);
+ }
+ }
+ this.buffer = null;
+ }
+
+ private function redirectConnectEvent():void
+ {
+ super.removeEventListener(Event.CONNECT, onConnect);
+ var deferredEventHandler:Object = this.deferredEventHandlers[Event.CONNECT];
+ if (deferredEventHandler != null)
+ {
+ super.addEventListener(Event.CONNECT, deferredEventHandler.listener, deferredEventHandler.useCapture, deferredEventHandler.priority, deferredEventHandler.useWeakReference);
+ }
+ }
+
+ private function redirectSocketDataEvent():void
+ {
+ super.removeEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
+ var deferredEventHandler:Object = this.deferredEventHandlers[ProgressEvent.SOCKET_DATA];
+ if (deferredEventHandler != null)
+ {
+ super.addEventListener(ProgressEvent.SOCKET_DATA, deferredEventHandler.listener, deferredEventHandler.useCapture, deferredEventHandler.priority, deferredEventHandler.useWeakReference);
+ }
+ }
+
+ public override function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int=0.0, useWeakReference:Boolean=false):void
+ {
+ if (type == Event.CONNECT || type == ProgressEvent.SOCKET_DATA)
+ {
+ this.deferredEventHandlers[type] = {listener:listener,useCapture:useCapture, priority:priority, useWeakReference:useWeakReference};
+ }
+ else
+ {
+ super.addEventListener(type, listener, useCapture, priority, useWeakReference);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package com.gsolo.encryption { \r
+ public class MD5 {\r
+ /*\r
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\r
+ * Digest Algorithm, as defined in RFC 1321.\r
+ * Version 2.2-alpha Copyright (C) Paul Johnston 1999 - 2005\r
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\r
+ * Distributed under the BSD License\r
+ * See http://pajhome.org.uk/crypt/md5 for more info.\r
+ *\r
+ * Converted to AS3 By Geoffrey Williams\r
+ */\r
+ \r
+ /*\r
+ * Configurable variables. You may need to tweak these to be compatible with\r
+ * the server-side, but the defaults work in most cases.\r
+ */\r
+ \r
+ public static const HEX_FORMAT_LOWERCASE:uint = 0;\r
+ public static const HEX_FORMAT_UPPERCASE:uint = 1;\r
+ \r
+ public static const BASE64_PAD_CHARACTER_DEFAULT_COMPLIANCE:String = "";\r
+ public static const BASE64_PAD_CHARACTER_RFC_COMPLIANCE:String = "=";\r
+ \r
+ public static var hexcase:uint = 0; /* hex output format. 0 - lowercase; 1 - uppercase */\r
+ public static var b64pad:String = ""; /* base-64 pad character. "=" for strict RFC compliance */\r
+ \r
+ public static function encrypt (string:String):String {\r
+ return hex_md5 (string);\r
+ }\r
+ \r
+ /*\r
+ * These are the functions you'll usually want to call\r
+ * They take string arguments and return either hex or base-64 encoded strings\r
+ */\r
+ public static function hex_md5 (string:String):String {\r
+ return rstr2hex (rstr_md5 (str2rstr_utf8 (string)));\r
+ }\r
+ \r
+ public static function b64_md5 (string:String):String {\r
+ return rstr2b64 (rstr_md5 (str2rstr_utf8 (string)));\r
+ }\r
+ \r
+ public static function any_md5 (string:String, encoding:String):String {\r
+ return rstr2any (rstr_md5 (str2rstr_utf8 (string)), encoding);\r
+ }\r
+ public static function hex_hmac_md5 (key:String, data:String):String {\r
+ return rstr2hex (rstr_hmac_md5 (str2rstr_utf8 (key), str2rstr_utf8 (data)));\r
+ }\r
+ public static function b64_hmac_md5 (key:String, data:String):String {\r
+ return rstr2b64 (rstr_hmac_md5 (str2rstr_utf8 (key), str2rstr_utf8 (data)));\r
+ }\r
+ public static function any_hmac_md5 (key:String, data:String, encoding:String):String {\r
+ return rstr2any(rstr_hmac_md5(str2rstr_utf8(key), str2rstr_utf8(data)), encoding);\r
+ }\r
+ \r
+ /*\r
+ * Perform a simple self-test to see if the VM is working\r
+ */\r
+ public static function md5_vm_test ():Boolean {\r
+ return hex_md5 ("abc") == "900150983cd24fb0d6963f7d28e17f72";\r
+ }\r
+ \r
+ /*\r
+ * Calculate the MD5 of a raw string\r
+ */\r
+ public static function rstr_md5 (string:String):String {\r
+ return binl2rstr (binl_md5 (rstr2binl (string), string.length * 8));\r
+ }\r
+ \r
+ /*\r
+ * Calculate the HMAC-MD5, of a key and some data (raw strings)\r
+ */\r
+ public static function rstr_hmac_md5 (key:String, data:String):String {\r
+ var bkey:Array = rstr2binl (key);\r
+ if (bkey.length > 16) bkey = binl_md5 (bkey, key.length * 8);\r
+ \r
+ var ipad:Array = new Array(16), opad:Array = new Array(16);\r
+ for(var i:Number = 0; i < 16; i++) {\r
+ ipad[i] = bkey[i] ^ 0x36363636;\r
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;\r
+ }\r
+ \r
+ var hash:Array = binl_md5 (ipad.concat (rstr2binl (data)), 512 + data.length * 8);\r
+ return binl2rstr (binl_md5 (opad.concat (hash), 512 + 128));\r
+ }\r
+ \r
+ /*\r
+ * Convert a raw string to a hex string\r
+ */\r
+ public static function rstr2hex (input:String):String {\r
+ var hex_tab:String = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";\r
+ var output:String = "";\r
+ var x:Number;\r
+ for(var i:Number = 0; i < input.length; i++) {\r
+ x = input.charCodeAt(i);\r
+ output += hex_tab.charAt((x >>> 4) & 0x0F)\r
+ + hex_tab.charAt( x & 0x0F);\r
+ }\r
+ return output;\r
+ }\r
+ \r
+ /*\r
+ * Convert a raw string to a base-64 string\r
+ */\r
+ public static function rstr2b64 (input:String):String {\r
+ var tab:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
+ var output:String = "";\r
+ var len:Number = input.length;\r
+ for(var i:Number = 0; i < len; i += 3) {\r
+ var triplet:Number = (input.charCodeAt(i) << 16)\r
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)\r
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);\r
+ for(var j:Number = 0; j < 4; j++) {\r
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;\r
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);\r
+ }\r
+ }\r
+ return output;\r
+ }\r
+ \r
+ /*\r
+ * Convert a raw string to an arbitrary string encoding\r
+ */\r
+ public static function rstr2any(input:String, encoding:String):String {\r
+ var divisor:Number = encoding.length;\r
+ var remainders:Array = [];\r
+ var i:Number, q:Number, x:Number, quotient:Array;\r
+ \r
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */\r
+ var dividend:Array = new Array(input.length / 2);\r
+ for(i = 0; i < dividend.length; i++) {\r
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);\r
+ }\r
+ \r
+ /*\r
+ * Repeatedly perform a long division. The binary array forms the dividend,\r
+ * the length of the encoding is the divisor. Once computed, the quotient\r
+ * forms the dividend for the next step. We stop when the dividend is zero.\r
+ * All remainders are stored for later use.\r
+ */\r
+ while(dividend.length > 0) {\r
+ quotient = [];\r
+ x = 0;\r
+ for(i = 0; i < dividend.length; i++) {\r
+ x = (x << 16) + dividend[i];\r
+ q = Math.floor(x / divisor);\r
+ x -= q * divisor;\r
+ if(quotient.length > 0 || q > 0)\r
+ quotient[quotient.length] = q;\r
+ }\r
+ remainders[remainders.length] = x;\r
+ dividend = quotient;\r
+ }\r
+ \r
+ /* Convert the remainders to the output string */\r
+ var output:String = "";\r
+ for(i = remainders.length - 1; i >= 0; i--)\r
+ output += encoding.charAt (remainders[i]);\r
+ \r
+ return output;\r
+ }\r
+ \r
+ /*\r
+ * Encode a string as utf-8.\r
+ * For efficiency, this assumes the input is valid utf-16.\r
+ */\r
+ public static function str2rstr_utf8 (input:String):String {\r
+ var output:String = "";\r
+ var i:Number = -1;\r
+ var x:Number, y:Number;\r
+ \r
+ while(++i < input.length) {\r
+ /* Decode utf-16 surrogate pairs */\r
+ x = input.charCodeAt(i);\r
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;\r
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {\r
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);\r
+ i++;\r
+ }\r
+ \r
+ /* Encode output as utf-8 */\r
+ if(x <= 0x7F)\r
+ output += String.fromCharCode(x);\r
+ else if(x <= 0x7FF)\r
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),\r
+ 0x80 | ( x & 0x3F));\r
+ else if(x <= 0xFFFF)\r
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),\r
+ 0x80 | ((x >>> 6 ) & 0x3F),\r
+ 0x80 | ( x & 0x3F));\r
+ else if(x <= 0x1FFFFF)\r
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),\r
+ 0x80 | ((x >>> 12) & 0x3F),\r
+ 0x80 | ((x >>> 6 ) & 0x3F),\r
+ 0x80 | ( x & 0x3F));\r
+ }\r
+ return output;\r
+ }\r
+ \r
+ /*\r
+ * Encode a string as utf-16\r
+ */\r
+ public static function str2rstr_utf16le (input:String):String {\r
+ var output:String = "";\r
+ for(var i:Number = 0; i < input.length; i++)\r
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,\r
+ (input.charCodeAt(i) >>> 8) & 0xFF);\r
+ return output;\r
+ }\r
+ \r
+ public static function str2rstr_utf16be (input:String):String {\r
+ var output:String = "";\r
+ for(var i:Number = 0; i < input.length; i++)\r
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,\r
+ input.charCodeAt(i) & 0xFF);\r
+ return output;\r
+ }\r
+ \r
+ /*\r
+ * Convert a raw string to an array of little-endian words\r
+ * Characters >255 have their high-byte silently ignored.\r
+ */\r
+ public static function rstr2binl (input:String):Array {\r
+ var output:Array = new Array(input.length >> 2);\r
+ for(var i:Number = 0; i < output.length; i++)\r
+ output[i] = 0;\r
+ for(i = 0; i < input.length * 8; i += 8)\r
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);\r
+ return output;\r
+ }\r
+ \r
+ /*\r
+ * Convert an array of little-endian words to a string\r
+ */\r
+ public static function binl2rstr (input:Array):String {\r
+ var output:String = "";\r
+ for(var i:Number = 0; i < input.length * 32; i += 8)\r
+ output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);\r
+ return output;\r
+ }\r
+ \r
+ /*\r
+ * Calculate the MD5 of an array of little-endian words, and a bit length.\r
+ */\r
+ public static function binl_md5 (x:Array, len:Number):Array {\r
+ /* append padding */\r
+ x[len >> 5] |= 0x80 << ((len) % 32);\r
+ x[(((len + 64) >>> 9) << 4) + 14] = len;\r
+ \r
+ var a:Number = 1732584193;\r
+ var b:Number = -271733879;\r
+ var c:Number = -1732584194;\r
+ var d:Number = 271733878;\r
+ \r
+ for(var i:Number = 0; i < x.length; i += 16) {\r
+ var olda:Number = a;\r
+ var oldb:Number = b;\r
+ var oldc:Number = c;\r
+ var oldd:Number = d;\r
+ \r
+ a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);\r
+ d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);\r
+ c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);\r
+ b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);\r
+ a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);\r
+ d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);\r
+ c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);\r
+ b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);\r
+ a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);\r
+ d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);\r
+ c = md5_ff(c, d, a, b, x[i+10], 17, -42063);\r
+ b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);\r
+ a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);\r
+ d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);\r
+ c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);\r
+ b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);\r
+ \r
+ a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);\r
+ d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);\r
+ c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);\r
+ b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);\r
+ a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);\r
+ d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);\r
+ c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);\r
+ b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);\r
+ a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);\r
+ d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);\r
+ c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);\r
+ b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);\r
+ a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);\r
+ d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);\r
+ c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);\r
+ b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);\r
+ \r
+ a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);\r
+ d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);\r
+ c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);\r
+ b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);\r
+ a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);\r
+ d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);\r
+ c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);\r
+ b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);\r
+ a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);\r
+ d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);\r
+ c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);\r
+ b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);\r
+ a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);\r
+ d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);\r
+ c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);\r
+ b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);\r
+ \r
+ a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);\r
+ d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);\r
+ c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);\r
+ b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);\r
+ a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);\r
+ d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);\r
+ c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);\r
+ b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);\r
+ a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);\r
+ d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);\r
+ c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);\r
+ b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);\r
+ a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);\r
+ d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);\r
+ c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);\r
+ b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);\r
+ \r
+ a = safe_add(a, olda);\r
+ b = safe_add(b, oldb);\r
+ c = safe_add(c, oldc);\r
+ d = safe_add(d, oldd);\r
+ }\r
+ return [a, b, c, d];\r
+ }\r
+ \r
+ /*\r
+ * These functions implement the four basic operations the algorithm uses.\r
+ */\r
+ public static function md5_cmn (q:Number, a:Number, b:Number, x:Number, s:Number, t:Number):Number {\r
+ return safe_add (bit_rol (safe_add (safe_add (a, q), safe_add(x, t)), s), b);\r
+ }\r
+ public static function md5_ff (a:Number, b:Number, c:Number, d:Number, x:Number, s:Number, t:Number):Number {\r
+ return md5_cmn ((b & c) | ((~b) & d), a, b, x, s, t);\r
+ }\r
+ public static function md5_gg (a:Number, b:Number, c:Number, d:Number, x:Number, s:Number, t:Number):Number {\r
+ return md5_cmn ((b & d) | (c & (~d)), a, b, x, s, t);\r
+ }\r
+ public static function md5_hh (a:Number, b:Number, c:Number, d:Number, x:Number, s:Number, t:Number):Number {\r
+ return md5_cmn (b ^ c ^ d, a, b, x, s, t);\r
+ }\r
+ public static function md5_ii (a:Number, b:Number, c:Number, d:Number, x:Number, s:Number, t:Number):Number {\r
+ return md5_cmn (c ^ (b | (~d)), a, b, x, s, t);\r
+ }\r
+ \r
+ /*\r
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally\r
+ * to work around bugs in some JS interpreters.\r
+ */\r
+ public static function safe_add (x:Number, y:Number):Number {\r
+ var lsw:Number = (x & 0xFFFF) + (y & 0xFFFF);\r
+ var msw:Number = (x >> 16) + (y >> 16) + (lsw >> 16);\r
+ return (msw << 16) | (lsw & 0xFFFF);\r
+ }\r
+ \r
+ /*\r
+ * Bitwise rotate a 32-bit number to the left.\r
+ */\r
+ public static function bit_rol (num:Number, cnt:Number):Number {\r
+ return (num << cnt) | (num >>> (32 - cnt));\r
+ }\r
+ \r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Crypto\r
+ * \r
+ * An abstraction layer to instanciate our crypto algorithms\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto\r
+{\r
+ import com.hurlant.crypto.hash.HMAC;\r
+ import com.hurlant.crypto.hash.MAC;\r
+ import com.hurlant.crypto.hash.IHash;\r
+ import com.hurlant.crypto.hash.MD2;\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ import com.hurlant.crypto.hash.SHA224;\r
+ import com.hurlant.crypto.hash.SHA256;\r
+ import com.hurlant.crypto.prng.ARC4;\r
+ import com.hurlant.crypto.rsa.RSAKey;\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.BlowFishKey;\r
+ import com.hurlant.crypto.symmetric.CBCMode;\r
+ import com.hurlant.crypto.symmetric.CFB8Mode;\r
+ import com.hurlant.crypto.symmetric.CFBMode;\r
+ import com.hurlant.crypto.symmetric.CTRMode;\r
+ import com.hurlant.crypto.symmetric.DESKey;\r
+ import com.hurlant.crypto.symmetric.ECBMode;\r
+ import com.hurlant.crypto.symmetric.ICipher;\r
+ import com.hurlant.crypto.symmetric.IMode;\r
+ import com.hurlant.crypto.symmetric.IPad;\r
+ import com.hurlant.crypto.symmetric.ISymmetricKey;\r
+ import com.hurlant.crypto.symmetric.IVMode;\r
+ import com.hurlant.crypto.symmetric.NullPad;\r
+ import com.hurlant.crypto.symmetric.OFBMode;\r
+ import com.hurlant.crypto.symmetric.PKCS5;\r
+ import com.hurlant.crypto.symmetric.SimpleIVMode;\r
+ import com.hurlant.crypto.symmetric.TripleDESKey;\r
+ import com.hurlant.crypto.symmetric.XTeaKey;\r
+ import com.hurlant.util.Base64;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ /**\r
+ * A class to make it easy to use the rest of the framework.\r
+ * As a side-effect, using this class will cause most of the framework\r
+ * to be linked into your application, which is not always what you want.\r
+ * \r
+ * If you want to optimize your download size, don't use this class.\r
+ * (But feel free to read it to get ideas on how to get the algorithm you want.)\r
+ */\r
+ public class Crypto\r
+ {\r
+ private var b64:Base64; // we don't use it, but we want the swc to include it, so cheap trick.\r
+ \r
+ public function Crypto(){\r
+ }\r
+ \r
+ /**\r
+ * Things that should work, among others:\r
+ * "aes"\r
+ * "aes-128-ecb"\r
+ * "aes-128-cbc"\r
+ * "aes-128-cfb"\r
+ * "aes-128-cfb8"\r
+ * "aes-128-ofb"\r
+ * "aes-192-cfb"\r
+ * "aes-256-ofb"\r
+ * "blowfish-cbc"\r
+ * "des-ecb"\r
+ * "xtea"\r
+ * "xtea-ecb"\r
+ * "xtea-cbc"\r
+ * "xtea-cfb"\r
+ * "xtea-cfb8"\r
+ * "xtea-ofb"\r
+ * "rc4"\r
+ * "simple-aes-cbc"\r
+ */\r
+ public static function getCipher(name:String, key:ByteArray, pad:IPad=null):ICipher {\r
+ // split name into an array.\r
+ var keys:Array = name.split("-");\r
+ switch (keys[0]) {\r
+ /**\r
+ * "simple" is a special case. It means:\r
+ * "If using an IV mode, prepend the IV to the ciphertext"\r
+ */\r
+ case "simple":\r
+ keys.shift();\r
+ name = keys.join("-");\r
+ var cipher:ICipher = getCipher(name, key, pad);\r
+ if (cipher is IVMode) {\r
+ return new SimpleIVMode(cipher as IVMode);\r
+ } else {\r
+ return cipher;\r
+ }\r
+ /**\r
+ * we support both "aes-128" and "aes128"\r
+ * Technically, you could use "aes192-128", but you'd\r
+ * only be hurting yourself.\r
+ */\r
+ case "aes":\r
+ case "aes128":\r
+ case "aes192":\r
+ case "aes256":\r
+ keys.shift();\r
+ if (key.length*8==keys[0]) {\r
+ // support for "aes-128-..." and such.\r
+ keys.shift();\r
+ }\r
+ return getMode(keys[0], new AESKey(key), pad);\r
+ break;\r
+ case "bf":\r
+ case "blowfish":\r
+ keys.shift();\r
+ return getMode(keys[0], new BlowFishKey(key), pad);\r
+ /**\r
+ * des-ede and des-ede3 are both equivalent to des3.\r
+ * the choice between 2tdes and 3tdes is made based\r
+ * on the length of the key provided.\r
+ */\r
+ case "des":\r
+ keys.shift();\r
+ if (keys[0]!="ede" && keys[0]!="ede3") {\r
+ return getMode(keys[0], new DESKey(key), pad);\r
+ }\r
+ if (keys.length==1) {\r
+ keys.push("ecb"); // default mode for 2tdes and 3tdes with openssl enc\r
+ }\r
+ // fall-through to triple des\r
+ case "3des":\r
+ case "des3":\r
+ keys.shift();\r
+ return getMode(keys[0], new TripleDESKey(key), pad);\r
+ case "xtea":\r
+ keys.shift();\r
+ return getMode(keys[0], new XTeaKey(key), pad);\r
+ break;\r
+ /**\r
+ * Technically, you could say "rc4-128" or whatever,\r
+ * but really, the length of the key is what counts here.\r
+ */\r
+ case "rc4":\r
+ keys.shift();\r
+ return new ARC4(key);\r
+ break;\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ /**\r
+ * Returns the size of a key for a given cipher identifier.\r
+ */\r
+ public static function getKeySize(name:String):uint {\r
+ var keys:Array = name.split("-");\r
+ switch (keys[0]) {\r
+ case "simple":\r
+ keys.shift();\r
+ return getKeySize(keys.join("-"));\r
+ case "aes128":\r
+ return 16;\r
+ case "aes192":\r
+ return 24;\r
+ case "aes256":\r
+ return 32;\r
+ case "aes":\r
+ keys.shift();\r
+ return parseInt(keys[0])/8;\r
+ case "bf":\r
+ case "blowfish":\r
+ return 16;\r
+ case "des":\r
+ keys.shift();\r
+ switch (keys[0]) {\r
+ case "ede":\r
+ return 16;\r
+ case "ede3":\r
+ return 24;\r
+ default:\r
+ return 8;\r
+ }\r
+ case "3des":\r
+ case "des3":\r
+ return 24;\r
+ case "xtea":\r
+ return 8;\r
+ case "rc4":\r
+ if (parseInt(keys[1])>0) {\r
+ return parseInt(keys[1])/8;\r
+ }\r
+ return 16; // why not.\r
+ }\r
+ return 0; // unknown;\r
+ }\r
+ \r
+ private static function getMode(name:String, alg:ISymmetricKey, padding:IPad=null):IMode {\r
+ switch (name) {\r
+ case "ecb":\r
+ return new ECBMode(alg, padding);\r
+ case "cfb":\r
+ return new CFBMode(alg, padding);\r
+ case "cfb8":\r
+ return new CFB8Mode(alg, padding);\r
+ case "ofb":\r
+ return new OFBMode(alg, padding);\r
+ case "ctr":\r
+ return new CTRMode(alg, padding);\r
+ case "cbc":\r
+ default:\r
+ return new CBCMode(alg, padding);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Things that should work:\r
+ * "md5"\r
+ * "sha"\r
+ * "sha1"\r
+ * "sha224"\r
+ * "sha256"\r
+ */\r
+ public static function getHash(name:String):IHash {\r
+ switch(name) {\r
+ case "md2":\r
+ return new MD2;\r
+ case "md5":\r
+ return new MD5;\r
+ case "sha": // let's hope you didn't mean sha-0\r
+ case "sha1":\r
+ return new SHA1;\r
+ case "sha224":\r
+ return new SHA224;\r
+ case "sha256":\r
+ return new SHA256;\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ /**\r
+ * Things that should work:\r
+ * "sha1"\r
+ * "md5-64"\r
+ * "hmac-md5-96"\r
+ * "hmac-sha1-128"\r
+ * "hmac-sha256-192"\r
+ * etc.\r
+ */\r
+ public static function getHMAC(name:String):HMAC {\r
+ var keys:Array = name.split("-");\r
+ if (keys[0]=="hmac") keys.shift();\r
+ var bits:uint = 0;\r
+ if (keys.length>1) {\r
+ bits = parseInt(keys[1]);\r
+ }\r
+ return new HMAC(getHash(keys[0]), bits);\r
+ }\r
+ \r
+\r
+ public static function getMAC(name:String):MAC {\r
+ \r
+ var keys:Array = name.split("-");\r
+ if (keys[0]=="mac") keys.shift();\r
+ var bits:uint = 0;\r
+ if (keys.length > 1) {\r
+ bits = parseInt(keys[1]);\r
+ }\r
+ return new MAC(getHash(keys[0]), bits);\r
+ }\r
+ \r
+ \r
+ public static function getPad(name:String):IPad {\r
+ switch(name) {\r
+ case "null":\r
+ return new NullPad;\r
+ case "pkcs5":\r
+ default:\r
+ return new PKCS5;\r
+ }\r
+ }\r
+ \r
+ /** mostly useless.\r
+ */\r
+ public static function getRSA(E:String, M:String):RSAKey {\r
+ return RSAKey.parsePublicKey(M,E);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/* THIS IS A GENERATED FILE */
+/**
+ * MozillaRootCertificates
+ *
+ * A list of built-in Certificate Authorities,
+ * pilfered from Mozilla.
+ *
+ * See certs/tool/grabRootCAs.pl for details.
+ *
+ * Copyright (c) 2007 Henri Torgemane
+ *
+ * See LICENSE.txt for full license information.
+ */
+package com.hurlant.crypto.cert {
+ public class MozillaRootCertificates extends X509CertificateCollection {
+ public function MozillaRootCertificates() {
+ super.addPEMCertificate("Verisign/RSA Secure Server CA",
+ // X500 Subject, for lookups.
+ "MF8xCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjEuMCwGA1UE"+
+ "CxMlU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG\n"+
+ "A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD\n"+
+ "VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0\n"+
+ "MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV\n"+
+ "BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy\n"+
+ "dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ\n"+
+ "ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII\n"+
+ "0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI\n"+
+ "uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI\n"+
+ "hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3\n"+
+ "YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc\n"+
+ "1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GTE CyberTrust Root CA",
+ // X500 Subject, for lookups.
+ "MEUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBD"+
+ "eWJlclRydXN0IFJvb3Q=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD\n"+
+ "VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv\n"+
+ "b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV\n"+
+ "UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU\n"+
+ "cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv\n"+
+ "RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M\n"+
+ "ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5\n"+
+ "1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz\n"+
+ "dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl\n"+
+ "IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy\n"+
+ "bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GTE CyberTrust Global Root",
+ // X500 Subject, for lookups.
+ "MHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBD"+
+ "eWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFs"+
+ "IFJvb3Q=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD\n"+
+ "VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv\n"+
+ "bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv\n"+
+ "b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV\n"+
+ "UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU\n"+
+ "cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds\n"+
+ "b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH\n"+
+ "iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS\n"+
+ "r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4\n"+
+ "04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r\n"+
+ "GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9\n"+
+ "3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P\n"+
+ "lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Thawte Personal Basic CA",
+ // X500 Subject, for lookups.
+ "MIHLMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRv"+
+ "d24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNl"+
+ "cnZpY2VzIERpdmlzaW9uMSEwHwYDVQQDExhUaGF3dGUgUGVyc29uYWwgQmFzaWMgQ0ExKDAmBgkq"+
+ "hkiG9w0BCQEWGXBlcnNvbmFsLWJhc2ljQHRoYXd0ZS5jb20=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx\n"+
+ "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD\n"+
+ "VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT\n"+
+ "ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj\n"+
+ "IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X\n"+
+ "DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw\n"+
+ "EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE\n"+
+ "ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy\n"+
+ "dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD\n"+
+ "QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN\n"+
+ "BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53\n"+
+ "dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK\n"+
+ "wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7\n"+
+ "G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF\n"+
+ "AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7\n"+
+ "c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P\n"+
+ "9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Thawte Personal Premium CA",
+ // X500 Subject, for lookups.
+ "MIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRv"+
+ "d24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNl"+
+ "cnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgG"+
+ "CSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29t",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx\n"+
+ "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD\n"+
+ "VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT\n"+
+ "ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p\n"+
+ "dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv\n"+
+ "bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa\n"+
+ "QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY\n"+
+ "BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u\n"+
+ "IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl\n"+
+ "bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu\n"+
+ "Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs\n"+
+ "Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI\n"+
+ "Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD\n"+
+ "ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG\n"+
+ "SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH\n"+
+ "b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh\n"+
+ "KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Thawte Personal Freemail CA",
+ // X500 Subject, for lookups.
+ "MIHRMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRv"+
+ "d24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNl"+
+ "cnZpY2VzIERpdmlzaW9uMSQwIgYDVQQDExtUaGF3dGUgUGVyc29uYWwgRnJlZW1haWwgQ0ExKzAp"+
+ "BgkqhkiG9w0BCQEWHHBlcnNvbmFsLWZyZWVtYWlsQHRoYXd0ZS5jb20=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx\n"+
+ "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD\n"+
+ "VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT\n"+
+ "ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt\n"+
+ "YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu\n"+
+ "Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT\n"+
+ "AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa\n"+
+ "MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp\n"+
+ "b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG\n"+
+ "cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh\n"+
+ "d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY\n"+
+ "DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E\n"+
+ "rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq\n"+
+ "uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN\n"+
+ "BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP\n"+
+ "MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa\n"+
+ "/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei\n"+
+ "gQ==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Thawte Server CA",
+ // X500 Subject, for lookups.
+ "MIHEMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRv"+
+ "d24xHTAbBgNVBAoTFFRoYXd0ZSBDb25zdWx0aW5nIGNjMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u"+
+ "IFNlcnZpY2VzIERpdmlzaW9uMRkwFwYDVQQDExBUaGF3dGUgU2VydmVyIENBMSYwJAYJKoZIhvcN"+
+ "AQkBFhdzZXJ2ZXItY2VydHNAdGhhd3RlLmNvbQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx\n"+
+ "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD\n"+
+ "VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv\n"+
+ "biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm\n"+
+ "MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx\n"+
+ "MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT\n"+
+ "DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3\n"+
+ "dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl\n"+
+ "cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3\n"+
+ "DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD\n"+
+ "gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91\n"+
+ "yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX\n"+
+ "L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj\n"+
+ "EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG\n"+
+ "7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e\n"+
+ "QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ\n"+
+ "qdq5snUb9kLy78fyGPmJvKP/iiMucEc=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Thawte Premium Server CA",
+ // X500 Subject, for lookups.
+ "MIHOMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRv"+
+ "d24xHTAbBgNVBAoTFFRoYXd0ZSBDb25zdWx0aW5nIGNjMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u"+
+ "IFNlcnZpY2VzIERpdmlzaW9uMSEwHwYDVQQDExhUaGF3dGUgUHJlbWl1bSBTZXJ2ZXIgQ0ExKDAm"+
+ "BgkqhkiG9w0BCQEWGXByZW1pdW0tc2VydmVyQHRoYXd0ZS5jb20=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx\n"+
+ "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD\n"+
+ "VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv\n"+
+ "biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy\n"+
+ "dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t\n"+
+ "MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB\n"+
+ "MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG\n"+
+ "A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp\n"+
+ "b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl\n"+
+ "cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv\n"+
+ "bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE\n"+
+ "VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ\n"+
+ "ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR\n"+
+ "uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG\n"+
+ "9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n"+
+ "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM\n"+
+ "pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Equifax Secure CA",
+ // X500 Subject, for lookups.
+ "ME4xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3Vy"+
+ "ZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHk=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV\n"+
+ "UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy\n"+
+ "dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1\n"+
+ "MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx\n"+
+ "dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B\n"+
+ "AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f\n"+
+ "BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A\n"+
+ "cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC\n"+
+ "AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ\n"+
+ "MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm\n"+
+ "aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw\n"+
+ "ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj\n"+
+ "IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF\n"+
+ "MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA\n"+
+ "A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n"+
+ "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh\n"+
+ "1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("ABAecom (sub., Am. Bankers Assn.) Root CA",
+ // X500 Subject, for lookups.
+ "MIGJMQswCQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNV"+
+ "BAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcN"+
+ "AQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw\n"+
+ "gYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2FzaGluZ3Rv\n"+
+ "bjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFCQS5FQ09NIFJv\n"+
+ "b3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3RydXN0LmNvbTAeFw05\n"+
+ "OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQswCQYDVQQGEwJVUzELMAkG\n"+
+ "A1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNVBAoTDkFCQS5FQ09N\n"+
+ "LCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcNAQkB\n"+
+ "FhVhZG1pbkBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n"+
+ "ggEKAoIBAQCx0xHgeVVDBwhMywVCAOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM\n"+
+ "0KLMsFWWU4RmBQDaREmA2FQKpSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFG\n"+
+ "PR7wuSw0X4x8TAgpnUBV6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGU\n"+
+ "LOR4SCQaJRk665WcOQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZs\n"+
+ "iSrK2jMTecJVjO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU\n"+
+ "+/94Qby9cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYB\n"+
+ "Af8CAQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k\n"+
+ "qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvTZOir\n"+
+ "vRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHegTYjHInYZ\n"+
+ "w8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm/lowdiT/QHI8\n"+
+ "eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgxfexgeqMiKL0ZJGA/\n"+
+ "O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJTzFxiNmIf1Q=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Digital Signature Trust Co. Global CA 1",
+ // X500 Subject, for lookups.
+ "MEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xETAP"+
+ "BgNVBAsTCERTVENBIEUx",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV\n"+
+ "UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL\n"+
+ "EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ\n"+
+ "BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x\n"+
+ "ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg\n"+
+ "bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ\n"+
+ "j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV\n"+
+ "Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG\n"+
+ "SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx\n"+
+ "JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI\n"+
+ "RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw\n"+
+ "MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5\n"+
+ "fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i\n"+
+ "+DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG\n"+
+ "SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN\n"+
+ "QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+\n"+
+ "gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Digital Signature Trust Co. Global CA 3",
+ // X500 Subject, for lookups.
+ "MEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xETAP"+
+ "BgNVBAsTCERTVENBIEUy",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV\n"+
+ "UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL\n"+
+ "EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ\n"+
+ "BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x\n"+
+ "ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/\n"+
+ "k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso\n"+
+ "LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o\n"+
+ "TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG\n"+
+ "SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx\n"+
+ "JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI\n"+
+ "RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3\n"+
+ "MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C\n"+
+ "TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5\n"+
+ "WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG\n"+
+ "SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR\n"+
+ "xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL\n"+
+ "B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Digital Signature Trust Co. Global CA 2",
+ // X500 Subject, for lookups.
+ "MIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx"+
+ "JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx"+
+ "FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNv"+
+ "bQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw\n"+
+ "CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp\n"+
+ "dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE\n"+
+ "CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B\n"+
+ "CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx\n"+
+ "ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO\n"+
+ "U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0\n"+
+ "IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx\n"+
+ "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN\n"+
+ "AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf\n"+
+ "WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK\n"+
+ "xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE\n"+
+ "zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F\n"+
+ "5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv\n"+
+ "OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG\n"+
+ "9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz\n"+
+ "ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME\n"+
+ "lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG\n"+
+ "Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q\n"+
+ "gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k\n"+
+ "Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Digital Signature Trust Co. Global CA 4",
+ // X500 Subject, for lookups.
+ "MIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx"+
+ "JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx"+
+ "FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNv"+
+ "bQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw\n"+
+ "CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp\n"+
+ "dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE\n"+
+ "CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B\n"+
+ "CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy\n"+
+ "MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO\n"+
+ "U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0\n"+
+ "IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx\n"+
+ "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN\n"+
+ "AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV\n"+
+ "p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw\n"+
+ "BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl\n"+
+ "5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi\n"+
+ "3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+\n"+
+ "QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG\n"+
+ "9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ\n"+
+ "2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN\n"+
+ "I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL\n"+
+ "553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q\n"+
+ "10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN\n"+
+ "uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 1 Public Primary Certification Authority",
+ // X500 Subject, for lookups.
+ "MF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3Mg"+
+ "MSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ\n"+
+ "BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh\n"+
+ "c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05\n"+
+ "NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD\n"+
+ "VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp\n"+
+ "bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB\n"+
+ "jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N\n"+
+ "H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR\n"+
+ "4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN\n"+
+ "BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo\n"+
+ "EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5\n"+
+ "FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx\n"+
+ "lA==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 2 Public Primary Certification Authority",
+ // X500 Subject, for lookups.
+ "MF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3Mg"+
+ "MiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG\n"+
+ "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n"+
+ "cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2\n"+
+ "MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV\n"+
+ "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt\n"+
+ "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN\n"+
+ "ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh\n"+
+ "YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7\n"+
+ "FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G\n"+
+ "CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg\n"+
+ "J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc\n"+
+ "r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 3 Public Primary Certification Authority",
+ // X500 Subject, for lookups.
+ "MF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3Mg"+
+ "MyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG\n"+
+ "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n"+
+ "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2\n"+
+ "MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV\n"+
+ "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt\n"+
+ "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN\n"+
+ "ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE\n"+
+ "BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is\n"+
+ "I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G\n"+
+ "CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do\n"+
+ "lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc\n"+
+ "AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 1 Public Primary Certification Authority - G2",
+ // X500 Subject, for lookups.
+ "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNz"+
+ "IDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx"+
+ "KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UE"+
+ "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yaw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ\n"+
+ "BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh\n"+
+ "c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy\n"+
+ "MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp\n"+
+ "emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X\n"+
+ "DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw\n"+
+ "FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg\n"+
+ "UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo\n"+
+ "YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5\n"+
+ "MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB\n"+
+ "AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK\n"+
+ "VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm\n"+
+ "Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID\n"+
+ "AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J\n"+
+ "h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul\n"+
+ "uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68\n"+
+ "DzFc6PLZ\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 2 Public Primary Certification Authority - G2",
+ // X500 Subject, for lookups.
+ "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNz"+
+ "IDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx"+
+ "KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UE"+
+ "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yaw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw\n"+
+ "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns\n"+
+ "YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH\n"+
+ "MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y\n"+
+ "aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe\n"+
+ "Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX\n"+
+ "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj\n"+
+ "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx\n"+
+ "KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s\n"+
+ "eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B\n"+
+ "AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM\n"+
+ "HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw\n"+
+ "DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC\n"+
+ "AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji\n"+
+ "nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX\n"+
+ "rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn\n"+
+ "jBJ7xUS0rg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 3 Public Primary Certification Authority - G2",
+ // X500 Subject, for lookups.
+ "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNz"+
+ "IDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx"+
+ "KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UE"+
+ "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yaw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ\n"+
+ "BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh\n"+
+ "c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy\n"+
+ "MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp\n"+
+ "emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X\n"+
+ "DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw\n"+
+ "FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg\n"+
+ "UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo\n"+
+ "YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5\n"+
+ "MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB\n"+
+ "AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4\n"+
+ "pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0\n"+
+ "13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID\n"+
+ "AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk\n"+
+ "U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i\n"+
+ "F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY\n"+
+ "oJ2daZH9\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 4 Public Primary Certification Authority - G2",
+ // X500 Subject, for lookups.
+ "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNz"+
+ "IDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx"+
+ "KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UE"+
+ "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yaw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ\n"+
+ "BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh\n"+
+ "c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy\n"+
+ "MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp\n"+
+ "emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X\n"+
+ "DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw\n"+
+ "FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg\n"+
+ "UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo\n"+
+ "YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5\n"+
+ "MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB\n"+
+ "AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM\n"+
+ "HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK\n"+
+ "qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID\n"+
+ "AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj\n"+
+ "cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y\n"+
+ "cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP\n"+
+ "T8qAkbYp\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GlobalSign Root CA",
+ // X500 Subject, for lookups.
+ "MFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290"+
+ "IENBMRswGQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0E=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG\n"+
+ "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"+
+ "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n"+
+ "MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"+
+ "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n"+
+ "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n"+
+ "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n"+
+ "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n"+
+ "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n"+
+ "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n"+
+ "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n"+
+ "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU\n"+
+ "YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n"+
+ "AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7\n"+
+ "5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q\n"+
+ "gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR\n"+
+ "rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7\n"+
+ "ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o\n"+
+ "Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GlobalSign Root CA - R2",
+ // X500 Subject, for lookups.
+ "MEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFIyMRMwEQYDVQQKEwpHbG9iYWxTaWdu"+
+ "MRMwEQYDVQQDEwpHbG9iYWxTaWdu",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\n"+
+ "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\n"+
+ "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\n"+
+ "MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\n"+
+ "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n"+
+ "hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\n"+
+ "v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\n"+
+ "eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\n"+
+ "tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n"+
+ "C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\n"+
+ "zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\n"+
+ "mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\n"+
+ "V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\n"+
+ "bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n"+
+ "3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\n"+
+ "J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n"+
+ "291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\n"+
+ "ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n"+
+ "AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n"+
+ "TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("ValiCert Class 1 VA",
+ // X500 Subject, for lookups.
+ "MIG7MSQwIgYDVQQHExtWYWxpQ2VydCBWYWxpZGF0aW9uIE5ldHdvcmsxFzAVBgNVBAoTDlZhbGlD"+
+ "ZXJ0LCBJbmMuMTUwMwYDVQQLEyxWYWxpQ2VydCBDbGFzcyAxIFBvbGljeSBWYWxpZGF0aW9uIEF1"+
+ "dGhvcml0eTEhMB8GA1UEAxMYaHR0cDovL3d3dy52YWxpY2VydC5jb20vMSAwHgYJKoZIhvcNAQkB"+
+ "FhFpbmZvQHZhbGljZXJ0LmNvbQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n"+
+ "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz\n"+
+ "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y\n"+
+ "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG\n"+
+ "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy\n"+
+ "NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y\n"+
+ "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs\n"+
+ "YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\n"+
+ "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\n"+
+ "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y\n"+
+ "LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+\n"+
+ "TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y\n"+
+ "TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0\n"+
+ "LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW\n"+
+ "I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw\n"+
+ "nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("ValiCert Class 2 VA",
+ // X500 Subject, for lookups.
+ "MIG7MSQwIgYDVQQHExtWYWxpQ2VydCBWYWxpZGF0aW9uIE5ldHdvcmsxFzAVBgNVBAoTDlZhbGlD"+
+ "ZXJ0LCBJbmMuMTUwMwYDVQQLEyxWYWxpQ2VydCBDbGFzcyAyIFBvbGljeSBWYWxpZGF0aW9uIEF1"+
+ "dGhvcml0eTEhMB8GA1UEAxMYaHR0cDovL3d3dy52YWxpY2VydC5jb20vMSAwHgYJKoZIhvcNAQkB"+
+ "FhFpbmZvQHZhbGljZXJ0LmNvbQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n"+
+ "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz\n"+
+ "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y\n"+
+ "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG\n"+
+ "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy\n"+
+ "NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y\n"+
+ "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs\n"+
+ "YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\n"+
+ "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\n"+
+ "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY\n"+
+ "dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9\n"+
+ "WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS\n"+
+ "v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v\n"+
+ "UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu\n"+
+ "IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n"+
+ "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("RSA Root Certificate 1",
+ // X500 Subject, for lookups.
+ "MIG7MSQwIgYDVQQHExtWYWxpQ2VydCBWYWxpZGF0aW9uIE5ldHdvcmsxFzAVBgNVBAoTDlZhbGlD"+
+ "ZXJ0LCBJbmMuMTUwMwYDVQQLEyxWYWxpQ2VydCBDbGFzcyAzIFBvbGljeSBWYWxpZGF0aW9uIEF1"+
+ "dGhvcml0eTEhMB8GA1UEAxMYaHR0cDovL3d3dy52YWxpY2VydC5jb20vMSAwHgYJKoZIhvcNAQkB"+
+ "FhFpbmZvQHZhbGljZXJ0LmNvbQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n"+
+ "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz\n"+
+ "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y\n"+
+ "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG\n"+
+ "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy\n"+
+ "NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y\n"+
+ "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs\n"+
+ "YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\n"+
+ "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\n"+
+ "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD\n"+
+ "cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs\n"+
+ "2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY\n"+
+ "JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE\n"+
+ "Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ\n"+
+ "n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A\n"+
+ "PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 1 Public Primary Certification Authority - G3",
+ // X500 Subject, for lookups.
+ "MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT"+
+ "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9y"+
+ "IGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy"+
+ "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw\n"+
+ "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n"+
+ "cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu\n"+
+ "LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT\n"+
+ "aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\n"+
+ "dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD\n"+
+ "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT\n"+
+ "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ\n"+
+ "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu\n"+
+ "IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\n"+
+ "LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4\n"+
+ "nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO\n"+
+ "8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV\n"+
+ "ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb\n"+
+ "PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2\n"+
+ "6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr\n"+
+ "n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a\n"+
+ "qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4\n"+
+ "wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3\n"+
+ "ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs\n"+
+ "pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4\n"+
+ "E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 2 Public Primary Certification Authority - G3",
+ // X500 Subject, for lookups.
+ "MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT"+
+ "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9y"+
+ "IGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDIgUHVibGljIFBy"+
+ "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ\n"+
+ "BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy\n"+
+ "aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s\n"+
+ "IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp\n"+
+ "Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0\n"+
+ "eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV\n"+
+ "BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp\n"+
+ "Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu\n"+
+ "Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g\n"+
+ "Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt\n"+
+ "IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU\n"+
+ "J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO\n"+
+ "JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY\n"+
+ "wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o\n"+
+ "koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN\n"+
+ "qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E\n"+
+ "Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe\n"+
+ "xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u\n"+
+ "7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU\n"+
+ "sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI\n"+
+ "sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP\n"+
+ "cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 3 Public Primary Certification Authority - G3",
+ // X500 Subject, for lookups.
+ "MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT"+
+ "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9y"+
+ "IGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy"+
+ "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw\n"+
+ "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n"+
+ "cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu\n"+
+ "LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT\n"+
+ "aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\n"+
+ "dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD\n"+
+ "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT\n"+
+ "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ\n"+
+ "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu\n"+
+ "IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\n"+
+ "LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b\n"+
+ "N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t\n"+
+ "KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu\n"+
+ "kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm\n"+
+ "CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ\n"+
+ "Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu\n"+
+ "imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te\n"+
+ "2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe\n"+
+ "DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC\n"+
+ "/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p\n"+
+ "F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt\n"+
+ "TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Class 4 Public Primary Certification Authority - G3",
+ // X500 Subject, for lookups.
+ "MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT"+
+ "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9y"+
+ "IGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy"+
+ "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw\n"+
+ "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n"+
+ "cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu\n"+
+ "LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT\n"+
+ "aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\n"+
+ "dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD\n"+
+ "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT\n"+
+ "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ\n"+
+ "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu\n"+
+ "IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\n"+
+ "LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1\n"+
+ "GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ\n"+
+ "+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd\n"+
+ "U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm\n"+
+ "NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY\n"+
+ "ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/\n"+
+ "ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1\n"+
+ "CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq\n"+
+ "g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm\n"+
+ "fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c\n"+
+ "2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/\n"+
+ "bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Entrust.net Secure Server CA",
+ // X500 Subject, for lookups.
+ "MIHDMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRy"+
+ "dXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg"+
+ "MTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2Vy"+
+ "dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC\n"+
+ "VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u\n"+
+ "ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc\n"+
+ "KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u\n"+
+ "ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1\n"+
+ "MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE\n"+
+ "ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j\n"+
+ "b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF\n"+
+ "bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg\n"+
+ "U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA\n"+
+ "A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/\n"+
+ "I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3\n"+
+ "wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC\n"+
+ "AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb\n"+
+ "oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5\n"+
+ "BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p\n"+
+ "dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk\n"+
+ "MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\n"+
+ "b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu\n"+
+ "dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0\n"+
+ "MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi\n"+
+ "E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa\n"+
+ "MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI\n"+
+ "hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN\n"+
+ "95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd\n"+
+ "2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Entrust.net Secure Personal CA",
+ // X500 Subject, for lookups.
+ "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRy"+
+ "dXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl"+
+ "MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u"+
+ "ZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC\n"+
+ "VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u\n"+
+ "ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh\n"+
+ "Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV\n"+
+ "BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n"+
+ "Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU\n"+
+ "MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D\n"+
+ "bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl\n"+
+ "MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq\n"+
+ "RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G\n"+
+ "CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo\n"+
+ "6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux\n"+
+ "5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm\n"+
+ "AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC\n"+
+ "ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50\n"+
+ "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m\n"+
+ "by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp\n"+
+ "IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg\n"+
+ "Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg\n"+
+ "KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV\n"+
+ "HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E\n"+
+ "BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE\n"+
+ "FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA\n"+
+ "BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7\n"+
+ "pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz\n"+
+ "wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a\n"+
+ "EkP/TOYGJqibGapEPHayXOw=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Entrust.net Premium 2048 Secure Server CA",
+ // X500 Subject, for lookups.
+ "MIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18y"+
+ "MDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50"+
+ "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRo"+
+ "b3JpdHkgKDIwNDgp",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML\n"+
+ "RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp\n"+
+ "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5\n"+
+ "IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp\n"+
+ "ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy\n"+
+ "MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3\n"+
+ "LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp\n"+
+ "YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG\n"+
+ "A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp\n"+
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq\n"+
+ "K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe\n"+
+ "sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX\n"+
+ "MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT\n"+
+ "XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/\n"+
+ "HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n"+
+ "4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA\n"+
+ "vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G\n"+
+ "CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA\n"+
+ "WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo\n"+
+ "oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ\n"+
+ "h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18\n"+
+ "f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN\n"+
+ "B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy\n"+
+ "vUxFnmG6v4SBkgPR0ml8xQ==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Baltimore CyberTrust Root",
+ // X500 Subject, for lookups.
+ "MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3Qx"+
+ "IjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n"+
+ "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n"+
+ "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n"+
+ "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n"+
+ "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n"+
+ "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n"+
+ "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n"+
+ "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n"+
+ "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n"+
+ "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n"+
+ "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n"+
+ "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n"+
+ "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n"+
+ "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n"+
+ "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n"+
+ "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n"+
+ "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n"+
+ "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n"+
+ "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Equifax Secure Global eBusiness CA",
+ // X500 Subject, for lookups.
+ "MFoxCzAJBgNVBAYTAlVTMRwwGgYDVQQKExNFcXVpZmF4IFNlY3VyZSBJbmMuMS0wKwYDVQQDEyRF"+
+ "cXVpZmF4IFNlY3VyZSBHbG9iYWwgZUJ1c2luZXNzIENBLTE=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc\n"+
+ "MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT\n"+
+ "ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw\n"+
+ "MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj\n"+
+ "dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l\n"+
+ "c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC\n"+
+ "UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc\n"+
+ "58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/\n"+
+ "o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH\n"+
+ "MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr\n"+
+ "aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA\n"+
+ "A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA\n"+
+ "Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv\n"+
+ "8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Equifax Secure eBusiness CA 1",
+ // X500 Subject, for lookups.
+ "MFMxCzAJBgNVBAYTAlVTMRwwGgYDVQQKExNFcXVpZmF4IFNlY3VyZSBJbmMuMSYwJAYDVQQDEx1F"+
+ "cXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc\n"+
+ "MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT\n"+
+ "ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw\n"+
+ "MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j\n"+
+ "LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ\n"+
+ "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo\n"+
+ "RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu\n"+
+ "WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw\n"+
+ "Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD\n"+
+ "AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK\n"+
+ "eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM\n"+
+ "zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+\n"+
+ "WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN\n"+
+ "/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Equifax Secure eBusiness CA 2",
+ // X500 Subject, for lookups.
+ "ME4xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5FcXVpZmF4IFNlY3VyZTEmMCQGA1UECxMdRXF1aWZh"+
+ "eCBTZWN1cmUgZUJ1c2luZXNzIENBLTI=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV\n"+
+ "UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj\n"+
+ "dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0\n"+
+ "NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD\n"+
+ "VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B\n"+
+ "AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G\n"+
+ "vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/\n"+
+ "BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C\n"+
+ "AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX\n"+
+ "MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl\n"+
+ "IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw\n"+
+ "NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq\n"+
+ "y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF\n"+
+ "MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA\n"+
+ "A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy\n"+
+ "0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1\n"+
+ "E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Visa International Global Root 2",
+ // X500 Subject, for lookups.
+ "MGExCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQLEyZWaXNhIEludGVybmF0aW9u"+
+ "YWwgU2VydmljZSBBc3NvY2lhdGlvbjESMBAGA1UEAxMJR1AgUm9vdCAy",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx\n"+
+ "DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2\n"+
+ "aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1\n"+
+ "MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT\n"+
+ "QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp\n"+
+ "b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n"+
+ "AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX\n"+
+ "ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i\n"+
+ "/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU\n"+
+ "58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g\n"+
+ "halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E\n"+
+ "1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/\n"+
+ "ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG\n"+
+ "MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb\n"+
+ "mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ\n"+
+ "kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN\n"+
+ "dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ\n"+
+ "ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn\n"+
+ "B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("beTRUSTed Root CA",
+ // X500 Subject, for lookups.
+ "MFoxCzAJBgNVBAYTAldXMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAMTEmJlVFJVU1RlZCBS"+
+ "b290IENBczEaMBgGA1UEAxMRYmVUUlVTVGVkIFJvb3QgQ0E=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJX\n"+
+ "VzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQgUm9vdCBD\n"+
+ "QXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYyMDE0MjEwNFoX\n"+
+ "DTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNVBAoTCWJlVFJVU1Rl\n"+
+ "ZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRowGAYDVQQDExFiZVRSVVNU\n"+
+ "ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS0c3oT\n"+
+ "CjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4SP+00PpeQY1hRIfo7clY+vyTmt9P\n"+
+ "6j41ffgzeubx181vSUs9Ty1uDoM6GHh3o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwM\n"+
+ "jmVZxXH/YgmPqsWPzGCgc0rXOD8Vcr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX\n"+
+ "2P8ZDoMbjNx4RWc0PfSvHI3kbWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2N\n"+
+ "R47rtMNE5qdMf1ZD6Li8tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5j\n"+
+ "rEq2I8QBoa2k5MUCAwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNV\n"+
+ "HSAEggFQMIIBTDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQa\n"+
+ "gfFSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1\n"+
+ "bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0\n"+
+ "ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9uIHBy\n"+
+ "YWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJlVFJVU1Rl\n"+
+ "ZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rl\n"+
+ "cm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0\n"+
+ "L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYDVQQKEwliZVRSVVNUZWQx\n"+
+ "CzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub2M3eKjEENGvKBxirZzAfBgNV\n"+
+ "HSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxirZzAOBgNVHQ8BAf8EBAMCAf4wDQYJ\n"+
+ "KoZIhvcNAQEFBQADggEBAHlh26Nebhax6nZR+csVm8tpvuaBa58oH2U+3RGFktTo\n"+
+ "Qb9+M70j5/Egv6S0phkBxoyNNXxlpE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2\n"+
+ "jCBHOElQBp1yZzrwmAOtlmdE/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe\n"+
+ "1lMBzW1MaFVA4e5rxyoAAEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5\n"+
+ "mlWXKWWuGVUlBXJH0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYc\n"+
+ "tmBjRYoQtLpGEK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("AddTrust Low-Value Services Root",
+ // X500 Subject, for lookups.
+ "MGUxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg"+
+ "VFRQIE5ldHdvcmsxITAfBgNVBAMTGEFkZFRydXN0IENsYXNzIDEgQ0EgUm9vdA==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU\n"+
+ "MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3\n"+
+ "b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw\n"+
+ "MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\n"+
+ "QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD\n"+
+ "VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA\n"+
+ "A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul\n"+
+ "CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n\n"+
+ "tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl\n"+
+ "dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch\n"+
+ "PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC\n"+
+ "+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O\n"+
+ "BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E\n"+
+ "BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl\n"+
+ "MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk\n"+
+ "ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB\n"+
+ "IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X\n"+
+ "7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz\n"+
+ "43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY\n"+
+ "eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl\n"+
+ "pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA\n"+
+ "WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("AddTrust External Root",
+ // X500 Subject, for lookups.
+ "MG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3Qg"+
+ "RXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3Q=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU\n"+
+ "MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs\n"+
+ "IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290\n"+
+ "MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux\n"+
+ "FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h\n"+
+ "bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v\n"+
+ "dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt\n"+
+ "H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9\n"+
+ "uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX\n"+
+ "mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX\n"+
+ "a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN\n"+
+ "E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0\n"+
+ "WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD\n"+
+ "VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0\n"+
+ "Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n"+
+ "cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx\n"+
+ "IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN\n"+
+ "AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH\n"+
+ "YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5\n"+
+ "6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC\n"+
+ "Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX\n"+
+ "c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a\n"+
+ "mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("AddTrust Public Services Root",
+ // X500 Subject, for lookups.
+ "MGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg"+
+ "VFRQIE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU\n"+
+ "MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3\n"+
+ "b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx\n"+
+ "MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB\n"+
+ "ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV\n"+
+ "BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC\n"+
+ "AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV\n"+
+ "6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX\n"+
+ "GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP\n"+
+ "dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH\n"+
+ "1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF\n"+
+ "62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW\n"+
+ "BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw\n"+
+ "AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL\n"+
+ "MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU\n"+
+ "cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv\n"+
+ "b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6\n"+
+ "IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/\n"+
+ "iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao\n"+
+ "GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh\n"+
+ "4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm\n"+
+ "XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("AddTrust Qualified Certificates Root",
+ // X500 Subject, for lookups.
+ "MGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg"+
+ "VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU\n"+
+ "MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3\n"+
+ "b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1\n"+
+ "MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK\n"+
+ "EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh\n"+
+ "BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B\n"+
+ "AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq\n"+
+ "xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G\n"+
+ "87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i\n"+
+ "2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U\n"+
+ "WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1\n"+
+ "0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G\n"+
+ "A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T\n"+
+ "AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr\n"+
+ "pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL\n"+
+ "ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm\n"+
+ "aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv\n"+
+ "hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm\n"+
+ "hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X\n"+
+ "dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3\n"+
+ "P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y\n"+
+ "iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no\n"+
+ "xqE=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Verisign Time Stamping Authority CA",
+ // X500 Subject, for lookups.
+ "MIGlMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0"+
+ "d29yazE7MDkGA1UECxMyVGVybXMgb2YgdXNlIGF0IGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9y"+
+ "cGEgKGMpMDAxLDAqBgNVBAMTI1ZlcmlTaWduIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5IENB",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUFADCB\n"+
+ "wTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTwwOgYDVQQL\n"+
+ "EzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n"+
+ "IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1\n"+
+ "dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv\n"+
+ "cmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1OTU5WjCBpTEXMBUGA1UEChMO\n"+
+ "VmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx\n"+
+ "OzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5j\n"+
+ "b20vcnBhIChjKTAwMSwwKgYDVQQDEyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1\n"+
+ "dGhvcml0eSBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVli\n"+
+ "zrQJIkRpivglWtvtDbc2fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU\n"+
+ "/OB4naCTuQk9I1F/RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11\n"+
+ "S7zi6ESHzeZBCiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/\n"+
+ "AgEAMEUGA1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0\n"+
+ "dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0\n"+
+ "cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIGCCsG\n"+
+ "AQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n"+
+ "b20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2DcIBcBlK0lRW\n"+
+ "HqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQnKeg3S/LvRJdrF1Ea\n"+
+ "w1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937ntag+RaypJXUie28/sJyU\n"+
+ "58dzq6wf7iWbwBbtt8pb8BQ=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Thawte Time Stamping CA",
+ // X500 Subject, for lookups.
+ "MIGLMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52"+
+ "aWxsZTEPMA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRUaGF3dGUgQ2VydGlmaWNhdGlvbjEfMB0G"+
+ "A1UEAxMWVGhhd3RlIFRpbWVzdGFtcGluZyBDQQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx\n"+
+ "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN\n"+
+ "BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd\n"+
+ "BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN\n"+
+ "MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g\n"+
+ "Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG\n"+
+ "A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l\n"+
+ "c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT\n"+
+ "6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa\n"+
+ "Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL\n"+
+ "8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB\n"+
+ "Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC\n"+
+ "9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ\n"+
+ "pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ\n"+
+ "CayJSdM=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Entrust.net Global Secure Server CA",
+ // X500 Subject, for lookups.
+ "MIG6MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9D"+
+ "UFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRy"+
+ "dXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRp"+
+ "ZmljYXRpb24gQXV0aG9yaXR5",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UEChML\n"+
+ "RW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xfQ1BTIGlu\n"+
+ "Y29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg\n"+
+ "RW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJl\n"+
+ "IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDQxNzIwMDBa\n"+
+ "Fw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE/MD0GA1UE\n"+
+ "CxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p\n"+
+ "dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVk\n"+
+ "MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\n"+
+ "b24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO\n"+
+ "8GCGD9JYf9Mzly0XonUwtZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaB\n"+
+ "bL3+qPZ1V1eMkGxKwz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2\n"+
+ "dWcTC5/oVzbIXQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4\n"+
+ "QgEBBAQDAgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoT\n"+
+ "C0VudHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp\n"+
+ "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw\n"+
+ "IEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0IFNlY3Vy\n"+
+ "ZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEw\n"+
+ "KwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIwNDE3NTAwMFowCwYD\n"+
+ "VR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc/vuLkpyw8m4iMB0GA1Ud\n"+
+ "DgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2\n"+
+ "fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBi24GRzsia\n"+
+ "d0Iv7L0no1MPUBvqTpLwqa+poLpIYcvvyQbvH9X07t9WLebKahlzqlO+krNQAraF\n"+
+ "JnJj2HVQYnUUt7NQGj/KEQALhUVpbbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1U\n"+
+ "yrrJzOCE98g+EZfTYAkYvAX/bIkz8OwVDw==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Entrust.net Global Secure Personal CA",
+ // X500 Subject, for lookups.
+ "MIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0Ff"+
+ "Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAgRW50"+
+ "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRp"+
+ "b24gQXV0aG9yaXR5",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UEChML\n"+
+ "RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NBX0NQUyBp\n"+
+ "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw\n"+
+ "IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVu\n"+
+ "dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDcxNjE2NDBaFw0yMDAy\n"+
+ "MDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3\n"+
+ "LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp\n"+
+ "YWIuKTElMCMGA1UECxMcKGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG\n"+
+ "A1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n"+
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7Ny\n"+
+ "Spj10InJrWPNTTVRaoTUrcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0\n"+
+ "iJBeAZfv6lOm3fzB3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn\n"+
+ "5JVn1j+SgF7yNH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHd\n"+
+ "BgNVHR8EgdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0\n"+
+ "MUAwPgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy\n"+
+ "ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5l\n"+
+ "dCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2VydGlmaWNh\n"+
+ "dGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAy\n"+
+ "MDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQDAgEGMB8GA1UdIwQY\n"+
+ "MBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQWBBSEi3T9xY3A/ydtIDdF\n"+
+ "fP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4w\n"+
+ "AwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWAO9GK9Q6nIMstZVXQkvTnhLUGJoMS\n"+
+ "hAusO7JE7r3PQNsgDrpuFOow4DtifH+La3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/\n"+
+ "GpsKkMWr2tGzhtQvJFJcem3G8v7lTRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKd\n"+
+ "zmVml64mXg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("AOL Time Warner Root Certification Authority 1",
+ // X500 Subject, for lookups.
+ "MIGDMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUQU9MIFRpbWUgV2FybmVyIEluYy4xHDAaBgNVBAsT"+
+ "E0FtZXJpY2EgT25saW5lIEluYy4xNzA1BgNVBAMTLkFPTCBUaW1lIFdhcm5lciBSb290IENlcnRp"+
+ "ZmljYXRpb24gQXV0aG9yaXR5IDE=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx\n"+
+ "HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh\n"+
+ "IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0\n"+
+ "aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1\n"+
+ "MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg\n"+
+ "SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M\n"+
+ "IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw\n"+
+ "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U\n"+
+ "0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI\n"+
+ "TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf\n"+
+ "RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF\n"+
+ "zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh\n"+
+ "BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA\n"+
+ "AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY\n"+
+ "PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/\n"+
+ "BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn\n"+
+ "9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT\n"+
+ "Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF\n"+
+ "Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX\n"+
+ "n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW\n"+
+ "H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("AOL Time Warner Root Certification Authority 2",
+ // X500 Subject, for lookups.
+ "MIGDMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUQU9MIFRpbWUgV2FybmVyIEluYy4xHDAaBgNVBAsT"+
+ "E0FtZXJpY2EgT25saW5lIEluYy4xNzA1BgNVBAMTLkFPTCBUaW1lIFdhcm5lciBSb290IENlcnRp"+
+ "ZmljYXRpb24gQXV0aG9yaXR5IDI=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx\n"+
+ "HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh\n"+
+ "IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0\n"+
+ "aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz\n"+
+ "NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg\n"+
+ "SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M\n"+
+ "IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw\n"+
+ "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ\n"+
+ "7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb\n"+
+ "m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY\n"+
+ "xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ\n"+
+ "YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq\n"+
+ "JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx\n"+
+ "I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz\n"+
+ "kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh\n"+
+ "EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S\n"+
+ "Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM\n"+
+ "gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu\n"+
+ "rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\n"+
+ "FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO\n"+
+ "1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu\n"+
+ "h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP\n"+
+ "yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q\n"+
+ "7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT\n"+
+ "RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/\n"+
+ "ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB\n"+
+ "M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ\n"+
+ "my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO\n"+
+ "AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT\n"+
+ "9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H\n"+
+ "hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5\n"+
+ "fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("beTRUSTed Root CA-Baltimore Implementation",
+ // X500 Subject, for lookups.
+ "MGYxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYD"+
+ "VQQDEypiZVRSVVNUZWQgUm9vdCBDQS1CYWx0aW1vcmUgSW1wbGVtZW50YXRpb24=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli\n"+
+ "ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq\n"+
+ "YmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0aW9uMB4XDTAy\n"+
+ "MDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UEChMJYmVUUlVTVGVk\n"+
+ "MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl\n"+
+ "ZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN\n"+
+ "AQEBBQADggEPADCCAQoCggEBALx+xDmcjOPWHIb/ymKt4H8wRXqOGrO4x/nRNv8i\n"+
+ "805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R9U+jK7wYFuK13XneIviCfsuBH/0nLI/6\n"+
+ "l2Qijvj/YaOcGx6Sj8CoCd8JEey3fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92B\n"+
+ "FODEPM2dMPgwqZfT7syj0B9fHBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+Ymp\n"+
+ "kbIq2eszh+6l/ePazIjmiSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7\n"+
+ "eHgZFLL8kFKJOGJgB7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIa\n"+
+ "MA8GA1UdEwEB/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4A\n"+
+ "AAEJKIORMTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3Ig\n"+
+ "dXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu\n"+
+ "dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk\n"+
+ "IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmljYXRpb24g\n"+
+ "UHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1l\n"+
+ "bnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVTVGVkIHdlYiBzaXRl\n"+
+ "LCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVjdHNfc2VydmljZXMvaW5k\n"+
+ "ZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3dy5iZXRydXN0ZWQuY29tL3By\n"+
+ "b2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwHQYDVR0OBBYEFEU9w6nR3D8kVpgc\n"+
+ "cxiIav+DR+22MB8GA1UdIwQYMBaAFEU9w6nR3D8kVpgccxiIav+DR+22MA4GA1Ud\n"+
+ "DwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCA\n"+
+ "WXf82n+0S9/DZEtqTg6t8n1ZdwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu6\n"+
+ "7RMdmgduyzFiEuhjA6p9beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AY\n"+
+ "gkHNZTfqjjJ+vWuZXTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb\n"+
+ "4cV97yHgjQ5dUX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9\n"+
+ "CReJf8Py05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("beTRUSTed Root CA - Entrust Implementation",
+ // X500 Subject, for lookups.
+ "MGYxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYD"+
+ "VQQDEypiZVRSVVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli\n"+
+ "ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq\n"+
+ "YmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0aW9uMB4XDTAy\n"+
+ "MDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UEChMJYmVUUlVTVGVk\n"+
+ "MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl\n"+
+ "ZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN\n"+
+ "AQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1Q+xVkrYwfTVXDNvzDSduTPdQqJtO\n"+
+ "K2/b9a0cS12zqcH+e0TrW6MFDR/FNCswACnxeECypP869AGIF37m1CbTukzqMvtD\n"+
+ "d5eHI8XbQ6P1KqNRXuE70mVpflUVm3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdj\n"+
+ "DheT389Lrm5zdeDzqrmkwAkbhepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCe\n"+
+ "yv78IZTuEyhL11xeDGbu6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCkt\n"+
+ "VjMFu5dZfsZJT4nXLySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMB\n"+
+ "MIIBtwYDVR0gBIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYI\n"+
+ "KwYBBQUHAgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRp\n"+
+ "ZmljYXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug\n"+
+ "b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0\n"+
+ "aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu\n"+
+ "dCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGljaCBjYW4gYmUg\n"+
+ "Zm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0cHM6Ly93d3cuYmV0\n"+
+ "cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMEIGCCsGAQUF\n"+
+ "BwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2Vz\n"+
+ "L2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQDAgAHMIGJBgNVHR8EgYEwfzB9oHug\n"+
+ "eaR3MHUxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJv\n"+
+ "b3QgQ0FzMTMwMQYDVQQDEypiZVRSVVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1w\n"+
+ "bGVtZW50YXRpb24xDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEw\n"+
+ "ODI0MjdagQ8yMDIyMDQxMTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaA\n"+
+ "FH1w5a44iwY/qhwaj/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQw\n"+
+ "qoSEFjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIE\n"+
+ "kDANBgkqhkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ\n"+
+ "5V04ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB\n"+
+ "evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220Y/oz\n"+
+ "ADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2KjiS2d2k\n"+
+ "XgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFiaDrmLzfzgYYh\n"+
+ "xKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep9w==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("beTRUSTed Root CA - RSA Implementation",
+ // X500 Subject, for lookups.
+ "MGIxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMS8wLQYD"+
+ "VQQDEyZiZVRSVVNUZWQgUm9vdCBDQSAtIFJTQSBJbXBsZW1lbnRhdGlvbg==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUFADBi\n"+
+ "MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENB\n"+
+ "czEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRp\n"+
+ "b24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBiMRIwEAYDVQQKEwli\n"+
+ "ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEvMC0GA1UEAxMm\n"+
+ "YmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRpb24wggEiMA0GCSqG\n"+
+ "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQwCY5X0LkGLG9uJIAiv11DpvpPrILn\n"+
+ "HGhwhRujbrWqeNluB0s/6d/16uhUoWGKDi9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I\n"+
+ "1DpAa5LxmZZk3tv/ePTulh1HiXzUvrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPk\n"+
+ "tPDgaTuID0GQ+NRxQyTBjyZLO1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnU\n"+
+ "GxlkVgoZ98zh/4avflherHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8er\n"+
+ "cmsl9fNTGwxMLvF1S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIY\n"+
+ "MIICFDAMBgNVHRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+\n"+
+ "AAADCSiDkTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5j\n"+
+ "b20vcHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB\n"+
+ "OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjcmVh\n"+
+ "dGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRoZSB0aGVu\n"+
+ "IGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNl\n"+
+ "LCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgYW5kIHRoZSBS\n"+
+ "ZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IHRo\n"+
+ "ZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93d3cuYmV0cnVzdGVkLmNvbS9w\n"+
+ "cm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMAsGA1UdDwQEAwIBBjAfBgNVHSME\n"+
+ "GDAWgBSp7BR++dlDzFMrFK3P9/BZiUHNGTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxSt\n"+
+ "z/fwWYlBzRkwDQYJKoZIhvcNAQEFBQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g\n"+
+ "6IHHtt9DwSwddUvUQo3neqh03GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuK\n"+
+ "mET7m9cqg5c0Lcd9NUwtNLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbd\n"+
+ "LrML3kqNWz2rDcI1UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28Bb\n"+
+ "J1zTcwfBwvNMm2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3\n"+
+ "SK41ty8ymmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("RSA Security 2048 v3",
+ // X500 Subject, for lookups.
+ "MDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4"+
+ "IFYz",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6\n"+
+ "MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp\n"+
+ "dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX\n"+
+ "BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy\n"+
+ "MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp\n"+
+ "eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg\n"+
+ "/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl\n"+
+ "wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh\n"+
+ "AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2\n"+
+ "PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu\n"+
+ "AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\n"+
+ "BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR\n"+
+ "MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc\n"+
+ "HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/\n"+
+ "Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+\n"+
+ "f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO\n"+
+ "rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch\n"+
+ "6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3\n"+
+ "7CAFYd4=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("RSA Security 1024 v3",
+ // X500 Subject, for lookups.
+ "MDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAxMDI0"+
+ "IFYz",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUFADA6\n"+
+ "MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp\n"+
+ "dHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAxNDlaMDoxGTAX\n"+
+ "BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAx\n"+
+ "MDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV3f5mCc8kPD6ugU5O\n"+
+ "isRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dYrIMKo1W1exeQFYRMiu4mmdxY\n"+
+ "78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYtbzZUaMjShFbuklNhCbM/OZuoyZu9\n"+
+ "zp9+1BlqFikYvtc6adwlWzMaUQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4G\n"+
+ "A1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAd\n"+
+ "BgNVHQ4EFgQUxMAcpAeU/c1NAdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEA\n"+
+ "Py1q4yZDlX2Jl2X7deRyHUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdN\n"+
+ "T1+nr6JGFLkM88y9am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgD\n"+
+ "mMrzVcydro7BqkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GeoTrust Global CA",
+ // X500 Subject, for lookups.
+ "MEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz"+
+ "dCBHbG9iYWwgQ0E=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n"+
+ "MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\n"+
+ "YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\n"+
+ "EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\n"+
+ "R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n"+
+ "9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\n"+
+ "fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\n"+
+ "iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n"+
+ "1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\n"+
+ "bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\n"+
+ "MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\n"+
+ "ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\n"+
+ "uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\n"+
+ "Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\n"+
+ "tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n"+
+ "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\n"+
+ "hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n"+
+ "5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GeoTrust Global CA 2",
+ // X500 Subject, for lookups.
+ "MEQxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQDExRHZW9UcnVz"+
+ "dCBHbG9iYWwgQ0EgMg==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW\n"+
+ "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs\n"+
+ "IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG\n"+
+ "EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg\n"+
+ "R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A\n"+
+ "PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8\n"+
+ "Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL\n"+
+ "TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL\n"+
+ "5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7\n"+
+ "S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe\n"+
+ "2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\n"+
+ "FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap\n"+
+ "EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td\n"+
+ "EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv\n"+
+ "/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN\n"+
+ "A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0\n"+
+ "abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF\n"+
+ "I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz\n"+
+ "4iIprn2DQKi6bA==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GeoTrust Universal CA",
+ // X500 Subject, for lookups.
+ "MEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVz"+
+ "dCBVbml2ZXJzYWwgQ0E=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW\n"+
+ "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy\n"+
+ "c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE\n"+
+ "BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0\n"+
+ "IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV\n"+
+ "VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8\n"+
+ "cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT\n"+
+ "QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh\n"+
+ "F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v\n"+
+ "c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w\n"+
+ "mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd\n"+
+ "VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX\n"+
+ "teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ\n"+
+ "f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe\n"+
+ "Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+\n"+
+ "nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB\n"+
+ "/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY\n"+
+ "MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n"+
+ "9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc\n"+
+ "aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX\n"+
+ "IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn\n"+
+ "ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z\n"+
+ "uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN\n"+
+ "Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja\n"+
+ "QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW\n"+
+ "koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9\n"+
+ "ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt\n"+
+ "DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm\n"+
+ "bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("GeoTrust Universal CA 2",
+ // X500 Subject, for lookups.
+ "MEcxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMSAwHgYDVQQDExdHZW9UcnVz"+
+ "dCBVbml2ZXJzYWwgQ0EgMg==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW\n"+
+ "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy\n"+
+ "c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD\n"+
+ "VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1\n"+
+ "c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n"+
+ "AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81\n"+
+ "WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG\n"+
+ "FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq\n"+
+ "XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL\n"+
+ "se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb\n"+
+ "KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd\n"+
+ "IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73\n"+
+ "y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt\n"+
+ "hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc\n"+
+ "QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4\n"+
+ "Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV\n"+
+ "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV\n"+
+ "HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ\n"+
+ "KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z\n"+
+ "dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ\n"+
+ "L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr\n"+
+ "Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo\n"+
+ "ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY\n"+
+ "T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz\n"+
+ "GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m\n"+
+ "1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV\n"+
+ "OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH\n"+
+ "6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX\n"+
+ "QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("UTN-USER First-Network Applications",
+ // X500 Subject, for lookups.
+ "MIGjMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w"+
+ "HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy"+
+ "dXN0LmNvbTErMCkGA1UEAxMiVVROLVVTRVJGaXJzdC1OZXR3b3JrIEFwcGxpY2F0aW9ucw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB\n"+
+ "ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug\n"+
+ "Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho\n"+
+ "dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt\n"+
+ "TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1\n"+
+ "NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0\n"+
+ "IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD\n"+
+ "VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS\n"+
+ "Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n"+
+ "DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2\n"+
+ "N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH\n"+
+ "iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe\n"+
+ "YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1\n"+
+ "axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g\n"+
+ "yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD\n"+
+ "AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh\n"+
+ "ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V\n"+
+ "VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB\n"+
+ "BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y\n"+
+ "IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs\n"+
+ "QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4\n"+
+ "ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM\n"+
+ "YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb\n"+
+ "QErNaLly7HF27FSOH4UMAWr6pjisH8SE\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("America Online Root Certification Authority 1",
+ // X500 Subject, for lookups.
+ "MGMxCzAJBgNVBAYTAlVTMRwwGgYDVQQKExNBbWVyaWNhIE9ubGluZSBJbmMuMTYwNAYDVQQDEy1B"+
+ "bWVyaWNhIE9ubGluZSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDE=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc\n"+
+ "MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP\n"+
+ "bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2\n"+
+ "MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft\n"+
+ "ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg\n"+
+ "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n"+
+ "ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk\n"+
+ "hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym\n"+
+ "1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW\n"+
+ "OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb\n"+
+ "2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko\n"+
+ "O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw\n"+
+ "AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU\n"+
+ "AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\n"+
+ "BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF\n"+
+ "Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb\n"+
+ "LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir\n"+
+ "oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C\n"+
+ "MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds\n"+
+ "sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("America Online Root Certification Authority 2",
+ // X500 Subject, for lookups.
+ "MGMxCzAJBgNVBAYTAlVTMRwwGgYDVQQKExNBbWVyaWNhIE9ubGluZSBJbmMuMTYwNAYDVQQDEy1B"+
+ "bWVyaWNhIE9ubGluZSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDI=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc\n"+
+ "MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP\n"+
+ "bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2\n"+
+ "MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft\n"+
+ "ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg\n"+
+ "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP\n"+
+ "ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC\n"+
+ "206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci\n"+
+ "KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2\n"+
+ "JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9\n"+
+ "BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e\n"+
+ "Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B\n"+
+ "PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67\n"+
+ "Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq\n"+
+ "Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ\n"+
+ "o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3\n"+
+ "+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj\n"+
+ "YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj\n"+
+ "FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE\n"+
+ "AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn\n"+
+ "xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2\n"+
+ "LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc\n"+
+ "obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8\n"+
+ "CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe\n"+
+ "IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA\n"+
+ "DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F\n"+
+ "AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX\n"+
+ "Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb\n"+
+ "AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl\n"+
+ "Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw\n"+
+ "RY8mkaKO/qk=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Visa eCommerce Root",
+ // X500 Subject, for lookups.
+ "MGsxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQLEyZWaXNhIEludGVybmF0aW9u"+
+ "YWwgU2VydmljZSBBc3NvY2lhdGlvbjEcMBoGA1UEAxMTVmlzYSBlQ29tbWVyY2UgUm9vdA==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr\n"+
+ "MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl\n"+
+ "cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv\n"+
+ "bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw\n"+
+ "CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h\n"+
+ "dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l\n"+
+ "cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h\n"+
+ "2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E\n"+
+ "lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV\n"+
+ "ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq\n"+
+ "299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t\n"+
+ "vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL\n"+
+ "dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\n"+
+ "AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF\n"+
+ "AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR\n"+
+ "zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3\n"+
+ "LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd\n"+
+ "7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw\n"+
+ "++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt\n"+
+ "398znM/jra6O1I7mT1GvFpLgXPYHDw==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("TC TrustCenter, Germany, Class 2 CA",
+ // X500 Subject, for lookups.
+ "MIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgG"+
+ "A1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEi"+
+ "MCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlm"+
+ "aWNhdGVAdHJ1c3RjZW50ZXIuZGU=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF\n"+
+ "MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU\n"+
+ "QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI\n"+
+ "MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN\n"+
+ "AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla\n"+
+ "Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy\n"+
+ "ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y\n"+
+ "IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1\n"+
+ "c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA\n"+
+ "dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y\n"+
+ "AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw\n"+
+ "TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8\n"+
+ "/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF\n"+
+ "MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3\n"+
+ "LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n"+
+ "CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/\n"+
+ "jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms\n"+
+ "Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("TC TrustCenter, Germany, Class 3 CA",
+ // X500 Subject, for lookups.
+ "MIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgG"+
+ "A1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEi"+
+ "MCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlm"+
+ "aWNhdGVAdHJ1c3RjZW50ZXIuZGU=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF\n"+
+ "MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU\n"+
+ "QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI\n"+
+ "MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN\n"+
+ "AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla\n"+
+ "Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy\n"+
+ "ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y\n"+
+ "IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1\n"+
+ "c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA\n"+
+ "dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF\n"+
+ "Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw\n"+
+ "Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW\n"+
+ "w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF\n"+
+ "MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3\n"+
+ "LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n"+
+ "CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE\n"+
+ "Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD\n"+
+ "2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Certum Root CA",
+ // X500 Subject, for lookups.
+ "MD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNl"+
+ "cnR1bSBDQQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM\n"+
+ "MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD\n"+
+ "QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM\n"+
+ "MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD\n"+
+ "QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E\n"+
+ "jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo\n"+
+ "ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI\n"+
+ "ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu\n"+
+ "Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg\n"+
+ "AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7\n"+
+ "HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA\n"+
+ "uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa\n"+
+ "TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg\n"+
+ "xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q\n"+
+ "CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x\n"+
+ "O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs\n"+
+ "6GAqm4VKQPNriiTsBhYscw==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Comodo AAA Services root",
+ // X500 Subject, for lookups.
+ "MHsxCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1Nh"+
+ "bGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNh"+
+ "dGUgU2VydmljZXM=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\n"+
+ "MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n"+
+ "GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\n"+
+ "YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\n"+
+ "MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n"+
+ "BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\n"+
+ "GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\n"+
+ "ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\n"+
+ "BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n"+
+ "3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\n"+
+ "YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\n"+
+ "rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\n"+
+ "ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\n"+
+ "oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n"+
+ "MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\n"+
+ "QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\n"+
+ "b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\n"+
+ "AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\n"+
+ "GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\n"+
+ "Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\n"+
+ "G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\n"+
+ "l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\n"+
+ "smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Comodo Secure Services root",
+ // X500 Subject, for lookups.
+ "MH4xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1Nh"+
+ "bGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSQwIgYDVQQDDBtTZWN1cmUgQ2VydGlm"+
+ "aWNhdGUgU2VydmljZXM=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb\n"+
+ "MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n"+
+ "GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp\n"+
+ "ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow\n"+
+ "fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n"+
+ "A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV\n"+
+ "BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB\n"+
+ "BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM\n"+
+ "cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S\n"+
+ "HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996\n"+
+ "CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk\n"+
+ "3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz\n"+
+ "6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV\n"+
+ "HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud\n"+
+ "EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv\n"+
+ "Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw\n"+
+ "Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww\n"+
+ "DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0\n"+
+ "5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj\n"+
+ "Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI\n"+
+ "gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ\n"+
+ "aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl\n"+
+ "izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Comodo Trusted Services root",
+ // X500 Subject, for lookups.
+ "MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1Nh"+
+ "bGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYDVQQDDBxUcnVzdGVkIENlcnRp"+
+ "ZmljYXRlIFNlcnZpY2Vz",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb\n"+
+ "MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n"+
+ "GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0\n"+
+ "aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla\n"+
+ "MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\n"+
+ "BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD\n"+
+ "VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B\n"+
+ "AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW\n"+
+ "fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt\n"+
+ "TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL\n"+
+ "fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW\n"+
+ "1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7\n"+
+ "kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G\n"+
+ "A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD\n"+
+ "VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v\n"+
+ "ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo\n"+
+ "dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu\n"+
+ "Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/\n"+
+ "HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32\n"+
+ "pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS\n"+
+ "jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+\n"+
+ "xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn\n"+
+ "dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("IPS Chained CAs root",
+ // X500 Subject, for lookups.
+ "MIIBHDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25h"+
+ "MS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQK"+
+ "FCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hh"+
+ "aW5lZCBDQXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFpbmVk"+
+ "IENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBz"+
+ "LmVz",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYTAkVT\n"+
+ "MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE\n"+
+ "ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE\n"+
+ "ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEzMDEGA1UECxMq\n"+
+ "SVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYD\n"+
+ "VQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx\n"+
+ "HjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczAeFw0wMTEyMjkwMDUzNTha\n"+
+ "Fw0yNTEyMjcwMDUzNThaMIIBHDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl\n"+
+ "bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQg\n"+
+ "cHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMu\n"+
+ "ZXMgQy5JLkYuICBCLTYwOTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBD\n"+
+ "QXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFp\n"+
+ "bmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYP\n"+
+ "aXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJ\n"+
+ "spQgvJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB\n"+
+ "hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQTy2nB\n"+
+ "Bt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8wHQYDVR0O\n"+
+ "BBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCCAUGAFKGtMbH5\n"+
+ "PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQGEwJFUzESMBAGA1UE\n"+
+ "CBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJ\n"+
+ "bnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0Bt\n"+
+ "YWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxMzAxBgNVBAsTKklQUyBDQSBD\n"+
+ "aGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAxMqSVBT\n"+
+ "IENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI\n"+
+ "hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E\n"+
+ "BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG\n"+
+ "CCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYB\n"+
+ "BAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw\n"+
+ "EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBC\n"+
+ "BglghkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg\n"+
+ "aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlw\n"+
+ "cy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5pcHMuZXMv\n"+
+ "aXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYtaHR0cDovL3d3\n"+
+ "dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/MDkGCWCGSAGG+EIB\n"+
+ "BwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3JlbmV3YWxDQUMuaHRtbD8w\n"+
+ "NwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5\n"+
+ "Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYoaHR0cDovL3d3dy5pcHMuZXMvaXBz\n"+
+ "MjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCgLoYsaHR0cDovL3d3d2JhY2suaXBzLmVz\n"+
+ "L2lwczIwMDIvaXBzMjAwMkNBQy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF\n"+
+ "BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1W\n"+
+ "WKJBGyi3leGmGpVfp3hAK+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfN\n"+
+ "HnNDJGD1HWHc3JagvPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvN\n"+
+ "b2ar7QMiRDjMWb2f2/YHogF/JsRj9SVCXmK9\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("IPS CLASE1 root",
+ // X500 Subject, for lookups.
+ "MIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25h"+
+ "MS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQK"+
+ "FCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xB"+
+ "U0UxIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UxIENlcnRp"+
+ "ZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXM=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT\n"+
+ "MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE\n"+
+ "ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE\n"+
+ "ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl\n"+
+ "SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl\n"+
+ "SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3\n"+
+ "DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAwNTkzOFoXDTI1MTIyNzAw\n"+
+ "NTkzOFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD\n"+
+ "VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n\n"+
+ "IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g\n"+
+ "IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv\n"+
+ "biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv\n"+
+ "biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN\n"+
+ "BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywS\n"+
+ "zHb5BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS\n"+
+ "YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJZHMQ\n"+
+ "KD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzcuh9morKb\n"+
+ "adB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKbadB4CKGCARqk\n"+
+ "ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE\n"+
+ "BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT\n"+
+ "ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC\n"+
+ "LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g\n"+
+ "QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g\n"+
+ "QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD\n"+
+ "VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr\n"+
+ "BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB\n"+
+ "FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC\n"+
+ "AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB\n"+
+ "D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRp\n"+
+ "ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC\n"+
+ "BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito\n"+
+ "dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMD8GCWCG\n"+
+ "SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D\n"+
+ "TEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw\n"+
+ "czIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov\n"+
+ "L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTEuaHRtbDBzBgNVHR8EbDBq\n"+
+ "MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEu\n"+
+ "Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy\n"+
+ "Q0xBU0UxLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v\n"+
+ "Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuK\n"+
+ "Yn4VLenZMdMu9Ccj/1urxUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpj\n"+
+ "V4F1Wo7ojPsCwJTGKbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+\n"+
+ "hjM+5i9Ibq9UkE6tsSU=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("IPS CLASE3 root",
+ // X500 Subject, for lookups.
+ "MIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25h"+
+ "MS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQK"+
+ "FCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xB"+
+ "U0UzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UzIENlcnRp"+
+ "ZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXM=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT\n"+
+ "MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE\n"+
+ "ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE\n"+
+ "ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl\n"+
+ "SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl\n"+
+ "SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3\n"+
+ "DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMDE0NFoXDTI1MTIyNzAx\n"+
+ "MDE0NFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD\n"+
+ "VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n\n"+
+ "IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g\n"+
+ "IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv\n"+
+ "biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv\n"+
+ "biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN\n"+
+ "BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZ\n"+
+ "H49NzjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY\n"+
+ "8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBxRiVr\n"+
+ "SXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLnev42USGj\n"+
+ "mFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGjmFsMNKGCARqk\n"+
+ "ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE\n"+
+ "BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT\n"+
+ "ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC\n"+
+ "LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g\n"+
+ "QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g\n"+
+ "QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD\n"+
+ "VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr\n"+
+ "BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB\n"+
+ "FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC\n"+
+ "AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB\n"+
+ "D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRp\n"+
+ "ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC\n"+
+ "BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito\n"+
+ "dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMD8GCWCG\n"+
+ "SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D\n"+
+ "TEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw\n"+
+ "czIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov\n"+
+ "L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTMuaHRtbDBzBgNVHR8EbDBq\n"+
+ "MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMu\n"+
+ "Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy\n"+
+ "Q0xBU0UzLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v\n"+
+ "Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dD\n"+
+ "qsfwfewPxqmurpYPdikc4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9\n"+
+ "D6eSb9ijBmgpjnn1/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGy\n"+
+ "r33I6unUVtkOE7LFRVA=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("IPS CLASEA1 root",
+ // X500 Subject, for lookups.
+ "MIIBFDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25h"+
+ "MS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQK"+
+ "FCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS8wLQYDVQQLEyZJUFMgQ0EgQ0xB"+
+ "U0VBMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmSVBTIENBIENMQVNFQTEgQ2Vy"+
+ "dGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lcw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT\n"+
+ "MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE\n"+
+ "ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE\n"+
+ "ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm\n"+
+ "SVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT\n"+
+ "JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI\n"+
+ "hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNTMyWhcNMjUxMjI3\n"+
+ "MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ\n"+
+ "BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp\n"+
+ "bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G\n"+
+ "LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh\n"+
+ "dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj\n"+
+ "YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw\n"+
+ "gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8\n"+
+ "m2mdd81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd\n"+
+ "ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1e+J8\n"+
+ "eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/2LUDnf47\n"+
+ "3P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf473P7yiuYV3TCh\n"+
+ "ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ\n"+
+ "BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp\n"+
+ "bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G\n"+
+ "LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh\n"+
+ "dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj\n"+
+ "YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC\n"+
+ "AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF\n"+
+ "BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB\n"+
+ "BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg\n"+
+ "hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud\n"+
+ "EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBD\n"+
+ "QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG\n"+
+ "SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC\n"+
+ "AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j\n"+
+ "cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2\n"+
+ "b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu\n"+
+ "aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRtbD8wOwYJYIZIAYb4QgEI\n"+
+ "BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMS5odG1s\n"+
+ "MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz\n"+
+ "MjAwMkNMQVNFQTEuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz\n"+
+ "MjAwMi9pcHMyMDAyQ0xBU0VBMS5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF\n"+
+ "BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyA\n"+
+ "AIQVCtWYUQxkxZwCWINmyq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeF\n"+
+ "aQoO42Hu6r4okzPV7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aL\n"+
+ "H2betgPAK7N41lUH5Y85UN4HI3LmvSAUS7SG\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("IPS CLASEA3 root",
+ // X500 Subject, for lookups.
+ "MIIBFDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25h"+
+ "MS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQK"+
+ "FCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS8wLQYDVQQLEyZJUFMgQ0EgQ0xB"+
+ "U0VBMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmSVBTIENBIENMQVNFQTMgQ2Vy"+
+ "dGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lcw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT\n"+
+ "MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE\n"+
+ "ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE\n"+
+ "ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm\n"+
+ "SVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT\n"+
+ "JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI\n"+
+ "hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNzUwWhcNMjUxMjI3\n"+
+ "MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ\n"+
+ "BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp\n"+
+ "bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G\n"+
+ "LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh\n"+
+ "dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj\n"+
+ "YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw\n"+
+ "gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvN\n"+
+ "G7uGBiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU\n"+
+ "VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4Ninn\n"+
+ "6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2YZM50yz8\n"+
+ "2l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz82l09BXW3mQKh\n"+
+ "ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ\n"+
+ "BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp\n"+
+ "bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G\n"+
+ "LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh\n"+
+ "dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj\n"+
+ "YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC\n"+
+ "AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF\n"+
+ "BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB\n"+
+ "BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg\n"+
+ "hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud\n"+
+ "EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBD\n"+
+ "QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG\n"+
+ "SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC\n"+
+ "AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j\n"+
+ "cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2\n"+
+ "b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu\n"+
+ "aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRtbD8wOwYJYIZIAYb4QgEI\n"+
+ "BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMy5odG1s\n"+
+ "MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz\n"+
+ "MjAwMkNMQVNFQTMuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz\n"+
+ "MjAwMi9pcHMyMDAyQ0xBU0VBMy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF\n"+
+ "BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca\n"+
+ "2on0eisxeewBwMwB9dbB/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI\n"+
+ "3y2s6Q73nMify5NF8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYS\n"+
+ "AfWRMS1Jjbs/RU4s4OjNtckUFQzjB4ObJnXv\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("IPS Servidores root",
+ // X500 Subject, for lookups.
+ "MIGjMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQkFSQ0VMT05BMRIwEAYDVQQHEwlCQVJDRUxPTkEx"+
+ "GTAXBgNVBAoTEElQUyBTZWd1cmlkYWQgQ0ExGDAWBgNVBAsTD0NlcnRpZmljYWNpb25lczEXMBUG"+
+ "A1UEAxMOSVBTIFNFUlZJRE9SRVMxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lcw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYD\n"+
+ "VQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBT\n"+
+ "IFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQD\n"+
+ "Ew5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVz\n"+
+ "MB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVT\n"+
+ "MRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE\n"+
+ "ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcw\n"+
+ "FQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu\n"+
+ "aXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyY\n"+
+ "XZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1\n"+
+ "gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4\n"+
+ "Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lY\n"+
+ "JN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsU\n"+
+ "dx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14\n"+
+ "cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("IPS Timestamping root",
+ // X500 Subject, for lookups.
+ "MIIBHjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25h"+
+ "MS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQK"+
+ "FCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTQwMgYDVQQLEytJUFMgQ0EgVGlt"+
+ "ZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTQwMgYDVQQDEytJUFMgQ0EgVGltZXN0"+
+ "YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5p"+
+ "cHMuZXM=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYTAkVT\n"+
+ "MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE\n"+
+ "ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE\n"+
+ "ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjE0MDIGA1UECxMr\n"+
+ "SVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE0MDIG\n"+
+ "A1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0\n"+
+ "eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMTAx\n"+
+ "OFoXDTI1MTIyNzAxMTAxOFowggEeMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFy\n"+
+ "Y2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5l\n"+
+ "dCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlw\n"+
+ "cy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3Rh\n"+
+ "bXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBU\n"+
+ "aW1lc3RhbXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0B\n"+
+ "CQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n"+
+ "vLjuVqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4\n"+
+ "Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6KaFY\n"+
+ "q6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAwggR8MB0G\n"+
+ "A1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSCAUcwggFDgBSL\n"+
+ "0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkGA1UEBhMCRVMxEjAQ\n"+
+ "BgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJ\n"+
+ "UFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJp\n"+
+ "cHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTQwMgYDVQQLEytJUFMg\n"+
+ "Q0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTQwMgYDVQQD\n"+
+ "EytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4w\n"+
+ "HAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM\n"+
+ "BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB\n"+
+ "BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB\n"+
+ "FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYD\n"+
+ "VR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlw\n"+
+ "cy5lczBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl\n"+
+ "IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwWGmh0\n"+
+ "dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFodHRwOi8v\n"+
+ "d3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMEUGCWCG\n"+
+ "SAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25U\n"+
+ "aW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUWM2h0dHA6Ly93d3cuaXBz\n"+
+ "LmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGluZy5odG1sPzBABglghkgBhvhC\n"+
+ "AQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lUaW1lc3RhbXBp\n"+
+ "bmcuaHRtbDB/BgNVHR8EeDB2MDegNaAzhjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMy\n"+
+ "MDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFj\n"+
+ "ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEF\n"+
+ "BQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI\n"+
+ "hvcNAQEFBQADgYEAZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk3\n"+
+ "6MNbsMRnLWhasl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I\n"+
+ "3pGW7hdbrqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("QuoVadis Root CA",
+ // X500 Subject, for lookups.
+ "MH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290"+
+ "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmlj"+
+ "YXRpb24gQXV0aG9yaXR5",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC\n"+
+ "TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0\n"+
+ "aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0\n"+
+ "aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz\n"+
+ "MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw\n"+
+ "IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR\n"+
+ "dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG\n"+
+ "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp\n"+
+ "li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D\n"+
+ "rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ\n"+
+ "WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug\n"+
+ "F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU\n"+
+ "xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC\n"+
+ "Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv\n"+
+ "dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw\n"+
+ "ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl\n"+
+ "IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh\n"+
+ "c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy\n"+
+ "ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh\n"+
+ "Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI\n"+
+ "KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T\n"+
+ "KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq\n"+
+ "y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p\n"+
+ "dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD\n"+
+ "VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL\n"+
+ "MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk\n"+
+ "fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8\n"+
+ "7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R\n"+
+ "cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y\n"+
+ "mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW\n"+
+ "xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK\n"+
+ "SnQ2+Q==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("QuoVadis Root CA 2",
+ // X500 Subject, for lookups.
+ "MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W"+
+ "YWRpcyBSb290IENBIDI=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x\n"+
+ "GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv\n"+
+ "b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV\n"+
+ "BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W\n"+
+ "YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa\n"+
+ "GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg\n"+
+ "Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J\n"+
+ "WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB\n"+
+ "rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp\n"+
+ "+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1\n"+
+ "ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i\n"+
+ "Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz\n"+
+ "PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og\n"+
+ "/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH\n"+
+ "oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI\n"+
+ "yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud\n"+
+ "EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2\n"+
+ "A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL\n"+
+ "MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT\n"+
+ "ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f\n"+
+ "BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn\n"+
+ "g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl\n"+
+ "fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K\n"+
+ "WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha\n"+
+ "B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc\n"+
+ "hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR\n"+
+ "TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD\n"+
+ "mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z\n"+
+ "ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y\n"+
+ "4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza\n"+
+ "8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("QuoVadis Root CA 3",
+ // X500 Subject, for lookups.
+ "MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W"+
+ "YWRpcyBSb290IENBIDM=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x\n"+
+ "GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv\n"+
+ "b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV\n"+
+ "BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W\n"+
+ "YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM\n"+
+ "V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB\n"+
+ "4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr\n"+
+ "H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd\n"+
+ "8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv\n"+
+ "vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT\n"+
+ "mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe\n"+
+ "btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc\n"+
+ "T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt\n"+
+ "WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ\n"+
+ "c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A\n"+
+ "4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD\n"+
+ "VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG\n"+
+ "CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0\n"+
+ "aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0\n"+
+ "aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu\n"+
+ "dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw\n"+
+ "czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G\n"+
+ "A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC\n"+
+ "TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg\n"+
+ "Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0\n"+
+ "7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem\n"+
+ "d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd\n"+
+ "+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B\n"+
+ "4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN\n"+
+ "t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x\n"+
+ "DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57\n"+
+ "k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s\n"+
+ "zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j\n"+
+ "Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT\n"+
+ "mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK\n"+
+ "4SVhM7JZG+Ju1zdXtg2pEto=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Security Communication Root CA",
+ // X500 Subject, for lookups.
+ "MFAxCzAJBgNVBAYTAkpQMRgwFgYDVQQKEw9TRUNPTSBUcnVzdC5uZXQxJzAlBgNVBAsTHlNlY3Vy"+
+ "aXR5IENvbW11bmljYXRpb24gUm9vdENBMQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY\n"+
+ "MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t\n"+
+ "dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5\n"+
+ "WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD\n"+
+ "VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3\n"+
+ "DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8\n"+
+ "9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ\n"+
+ "DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9\n"+
+ "Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N\n"+
+ "QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ\n"+
+ "xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G\n"+
+ "A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T\n"+
+ "AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG\n"+
+ "kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr\n"+
+ "Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5\n"+
+ "Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU\n"+
+ "JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot\n"+
+ "RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Sonera Class 1 Root CA",
+ // X500 Subject, for lookups.
+ "MDkxCzAJBgNVBAYTAkZJMQ8wDQYDVQQKEwZTb25lcmExGTAXBgNVBAMTEFNvbmVyYSBDbGFzczEg"+
+ "Q0E=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP\n"+
+ "MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx\n"+
+ "MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV\n"+
+ "BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI\n"+
+ "hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG\n"+
+ "29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk\n"+
+ "oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk\n"+
+ "3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL\n"+
+ "qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN\n"+
+ "nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw\n"+
+ "DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG\n"+
+ "MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX\n"+
+ "ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H\n"+
+ "DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO\n"+
+ "TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv\n"+
+ "kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w\n"+
+ "zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Sonera Class 2 Root CA",
+ // X500 Subject, for lookups.
+ "MDkxCzAJBgNVBAYTAkZJMQ8wDQYDVQQKEwZTb25lcmExGTAXBgNVBAMTEFNvbmVyYSBDbGFzczIg"+
+ "Q0E=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP\n"+
+ "MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx\n"+
+ "MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV\n"+
+ "BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI\n"+
+ "hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o\n"+
+ "Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt\n"+
+ "5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s\n"+
+ "3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej\n"+
+ "vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu\n"+
+ "8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw\n"+
+ "DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG\n"+
+ "MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil\n"+
+ "zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/\n"+
+ "3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD\n"+
+ "FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6\n"+
+ "Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2\n"+
+ "ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Staat der Nederlanden Root CA",
+ // X500 Subject, for lookups.
+ "MFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMT"+
+ "HVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO\n"+
+ "TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh\n"+
+ "dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy\n"+
+ "MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk\n"+
+ "ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB\n"+
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn\n"+
+ "ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71\n"+
+ "9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO\n"+
+ "hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U\n"+
+ "tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o\n"+
+ "BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh\n"+
+ "SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww\n"+
+ "OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv\n"+
+ "cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA\n"+
+ "7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k\n"+
+ "/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm\n"+
+ "eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6\n"+
+ "u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy\n"+
+ "7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR\n"+
+ "iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("TDC Internet Root CA",
+ // X500 Subject, for lookups.
+ "MEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl"+
+ "cm5ldCBSb290IENB",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE\n"+
+ "SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg\n"+
+ "Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV\n"+
+ "BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl\n"+
+ "cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA\n"+
+ "vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu\n"+
+ "Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a\n"+
+ "0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1\n"+
+ "4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN\n"+
+ "eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD\n"+
+ "R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG\n"+
+ "A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu\n"+
+ "dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME\n"+
+ "Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3\n"+
+ "WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw\n"+
+ "HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ\n"+
+ "KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO\n"+
+ "Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX\n"+
+ "wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+\n"+
+ "2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89\n"+
+ "9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0\n"+
+ "jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38\n"+
+ "aQNiuJkFBT1reBK9sG9l\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("TDC OCES Root CA",
+ // X500 Subject, for lookups.
+ "MDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENB",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE\n"+
+ "SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw\n"+
+ "ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU\n"+
+ "REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"+
+ "MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr\n"+
+ "2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s\n"+
+ "2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU\n"+
+ "GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj\n"+
+ "dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r\n"+
+ "TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/\n"+
+ "BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB\n"+
+ "AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv\n"+
+ "c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl\n"+
+ "ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu\n"+
+ "MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg\n"+
+ "T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud\n"+
+ "HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD\n"+
+ "VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny\n"+
+ "bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy\n"+
+ "MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ\n"+
+ "J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG\n"+
+ "SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom\n"+
+ "JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO\n"+
+ "inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y\n"+
+ "caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB\n"+
+ "mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ\n"+
+ "YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9\n"+
+ "BKNDLdr8C2LqL19iUw==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("UTN DATACorp SGC Root CA",
+ // X500 Subject, for lookups.
+ "MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w"+
+ "HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy"+
+ "dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dD",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB\n"+
+ "kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug\n"+
+ "Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho\n"+
+ "dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw\n"+
+ "IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG\n"+
+ "EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD\n"+
+ "VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu\n"+
+ "dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN\n"+
+ "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6\n"+
+ "E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ\n"+
+ "D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK\n"+
+ "4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq\n"+
+ "lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW\n"+
+ "bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB\n"+
+ "o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT\n"+
+ "MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js\n"+
+ "LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr\n"+
+ "BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB\n"+
+ "AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft\n"+
+ "Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj\n"+
+ "j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH\n"+
+ "KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv\n"+
+ "2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3\n"+
+ "mfnGV/TJVTl4uix5yaaIK/QI\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("UTN USERFirst Email Root CA",
+ // X500 Subject, for lookups.
+ "MIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w"+
+ "HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy"+
+ "dXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5k"+
+ "IEVtYWls",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB\n"+
+ "rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug\n"+
+ "Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho\n"+
+ "dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt\n"+
+ "Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa\n"+
+ "Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV\n"+
+ "BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l\n"+
+ "dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE\n"+
+ "AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls\n"+
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B\n"+
+ "YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9\n"+
+ "hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l\n"+
+ "L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm\n"+
+ "SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM\n"+
+ "1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws\n"+
+ "6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n"+
+ "DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw\n"+
+ "Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50\n"+
+ "aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH\n"+
+ "AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u\n"+
+ "7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0\n"+
+ "xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ\n"+
+ "rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim\n"+
+ "eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk\n"+
+ "USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("UTN USERFirst Hardware Root CA",
+ // X500 Subject, for lookups.
+ "MIGXMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w"+
+ "HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy"+
+ "dXN0LmNvbTEfMB0GA1UEAxMWVVROLVVTRVJGaXJzdC1IYXJkd2FyZQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB\n"+
+ "lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug\n"+
+ "Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho\n"+
+ "dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt\n"+
+ "SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG\n"+
+ "A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe\n"+
+ "MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v\n"+
+ "d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh\n"+
+ "cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn\n"+
+ "0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ\n"+
+ "M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a\n"+
+ "MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd\n"+
+ "oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI\n"+
+ "DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy\n"+
+ "oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD\n"+
+ "VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0\n"+
+ "dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy\n"+
+ "bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF\n"+
+ "BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM\n"+
+ "//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli\n"+
+ "CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE\n"+
+ "CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t\n"+
+ "3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS\n"+
+ "KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("UTN USERFirst Object Root CA",
+ // X500 Subject, for lookups.
+ "MIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w"+
+ "HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy"+
+ "dXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJGaXJzdC1PYmplY3Q=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB\n"+
+ "lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug\n"+
+ "Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho\n"+
+ "dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt\n"+
+ "T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV\n"+
+ "BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc\n"+
+ "BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3\n"+
+ "dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC\n"+
+ "ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP\n"+
+ "HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO\n"+
+ "KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo\n"+
+ "5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+\n"+
+ "pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb\n"+
+ "kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC\n"+
+ "AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\n"+
+ "FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov\n"+
+ "L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV\n"+
+ "HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN\n"+
+ "AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw\n"+
+ "NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB\n"+
+ "mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU\n"+
+ "4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5\n"+
+ "81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR\n"+
+ "Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Camerfirma Chambers of Commerce Root",
+ // X500 Subject, for lookups.
+ "MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBBODI3NDMyODcx"+
+ "IzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIwIAYDVQQDExlDaGFtYmVycyBv"+
+ "ZiBDb21tZXJjZSBSb290",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn\n"+
+ "MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL\n"+
+ "ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg\n"+
+ "b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa\n"+
+ "MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB\n"+
+ "ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw\n"+
+ "IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B\n"+
+ "AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb\n"+
+ "unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d\n"+
+ "BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq\n"+
+ "7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3\n"+
+ "0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX\n"+
+ "roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG\n"+
+ "A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j\n"+
+ "aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p\n"+
+ "26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA\n"+
+ "BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud\n"+
+ "EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN\n"+
+ "BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz\n"+
+ "aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB\n"+
+ "AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd\n"+
+ "p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi\n"+
+ "1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc\n"+
+ "XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0\n"+
+ "eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu\n"+
+ "tGWaIZDgqtCYvDi1czyL+Nw=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Camerfirma Global Chambersign Root",
+ // X500 Subject, for lookups.
+ "MH0xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBBODI3NDMyODcx"+
+ "IzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSAwHgYDVQQDExdHbG9iYWwgQ2hh"+
+ "bWJlcnNpZ24gUm9vdA==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn\n"+
+ "MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL\n"+
+ "ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo\n"+
+ "YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9\n"+
+ "MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy\n"+
+ "NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G\n"+
+ "A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA\n"+
+ "A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0\n"+
+ "Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s\n"+
+ "QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV\n"+
+ "eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795\n"+
+ "B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh\n"+
+ "z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T\n"+
+ "AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i\n"+
+ "ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w\n"+
+ "TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH\n"+
+ "MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD\n"+
+ "VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE\n"+
+ "VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh\n"+
+ "bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B\n"+
+ "AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM\n"+
+ "bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi\n"+
+ "ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG\n"+
+ "VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c\n"+
+ "ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/\n"+
+ "AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("NetLock Qualified (Class QA) Root",
+ // X500 Subject, for lookups.
+ "MIHJMQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFs"+
+ "b3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMT"+
+ "OU5ldExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFk"+
+ "bzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx\n"+
+ "ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0\n"+
+ "b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD\n"+
+ "EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz\n"+
+ "aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w\n"+
+ "MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G\n"+
+ "A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh\n"+
+ "Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l\n"+
+ "dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh\n"+
+ "bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq\n"+
+ "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq\n"+
+ "eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe\n"+
+ "r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5\n"+
+ "3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd\n"+
+ "vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l\n"+
+ "mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC\n"+
+ "wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg\n"+
+ "hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0\n"+
+ "TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh\n"+
+ "biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg\n"+
+ "ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg\n"+
+ "dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6\n"+
+ "b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl\n"+
+ "c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0\n"+
+ "ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3\n"+
+ "dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu\n"+
+ "ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh\n"+
+ "bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo\n"+
+ "ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3\n"+
+ "Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u\n"+
+ "ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA\n"+
+ "A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ\n"+
+ "MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+\n"+
+ "NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR\n"+
+ "VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY\n"+
+ "83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3\n"+
+ "macqaJVmlaut74nLYKkGEsaUR+ko\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("NetLock Notary (Class A) Root",
+ // X500 Subject, for lookups.
+ "MIGvMQswCQYDVQQGEwJIVTEQMA4GA1UECBMHSHVuZ2FyeTERMA8GA1UEBxMIQnVkYXBlc3QxJzAl"+
+ "BgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZh"+
+ "bnlraWFkb2sxNjA0BgNVBAMTLU5ldExvY2sgS296amVneXpvaSAoQ2xhc3MgQSkgVGFudXNpdHZh"+
+ "bnlraWFkbw==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV\n"+
+ "MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe\n"+
+ "TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0\n"+
+ "dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB\n"+
+ "KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0\n"+
+ "N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC\n"+
+ "dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu\n"+
+ "MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL\n"+
+ "b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG\n"+
+ "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD\n"+
+ "zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi\n"+
+ "3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8\n"+
+ "WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY\n"+
+ "Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi\n"+
+ "NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC\n"+
+ "ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4\n"+
+ "QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0\n"+
+ "YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz\n"+
+ "aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu\n"+
+ "IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm\n"+
+ "ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg\n"+
+ "ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs\n"+
+ "amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv\n"+
+ "IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3\n"+
+ "Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6\n"+
+ "ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1\n"+
+ "YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg\n"+
+ "dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs\n"+
+ "b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G\n"+
+ "CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO\n"+
+ "xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP\n"+
+ "0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ\n"+
+ "QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk\n"+
+ "f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK\n"+
+ "8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("NetLock Business (Class B) Root",
+ // X500 Subject, for lookups.
+ "MIGZMQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFs"+
+ "b3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMT"+
+ "KU5ldExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRv",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx\n"+
+ "ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0\n"+
+ "b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD\n"+
+ "EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05\n"+
+ "OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G\n"+
+ "A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh\n"+
+ "Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l\n"+
+ "dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG\n"+
+ "SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK\n"+
+ "gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX\n"+
+ "iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc\n"+
+ "Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E\n"+
+ "BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G\n"+
+ "SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu\n"+
+ "b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh\n"+
+ "bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv\n"+
+ "Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln\n"+
+ "aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0\n"+
+ "IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh\n"+
+ "c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph\n"+
+ "biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo\n"+
+ "ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP\n"+
+ "UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj\n"+
+ "YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo\n"+
+ "dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA\n"+
+ "bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06\n"+
+ "sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa\n"+
+ "n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS\n"+
+ "NitjrFgBazMpUIaD8QFI\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("NetLock Express (Class C) Root",
+ // X500 Subject, for lookups.
+ "MIGbMQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFs"+
+ "b3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxNDAyBgNVBAMT"+
+ "K05ldExvY2sgRXhwcmVzc3ogKENsYXNzIEMpIFRhbnVzaXR2YW55a2lhZG8=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx\n"+
+ "ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0\n"+
+ "b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD\n"+
+ "EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X\n"+
+ "DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw\n"+
+ "DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u\n"+
+ "c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr\n"+
+ "TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN\n"+
+ "BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA\n"+
+ "OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC\n"+
+ "2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW\n"+
+ "RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P\n"+
+ "AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW\n"+
+ "ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0\n"+
+ "YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz\n"+
+ "b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO\n"+
+ "ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB\n"+
+ "IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs\n"+
+ "b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs\n"+
+ "ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s\n"+
+ "YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg\n"+
+ "a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g\n"+
+ "SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0\n"+
+ "aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg\n"+
+ "YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg\n"+
+ "Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY\n"+
+ "ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g\n"+
+ "pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4\n"+
+ "Fp1hBWeAyNDYpQcCNJgEjTME1A==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("XRamp Global CA Root",
+ // X500 Subject, for lookups.
+ "MIGCMQswCQYDVQQGEwJVUzEeMBwGA1UECxMVd3d3LnhyYW1wc2VjdXJpdHkuY29tMSQwIgYDVQQK"+
+ "ExtYUmFtcCBTZWN1cml0eSBTZXJ2aWNlcyBJbmMxLTArBgNVBAMTJFhSYW1wIEdsb2JhbCBDZXJ0"+
+ "aWZpY2F0aW9uIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB\n"+
+ "gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk\n"+
+ "MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY\n"+
+ "UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx\n"+
+ "NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3\n"+
+ "dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy\n"+
+ "dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB\n"+
+ "dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6\n"+
+ "38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP\n"+
+ "KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q\n"+
+ "DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4\n"+
+ "qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa\n"+
+ "JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi\n"+
+ "PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P\n"+
+ "BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs\n"+
+ "jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0\n"+
+ "eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD\n"+
+ "ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR\n"+
+ "vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt\n"+
+ "qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa\n"+
+ "IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy\n"+
+ "i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ\n"+
+ "O+7ETPTsJ3xCwnR8gooJybQDJbw=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Go Daddy Class 2 CA",
+ // X500 Subject, for lookups.
+ "MGMxCzAJBgNVBAYTAlVTMSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNV"+
+ "BAsTKEdvIERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHk=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh\n"+
+ "MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE\n"+
+ "YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3\n"+
+ "MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo\n"+
+ "ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg\n"+
+ "MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN\n"+
+ "ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA\n"+
+ "PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w\n"+
+ "wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\n"+
+ "EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY\n"+
+ "avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+\n"+
+ "YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE\n"+
+ "sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h\n"+
+ "/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5\n"+
+ "IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj\n"+
+ "YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD\n"+
+ "ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy\n"+
+ "OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\n"+
+ "TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\n"+
+ "HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER\n"+
+ "dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf\n"+
+ "ReYNnyicsbkqWletNw+vHX/bvZ8=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Starfield Class 2 CA",
+ // X500 Subject, for lookups.
+ "MGgxCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIw"+
+ "MAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"+
+ "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"+
+ "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"+
+ "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"+
+ "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"+
+ "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"+
+ "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"+
+ "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"+
+ "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"+
+ "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"+
+ "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"+
+ "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"+
+ "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"+
+ "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"+
+ "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"+
+ "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"+
+ "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"+
+ "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"+
+ "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"+
+ "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"+
+ "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"+
+ "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("StartCom Ltd.",
+ // X500 Subject, for lookups.
+ "MIGwMQswCQYDVQQGEwJJTDEPMA0GA1UECBMGSXNyYWVsMQ4wDAYDVQQHEwVFaWxhdDEWMBQGA1UE"+
+ "ChMNU3RhcnRDb20gTHRkLjEaMBgGA1UECxMRQ0EgQXV0aG9yaXR5IERlcC4xKTAnBgNVBAMTIEZy"+
+ "ZWUgU1NMIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJhZG1pbkBzdGFy"+
+ "dGNvbS5vcmc=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx\n"+
+ "DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0\n"+
+ "Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG\n"+
+ "cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS\n"+
+ "YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0\n"+
+ "OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp\n"+
+ "bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp\n"+
+ "dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\n"+
+ "dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG\n"+
+ "9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x\n"+
+ "18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5\n"+
+ "yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI\n"+
+ "LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G\n"+
+ "A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW\n"+
+ "zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT\n"+
+ "BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x\n"+
+ "GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD\n"+
+ "ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh\n"+
+ "cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV\n"+
+ "HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G\n"+
+ "CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy\n"+
+ "BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j\n"+
+ "cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ\n"+
+ "YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/\n"+
+ "YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1\n"+
+ "ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p\n"+
+ "00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb\n"+
+ "cCOxgN8aIDjnfg==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("StartCom Certification Authority",
+ // X500 Subject, for lookups.
+ "MH0xCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUg"+
+ "RGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWduaW5nMSkwJwYDVQQDEyBTdGFydENvbSBDZXJ0aWZpY2F0"+
+ "aW9uIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW\n"+
+ "MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg\n"+
+ "Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh\n"+
+ "dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9\n"+
+ "MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi\n"+
+ "U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh\n"+
+ "cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA\n"+
+ "A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk\n"+
+ "pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf\n"+
+ "OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C\n"+
+ "Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT\n"+
+ "Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi\n"+
+ "HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM\n"+
+ "Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w\n"+
+ "+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+\n"+
+ "Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3\n"+
+ "Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B\n"+
+ "26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID\n"+
+ "AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE\n"+
+ "FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j\n"+
+ "ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js\n"+
+ "LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM\n"+
+ "BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0\n"+
+ "Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy\n"+
+ "dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh\n"+
+ "cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh\n"+
+ "YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg\n"+
+ "dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp\n"+
+ "bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ\n"+
+ "YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT\n"+
+ "TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ\n"+
+ "9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8\n"+
+ "jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW\n"+
+ "FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz\n"+
+ "ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1\n"+
+ "ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L\n"+
+ "EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu\n"+
+ "L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq\n"+
+ "yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC\n"+
+ "O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V\n"+
+ "um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh\n"+
+ "NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Taiwan GRCA",
+ // X500 Subject, for lookups.
+ "MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlmaWNhdGlvbiBB"+
+ "dXRob3JpdHk=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/\n"+
+ "MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj\n"+
+ "YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow\n"+
+ "PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp\n"+
+ "Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB\n"+
+ "AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR\n"+
+ "IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q\n"+
+ "gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy\n"+
+ "yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts\n"+
+ "F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2\n"+
+ "jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx\n"+
+ "ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC\n"+
+ "VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK\n"+
+ "YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH\n"+
+ "EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN\n"+
+ "Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud\n"+
+ "DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE\n"+
+ "MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK\n"+
+ "UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ\n"+
+ "TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf\n"+
+ "qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK\n"+
+ "ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE\n"+
+ "JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7\n"+
+ "hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1\n"+
+ "EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm\n"+
+ "nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX\n"+
+ "udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz\n"+
+ "ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe\n"+
+ "LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl\n"+
+ "pYYsfPQS\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Firmaprofesional Root CA",
+ // X500 Subject, for lookups.
+ "MIGdMQswCQYDVQQGEwJFUzEiMCAGA1UEBxMZQy8gTXVudGFuZXIgMjQ0IEJhcmNlbG9uYTFCMEAG"+
+ "A1UEAxM5QXV0b3JpZGFkIGRlIENlcnRpZmljYWNpb24gRmlybWFwcm9mZXNpb25hbCBDSUYgQTYy"+
+ "NjM0MDY4MSYwJAYJKoZIhvcNAQkBFhdjYUBmaXJtYXByb2Zlc2lvbmFsLmNvbQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx\n"+
+ "IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1\n"+
+ "dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2\n"+
+ "MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w\n"+
+ "HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx\n"+
+ "IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1\n"+
+ "dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2\n"+
+ "MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w\n"+
+ "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u\n"+
+ "Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY\n"+
+ "rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z\n"+
+ "hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay\n"+
+ "BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL\n"+
+ "iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb\n"+
+ "AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv\n"+
+ "bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0\n"+
+ "MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E\n"+
+ "FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n\n"+
+ "VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq\n"+
+ "u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m\n"+
+ "hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl\n"+
+ "ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp\n"+
+ "QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5\n"+
+ "quGnM/b9Sh/22WA=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Wells Fargo Root CA",
+ // X500 Subject, for lookups.
+ "MIGCMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLV2VsbHMgRmFyZ28xLDAqBgNVBAsTI1dlbGxzIEZh"+
+ "cmdvIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS8wLQYDVQQDEyZXZWxscyBGYXJnbyBSb290IENl"+
+ "cnRpZmljYXRlIEF1dGhvcml0eQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC\n"+
+ "VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD\n"+
+ "ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v\n"+
+ "dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0\n"+
+ "MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww\n"+
+ "KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G\n"+
+ "A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi\n"+
+ "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13\n"+
+ "5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE\n"+
+ "SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O\n"+
+ "JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu\n"+
+ "ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE\n"+
+ "AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB\n"+
+ "AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB\n"+
+ "CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw\n"+
+ "b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo\n"+
+ "7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/\n"+
+ "0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7\n"+
+ "nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx\n"+
+ "x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ\n"+
+ "33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Swisscom Root CA 1",
+ // X500 Subject, for lookups.
+ "MGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0"+
+ "aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAx",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk\n"+
+ "MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0\n"+
+ "YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg\n"+
+ "Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT\n"+
+ "AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp\n"+
+ "Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN\n"+
+ "BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9\n"+
+ "m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih\n"+
+ "FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/\n"+
+ "TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F\n"+
+ "EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco\n"+
+ "kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu\n"+
+ "HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF\n"+
+ "vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo\n"+
+ "19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC\n"+
+ "L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW\n"+
+ "bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX\n"+
+ "JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw\n"+
+ "FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j\n"+
+ "BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc\n"+
+ "K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf\n"+
+ "ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik\n"+
+ "Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB\n"+
+ "sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e\n"+
+ "3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR\n"+
+ "ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip\n"+
+ "mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH\n"+
+ "b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf\n"+
+ "rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms\n"+
+ "hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y\n"+
+ "zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6\n"+
+ "MBr1mmz0DlP5OlvRHA==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("DigiCert Assured ID Root CA",
+ // X500 Subject, for lookups.
+ "MGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp"+
+ "Y2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQQ==",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl\n"+
+ "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"+
+ "d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv\n"+
+ "b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG\n"+
+ "EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl\n"+
+ "cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi\n"+
+ "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c\n"+
+ "JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP\n"+
+ "mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+\n"+
+ "wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4\n"+
+ "VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/\n"+
+ "AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB\n"+
+ "AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW\n"+
+ "BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun\n"+
+ "pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC\n"+
+ "dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf\n"+
+ "fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm\n"+
+ "NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx\n"+
+ "H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\n"+
+ "+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("DigiCert Global Root CA",
+ // X500 Subject, for lookups.
+ "MGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp"+
+ "Y2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENB",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"+
+ "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"+
+ "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"+
+ "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"+
+ "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"+
+ "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"+
+ "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"+
+ "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"+
+ "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"+
+ "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"+
+ "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"+
+ "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"+
+ "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"+
+ "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"+
+ "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"+
+ "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"+
+ "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"+
+ "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"+
+ "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"+
+ "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("DigiCert High Assurance EV Root CA",
+ // X500 Subject, for lookups.
+ "MGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp"+
+ "Y2VydC5jb20xKzApBgNVBAMTIkRpZ2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0E=",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n"+
+ "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"+
+ "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n"+
+ "ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n"+
+ "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n"+
+ "LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n"+
+ "RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n"+
+ "+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n"+
+ "PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n"+
+ "xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n"+
+ "Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n"+
+ "hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n"+
+ "EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n"+
+ "MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n"+
+ "FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n"+
+ "nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n"+
+ "eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n"+
+ "hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n"+
+ "Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n"+
+ "vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n"+
+ "+OkuE6N36B9K\n"+
+ "-----END CERTIFICATE-----");
+ super.addPEMCertificate("Certplus Class 2 Primary CA",
+ // X500 Subject, for lookups.
+ "MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xhc3MgMiBQcmlt"+
+ "YXJ5IENB",
+ "-----BEGIN CERTIFICATE-----\n"+
+ "MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw\n"+
+ "PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz\n"+
+ "cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9\n"+
+ "MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz\n"+
+ "IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ\n"+
+ "ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR\n"+
+ "VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL\n"+
+ "kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd\n"+
+ "EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas\n"+
+ "H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0\n"+
+ "HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud\n"+
+ "DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4\n"+
+ "QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu\n"+
+ "Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/\n"+
+ "AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8\n"+
+ "yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR\n"+
+ "FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA\n"+
+ "ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB\n"+
+ "kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7\n"+
+ "l7+ijrRU\n"+
+ "-----END CERTIFICATE-----");
+ }
+ override public function addPEMCertificate(name:String,subject:String,pem:String):void {
+ throw new Error("Cannot add certificates to the Root CA store.");
+ }
+ override public function addCertificate(cert:X509Certificate):void {
+ throw new Error("Cannot add certificates to the Root CA store.");
+ }
+ }
+}
--- /dev/null
+/**\r
+ * X509Certificate\r
+ * \r
+ * A representation for a X509 Certificate, with\r
+ * methods to parse, verify and sign it.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.cert {\r
+ import com.hurlant.crypto.hash.IHash;\r
+ import com.hurlant.crypto.hash.MD2;\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ import com.hurlant.crypto.rsa.RSAKey;\r
+ import com.hurlant.util.ArrayUtil;\r
+ import com.hurlant.util.Base64;\r
+ import com.hurlant.util.der.ByteString;\r
+ import com.hurlant.util.der.DER;\r
+ import com.hurlant.util.der.OID;\r
+ import com.hurlant.util.der.ObjectIdentifier;\r
+ import com.hurlant.util.der.PEM;\r
+ import com.hurlant.util.der.PrintableString;\r
+ import com.hurlant.util.der.Sequence;\r
+ import com.hurlant.util.der.Type;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class X509Certificate {\r
+ private var _loaded:Boolean;\r
+ private var _param:*;\r
+ private var _obj:Object;\r
+ public function X509Certificate(p:*) {\r
+ _loaded = false;\r
+ _param = p;\r
+ // lazy initialization, to avoid unnecessary parsing of every builtin CA at start-up.\r
+ }\r
+ private function load():void {\r
+ if (_loaded) return;\r
+ var p:* = _param;\r
+ var b:ByteArray;\r
+ if (p is String) {\r
+ b = PEM.readCertIntoArray(p as String);\r
+ } else if (p is ByteArray) {\r
+ b = p;\r
+ }\r
+ if (b!=null) {\r
+ _obj = DER.parse(b, Type.TLS_CERT);\r
+ _loaded = true;\r
+ } else {\r
+ throw new Error("Invalid x509 Certificate parameter: "+p);\r
+ }\r
+ }\r
+ public function isSigned(store:X509CertificateCollection, CAs:X509CertificateCollection, time:Date=null):Boolean {\r
+ load();\r
+ // check timestamps first. cheapest.\r
+ if (time==null) {\r
+ time = new Date;\r
+ }\r
+ var notBefore:Date = getNotBefore();\r
+ var notAfter:Date = getNotAfter();\r
+ if (time.getTime()<notBefore.getTime()) return false; // cert isn't born yet.\r
+ if (time.getTime()>notAfter.getTime()) return false; // cert died of old age.\r
+ // check signature.\r
+ var subject:String = getIssuerPrincipal();\r
+ // try from CA first, since they're treated better.\r
+ var parent:X509Certificate = CAs.getCertificate(subject);\r
+ var parentIsAuthoritative:Boolean = false;\r
+ if (parent == null) {\r
+ parent = store.getCertificate(subject);\r
+ if (parent == null) {\r
+ return false; // issuer not found\r
+ }\r
+ } else {\r
+ parentIsAuthoritative = true;\r
+ }\r
+ if (parent == this) { // pathological case. avoid infinite loop\r
+ return false; // isSigned() returns false if we're self-signed.\r
+ }\r
+ if (!(parentIsAuthoritative&&parent.isSelfSigned(time)) &&\r
+ !parent.isSigned(store, CAs, time)) {\r
+ return false;\r
+ }\r
+ var key:RSAKey = parent.getPublicKey();\r
+ return verifyCertificate(key);\r
+ }\r
+ public function isSelfSigned(time:Date):Boolean {\r
+ load();\r
+ \r
+ var key:RSAKey = getPublicKey();\r
+ return verifyCertificate(key);\r
+ }\r
+ private function verifyCertificate(key:RSAKey):Boolean {\r
+ var algo:String = getAlgorithmIdentifier();\r
+ var hash:IHash;\r
+ var oid:String;\r
+ switch (algo) {\r
+ case OID.SHA1_WITH_RSA_ENCRYPTION:\r
+ hash = new SHA1;\r
+ oid = OID.SHA1_ALGORITHM;\r
+ break;\r
+ case OID.MD2_WITH_RSA_ENCRYPTION:\r
+ hash = new MD2;\r
+ oid = OID.MD2_ALGORITHM;\r
+ break;\r
+ case OID.MD5_WITH_RSA_ENCRYPTION:\r
+ hash = new MD5;\r
+ oid = OID.MD5_ALGORITHM;\r
+ break;\r
+ default:\r
+ return false;\r
+ }\r
+ var data:ByteArray = _obj.signedCertificate_bin;\r
+ var buf:ByteArray = new ByteArray;\r
+ key.verify(_obj.encrypted, buf, _obj.encrypted.length);\r
+ buf.position=0;\r
+ data = hash.hash(data);\r
+ var obj:Object = DER.parse(buf, Type.RSA_SIGNATURE);\r
+ if (obj.algorithm.algorithmId.toString() != oid) {\r
+ return false; // wrong algorithm\r
+ }\r
+ if (!ArrayUtil.equals(obj.hash, data)) {\r
+ return false; // hashes don't match\r
+ }\r
+ return true;\r
+ }\r
+ \r
+ /**\r
+ * This isn't used anywhere so far.\r
+ * It would become useful if we started to offer facilities\r
+ * to generate and sign X509 certificates.\r
+ * \r
+ * @param key\r
+ * @param algo\r
+ * @return \r
+ * \r
+ */\r
+ private function signCertificate(key:RSAKey, algo:String):ByteArray {\r
+ var hash:IHash;\r
+ var oid:String;\r
+ switch (algo) {\r
+ case OID.SHA1_WITH_RSA_ENCRYPTION:\r
+ hash = new SHA1;\r
+ oid = OID.SHA1_ALGORITHM;\r
+ break;\r
+ case OID.MD2_WITH_RSA_ENCRYPTION:\r
+ hash = new MD2;\r
+ oid = OID.MD2_ALGORITHM;\r
+ break;\r
+ case OID.MD5_WITH_RSA_ENCRYPTION:\r
+ hash = new MD5;\r
+ oid = OID.MD5_ALGORITHM;\r
+ break;\r
+ default:\r
+ return null\r
+ }\r
+ var data:ByteArray = _obj.signedCertificate_bin;\r
+ data = hash.hash(data);\r
+ var seq1:Sequence = new Sequence;\r
+ seq1[0] = new Sequence;\r
+ seq1[0][0] = new ObjectIdentifier(0,0, oid);\r
+ seq1[0][1] = null;\r
+ seq1[1] = new ByteString;\r
+ seq1[1].writeBytes(data);\r
+ data = seq1.toDER();\r
+ var buf:ByteArray = new ByteArray;\r
+ key.sign(data, buf, data.length);\r
+ return buf;\r
+ }\r
+ \r
+ public function getPublicKey():RSAKey {\r
+ load();\r
+ var pk:ByteArray = _obj.signedCertificate.subjectPublicKeyInfo.subjectPublicKey as ByteArray;\r
+ pk.position = 0;\r
+ var rsaKey:Object = DER.parse(pk, [{name:"N"},{name:"E"}]);\r
+ return new RSAKey(rsaKey.N, rsaKey.E.valueOf());\r
+ }\r
+ \r
+ /**\r
+ * Returns a subject principal, as an opaque base64 string.\r
+ * This is only used as a hash key for known certificates.\r
+ * \r
+ * Note that this assumes X509 DER-encoded certificates are uniquely encoded,\r
+ * as we look for exact matches between Issuer and Subject fields.\r
+ * \r
+ */\r
+ public function getSubjectPrincipal():String {\r
+ load();\r
+ return Base64.encodeByteArray(_obj.signedCertificate.subject_bin);\r
+ }\r
+ /**\r
+ * Returns an issuer principal, as an opaque base64 string.\r
+ * This is only used to quickly find matching parent certificates.\r
+ * \r
+ * Note that this assumes X509 DER-encoded certificates are uniquely encoded,\r
+ * as we look for exact matches between Issuer and Subject fields.\r
+ * \r
+ */\r
+ public function getIssuerPrincipal():String {\r
+ load();\r
+ return Base64.encodeByteArray(_obj.signedCertificate.issuer_bin);\r
+ }\r
+ public function getAlgorithmIdentifier():String {\r
+ return _obj.algorithmIdentifier.algorithmId.toString();\r
+ }\r
+ public function getNotBefore():Date {\r
+ return _obj.signedCertificate.validity.notBefore.date;\r
+ }\r
+ public function getNotAfter():Date {\r
+ return _obj.signedCertificate.validity.notAfter.date;\r
+ }\r
+ \r
+ public function getCommonName():String {\r
+ var subject:Sequence = _obj.signedCertificate.subject;\r
+ return (subject.findAttributeValue(OID.COMMON_NAME) as PrintableString).getString();\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * X509CertificateCollection\r
+ * \r
+ * A class to store and index X509 Certificates by Subject.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.cert {\r
+ \r
+ public class X509CertificateCollection {\r
+ \r
+ private var _map:Object;\r
+ \r
+ public function X509CertificateCollection() {\r
+ _map = {};\r
+ }\r
+ \r
+ /**\r
+ * Mostly meant for built-in CA loading.\r
+ * This entry-point allows to index CAs without parsing them.\r
+ * \r
+ * @param name A friendly name. not currently used\r
+ * @param subject base64 DER encoded Subject principal for the Cert\r
+ * @param pem PEM encoded certificate data\r
+ * \r
+ */\r
+ public function addPEMCertificate(name:String, subject:String, pem:String):void {\r
+ _map[subject] = new X509Certificate(pem);\r
+ }\r
+ \r
+ /**\r
+ * Adds a X509 certificate to the collection.\r
+ * This call will force the certificate to be parsed.\r
+ * \r
+ * @param cert A X509 certificate\r
+ * \r
+ */\r
+ public function addCertificate(cert:X509Certificate):void {\r
+ var subject:String = cert.getSubjectPrincipal();\r
+ _map[subject] = cert;\r
+ }\r
+ \r
+ /**\r
+ * Returns a X509 Certificate present in the collection, given\r
+ * a base64 DER encoded X500 Subject principal\r
+ * \r
+ * @param subject A Base64 DER-encoded Subject principal\r
+ * @return A matching certificate, or null.\r
+ * \r
+ */\r
+ public function getCertificate(subject:String):X509Certificate {\r
+ return _map[subject];\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * HMAC\r
+ * \r
+ * An ActionScript 3 implementation of HMAC, Keyed-Hashing for Message\r
+ * Authentication, as defined by RFC-2104\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ public class HMAC implements IHMAC\r
+ {\r
+ private var hash:IHash;\r
+ private var bits:uint;\r
+ \r
+ /**\r
+ * Create a HMAC object, using a Hash function, and \r
+ * optionally a number of bits to return. \r
+ * The HMAC will be truncated to that size if needed.\r
+ */\r
+ public function HMAC(hash:IHash, bits:uint=0) {\r
+ this.hash = hash;\r
+ this.bits = bits;\r
+ }\r
+ \r
+\r
+ public function getHashSize():uint {\r
+ if (bits!=0) {\r
+ return bits/8;\r
+ } else {\r
+ return hash.getHashSize();\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Compute a HMAC using a key and some data.\r
+ * It doesn't modify either, and returns a new ByteArray with the HMAC value.\r
+ */\r
+ public function compute(key:ByteArray, data:ByteArray):ByteArray {\r
+ var hashKey:ByteArray;\r
+ if (key.length>hash.getInputSize()) {\r
+ hashKey = hash.hash(key);\r
+ } else {\r
+ hashKey = new ByteArray;\r
+ hashKey.writeBytes(key);\r
+ }\r
+ while (hashKey.length<hash.getInputSize()) {\r
+ hashKey[hashKey.length]=0;\r
+ }\r
+ var innerKey:ByteArray = new ByteArray;\r
+ var outerKey:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<hashKey.length;i++) {\r
+ innerKey[i] = hashKey[i] ^ 0x36;\r
+ outerKey[i] = hashKey[i] ^ 0x5c;\r
+ }\r
+ // inner + data\r
+ innerKey.position = hashKey.length;\r
+ innerKey.writeBytes(data);\r
+ var innerHash:ByteArray = hash.hash(innerKey);\r
+ // outer + innerHash\r
+ outerKey.position = hashKey.length;\r
+ outerKey.writeBytes(innerHash);\r
+ var outerHash:ByteArray = hash.hash(outerKey);\r
+ if (bits>0 && bits<8*outerHash.length) {\r
+ outerHash.length = bits/8;\r
+ }\r
+ return outerHash;\r
+ }\r
+ public function dispose():void {\r
+ hash = null;\r
+ bits = 0;\r
+ }\r
+ public function toString():String {\r
+ return "hmac-"+(bits>0?bits+"-":"")+hash.toString();\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * HMAC\r
+ * \r
+ * An ActionScript 3 interface for HMAC & MAC \r
+ * implementations.\r
+ * \r
+ * Loosely copyrighted by Bobby Parker\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public interface IHMAC \r
+ {\r
+ function getHashSize():uint;\r
+ /**\r
+ * Compute a HMAC using a key and some data.\r
+ * It doesn't modify either, and returns a new ByteArray with the HMAC value.\r
+ */\r
+ function compute(key:ByteArray, data:ByteArray):ByteArray;\r
+ function dispose():void;\r
+ function toString():String;\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * IHash\r
+ * \r
+ * An interface for each hash function to implement\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ import flash.utils.ByteArray;\r
+\r
+ public interface IHash\r
+ {\r
+ function getInputSize():uint;\r
+ function getHashSize():uint;\r
+ function hash(src:ByteArray):ByteArray;\r
+ function toString():String;\r
+ function getPadSize():int;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * MAC\r
+ * \r
+ * An ActionScript 3 implementation of MAC, Message Authentication Code\r
+ * for use with SSL 3.0.\r
+ * Loosely copyrighted by Bobby Parker.\r
+ * As3crypto copyrighted by Henri Torgemane.\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ public class MAC implements IHMAC\r
+ {\r
+ private var hash:IHash;\r
+ private var bits:uint;\r
+ private var pad_1:ByteArray;\r
+ private var pad_2:ByteArray;\r
+ private var innerHash:ByteArray;\r
+ private var outerHash:ByteArray;\r
+ private var outerKey:ByteArray;\r
+ private var innerKey:ByteArray;\r
+ /**\r
+ * Create a MAC object (for SSL 3.0 ) and \r
+ * optionally a number of bits to return. \r
+ * The MAC will be truncated to that size if needed.\r
+ */\r
+ public function MAC(hash:IHash, bits:uint=0) {\r
+ this.hash = hash;\r
+ this.bits = bits;\r
+ innerHash = new ByteArray();\r
+ outerHash = new ByteArray();\r
+ innerKey = new ByteArray();\r
+ outerKey = new ByteArray();\r
+\r
+\r
+ if (hash != null) { \r
+ var pad_size:int = hash.getPadSize();\r
+ pad_1 = new ByteArray();\r
+ pad_2 = new ByteArray();\r
+ \r
+ for (var x:int = 0; x < pad_size; x++) {\r
+ pad_1.writeByte(0x36);\r
+ pad_2.writeByte(0x5c);\r
+ }\r
+ }\r
+ }\r
+ \r
+ public function setPadSize(pad_size:int) : void { }\r
+ \r
+ public function getHashSize():uint {\r
+ if (bits!=0) {\r
+ return bits/8;\r
+ } else {\r
+ return hash.getHashSize();\r
+ }\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Compute a MAC using a key and some data.\r
+ * \r
+ */ \r
+ public function compute(key:ByteArray, data:ByteArray):ByteArray {\r
+ // take that incoming key and do hash(key + pad_2 + hash(key + pad_1 + sequence + length + record)\r
+ // note that data = (sequence + type + length + record)\r
+\r
+ if (pad_1 == null) {\r
+ var pad_size:int = hash.getPadSize();\r
+ pad_1 = new ByteArray();\r
+ pad_2 = new ByteArray();\r
+ \r
+ for (var x:int = 0; x < pad_size; x++) {\r
+ pad_1.writeByte(0x36);\r
+ pad_2.writeByte(0x5c);\r
+ }\r
+ }\r
+ \r
+ // Do some preliminary checking on stuff\r
+ /* \r
+ if (key.length > hash.getInputSize()) {\r
+ hashKey = hash.hash(key); \r
+ } else {\r
+ hashKey = new ByteArray;\r
+ hashKey.writeBytes(key); \r
+ }\r
+ \r
+ while (hashKey.length < hash.getInputSize() ) {\r
+ hashKey[hashKey.length] = 0;\r
+ } */\r
+ // Henri's conventions work just fine here..\r
+ \r
+ innerKey.length = 0;\r
+ outerKey.length = 0;\r
+ // trace("MAC Key: " + Hex.fromArray(key));\r
+ // trace("Key Length: " + key.length);\r
+ // trace("Pad_1 : " + Hex.fromArray(pad_1));\r
+ // inner hash calc\r
+ innerKey.writeBytes(key);\r
+ innerKey.writeBytes(pad_1);\r
+ innerKey.writeBytes(data);\r
+ // trace("MAC Inner Key: " + Hex.fromArray(innerKey));\r
+ \r
+ innerHash = hash.hash(innerKey);\r
+ // trace("MAC Inner Hash: " + Hex.fromArray(innerHash));\r
+ \r
+ // outer hash calc \r
+ outerKey.writeBytes(key);\r
+ outerKey.writeBytes(pad_2);\r
+ outerKey.writeBytes(innerHash);\r
+ \r
+ // trace("MAC Outer Key: " + Hex.fromArray(outerKey));\r
+ outerHash = hash.hash(outerKey);\r
+ \r
+ \r
+ if (bits > 0 && bits < 8*outerHash.length) {\r
+ outerHash.length = bits/8;\r
+ }\r
+ \r
+ // trace("MAC for record: " + Hex.fromArray(outerHash)); \r
+ return outerHash;\r
+\r
+ }\r
+ \r
+ public function dispose():void {\r
+ hash = null;\r
+ bits = 0;\r
+ }\r
+ public function toString():String {\r
+ return "mac-"+(bits>0?bits+"-":"")+hash.toString();\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * MD2\r
+ * \r
+ * An ActionScript 3 implementation of the RSA Data Security, Inc MD2 Message\r
+ * Digest Algorithm, as defined in RFC 1319\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ * \r
+ * Excerpt from http://en.wikipedia.org/wiki/MD2:\r
+ * > \r
+ * > Rogier and Chauvaud (1997) described collisions of MD2's compression function,\r
+ * > although they were unable to extend the attack to the full MD2.\r
+ * > \r
+ * > In 2004, MD2 was shown to be vulnerable to a preimage attack with time \r
+ * > complexity equivalent to 2104 applications of the compression function \r
+ * > (Muller, 2004). \r
+ * > The author concludes, "MD2 can no longer be considered a secure one-way \r
+ * > hash function".\r
+ * \r
+ * also, this implementaton is quite slow.\r
+ */\r
+\r
+package com.hurlant.crypto.hash\r
+{\r
+ import flash.utils.ByteArray;\r
+\r
+ public class MD2 implements IHash\r
+ {\r
+ public static const HASH_SIZE:int = 16;\r
+ public var pad_size:int = 48; // probably will never get used, only here for SSL 3.0 support\r
+ \r
+ private static const S:Array = [ // PI Digits\r
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19,\r
+ 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202,\r
+ 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18,\r
+190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122,\r
+169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33,\r
+128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3,\r
+255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198,\r
+ 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241,\r
+ 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2,\r
+ 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,\r
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38,\r
+ 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82,\r
+106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,\r
+120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57,\r
+242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,\r
+ 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 ];\r
+ \r
+\r
+ public function MD2() { }\r
+\r
+ public function getInputSize():uint\r
+ {\r
+ return 16;\r
+ }\r
+ \r
+ public function getPadSize():int {\r
+ return pad_size;\r
+ }\r
+ \r
+ public function getHashSize():uint\r
+ {\r
+ return HASH_SIZE;\r
+ }\r
+ \r
+ public function hash(src:ByteArray):ByteArray\r
+ {\r
+ var savedLength:uint = src.length;\r
+ \r
+ // 3.1 Step 1. Padding\r
+ var i:uint = (16-src.length%16) || 16;\r
+ do {\r
+ src[src.length]=i;\r
+ } while (src.length%16!=0);\r
+ \r
+ // 3.2 Step 2. Checksum\r
+ var len:uint = src.length;\r
+ var checksum:ByteArray = new ByteArray;\r
+ var L:uint = 0;\r
+ for (i = 0;i<len;i+=16) {\r
+ for (var j:uint=0;j<16;j++) {\r
+ L = checksum[j] ^= S[src[i+j] ^ L];\r
+ }\r
+ }\r
+ src.position = src.length;\r
+ src.writeBytes(checksum);\r
+ len += 16;\r
+ \r
+ // 3.3 Step 3. MD Buffer\r
+ var X:ByteArray = new ByteArray;\r
+\r
+ // 3.4 Process Message\r
+ for (i=0;i<len;i+=16) {\r
+ \r
+ /* Copy block i into X */\r
+ for (j=0;j<16;j++) {\r
+ X[32+j] = (X[16+j] = src[i+j])^X[j];\r
+ }\r
+ var t:uint=0;\r
+ /* Do 18 rounds */\r
+ for (j=0;j<18;j++) {\r
+ /* Round j. */\r
+ for (var k:uint=0;k<48;k++) {\r
+ X[k] = t = X[k]^S[t];\r
+ }\r
+ t = (t+j)&0xff;\r
+ }\r
+ }\r
+ // 3.5 Step 5. Output\r
+ X.length = 16;\r
+ // restore original length;\r
+ src.length = savedLength;\r
+ return X;\r
+ }\r
+ \r
+ public function toString():String\r
+ {\r
+ return "md2";\r
+ }\r
+ \r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * MD5\r
+ * \r
+ * An ActionScript 3 implementation of the RSA Data Security, Inc. MD5 Message\r
+ * Digest Algorithm, as defined in RFC 1321.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from\r
+ * A JavaScript implementation of the same.\r
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.\r
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\r
+ * \r
+ * Note:\r
+ * This algorithm should not be your first choice for new developements, but is\r
+ * included to allow interoperability with existing codes and protocols.\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ import flash.utils.ByteArray;\r
+ import flash.utils.Endian;\r
+\r
+ public class MD5 implements IHash\r
+ {\r
+ public static const HASH_SIZE:int = 16;\r
+ public var pad_size:int = 48;\r
+\r
+ public function MD5() { }\r
+ \r
+ public function getInputSize():uint\r
+ {\r
+ return 64;\r
+ }\r
+ \r
+ public function getHashSize():uint\r
+ {\r
+ return HASH_SIZE;\r
+ }\r
+ \r
+ public function getPadSize():int \r
+ {\r
+ return pad_size;\r
+ }\r
+ \r
+ public function hash(src:ByteArray):ByteArray\r
+ {\r
+ var len:uint = src.length *8;\r
+ var savedEndian:String = src.endian;\r
+ // pad to nearest int.\r
+ while (src.length%4!=0) {\r
+ src[src.length]=0;\r
+ }\r
+ // convert ByteArray to an array of uint\r
+ src.position=0;\r
+ var a:Array = [];\r
+ src.endian=Endian.LITTLE_ENDIAN\r
+ for (var i:uint=0;i<src.length;i+=4) {\r
+ a.push(src.readUnsignedInt());\r
+ }\r
+ var h:Array = core_md5(a, len);\r
+ var out:ByteArray = new ByteArray;\r
+ out.endian=Endian.LITTLE_ENDIAN;\r
+ for (i=0;i<4;i++) {\r
+ out.writeUnsignedInt(h[i]);\r
+ }\r
+ // restore length!\r
+ src.length = len/8;\r
+ src.endian = savedEndian;\r
+ \r
+ return out;\r
+ }\r
+ \r
+ private function core_md5(x:Array, len:uint):Array {\r
+ /* append padding */\r
+ x[len >> 5] |= 0x80 << ((len) % 32);\r
+ x[(((len + 64) >>> 9) << 4) + 14] = len;\r
+\r
+ var a:uint = 0x67452301; // 1732584193;\r
+ var b:uint = 0xEFCDAB89; //-271733879;\r
+ var c:uint = 0x98BADCFE; //-1732584194;\r
+ var d:uint = 0x10325476; // 271733878;\r
+\r
+ for(var i:uint = 0; i < x.length; i += 16)\r
+ {\r
+ x[i]||=0; x[i+1]||=0; x[i+2]||=0; x[i+3]||=0;\r
+ x[i+4]||=0; x[i+5]||=0; x[i+6]||=0; x[i+7]||=0;\r
+ x[i+8]||=0; x[i+9]||=0; x[i+10]||=0; x[i+11]||=0;\r
+ x[i+12]||=0; x[i+13]||=0; x[i+14]||=0; x[i+15]||=0;\r
+\r
+ var olda:uint = a;\r
+ var oldb:uint = b;\r
+ var oldc:uint = c;\r
+ var oldd:uint = d;\r
+ \r
+ a = ff(a, b, c, d, x[i+ 0], 7 , 0xD76AA478);\r
+ d = ff(d, a, b, c, x[i+ 1], 12, 0xE8C7B756);\r
+ c = ff(c, d, a, b, x[i+ 2], 17, 0x242070DB);\r
+ b = ff(b, c, d, a, x[i+ 3], 22, 0xC1BDCEEE);\r
+ a = ff(a, b, c, d, x[i+ 4], 7 , 0xF57C0FAF);\r
+ d = ff(d, a, b, c, x[i+ 5], 12, 0x4787C62A);\r
+ c = ff(c, d, a, b, x[i+ 6], 17, 0xA8304613);\r
+ b = ff(b, c, d, a, x[i+ 7], 22, 0xFD469501);\r
+ a = ff(a, b, c, d, x[i+ 8], 7 , 0x698098D8);\r
+ d = ff(d, a, b, c, x[i+ 9], 12, 0x8B44F7AF);\r
+ c = ff(c, d, a, b, x[i+10], 17, 0xFFFF5BB1);\r
+ b = ff(b, c, d, a, x[i+11], 22, 0x895CD7BE);\r
+ a = ff(a, b, c, d, x[i+12], 7 , 0x6B901122);\r
+ d = ff(d, a, b, c, x[i+13], 12, 0xFD987193);\r
+ c = ff(c, d, a, b, x[i+14], 17, 0xA679438E);\r
+ b = ff(b, c, d, a, x[i+15], 22, 0x49B40821);\r
+\r
+ a = gg(a, b, c, d, x[i+ 1], 5 , 0xf61e2562);\r
+ d = gg(d, a, b, c, x[i+ 6], 9 , 0xc040b340);\r
+ c = gg(c, d, a, b, x[i+11], 14, 0x265e5a51);\r
+ b = gg(b, c, d, a, x[i+ 0], 20, 0xe9b6c7aa);\r
+ a = gg(a, b, c, d, x[i+ 5], 5 , 0xd62f105d);\r
+ d = gg(d, a, b, c, x[i+10], 9 , 0x2441453);\r
+ c = gg(c, d, a, b, x[i+15], 14, 0xd8a1e681);\r
+ b = gg(b, c, d, a, x[i+ 4], 20, 0xe7d3fbc8);\r
+ a = gg(a, b, c, d, x[i+ 9], 5 , 0x21e1cde6);\r
+ d = gg(d, a, b, c, x[i+14], 9 , 0xc33707d6);\r
+ c = gg(c, d, a, b, x[i+ 3], 14, 0xf4d50d87);\r
+ b = gg(b, c, d, a, x[i+ 8], 20, 0x455a14ed);\r
+ a = gg(a, b, c, d, x[i+13], 5 , 0xa9e3e905);\r
+ d = gg(d, a, b, c, x[i+ 2], 9 , 0xfcefa3f8);\r
+ c = gg(c, d, a, b, x[i+ 7], 14, 0x676f02d9);\r
+ b = gg(b, c, d, a, x[i+12], 20, 0x8d2a4c8a);\r
+\r
+ a = hh(a, b, c, d, x[i+ 5], 4 , 0xfffa3942);\r
+ d = hh(d, a, b, c, x[i+ 8], 11, 0x8771f681);\r
+ c = hh(c, d, a, b, x[i+11], 16, 0x6d9d6122);\r
+ b = hh(b, c, d, a, x[i+14], 23, 0xfde5380c);\r
+ a = hh(a, b, c, d, x[i+ 1], 4 , 0xa4beea44);\r
+ d = hh(d, a, b, c, x[i+ 4], 11, 0x4bdecfa9);\r
+ c = hh(c, d, a, b, x[i+ 7], 16, 0xf6bb4b60);\r
+ b = hh(b, c, d, a, x[i+10], 23, 0xbebfbc70);\r
+ a = hh(a, b, c, d, x[i+13], 4 , 0x289b7ec6);\r
+ d = hh(d, a, b, c, x[i+ 0], 11, 0xeaa127fa);\r
+ c = hh(c, d, a, b, x[i+ 3], 16, 0xd4ef3085);\r
+ b = hh(b, c, d, a, x[i+ 6], 23, 0x4881d05);\r
+ a = hh(a, b, c, d, x[i+ 9], 4 , 0xd9d4d039);\r
+ d = hh(d, a, b, c, x[i+12], 11, 0xe6db99e5);\r
+ c = hh(c, d, a, b, x[i+15], 16, 0x1fa27cf8);\r
+ b = hh(b, c, d, a, x[i+ 2], 23, 0xc4ac5665);\r
+ \r
+ a = ii(a, b, c, d, x[i+ 0], 6 , 0xf4292244);\r
+ d = ii(d, a, b, c, x[i+ 7], 10, 0x432aff97);\r
+ c = ii(c, d, a, b, x[i+14], 15, 0xab9423a7);\r
+ b = ii(b, c, d, a, x[i+ 5], 21, 0xfc93a039);\r
+ a = ii(a, b, c, d, x[i+12], 6 , 0x655b59c3);\r
+ d = ii(d, a, b, c, x[i+ 3], 10, 0x8f0ccc92);\r
+ c = ii(c, d, a, b, x[i+10], 15, 0xffeff47d);\r
+ b = ii(b, c, d, a, x[i+ 1], 21, 0x85845dd1);\r
+ a = ii(a, b, c, d, x[i+ 8], 6 , 0x6fa87e4f);\r
+ d = ii(d, a, b, c, x[i+15], 10, 0xfe2ce6e0);\r
+ c = ii(c, d, a, b, x[i+ 6], 15, 0xa3014314);\r
+ b = ii(b, c, d, a, x[i+13], 21, 0x4e0811a1);\r
+ a = ii(a, b, c, d, x[i+ 4], 6 , 0xf7537e82);\r
+ d = ii(d, a, b, c, x[i+11], 10, 0xbd3af235);\r
+ c = ii(c, d, a, b, x[i+ 2], 15, 0x2ad7d2bb);\r
+ b = ii(b, c, d, a, x[i+ 9], 21, 0xeb86d391);\r
+ \r
+ a += olda;\r
+ b += oldb;\r
+ c += oldc;\r
+ d += oldd;\r
+ \r
+ }\r
+ return [ a, b, c, d ];\r
+ }\r
+\r
+ /*\r
+ * Bitwise rotate a 32-bit number to the left.\r
+ */\r
+ private function rol(num:uint, cnt:uint):uint\r
+ {\r
+ return (num << cnt) | (num >>> (32 - cnt));\r
+ }\r
+\r
+ /*\r
+ * These functions implement the four basic operations the algorithm uses.\r
+ */\r
+ private function cmn(q:uint, a:uint, b:uint, x:uint, s:uint, t:uint):uint {\r
+ return rol(a + q + x + t, s) + b;\r
+ }\r
+ private function ff(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {\r
+ return cmn((b & c) | ((~b) & d), a, b, x, s, t);\r
+ }\r
+ private function gg(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {\r
+ return cmn((b & d) | (c & (~d)), a, b, x, s, t);\r
+ }\r
+ private function hh(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {\r
+ return cmn(b ^ c ^ d, a, b, x, s, t);\r
+ }\r
+ private function ii(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {\r
+ return cmn(c ^ (b | (~d)), a, b, x, s, t);\r
+ }\r
+\r
+ public function toString():String {\r
+ return "md5";\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * SHA1\r
+ * \r
+ * An ActionScript 3 implementation of Secure Hash Algorithm, SHA-1, as defined\r
+ * in FIPS PUB 180-1\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined\r
+ * in FIPS PUB 180-1\r
+ * Version 2.1a Copyright Paul Johnston 2000 - 2002.\r
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ \r
+\r
+ public class SHA1 extends SHABase implements IHash\r
+ {\r
+ public static const HASH_SIZE:int = 20;\r
+ \r
+ public override function getHashSize():uint {\r
+ return HASH_SIZE;\r
+ }\r
+ \r
+ protected override function core(x:Array, len:uint):Array\r
+ {\r
+ /* append padding */\r
+ x[len >> 5] |= 0x80 << (24 - len % 32);\r
+ x[((len + 64 >> 9) << 4) + 15] = len;\r
+ \r
+ var w:Array = [];\r
+ var a:uint = 0x67452301; //1732584193;\r
+ var b:uint = 0xEFCDAB89; //-271733879;\r
+ var c:uint = 0x98BADCFE; //-1732584194;\r
+ var d:uint = 0x10325476; //271733878;\r
+ var e:uint = 0xC3D2E1F0; //-1009589776;\r
+ \r
+ for(var i:uint = 0; i < x.length; i += 16)\r
+ {\r
+ \r
+ var olda:uint = a;\r
+ var oldb:uint = b;\r
+ var oldc:uint = c;\r
+ var oldd:uint = d;\r
+ var olde:uint = e;\r
+ \r
+ for(var j:uint = 0; j < 80; j++)\r
+ {\r
+ if (j < 16) {\r
+ w[j] = x[i + j] || 0;\r
+ } else {\r
+ w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);\r
+ }\r
+ var t:uint = rol(a,5) + ft(j,b,c,d) + e + w[j] + kt(j);\r
+ e = d;\r
+ d = c;\r
+ c = rol(b, 30);\r
+ b = a;\r
+ a = t;\r
+ }\r
+ a += olda;\r
+ b += oldb;\r
+ c += oldc;\r
+ d += oldd;\r
+ e += olde;\r
+ }\r
+ return [ a, b, c, d, e ];\r
+ \r
+ }\r
+ \r
+ /*\r
+ * Bitwise rotate a 32-bit number to the left.\r
+ */\r
+ private function rol(num:uint, cnt:uint):uint\r
+ {\r
+ return (num << cnt) | (num >>> (32 - cnt));\r
+ }\r
+ \r
+ /*\r
+ * Perform the appropriate triplet combination function for the current\r
+ * iteration\r
+ */\r
+ private function ft(t:uint, b:uint, c:uint, d:uint):uint\r
+ {\r
+ if(t < 20) return (b & c) | ((~b) & d);\r
+ if(t < 40) return b ^ c ^ d;\r
+ if(t < 60) return (b & c) | (b & d) | (c & d);\r
+ return b ^ c ^ d;\r
+ }\r
+ \r
+ /*\r
+ * Determine the appropriate additive constant for the current iteration\r
+ */\r
+ private function kt(t:uint):uint\r
+ {\r
+ return (t < 20) ? 0x5A827999 : (t < 40) ? 0x6ED9EBA1 :\r
+ (t < 60) ? 0x8F1BBCDC : 0xCA62C1D6;\r
+ }\r
+ public override function toString():String {\r
+ return "sha1";\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * SHA224\r
+ * \r
+ * An ActionScript 3 implementation of Secure Hash Algorithm, SHA-224, as defined\r
+ * in FIPS PUB 180-2\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ public class SHA224 extends SHA256\r
+ {\r
+ function SHA224() {\r
+ h = [\r
+ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,\r
+ 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4\r
+ ];\r
+ }\r
+ \r
+ public override function getHashSize():uint {\r
+ return 28;\r
+ }\r
+ public override function toString():String {\r
+ return "sha224";\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * SHA256\r
+ * \r
+ * An ActionScript 3 implementation of Secure Hash Algorithm, SHA-256, as defined\r
+ * in FIPS PUB 180-2\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * A JavaScript implementation of the Secure Hash Standard\r
+ * Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/\r
+ * Derived from:\r
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined\r
+ * in FIPS PUB 180-1\r
+ * Version 2.1a Copyright Paul Johnston 2000 - 2002.\r
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ \r
+\r
+ public class SHA256 extends SHABase implements IHash\r
+ {\r
+ \r
+ protected static const k:Array = [\r
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\r
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\r
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\r
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\r
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\r
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\r
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\r
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];\r
+ protected var h:Array = [\r
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19\r
+ ];\r
+ \r
+ public function SHA256(){\r
+ }\r
+ \r
+ public override function getHashSize():uint\r
+ {\r
+ return 32;\r
+ }\r
+ \r
+ protected override function core(x:Array, len:uint):Array {\r
+ /* append padding */\r
+ x[len >> 5] |= 0x80 << (24 - len % 32);\r
+ x[((len + 64 >> 9) << 4) + 15] = len;\r
+ \r
+ var w:Array = [];\r
+ var a:uint = h[0];\r
+ var b:uint = h[1];\r
+ var c:uint = h[2];\r
+ var d:uint = h[3];\r
+ var e:uint = h[4];\r
+ var f:uint = h[5];\r
+ var g:uint = h[6];\r
+ var h:uint = h[7];\r
+ \r
+ for (var i:uint=0; i<x.length; i+=16) {\r
+ var olda:uint = a;\r
+ var oldb:uint = b;\r
+ var oldc:uint = c;\r
+ var oldd:uint = d;\r
+ var olde:uint = e;\r
+ var oldf:uint = f;\r
+ var oldg:uint = g;\r
+ var oldh:uint = h;\r
+\r
+ for (var j:uint=0; j<64; j++) {\r
+ if (j<16) {\r
+ w[j] = x[i+j] || 0;\r
+ } else {\r
+ var s0:uint = rrol(w[j-15],7)^rrol(w[j-15],18)^(w[j-15]>>>3);\r
+ var s1:uint = rrol(w[j-2], 17)^rrol(w[j-2],19)^(w[j-2]>>>10);\r
+ w[j] = w[j-16] + s0 + w[j-7] + s1;\r
+ }\r
+ var t2:uint = (rrol(a,2) ^ rrol(a,13) ^ rrol(a,22)) + ((a&b) ^ (a&c) ^ (b&c));\r
+ var t1:uint = h + (rrol(e,6) ^ rrol(e,11) ^ rrol(e,25)) + ((e&f)^(g&~e)) + k[j] + w[j]\r
+ h = g;\r
+ g = f;\r
+ f = e;\r
+ e = d + t1;\r
+ d = c;\r
+ c = b;\r
+ b = a;\r
+ a = t1 + t2;\r
+\r
+ }\r
+ a += olda;\r
+ b += oldb;\r
+ c += oldc;\r
+ d += oldd;\r
+ e += olde;\r
+ f += oldf;\r
+ g += oldg;\r
+ h += oldh;\r
+ }\r
+ return [ a,b,c,d,e,f,g,h ];\r
+ }\r
+ \r
+ /*\r
+ * Bitwise rotate a 32-bit number to the right.\r
+ */\r
+ protected function rrol(num:uint, cnt:uint):uint {\r
+ return (num << (32-cnt)) | (num >>> cnt);\r
+ }\r
+ \r
+ public override function toString():String {\r
+ return "sha256";\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * SHABase\r
+ * \r
+ * An ActionScript 3 abstract class for the SHA family of hash functions\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.hash\r
+{\r
+ import flash.utils.ByteArray;\r
+ import flash.utils.Endian;\r
+\r
+ public class SHABase implements IHash\r
+ {\r
+\r
+ public function SHABase() { }\r
+\r
+ public var pad_size:int = 40;\r
+ public function getInputSize():uint\r
+ {\r
+ return 64;\r
+ }\r
+ \r
+ public function getHashSize():uint\r
+ {\r
+ return 0;\r
+ }\r
+ \r
+ public function getPadSize():int \r
+ {\r
+ return pad_size;\r
+ }\r
+ \r
+ public function hash(src:ByteArray):ByteArray\r
+ {\r
+ var savedLength:uint = src.length;\r
+ var savedEndian:String = src.endian;\r
+ \r
+ src.endian = Endian.BIG_ENDIAN;\r
+ var len:uint = savedLength *8;\r
+ // pad to nearest int.\r
+ while (src.length%4!=0) {\r
+ src[src.length]=0;\r
+ }\r
+ // convert ByteArray to an array of uint\r
+ src.position=0;\r
+ var a:Array = [];\r
+ for (var i:uint=0;i<src.length;i+=4) {\r
+ a.push(src.readUnsignedInt());\r
+ }\r
+ var h:Array = core(a, len);\r
+ var out:ByteArray = new ByteArray;\r
+ var words:uint = getHashSize()/4;\r
+ for (i=0;i<words;i++) {\r
+ out.writeUnsignedInt(h[i]);\r
+ }\r
+ // unpad, to leave the source untouched.\r
+ src.length = savedLength;\r
+ src.endian = savedEndian;\r
+ return out;\r
+ }\r
+ protected function core(x:Array, len:uint):Array {\r
+ return null;\r
+ }\r
+ \r
+ public function toString():String {\r
+ return "sha";\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * ARC4\r
+ * \r
+ * An ActionScript 3 implementation of RC4\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * The jsbn library, Copyright (c) 2003-2005 Tom Wu\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.prng\r
+{\r
+ import com.hurlant.crypto.symmetric.IStreamCipher;\r
+ import com.hurlant.util.Memory;\r
+ \r
+ import flash.utils.ByteArray;\r
+\r
+ public class ARC4 implements IPRNG, IStreamCipher {\r
+ private var i:int = 0;\r
+ private var j:int = 0;\r
+ private var S:ByteArray;\r
+ private const psize:uint = 256;\r
+ public function ARC4(key:ByteArray = null){\r
+ S = new ByteArray;\r
+ if (key) {\r
+ init(key);\r
+ }\r
+ }\r
+ public function getPoolSize():uint {\r
+ return psize;\r
+ }\r
+ public function init(key:ByteArray):void {\r
+ var i:int;\r
+ var j:int;\r
+ var t:int;\r
+ for (i=0; i<256; ++i) {\r
+ S[i] = i;\r
+ }\r
+ j=0;\r
+ for (i=0; i<256; ++i) {\r
+ j = (j + S[i] + key[i%key.length]) & 255;\r
+ t = S[i];\r
+ S[i] = S[j];\r
+ S[j] = t;\r
+ }\r
+ this.i=0;\r
+ this.j=0;\r
+ }\r
+ public function next():uint {\r
+ var t:int;\r
+ i = (i+1)&255;\r
+ j = (j+S[i])&255;\r
+ t = S[i];\r
+ S[i] = S[j];\r
+ S[j] = t;\r
+ return S[(t+S[i])&255];\r
+ }\r
+\r
+ public function getBlockSize():uint {\r
+ return 1;\r
+ }\r
+ \r
+ public function encrypt(block:ByteArray):void {\r
+ var i:uint = 0;\r
+ while (i<block.length) {\r
+ block[i++] ^= next();\r
+ }\r
+ }\r
+ public function decrypt(block:ByteArray):void {\r
+ encrypt(block); // the beauty of XOR.\r
+ }\r
+ public function dispose():void {\r
+ var i:uint = 0;\r
+ if (S!=null) {\r
+ for (i=0;i<S.length;i++) {\r
+ S[i] = Math.random()*256;\r
+ }\r
+ S.length=0;\r
+ S = null;\r
+ }\r
+ this.i = 0;\r
+ this.j = 0;\r
+ Memory.gc();\r
+ }\r
+ public function toString():String {\r
+ return "rc4";\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * IPRNG\r
+ * \r
+ * An interface for classes that can be used a pseudo-random number generators\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.prng\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public interface IPRNG {\r
+ function getPoolSize():uint;\r
+ function init(key:ByteArray):void;\r
+ function next():uint;\r
+ function dispose():void;\r
+ function toString():String;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Random\r
+ * \r
+ * An ActionScript 3 implementation of a Random Number Generator\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * The jsbn library, Copyright (c) 2003-2005 Tom Wu\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.prng\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Memory;\r
+ import flash.system.System;\r
+ import flash.system.Capabilities;\r
+ import flash.accessibility.AccessibilityProperties;\r
+ import flash.display.SWFVersion;\r
+ import flash.display.Stage;\r
+ import flash.utils.getTimer;\r
+ import flash.text.Font;\r
+ \r
+ public class Random\r
+ {\r
+ private var state:IPRNG;\r
+ private var ready:Boolean = false;\r
+ private var pool:ByteArray;\r
+ private var psize:int;\r
+ private var pptr:int;\r
+ private var seeded:Boolean = false;\r
+ \r
+ public function Random(prng:Class = null) {\r
+ if (prng==null) prng = ARC4;\r
+ state = new prng as IPRNG;\r
+ psize= state.getPoolSize();\r
+ pool = new ByteArray;\r
+ pptr = 0;\r
+ while (pptr <psize) {\r
+ var t:uint = 65536*Math.random();\r
+ pool[pptr++] = t >>> 8;\r
+ pool[pptr++] = t&255;\r
+ }\r
+ pptr=0;\r
+ seed();\r
+ }\r
+ \r
+ public function seed(x:int = 0):void {\r
+ if (x==0) {\r
+ x = new Date().getTime();\r
+ }\r
+ pool[pptr++] ^= x & 255;\r
+ pool[pptr++] ^= (x>>8)&255;\r
+ pool[pptr++] ^= (x>>16)&255;\r
+ pool[pptr++] ^= (x>>24)&255;\r
+ pptr %= psize;\r
+ seeded = true;\r
+ }\r
+ \r
+ /**\r
+ * Gather anything we have that isn't entirely predictable:\r
+ * - memory used\r
+ * - system capabilities\r
+ * - timing stuff\r
+ * - installed fonts\r
+ */\r
+ public function autoSeed():void {\r
+ var b:ByteArray = new ByteArray;\r
+ b.writeUnsignedInt(System.totalMemory);\r
+ b.writeUTF(Capabilities.serverString);\r
+ b.writeUnsignedInt(getTimer());\r
+ b.writeUnsignedInt((new Date).getTime());\r
+ var a:Array = Font.enumerateFonts(true);\r
+ for each (var f:Font in a) {\r
+ b.writeUTF(f.fontName);\r
+ b.writeUTF(f.fontStyle);\r
+ b.writeUTF(f.fontType);\r
+ }\r
+ b.position=0;\r
+ while (b.bytesAvailable>=4) {\r
+ seed(b.readUnsignedInt());\r
+ }\r
+ }\r
+ \r
+ \r
+ public function nextBytes(buffer:ByteArray, length:int):void {\r
+ while (length--) {\r
+ buffer.writeByte(nextByte());\r
+ }\r
+ }\r
+ public function nextByte():int {\r
+ if (!ready) {\r
+ if (!seeded) {\r
+ autoSeed();\r
+ }\r
+ state.init(pool);\r
+ pool.length = 0;\r
+ pptr = 0;\r
+ ready = true;\r
+ }\r
+ return state.next();\r
+ }\r
+ public function dispose():void {\r
+ for (var i:uint=0;i<pool.length;i++) {\r
+ pool[i] = Math.random()*256;\r
+ }\r
+ pool.length=0;\r
+ pool = null;\r
+ state.dispose();\r
+ state = null;\r
+ psize = 0;\r
+ pptr = 0;\r
+ Memory.gc();\r
+ }\r
+ public function toString():String {\r
+ return "random-"+state.toString();\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * TLSPRF\r
+ * \r
+ * An ActionScript 3 implementation of a pseudo-random generator\r
+ * that follows the TLS specification\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.prng\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.crypto.hash.HMAC;\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ import com.hurlant.util.Memory;\r
+ import com.hurlant.util.Hex;\r
+ import flash.utils.IDataOutput;\r
+\r
+ /**\r
+ * There's "Random", and then there's TLS Random.\r
+ * .\r
+ * Still Pseudo-random, though.\r
+ */\r
+ public class TLSPRF\r
+ {\r
+ // XXX WAY TOO MANY STRUCTURES HERE\r
+ \r
+ // seed\r
+ private var seed:ByteArray;\r
+ // P_MD5's secret\r
+ private var s1:ByteArray;\r
+ // P_SHA-1's secret\r
+ private var s2:ByteArray;\r
+ // HMAC_MD5's A\r
+ private var a1:ByteArray;\r
+ // HMAC_SHA1's A\r
+ private var a2:ByteArray;\r
+ // Pool for P_MD5\r
+ private var p1:ByteArray;\r
+ // Pool for P_SHA1\r
+ private var p2:ByteArray;\r
+ // Data for HMAC_MD5\r
+ private var d1:ByteArray;\r
+ // Data for HMAC_SHA1\r
+ private var d2:ByteArray;\r
+ \r
+ \r
+ private var hmac_md5:HMAC;\r
+ private var hmac_sha1:HMAC;\r
+ \r
+ public function TLSPRF(secret:ByteArray, label:String, seed:ByteArray) {\r
+ var l:int = Math.ceil(secret.length/2);\r
+ var s1:ByteArray = new ByteArray;\r
+ var s2:ByteArray = new ByteArray;\r
+ s1.writeBytes(secret, 0, l);\r
+ s2.writeBytes(secret, secret.length-l, l);\r
+ var s:ByteArray = new ByteArray;\r
+ s.writeUTFBytes(label);\r
+ s.writeBytes(seed);\r
+ this.seed = s;\r
+ this.s1 = s1;\r
+ this.s2 = s2;\r
+ hmac_md5 = new HMAC(new MD5);\r
+ hmac_sha1 = new HMAC(new SHA1);\r
+ \r
+ this.a1 = hmac_md5.compute(s1, this.seed);\r
+ this.a2 = hmac_sha1.compute(s2, this.seed);\r
+ \r
+ p1 = new ByteArray;\r
+ p2 = new ByteArray;\r
+ \r
+ d1 = new ByteArray;\r
+ d2 = new ByteArray;\r
+ d1.position = MD5.HASH_SIZE;\r
+ d1.writeBytes(this.seed);\r
+ d2.position = SHA1.HASH_SIZE;\r
+ d2.writeBytes(this.seed);\r
+ }\r
+ \r
+ // XXX HORRIBLY SLOW. REWRITE.\r
+ public function nextBytes(buffer:IDataOutput, length:int):void {\r
+ while (length--) {\r
+ buffer.writeByte(nextByte());\r
+ }\r
+ }\r
+ public function nextByte():int {\r
+ if (p1.bytesAvailable==0) {\r
+ more_md5();\r
+ }\r
+ if (p2.bytesAvailable==0) {\r
+ more_sha1();\r
+ }\r
+ return p1.readUnsignedByte()^p2.readUnsignedByte();\r
+ }\r
+ public function dispose():void {\r
+ seed = dba(seed);\r
+ s1 = dba(s1);\r
+ s2 = dba(s2);\r
+ a1 = dba(a1);\r
+ a2 = dba(a2);\r
+ p1 = dba(p1);\r
+ p2 = dba(p2);\r
+ d1 = dba(d1);\r
+ d2 = dba(d2);\r
+ hmac_md5.dispose();\r
+ hmac_md5 = null;\r
+ hmac_sha1.dispose();\r
+ hmac_sha1 = null;\r
+ Memory.gc();\r
+ }\r
+ public function toString():String {\r
+ return "tls-prf";\r
+ }\r
+ private function dba(ba:ByteArray):ByteArray {\r
+ for (var i:uint=0;i<ba.length;i++) {\r
+ ba[i]=0;\r
+ }\r
+ ba.length=0;\r
+ return null;\r
+ }\r
+ private function more_md5():void {\r
+ d1.position=0;\r
+ d1.writeBytes(a1);\r
+ var p:int = p1.position;\r
+ var more:ByteArray = hmac_md5.compute(s1, d1);\r
+ a1 = hmac_md5.compute(s1, a1);\r
+ p1.writeBytes(more);\r
+ p1.position=p;\r
+ }\r
+ private function more_sha1():void {\r
+ d2.position=0;\r
+ d2.writeBytes(a2);\r
+ var p:int = p2.position;\r
+ var more:ByteArray = hmac_sha1.compute(s2, d2);\r
+ a2 = hmac_sha1.compute(s2, a2);\r
+ p2.writeBytes(more);\r
+ p2.position=p;\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * RSAKey\r
+ * \r
+ * An ActionScript 3 implementation of RSA + PKCS#1 (light version)\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * The jsbn library, Copyright (c) 2003-2005 Tom Wu\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.rsa\r
+{\r
+ import com.hurlant.crypto.prng.Random;\r
+ import com.hurlant.math.BigInteger;\r
+ import com.hurlant.util.Memory;\r
+ \r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.crypto.hash.IHash;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.util.der.DER;\r
+ import com.hurlant.util.der.OID;\r
+ import com.hurlant.util.ArrayUtil;\r
+ import com.hurlant.util.der.Type;\r
+ import com.hurlant.util.der.Sequence;\r
+ import com.hurlant.util.der.ObjectIdentifier;\r
+ import com.hurlant.util.der.ByteString;
+ import com.hurlant.crypto.tls.TLSError;\r
+ \r
+ /**\r
+ * Current limitations:\r
+ * exponent must be smaller than 2^31.\r
+ */\r
+ public class RSAKey\r
+ {\r
+ // public key\r
+ public var e:int; // public exponent. must be <2^31\r
+ public var n:BigInteger; // modulus\r
+ // private key\r
+ public var d:BigInteger;\r
+ // extended private key\r
+ public var p:BigInteger;\r
+ public var q:BigInteger;\r
+ public var dmp1:BigInteger\r
+ public var dmq1:BigInteger;\r
+ public var coeff:BigInteger;\r
+ // flags. flags are cool.\r
+ protected var canDecrypt:Boolean;\r
+ protected var canEncrypt:Boolean;\r
+ \r
+ public function RSAKey(N:BigInteger, E:int, \r
+ D:BigInteger=null,\r
+ P:BigInteger = null, Q:BigInteger=null,\r
+ DP:BigInteger=null, DQ:BigInteger=null,\r
+ C:BigInteger=null) {\r
+ \r
+ this.n = N;\r
+ this.e = E;\r
+ this.d = D;\r
+ this.p = P;\r
+ this.q = Q;\r
+ this.dmp1 = DP;\r
+ this.dmq1 = DQ;\r
+ this.coeff = C;\r
+ \r
+ // adjust a few flags.\r
+ canEncrypt = (n!=null&&e!=0);\r
+ canDecrypt = (canEncrypt&&d!=null);\r
+ \r
+ \r
+ }\r
+\r\r
+ public static function parsePublicKey(N:String, E:String):RSAKey {\r
+ return new RSAKey(new BigInteger(N, 16, true), parseInt(E,16));\r
+ }\r
+ public static function parsePrivateKey(N:String, E:String, D:String, \r
+ P:String=null,Q:String=null, DMP1:String=null, DMQ1:String=null, IQMP:String=null):RSAKey {\r
+ if (P==null) {\r
+ return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true));\r
+ } else {\r
+ return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true),\r
+ new BigInteger(P,16, true), new BigInteger(Q,16, true),\r
+ new BigInteger(DMP1,16, true), new BigInteger(DMQ1, 16, true),\r
+ new BigInteger(IQMP, 16, true));\r
+ }\r
+ }\r
+ \r
+ public function getBlockSize():uint {\r
+ return (n.bitLength()+7)/8;\r
+ }\r
+ public function dispose():void {\r
+ e = 0;\r
+ n.dispose();\r
+ n = null;\r
+ Memory.gc();\r
+ }\r
+\r\r
+ public function encrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {\r
+ _encrypt(doPublic, src, dst, length, pad, 0x02);\r
+ }\r
+ public function decrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {\r
+ _decrypt(doPrivate2, src, dst, length, pad, 0x02);\r
+ }\r
+\r\r
+ public function sign(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {\r
+ _encrypt(doPrivate2, src, dst, length, pad, 0x01);\r
+ }\r
+ public function verify(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {\r
+ _decrypt(doPublic, src, dst, length, pad, 0x01);\r
+ }\r
+ \r
+\r\r
+ private function _encrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {\r
+ // adjust pad if needed\r
+ if (pad==null) pad = pkcs1pad;\r
+ // convert src to BigInteger\r
+ if (src.position >= src.length) {\r
+ src.position = 0;\r
+ }\r
+ var bl:uint = getBlockSize();\r
+ var end:int = src.position + length;\r
+ while (src.position<end) {\r
+ var block:BigInteger = new BigInteger(pad(src, end, bl, padType), bl, true);\r
+ var chunk:BigInteger = op(block);\r
+ chunk.toArray(dst);\r
+ }\r
+ }\r
+ private function _decrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {\r
+ // adjust pad if needed\r
+ if (pad==null) pad = pkcs1unpad;\r
+ \r
+ // convert src to BigInteger\r
+ if (src.position >= src.length) {\r
+ src.position = 0;\r
+ }\r
+ var bl:uint = getBlockSize();\r
+ var end:int = src.position + length;\r
+ while (src.position<end) {\r
+ var block:BigInteger = new BigInteger(src, bl, true);\r
+ var chunk:BigInteger = op(block);\r
+ var b:ByteArray = pad(chunk, bl, padType);\r
+ if (b == null) \r
+ throw new TLSError( "Decrypt error - padding function returned null!", TLSError.decode_error );\r
+ // if (b != null)\r
+ dst.writeBytes(b);\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * PKCS#1 pad. type 1 (0xff) or 2, random.\r
+ * puts as much data from src into it, leaves what doesn't fit alone.\r
+ */\r
+ private function pkcs1pad(src:ByteArray, end:int, n:uint, type:uint = 0x02):ByteArray {\r
+ var out:ByteArray = new ByteArray;\r
+ var p:uint = src.position;\r
+ end = Math.min(end, src.length, p+n-11);\r
+ src.position = end;\r
+ var i:int = end-1;\r
+ while (i>=p && n>11) {\r
+ out[--n] = src[i--];\r
+ }\r
+ out[--n] = 0;\r
+ if (type==0x02) { // type 2\r
+ var rng:Random = new Random;\r
+ var x:int = 0;\r
+ while (n>2) {\r
+ do {\r
+ x = rng.nextByte();\r
+ } while (x==0);\r
+ out[--n] = x;\r
+ }\r
+ } else { // type 1\r
+ while (n>2) {\r
+ out[--n] = 0xFF;\r
+ }\r
+ }\r
+ out[--n] = type;\r
+ out[--n] = 0;\r
+ return out;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param src\r
+ * @param n\r
+ * @param type Not used.\r
+ * @return \r
+ * \r
+ */\r
+ private function pkcs1unpad(src:BigInteger, n:uint, type:uint = 0x02):ByteArray {\r
+ var b:ByteArray = src.toByteArray();\r
+ var out:ByteArray = new ByteArray;\r
+ \r
+ b.position = 0;\r
+ var i:int = 0;\r
+ while (i<b.length && b[i]==0) ++i;\r
+ if (b.length-i != n-1 || b[i]!=type) {\r
+ trace("PKCS#1 unpad: i="+i+", expected b[i]=="+type+", got b[i]="+b[i].toString(16));\r
+ return null;\r
+ }\r
+ ++i;\r
+ while (b[i]!=0) {\r
+ if (++i>=b.length) {\r
+ trace("PKCS#1 unpad: i="+i+", b[i-1]!=0 (="+b[i-1].toString(16)+")");\r
+ return null;\r
+ }\r
+ }\r
+ while (++i < b.length) {\r
+ out.writeByte(b[i]);\r
+ }\r
+ out.position = 0;\r
+ return out;\r
+ }\r
+ /**\r
+ * Raw pad.\r
+ */\r
+ public function rawpad(src:ByteArray, end:int, n:uint, type:uint = 0):ByteArray {\r
+ return src;\r
+ }\r
+ public function rawunpad(src:BigInteger, n:uint, type:uint = 0):ByteArray {\r
+ return src.toByteArray();\r
+ }\r
+ \r
+ public function toString():String {\r
+ return "rsa";\r
+ }\r
+ \r
+ public function dump():String {\r
+ var s:String= "N="+n.toString(16)+"\n"+\r
+ "E="+e.toString(16)+"\n";\r
+ if (canDecrypt) {\r
+ s+="D="+d.toString(16)+"\n";\r
+ if (p!=null && q!=null) {\r
+ s+="P="+p.toString(16)+"\n";\r
+ s+="Q="+q.toString(16)+"\n";\r
+ s+="DMP1="+dmp1.toString(16)+"\n";\r
+ s+="DMQ1="+dmq1.toString(16)+"\n";\r
+ s+="IQMP="+coeff.toString(16)+"\n";\r
+ }\r
+ }\r
+ return s;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * \r
+ * note: We should have a "nice" variant of this function that takes a callback,\r
+ * and perform the computation is small fragments, to keep the web browser\r
+ * usable.\r
+ * \r
+ * @param B\r
+ * @param E\r
+ * @return a new random private key B bits long, using public expt E\r
+ * \r
+ */\r
+ public static function generate(B:uint, E:String):RSAKey {\r
+ var rng:Random = new Random;\r
+ var qs:uint = B>>1;\r
+ var key:RSAKey = new RSAKey(null,0,null);\r
+ key.e = parseInt(E, 16);\r
+ var ee:BigInteger = new BigInteger(E,16, true);\r
+ for (;;) {\r
+ for (;;) {\r
+ key.p = bigRandom(B-qs, rng);\r
+ if (key.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&\r
+ key.p.isProbablePrime(10)) break;\r
+ }\r
+ for (;;) {\r
+ key.q = bigRandom(qs, rng);\r
+ if (key.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&\r
+ key.q.isProbablePrime(10)) break;\r
+ }\r
+ if (key.p.compareTo(key.q)<=0) {\r
+ var t:BigInteger = key.p;\r
+ key.p = key.q;\r
+ key.q = t;\r
+ }\r
+ var p1:BigInteger = key.p.subtract(BigInteger.ONE);\r
+ var q1:BigInteger = key.q.subtract(BigInteger.ONE);\r
+ var phi:BigInteger = p1.multiply(q1);\r
+ if (phi.gcd(ee).compareTo(BigInteger.ONE)==0) {\r
+ key.n = key.p.multiply(key.q);\r
+ key.d = ee.modInverse(phi);\r
+ key.dmp1 = key.d.mod(p1);\r
+ key.dmq1 = key.d.mod(q1);\r
+ key.coeff = key.q.modInverse(key.p);\r
+ break;\r
+ }\r
+ }\r
+ return key;\r
+ }\r
+ \r
+ protected static function bigRandom(bits:int, rnd:Random):BigInteger {\r
+ if (bits<2) return BigInteger.nbv(1);\r
+ var x:ByteArray = new ByteArray;\r
+ rnd.nextBytes(x, (bits>>3));\r
+ x.position = 0;\r
+ var b:BigInteger = new BigInteger(x,0,true);\r
+ b.primify(bits, 1);\r
+ return b;\r
+ }\r
+ \r
+ protected function doPublic(x:BigInteger):BigInteger {\r
+ return x.modPowInt(e, n);\r
+ }\r
+ \r
+ protected function doPrivate2(x:BigInteger):BigInteger {\r
+ if (p==null && q==null) {\r
+ return x.modPow(d,n);\r
+ }\r
+ \r
+ var xp:BigInteger = x.mod(p).modPow(dmp1, p);\r
+ var xq:BigInteger = x.mod(q).modPow(dmq1, q);\r
+ \r
+ while (xp.compareTo(xq)<0) {\r
+ xp = xp.add(p);\r
+ }\r
+ var r:BigInteger = xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);\r
+ \r
+ return r;\r
+ }\r
+ \r
+ protected function doPrivate(x:BigInteger):BigInteger {\r
+ if (p==null || q==null) {\r
+ return x.modPow(d, n);\r
+ }\r
+ // TODO: re-calculate any missing CRT params\r
+ var xp:BigInteger = x.mod(p).modPow(dmp1, p);\r
+ var xq:BigInteger = x.mod(q).modPow(dmq1, q);\r
+ \r
+ while (xp.compareTo(xq)<0) {\r
+ xp = xp.add(p);\r
+ }\r
+ return xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);\r
+ }\r
+ \r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * AESKey\r
+ * \r
+ * An ActionScript 3 implementation of the Advanced Encryption Standard, as\r
+ * defined in FIPS PUB 197\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * A public domain implementation from Karl Malbrain, malbrain@yahoo.com\r
+ * (http://www.geocities.com/malbrain/aestable_c.html)\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import com.hurlant.crypto.prng.Random;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.util.Memory;\r
+ \r
+ import flash.utils.ByteArray;\r
+\r
+ public class AESKey implements ISymmetricKey\r
+ {\r
+ // AES only supports Nb=4\r
+ private static const Nb:uint = 4; // number of columns in the state & expanded key\r
+ \r
+ // TODO:\r
+ // - move those tables in binary files, then\r
+ // - [Embed()] them as ByteArray directly.\r
+ // (should result in smaller .swf, and faster initialization time.)\r
+ \r
+ private static const _Sbox:Array = [ // forward s-box\r
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,\r
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,\r
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,\r
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,\r
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,\r
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,\r
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,\r
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,\r
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,\r
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,\r
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,\r
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,\r
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,\r
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,\r
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,\r
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];\r
+ private static const _InvSbox:Array = [ // inverse s-box\r
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,\r
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,\r
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,\r
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,\r
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,\r
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,\r
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,\r
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,\r
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,\r
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,\r
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,\r
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,\r
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,\r
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,\r
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,\r
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]; \r
+ private static const _Xtime2Sbox:Array = [ // combined Xtimes2[Sbox[]]\r
+ 0xc6, 0xf8, 0xee, 0xf6, 0xff, 0xd6, 0xde, 0x91, 0x60, 0x02, 0xce, 0x56, 0xe7, 0xb5, 0x4d, 0xec, \r
+ 0x8f, 0x1f, 0x89, 0xfa, 0xef, 0xb2, 0x8e, 0xfb, 0x41, 0xb3, 0x5f, 0x45, 0x23, 0x53, 0xe4, 0x9b, \r
+ 0x75, 0xe1, 0x3d, 0x4c, 0x6c, 0x7e, 0xf5, 0x83, 0x68, 0x51, 0xd1, 0xf9, 0xe2, 0xab, 0x62, 0x2a, \r
+ 0x08, 0x95, 0x46, 0x9d, 0x30, 0x37, 0x0a, 0x2f, 0x0e, 0x24, 0x1b, 0xdf, 0xcd, 0x4e, 0x7f, 0xea, \r
+ 0x12, 0x1d, 0x58, 0x34, 0x36, 0xdc, 0xb4, 0x5b, 0xa4, 0x76, 0xb7, 0x7d, 0x52, 0xdd, 0x5e, 0x13, \r
+ 0xa6, 0xb9, 0x00, 0xc1, 0x40, 0xe3, 0x79, 0xb6, 0xd4, 0x8d, 0x67, 0x72, 0x94, 0x98, 0xb0, 0x85, \r
+ 0xbb, 0xc5, 0x4f, 0xed, 0x86, 0x9a, 0x66, 0x11, 0x8a, 0xe9, 0x04, 0xfe, 0xa0, 0x78, 0x25, 0x4b, \r
+ 0xa2, 0x5d, 0x80, 0x05, 0x3f, 0x21, 0x70, 0xf1, 0x63, 0x77, 0xaf, 0x42, 0x20, 0xe5, 0xfd, 0xbf, \r
+ 0x81, 0x18, 0x26, 0xc3, 0xbe, 0x35, 0x88, 0x2e, 0x93, 0x55, 0xfc, 0x7a, 0xc8, 0xba, 0x32, 0xe6, \r
+ 0xc0, 0x19, 0x9e, 0xa3, 0x44, 0x54, 0x3b, 0x0b, 0x8c, 0xc7, 0x6b, 0x28, 0xa7, 0xbc, 0x16, 0xad, \r
+ 0xdb, 0x64, 0x74, 0x14, 0x92, 0x0c, 0x48, 0xb8, 0x9f, 0xbd, 0x43, 0xc4, 0x39, 0x31, 0xd3, 0xf2, \r
+ 0xd5, 0x8b, 0x6e, 0xda, 0x01, 0xb1, 0x9c, 0x49, 0xd8, 0xac, 0xf3, 0xcf, 0xca, 0xf4, 0x47, 0x10, \r
+ 0x6f, 0xf0, 0x4a, 0x5c, 0x38, 0x57, 0x73, 0x97, 0xcb, 0xa1, 0xe8, 0x3e, 0x96, 0x61, 0x0d, 0x0f, \r
+ 0xe0, 0x7c, 0x71, 0xcc, 0x90, 0x06, 0xf7, 0x1c, 0xc2, 0x6a, 0xae, 0x69, 0x17, 0x99, 0x3a, 0x27, \r
+ 0xd9, 0xeb, 0x2b, 0x22, 0xd2, 0xa9, 0x07, 0x33, 0x2d, 0x3c, 0x15, 0xc9, 0x87, 0xaa, 0x50, 0xa5, \r
+ 0x03, 0x59, 0x09, 0x1a, 0x65, 0xd7, 0x84, 0xd0, 0x82, 0x29, 0x5a, 0x1e, 0x7b, 0xa8, 0x6d, 0x2c];\r
+ private static const _Xtime3Sbox:Array = [ // combined Xtimes3[Sbox[]]\r
+ 0xa5, 0x84, 0x99, 0x8d, 0x0d, 0xbd, 0xb1, 0x54, 0x50, 0x03, 0xa9, 0x7d, 0x19, 0x62, 0xe6, 0x9a, \r
+ 0x45, 0x9d, 0x40, 0x87, 0x15, 0xeb, 0xc9, 0x0b, 0xec, 0x67, 0xfd, 0xea, 0xbf, 0xf7, 0x96, 0x5b, \r
+ 0xc2, 0x1c, 0xae, 0x6a, 0x5a, 0x41, 0x02, 0x4f, 0x5c, 0xf4, 0x34, 0x08, 0x93, 0x73, 0x53, 0x3f, \r
+ 0x0c, 0x52, 0x65, 0x5e, 0x28, 0xa1, 0x0f, 0xb5, 0x09, 0x36, 0x9b, 0x3d, 0x26, 0x69, 0xcd, 0x9f, \r
+ 0x1b, 0x9e, 0x74, 0x2e, 0x2d, 0xb2, 0xee, 0xfb, 0xf6, 0x4d, 0x61, 0xce, 0x7b, 0x3e, 0x71, 0x97, \r
+ 0xf5, 0x68, 0x00, 0x2c, 0x60, 0x1f, 0xc8, 0xed, 0xbe, 0x46, 0xd9, 0x4b, 0xde, 0xd4, 0xe8, 0x4a, \r
+ 0x6b, 0x2a, 0xe5, 0x16, 0xc5, 0xd7, 0x55, 0x94, 0xcf, 0x10, 0x06, 0x81, 0xf0, 0x44, 0xba, 0xe3, \r
+ 0xf3, 0xfe, 0xc0, 0x8a, 0xad, 0xbc, 0x48, 0x04, 0xdf, 0xc1, 0x75, 0x63, 0x30, 0x1a, 0x0e, 0x6d, \r
+ 0x4c, 0x14, 0x35, 0x2f, 0xe1, 0xa2, 0xcc, 0x39, 0x57, 0xf2, 0x82, 0x47, 0xac, 0xe7, 0x2b, 0x95, \r
+ 0xa0, 0x98, 0xd1, 0x7f, 0x66, 0x7e, 0xab, 0x83, 0xca, 0x29, 0xd3, 0x3c, 0x79, 0xe2, 0x1d, 0x76, \r
+ 0x3b, 0x56, 0x4e, 0x1e, 0xdb, 0x0a, 0x6c, 0xe4, 0x5d, 0x6e, 0xef, 0xa6, 0xa8, 0xa4, 0x37, 0x8b, \r
+ 0x32, 0x43, 0x59, 0xb7, 0x8c, 0x64, 0xd2, 0xe0, 0xb4, 0xfa, 0x07, 0x25, 0xaf, 0x8e, 0xe9, 0x18, \r
+ 0xd5, 0x88, 0x6f, 0x72, 0x24, 0xf1, 0xc7, 0x51, 0x23, 0x7c, 0x9c, 0x21, 0xdd, 0xdc, 0x86, 0x85, \r
+ 0x90, 0x42, 0xc4, 0xaa, 0xd8, 0x05, 0x01, 0x12, 0xa3, 0x5f, 0xf9, 0xd0, 0x91, 0x58, 0x27, 0xb9, \r
+ 0x38, 0x13, 0xb3, 0x33, 0xbb, 0x70, 0x89, 0xa7, 0xb6, 0x22, 0x92, 0x20, 0x49, 0xff, 0x78, 0x7a, \r
+ 0x8f, 0xf8, 0x80, 0x17, 0xda, 0x31, 0xc6, 0xb8, 0xc3, 0xb0, 0x77, 0x11, 0xcb, 0xfc, 0xd6, 0x3a];\r
+ // modular multiplication tables\r
+ // based on:\r
+ \r
+ // Xtime2[x] = (x & 0x80 ? 0x1b : 0) ^ (x + x)\r
+ // Xtime3[x] = x^Xtime2[x];\r
+ private static const _Xtime2:Array = [ \r
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, \r
+ 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, \r
+ 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, \r
+ 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, \r
+ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, \r
+ 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, \r
+ 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, \r
+ 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, \r
+ 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, \r
+ 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, \r
+ 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, \r
+ 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, \r
+ 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, \r
+ 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, \r
+ 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, \r
+ 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5]; \r
+ private static const _Xtime9:Array = [\r
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, \r
+ 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, \r
+ 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, \r
+ 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, \r
+ 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, \r
+ 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, \r
+ 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, \r
+ 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, \r
+ 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, \r
+ 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, \r
+ 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, \r
+ 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, \r
+ 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, \r
+ 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, \r
+ 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, \r
+ 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46];\r
+ private static const _XtimeB:Array = [\r
+ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, \r
+ 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, \r
+ 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, \r
+ 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, \r
+ 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, \r
+ 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, \r
+ 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, \r
+ 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, \r
+ 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, \r
+ 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, \r
+ 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, \r
+ 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, \r
+ 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, \r
+ 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, \r
+ 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, \r
+ 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3]; \r
+ private static const _XtimeD:Array = [\r
+ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, \r
+ 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, \r
+ 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, \r
+ 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, \r
+ 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, \r
+ 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, \r
+ 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, \r
+ 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, \r
+ 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, \r
+ 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, \r
+ 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, \r
+ 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, \r
+ 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, \r
+ 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, \r
+ 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, \r
+ 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97];\r
+ private static const _XtimeE:Array = [\r
+ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, \r
+ 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, \r
+ 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, \r
+ 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, \r
+ 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, \r
+ 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, \r
+ 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, \r
+ 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, \r
+ 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, \r
+ 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, \r
+ 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, \r
+ 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, \r
+ 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, \r
+ 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, \r
+ 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, \r
+ 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d]; \r
+ static private var _Rcon:Array = [\r
+ 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];\r
+ static private var Sbox:ByteArray;\r
+ static private var InvSbox:ByteArray;\r
+ static private var Xtime2Sbox:ByteArray\r
+ static private var Xtime3Sbox:ByteArray\r
+ static private var Xtime2:ByteArray;\r
+ static private var Xtime9:ByteArray;\r
+ static private var XtimeB:ByteArray;\r
+ static private var XtimeD:ByteArray;\r
+ static private var XtimeE:ByteArray;\r
+ static private var Rcon:ByteArray;\r
+ // static initializer\r
+ {\r
+ static private var i:uint;\r
+ Sbox = new ByteArray;\r
+ InvSbox = new ByteArray;\r
+ Xtime2Sbox = new ByteArray;\r
+ Xtime3Sbox = new ByteArray;\r
+ Xtime2 = new ByteArray;\r
+ Xtime9 = new ByteArray;\r
+ XtimeB = new ByteArray;\r
+ XtimeD = new ByteArray;\r
+ XtimeE = new ByteArray;\r
+ /*\r
+ for (i=0;i<256;i++) {\r
+ Sbox[i] = _Sbox[i];\r
+ InvSbox[i] = _InvSbox[i];\r
+ Xtime2Sbox[i] = _Xtime2Sbox[i];\r
+ Xtime3Sbox[i] = _Xtime3Sbox[i];\r
+ Xtime2[i] = _Xtime2[i];\r
+ Xtime9[i] = _Xtime9[i];\r
+ XtimeB[i] = _XtimeB[i];\r
+ XtimeD[i] = _XtimeD[i];\r
+ XtimeE[i] = _XtimeE[i];\r
+ }\r
+ */\r
+ Sbox[0] = _Sbox[0]\r
+ InvSbox[0] = _InvSbox[0]\r
+ Xtime2Sbox[0] = _Xtime2Sbox[0]\r
+ Xtime3Sbox[0] = _Xtime3Sbox[0]\r
+ Xtime2[0] = _Xtime2[0]\r
+ Xtime9[0] = _Xtime9[0]\r
+ XtimeB[0] = _XtimeB[0]\r
+ XtimeD[0] = _XtimeD[0]\r
+ XtimeE[0] = _XtimeE[0]\r
+ Sbox[1] = _Sbox[1]\r
+ InvSbox[1] = _InvSbox[1]\r
+ Xtime2Sbox[1] = _Xtime2Sbox[1]\r
+ Xtime3Sbox[1] = _Xtime3Sbox[1]\r
+ Xtime2[1] = _Xtime2[1]\r
+ Xtime9[1] = _Xtime9[1]\r
+ XtimeB[1] = _XtimeB[1]\r
+ XtimeD[1] = _XtimeD[1]\r
+ XtimeE[1] = _XtimeE[1]\r
+ Sbox[2] = _Sbox[2]\r
+ InvSbox[2] = _InvSbox[2]\r
+ Xtime2Sbox[2] = _Xtime2Sbox[2]\r
+ Xtime3Sbox[2] = _Xtime3Sbox[2]\r
+ Xtime2[2] = _Xtime2[2]\r
+ Xtime9[2] = _Xtime9[2]\r
+ XtimeB[2] = _XtimeB[2]\r
+ XtimeD[2] = _XtimeD[2]\r
+ XtimeE[2] = _XtimeE[2]\r
+ Sbox[3] = _Sbox[3]\r
+ InvSbox[3] = _InvSbox[3]\r
+ Xtime2Sbox[3] = _Xtime2Sbox[3]\r
+ Xtime3Sbox[3] = _Xtime3Sbox[3]\r
+ Xtime2[3] = _Xtime2[3]\r
+ Xtime9[3] = _Xtime9[3]\r
+ XtimeB[3] = _XtimeB[3]\r
+ XtimeD[3] = _XtimeD[3]\r
+ XtimeE[3] = _XtimeE[3]\r
+ Sbox[4] = _Sbox[4]\r
+ InvSbox[4] = _InvSbox[4]\r
+ Xtime2Sbox[4] = _Xtime2Sbox[4]\r
+ Xtime3Sbox[4] = _Xtime3Sbox[4]\r
+ Xtime2[4] = _Xtime2[4]\r
+ Xtime9[4] = _Xtime9[4]\r
+ XtimeB[4] = _XtimeB[4]\r
+ XtimeD[4] = _XtimeD[4]\r
+ XtimeE[4] = _XtimeE[4]\r
+ Sbox[5] = _Sbox[5]\r
+ InvSbox[5] = _InvSbox[5]\r
+ Xtime2Sbox[5] = _Xtime2Sbox[5]\r
+ Xtime3Sbox[5] = _Xtime3Sbox[5]\r
+ Xtime2[5] = _Xtime2[5]\r
+ Xtime9[5] = _Xtime9[5]\r
+ XtimeB[5] = _XtimeB[5]\r
+ XtimeD[5] = _XtimeD[5]\r
+ XtimeE[5] = _XtimeE[5]\r
+ Sbox[6] = _Sbox[6]\r
+ InvSbox[6] = _InvSbox[6]\r
+ Xtime2Sbox[6] = _Xtime2Sbox[6]\r
+ Xtime3Sbox[6] = _Xtime3Sbox[6]\r
+ Xtime2[6] = _Xtime2[6]\r
+ Xtime9[6] = _Xtime9[6]\r
+ XtimeB[6] = _XtimeB[6]\r
+ XtimeD[6] = _XtimeD[6]\r
+ XtimeE[6] = _XtimeE[6]\r
+ Sbox[7] = _Sbox[7]\r
+ InvSbox[7] = _InvSbox[7]\r
+ Xtime2Sbox[7] = _Xtime2Sbox[7]\r
+ Xtime3Sbox[7] = _Xtime3Sbox[7]\r
+ Xtime2[7] = _Xtime2[7]\r
+ Xtime9[7] = _Xtime9[7]\r
+ XtimeB[7] = _XtimeB[7]\r
+ XtimeD[7] = _XtimeD[7]\r
+ XtimeE[7] = _XtimeE[7]\r
+ Sbox[8] = _Sbox[8]\r
+ InvSbox[8] = _InvSbox[8]\r
+ Xtime2Sbox[8] = _Xtime2Sbox[8]\r
+ Xtime3Sbox[8] = _Xtime3Sbox[8]\r
+ Xtime2[8] = _Xtime2[8]\r
+ Xtime9[8] = _Xtime9[8]\r
+ XtimeB[8] = _XtimeB[8]\r
+ XtimeD[8] = _XtimeD[8]\r
+ XtimeE[8] = _XtimeE[8]\r
+ Sbox[9] = _Sbox[9]\r
+ InvSbox[9] = _InvSbox[9]\r
+ Xtime2Sbox[9] = _Xtime2Sbox[9]\r
+ Xtime3Sbox[9] = _Xtime3Sbox[9]\r
+ Xtime2[9] = _Xtime2[9]\r
+ Xtime9[9] = _Xtime9[9]\r
+ XtimeB[9] = _XtimeB[9]\r
+ XtimeD[9] = _XtimeD[9]\r
+ XtimeE[9] = _XtimeE[9]\r
+ Sbox[10] = _Sbox[10]\r
+ InvSbox[10] = _InvSbox[10]\r
+ Xtime2Sbox[10] = _Xtime2Sbox[10]\r
+ Xtime3Sbox[10] = _Xtime3Sbox[10]\r
+ Xtime2[10] = _Xtime2[10]\r
+ Xtime9[10] = _Xtime9[10]\r
+ XtimeB[10] = _XtimeB[10]\r
+ XtimeD[10] = _XtimeD[10]\r
+ XtimeE[10] = _XtimeE[10]\r
+ Sbox[11] = _Sbox[11]\r
+ InvSbox[11] = _InvSbox[11]\r
+ Xtime2Sbox[11] = _Xtime2Sbox[11]\r
+ Xtime3Sbox[11] = _Xtime3Sbox[11]\r
+ Xtime2[11] = _Xtime2[11]\r
+ Xtime9[11] = _Xtime9[11]\r
+ XtimeB[11] = _XtimeB[11]\r
+ XtimeD[11] = _XtimeD[11]\r
+ XtimeE[11] = _XtimeE[11]\r
+ Sbox[12] = _Sbox[12]\r
+ InvSbox[12] = _InvSbox[12]\r
+ Xtime2Sbox[12] = _Xtime2Sbox[12]\r
+ Xtime3Sbox[12] = _Xtime3Sbox[12]\r
+ Xtime2[12] = _Xtime2[12]\r
+ Xtime9[12] = _Xtime9[12]\r
+ XtimeB[12] = _XtimeB[12]\r
+ XtimeD[12] = _XtimeD[12]\r
+ XtimeE[12] = _XtimeE[12]\r
+ Sbox[13] = _Sbox[13]\r
+ InvSbox[13] = _InvSbox[13]\r
+ Xtime2Sbox[13] = _Xtime2Sbox[13]\r
+ Xtime3Sbox[13] = _Xtime3Sbox[13]\r
+ Xtime2[13] = _Xtime2[13]\r
+ Xtime9[13] = _Xtime9[13]\r
+ XtimeB[13] = _XtimeB[13]\r
+ XtimeD[13] = _XtimeD[13]\r
+ XtimeE[13] = _XtimeE[13]\r
+ Sbox[14] = _Sbox[14]\r
+ InvSbox[14] = _InvSbox[14]\r
+ Xtime2Sbox[14] = _Xtime2Sbox[14]\r
+ Xtime3Sbox[14] = _Xtime3Sbox[14]\r
+ Xtime2[14] = _Xtime2[14]\r
+ Xtime9[14] = _Xtime9[14]\r
+ XtimeB[14] = _XtimeB[14]\r
+ XtimeD[14] = _XtimeD[14]\r
+ XtimeE[14] = _XtimeE[14]\r
+ Sbox[15] = _Sbox[15]\r
+ InvSbox[15] = _InvSbox[15]\r
+ Xtime2Sbox[15] = _Xtime2Sbox[15]\r
+ Xtime3Sbox[15] = _Xtime3Sbox[15]\r
+ Xtime2[15] = _Xtime2[15]\r
+ Xtime9[15] = _Xtime9[15]\r
+ XtimeB[15] = _XtimeB[15]\r
+ XtimeD[15] = _XtimeD[15]\r
+ XtimeE[15] = _XtimeE[15]\r
+ Sbox[16] = _Sbox[16]\r
+ InvSbox[16] = _InvSbox[16]\r
+ Xtime2Sbox[16] = _Xtime2Sbox[16]\r
+ Xtime3Sbox[16] = _Xtime3Sbox[16]\r
+ Xtime2[16] = _Xtime2[16]\r
+ Xtime9[16] = _Xtime9[16]\r
+ XtimeB[16] = _XtimeB[16]\r
+ XtimeD[16] = _XtimeD[16]\r
+ XtimeE[16] = _XtimeE[16]\r
+ Sbox[17] = _Sbox[17]\r
+ InvSbox[17] = _InvSbox[17]\r
+ Xtime2Sbox[17] = _Xtime2Sbox[17]\r
+ Xtime3Sbox[17] = _Xtime3Sbox[17]\r
+ Xtime2[17] = _Xtime2[17]\r
+ Xtime9[17] = _Xtime9[17]\r
+ XtimeB[17] = _XtimeB[17]\r
+ XtimeD[17] = _XtimeD[17]\r
+ XtimeE[17] = _XtimeE[17]\r
+ Sbox[18] = _Sbox[18]\r
+ InvSbox[18] = _InvSbox[18]\r
+ Xtime2Sbox[18] = _Xtime2Sbox[18]\r
+ Xtime3Sbox[18] = _Xtime3Sbox[18]\r
+ Xtime2[18] = _Xtime2[18]\r
+ Xtime9[18] = _Xtime9[18]\r
+ XtimeB[18] = _XtimeB[18]\r
+ XtimeD[18] = _XtimeD[18]\r
+ XtimeE[18] = _XtimeE[18]\r
+ Sbox[19] = _Sbox[19]\r
+ InvSbox[19] = _InvSbox[19]\r
+ Xtime2Sbox[19] = _Xtime2Sbox[19]\r
+ Xtime3Sbox[19] = _Xtime3Sbox[19]\r
+ Xtime2[19] = _Xtime2[19]\r
+ Xtime9[19] = _Xtime9[19]\r
+ XtimeB[19] = _XtimeB[19]\r
+ XtimeD[19] = _XtimeD[19]\r
+ XtimeE[19] = _XtimeE[19]\r
+ Sbox[20] = _Sbox[20]\r
+ InvSbox[20] = _InvSbox[20]\r
+ Xtime2Sbox[20] = _Xtime2Sbox[20]\r
+ Xtime3Sbox[20] = _Xtime3Sbox[20]\r
+ Xtime2[20] = _Xtime2[20]\r
+ Xtime9[20] = _Xtime9[20]\r
+ XtimeB[20] = _XtimeB[20]\r
+ XtimeD[20] = _XtimeD[20]\r
+ XtimeE[20] = _XtimeE[20]\r
+ Sbox[21] = _Sbox[21]\r
+ InvSbox[21] = _InvSbox[21]\r
+ Xtime2Sbox[21] = _Xtime2Sbox[21]\r
+ Xtime3Sbox[21] = _Xtime3Sbox[21]\r
+ Xtime2[21] = _Xtime2[21]\r
+ Xtime9[21] = _Xtime9[21]\r
+ XtimeB[21] = _XtimeB[21]\r
+ XtimeD[21] = _XtimeD[21]\r
+ XtimeE[21] = _XtimeE[21]\r
+ Sbox[22] = _Sbox[22]\r
+ InvSbox[22] = _InvSbox[22]\r
+ Xtime2Sbox[22] = _Xtime2Sbox[22]\r
+ Xtime3Sbox[22] = _Xtime3Sbox[22]\r
+ Xtime2[22] = _Xtime2[22]\r
+ Xtime9[22] = _Xtime9[22]\r
+ XtimeB[22] = _XtimeB[22]\r
+ XtimeD[22] = _XtimeD[22]\r
+ XtimeE[22] = _XtimeE[22]\r
+ Sbox[23] = _Sbox[23]\r
+ InvSbox[23] = _InvSbox[23]\r
+ Xtime2Sbox[23] = _Xtime2Sbox[23]\r
+ Xtime3Sbox[23] = _Xtime3Sbox[23]\r
+ Xtime2[23] = _Xtime2[23]\r
+ Xtime9[23] = _Xtime9[23]\r
+ XtimeB[23] = _XtimeB[23]\r
+ XtimeD[23] = _XtimeD[23]\r
+ XtimeE[23] = _XtimeE[23]\r
+ Sbox[24] = _Sbox[24]\r
+ InvSbox[24] = _InvSbox[24]\r
+ Xtime2Sbox[24] = _Xtime2Sbox[24]\r
+ Xtime3Sbox[24] = _Xtime3Sbox[24]\r
+ Xtime2[24] = _Xtime2[24]\r
+ Xtime9[24] = _Xtime9[24]\r
+ XtimeB[24] = _XtimeB[24]\r
+ XtimeD[24] = _XtimeD[24]\r
+ XtimeE[24] = _XtimeE[24]\r
+ Sbox[25] = _Sbox[25]\r
+ InvSbox[25] = _InvSbox[25]\r
+ Xtime2Sbox[25] = _Xtime2Sbox[25]\r
+ Xtime3Sbox[25] = _Xtime3Sbox[25]\r
+ Xtime2[25] = _Xtime2[25]\r
+ Xtime9[25] = _Xtime9[25]\r
+ XtimeB[25] = _XtimeB[25]\r
+ XtimeD[25] = _XtimeD[25]\r
+ XtimeE[25] = _XtimeE[25]\r
+ Sbox[26] = _Sbox[26]\r
+ InvSbox[26] = _InvSbox[26]\r
+ Xtime2Sbox[26] = _Xtime2Sbox[26]\r
+ Xtime3Sbox[26] = _Xtime3Sbox[26]\r
+ Xtime2[26] = _Xtime2[26]\r
+ Xtime9[26] = _Xtime9[26]\r
+ XtimeB[26] = _XtimeB[26]\r
+ XtimeD[26] = _XtimeD[26]\r
+ XtimeE[26] = _XtimeE[26]\r
+ Sbox[27] = _Sbox[27]\r
+ InvSbox[27] = _InvSbox[27]\r
+ Xtime2Sbox[27] = _Xtime2Sbox[27]\r
+ Xtime3Sbox[27] = _Xtime3Sbox[27]\r
+ Xtime2[27] = _Xtime2[27]\r
+ Xtime9[27] = _Xtime9[27]\r
+ XtimeB[27] = _XtimeB[27]\r
+ XtimeD[27] = _XtimeD[27]\r
+ XtimeE[27] = _XtimeE[27]\r
+ Sbox[28] = _Sbox[28]\r
+ InvSbox[28] = _InvSbox[28]\r
+ Xtime2Sbox[28] = _Xtime2Sbox[28]\r
+ Xtime3Sbox[28] = _Xtime3Sbox[28]\r
+ Xtime2[28] = _Xtime2[28]\r
+ Xtime9[28] = _Xtime9[28]\r
+ XtimeB[28] = _XtimeB[28]\r
+ XtimeD[28] = _XtimeD[28]\r
+ XtimeE[28] = _XtimeE[28]\r
+ Sbox[29] = _Sbox[29]\r
+ InvSbox[29] = _InvSbox[29]\r
+ Xtime2Sbox[29] = _Xtime2Sbox[29]\r
+ Xtime3Sbox[29] = _Xtime3Sbox[29]\r
+ Xtime2[29] = _Xtime2[29]\r
+ Xtime9[29] = _Xtime9[29]\r
+ XtimeB[29] = _XtimeB[29]\r
+ XtimeD[29] = _XtimeD[29]\r
+ XtimeE[29] = _XtimeE[29]\r
+ Sbox[30] = _Sbox[30]\r
+ InvSbox[30] = _InvSbox[30]\r
+ Xtime2Sbox[30] = _Xtime2Sbox[30]\r
+ Xtime3Sbox[30] = _Xtime3Sbox[30]\r
+ Xtime2[30] = _Xtime2[30]\r
+ Xtime9[30] = _Xtime9[30]\r
+ XtimeB[30] = _XtimeB[30]\r
+ XtimeD[30] = _XtimeD[30]\r
+ XtimeE[30] = _XtimeE[30]\r
+ Sbox[31] = _Sbox[31]\r
+ InvSbox[31] = _InvSbox[31]\r
+ Xtime2Sbox[31] = _Xtime2Sbox[31]\r
+ Xtime3Sbox[31] = _Xtime3Sbox[31]\r
+ Xtime2[31] = _Xtime2[31]\r
+ Xtime9[31] = _Xtime9[31]\r
+ XtimeB[31] = _XtimeB[31]\r
+ XtimeD[31] = _XtimeD[31]\r
+ XtimeE[31] = _XtimeE[31]\r
+ Sbox[32] = _Sbox[32]\r
+ InvSbox[32] = _InvSbox[32]\r
+ Xtime2Sbox[32] = _Xtime2Sbox[32]\r
+ Xtime3Sbox[32] = _Xtime3Sbox[32]\r
+ Xtime2[32] = _Xtime2[32]\r
+ Xtime9[32] = _Xtime9[32]\r
+ XtimeB[32] = _XtimeB[32]\r
+ XtimeD[32] = _XtimeD[32]\r
+ XtimeE[32] = _XtimeE[32]\r
+ Sbox[33] = _Sbox[33]\r
+ InvSbox[33] = _InvSbox[33]\r
+ Xtime2Sbox[33] = _Xtime2Sbox[33]\r
+ Xtime3Sbox[33] = _Xtime3Sbox[33]\r
+ Xtime2[33] = _Xtime2[33]\r
+ Xtime9[33] = _Xtime9[33]\r
+ XtimeB[33] = _XtimeB[33]\r
+ XtimeD[33] = _XtimeD[33]\r
+ XtimeE[33] = _XtimeE[33]\r
+ Sbox[34] = _Sbox[34]\r
+ InvSbox[34] = _InvSbox[34]\r
+ Xtime2Sbox[34] = _Xtime2Sbox[34]\r
+ Xtime3Sbox[34] = _Xtime3Sbox[34]\r
+ Xtime2[34] = _Xtime2[34]\r
+ Xtime9[34] = _Xtime9[34]\r
+ XtimeB[34] = _XtimeB[34]\r
+ XtimeD[34] = _XtimeD[34]\r
+ XtimeE[34] = _XtimeE[34]\r
+ Sbox[35] = _Sbox[35]\r
+ InvSbox[35] = _InvSbox[35]\r
+ Xtime2Sbox[35] = _Xtime2Sbox[35]\r
+ Xtime3Sbox[35] = _Xtime3Sbox[35]\r
+ Xtime2[35] = _Xtime2[35]\r
+ Xtime9[35] = _Xtime9[35]\r
+ XtimeB[35] = _XtimeB[35]\r
+ XtimeD[35] = _XtimeD[35]\r
+ XtimeE[35] = _XtimeE[35]\r
+ Sbox[36] = _Sbox[36]\r
+ InvSbox[36] = _InvSbox[36]\r
+ Xtime2Sbox[36] = _Xtime2Sbox[36]\r
+ Xtime3Sbox[36] = _Xtime3Sbox[36]\r
+ Xtime2[36] = _Xtime2[36]\r
+ Xtime9[36] = _Xtime9[36]\r
+ XtimeB[36] = _XtimeB[36]\r
+ XtimeD[36] = _XtimeD[36]\r
+ XtimeE[36] = _XtimeE[36]\r
+ Sbox[37] = _Sbox[37]\r
+ InvSbox[37] = _InvSbox[37]\r
+ Xtime2Sbox[37] = _Xtime2Sbox[37]\r
+ Xtime3Sbox[37] = _Xtime3Sbox[37]\r
+ Xtime2[37] = _Xtime2[37]\r
+ Xtime9[37] = _Xtime9[37]\r
+ XtimeB[37] = _XtimeB[37]\r
+ XtimeD[37] = _XtimeD[37]\r
+ XtimeE[37] = _XtimeE[37]\r
+ Sbox[38] = _Sbox[38]\r
+ InvSbox[38] = _InvSbox[38]\r
+ Xtime2Sbox[38] = _Xtime2Sbox[38]\r
+ Xtime3Sbox[38] = _Xtime3Sbox[38]\r
+ Xtime2[38] = _Xtime2[38]\r
+ Xtime9[38] = _Xtime9[38]\r
+ XtimeB[38] = _XtimeB[38]\r
+ XtimeD[38] = _XtimeD[38]\r
+ XtimeE[38] = _XtimeE[38]\r
+ Sbox[39] = _Sbox[39]\r
+ InvSbox[39] = _InvSbox[39]\r
+ Xtime2Sbox[39] = _Xtime2Sbox[39]\r
+ Xtime3Sbox[39] = _Xtime3Sbox[39]\r
+ Xtime2[39] = _Xtime2[39]\r
+ Xtime9[39] = _Xtime9[39]\r
+ XtimeB[39] = _XtimeB[39]\r
+ XtimeD[39] = _XtimeD[39]\r
+ XtimeE[39] = _XtimeE[39]\r
+ Sbox[40] = _Sbox[40]\r
+ InvSbox[40] = _InvSbox[40]\r
+ Xtime2Sbox[40] = _Xtime2Sbox[40]\r
+ Xtime3Sbox[40] = _Xtime3Sbox[40]\r
+ Xtime2[40] = _Xtime2[40]\r
+ Xtime9[40] = _Xtime9[40]\r
+ XtimeB[40] = _XtimeB[40]\r
+ XtimeD[40] = _XtimeD[40]\r
+ XtimeE[40] = _XtimeE[40]\r
+ Sbox[41] = _Sbox[41]\r
+ InvSbox[41] = _InvSbox[41]\r
+ Xtime2Sbox[41] = _Xtime2Sbox[41]\r
+ Xtime3Sbox[41] = _Xtime3Sbox[41]\r
+ Xtime2[41] = _Xtime2[41]\r
+ Xtime9[41] = _Xtime9[41]\r
+ XtimeB[41] = _XtimeB[41]\r
+ XtimeD[41] = _XtimeD[41]\r
+ XtimeE[41] = _XtimeE[41]\r
+ Sbox[42] = _Sbox[42]\r
+ InvSbox[42] = _InvSbox[42]\r
+ Xtime2Sbox[42] = _Xtime2Sbox[42]\r
+ Xtime3Sbox[42] = _Xtime3Sbox[42]\r
+ Xtime2[42] = _Xtime2[42]\r
+ Xtime9[42] = _Xtime9[42]\r
+ XtimeB[42] = _XtimeB[42]\r
+ XtimeD[42] = _XtimeD[42]\r
+ XtimeE[42] = _XtimeE[42]\r
+ Sbox[43] = _Sbox[43]\r
+ InvSbox[43] = _InvSbox[43]\r
+ Xtime2Sbox[43] = _Xtime2Sbox[43]\r
+ Xtime3Sbox[43] = _Xtime3Sbox[43]\r
+ Xtime2[43] = _Xtime2[43]\r
+ Xtime9[43] = _Xtime9[43]\r
+ XtimeB[43] = _XtimeB[43]\r
+ XtimeD[43] = _XtimeD[43]\r
+ XtimeE[43] = _XtimeE[43]\r
+ Sbox[44] = _Sbox[44]\r
+ InvSbox[44] = _InvSbox[44]\r
+ Xtime2Sbox[44] = _Xtime2Sbox[44]\r
+ Xtime3Sbox[44] = _Xtime3Sbox[44]\r
+ Xtime2[44] = _Xtime2[44]\r
+ Xtime9[44] = _Xtime9[44]\r
+ XtimeB[44] = _XtimeB[44]\r
+ XtimeD[44] = _XtimeD[44]\r
+ XtimeE[44] = _XtimeE[44]\r
+ Sbox[45] = _Sbox[45]\r
+ InvSbox[45] = _InvSbox[45]\r
+ Xtime2Sbox[45] = _Xtime2Sbox[45]\r
+ Xtime3Sbox[45] = _Xtime3Sbox[45]\r
+ Xtime2[45] = _Xtime2[45]\r
+ Xtime9[45] = _Xtime9[45]\r
+ XtimeB[45] = _XtimeB[45]\r
+ XtimeD[45] = _XtimeD[45]\r
+ XtimeE[45] = _XtimeE[45]\r
+ Sbox[46] = _Sbox[46]\r
+ InvSbox[46] = _InvSbox[46]\r
+ Xtime2Sbox[46] = _Xtime2Sbox[46]\r
+ Xtime3Sbox[46] = _Xtime3Sbox[46]\r
+ Xtime2[46] = _Xtime2[46]\r
+ Xtime9[46] = _Xtime9[46]\r
+ XtimeB[46] = _XtimeB[46]\r
+ XtimeD[46] = _XtimeD[46]\r
+ XtimeE[46] = _XtimeE[46]\r
+ Sbox[47] = _Sbox[47]\r
+ InvSbox[47] = _InvSbox[47]\r
+ Xtime2Sbox[47] = _Xtime2Sbox[47]\r
+ Xtime3Sbox[47] = _Xtime3Sbox[47]\r
+ Xtime2[47] = _Xtime2[47]\r
+ Xtime9[47] = _Xtime9[47]\r
+ XtimeB[47] = _XtimeB[47]\r
+ XtimeD[47] = _XtimeD[47]\r
+ XtimeE[47] = _XtimeE[47]\r
+ Sbox[48] = _Sbox[48]\r
+ InvSbox[48] = _InvSbox[48]\r
+ Xtime2Sbox[48] = _Xtime2Sbox[48]\r
+ Xtime3Sbox[48] = _Xtime3Sbox[48]\r
+ Xtime2[48] = _Xtime2[48]\r
+ Xtime9[48] = _Xtime9[48]\r
+ XtimeB[48] = _XtimeB[48]\r
+ XtimeD[48] = _XtimeD[48]\r
+ XtimeE[48] = _XtimeE[48]\r
+ Sbox[49] = _Sbox[49]\r
+ InvSbox[49] = _InvSbox[49]\r
+ Xtime2Sbox[49] = _Xtime2Sbox[49]\r
+ Xtime3Sbox[49] = _Xtime3Sbox[49]\r
+ Xtime2[49] = _Xtime2[49]\r
+ Xtime9[49] = _Xtime9[49]\r
+ XtimeB[49] = _XtimeB[49]\r
+ XtimeD[49] = _XtimeD[49]\r
+ XtimeE[49] = _XtimeE[49]\r
+ Sbox[50] = _Sbox[50]\r
+ InvSbox[50] = _InvSbox[50]\r
+ Xtime2Sbox[50] = _Xtime2Sbox[50]\r
+ Xtime3Sbox[50] = _Xtime3Sbox[50]\r
+ Xtime2[50] = _Xtime2[50]\r
+ Xtime9[50] = _Xtime9[50]\r
+ XtimeB[50] = _XtimeB[50]\r
+ XtimeD[50] = _XtimeD[50]\r
+ XtimeE[50] = _XtimeE[50]\r
+ Sbox[51] = _Sbox[51]\r
+ InvSbox[51] = _InvSbox[51]\r
+ Xtime2Sbox[51] = _Xtime2Sbox[51]\r
+ Xtime3Sbox[51] = _Xtime3Sbox[51]\r
+ Xtime2[51] = _Xtime2[51]\r
+ Xtime9[51] = _Xtime9[51]\r
+ XtimeB[51] = _XtimeB[51]\r
+ XtimeD[51] = _XtimeD[51]\r
+ XtimeE[51] = _XtimeE[51]\r
+ Sbox[52] = _Sbox[52]\r
+ InvSbox[52] = _InvSbox[52]\r
+ Xtime2Sbox[52] = _Xtime2Sbox[52]\r
+ Xtime3Sbox[52] = _Xtime3Sbox[52]\r
+ Xtime2[52] = _Xtime2[52]\r
+ Xtime9[52] = _Xtime9[52]\r
+ XtimeB[52] = _XtimeB[52]\r
+ XtimeD[52] = _XtimeD[52]\r
+ XtimeE[52] = _XtimeE[52]\r
+ Sbox[53] = _Sbox[53]\r
+ InvSbox[53] = _InvSbox[53]\r
+ Xtime2Sbox[53] = _Xtime2Sbox[53]\r
+ Xtime3Sbox[53] = _Xtime3Sbox[53]\r
+ Xtime2[53] = _Xtime2[53]\r
+ Xtime9[53] = _Xtime9[53]\r
+ XtimeB[53] = _XtimeB[53]\r
+ XtimeD[53] = _XtimeD[53]\r
+ XtimeE[53] = _XtimeE[53]\r
+ Sbox[54] = _Sbox[54]\r
+ InvSbox[54] = _InvSbox[54]\r
+ Xtime2Sbox[54] = _Xtime2Sbox[54]\r
+ Xtime3Sbox[54] = _Xtime3Sbox[54]\r
+ Xtime2[54] = _Xtime2[54]\r
+ Xtime9[54] = _Xtime9[54]\r
+ XtimeB[54] = _XtimeB[54]\r
+ XtimeD[54] = _XtimeD[54]\r
+ XtimeE[54] = _XtimeE[54]\r
+ Sbox[55] = _Sbox[55]\r
+ InvSbox[55] = _InvSbox[55]\r
+ Xtime2Sbox[55] = _Xtime2Sbox[55]\r
+ Xtime3Sbox[55] = _Xtime3Sbox[55]\r
+ Xtime2[55] = _Xtime2[55]\r
+ Xtime9[55] = _Xtime9[55]\r
+ XtimeB[55] = _XtimeB[55]\r
+ XtimeD[55] = _XtimeD[55]\r
+ XtimeE[55] = _XtimeE[55]\r
+ Sbox[56] = _Sbox[56]\r
+ InvSbox[56] = _InvSbox[56]\r
+ Xtime2Sbox[56] = _Xtime2Sbox[56]\r
+ Xtime3Sbox[56] = _Xtime3Sbox[56]\r
+ Xtime2[56] = _Xtime2[56]\r
+ Xtime9[56] = _Xtime9[56]\r
+ XtimeB[56] = _XtimeB[56]\r
+ XtimeD[56] = _XtimeD[56]\r
+ XtimeE[56] = _XtimeE[56]\r
+ Sbox[57] = _Sbox[57]\r
+ InvSbox[57] = _InvSbox[57]\r
+ Xtime2Sbox[57] = _Xtime2Sbox[57]\r
+ Xtime3Sbox[57] = _Xtime3Sbox[57]\r
+ Xtime2[57] = _Xtime2[57]\r
+ Xtime9[57] = _Xtime9[57]\r
+ XtimeB[57] = _XtimeB[57]\r
+ XtimeD[57] = _XtimeD[57]\r
+ XtimeE[57] = _XtimeE[57]\r
+ Sbox[58] = _Sbox[58]\r
+ InvSbox[58] = _InvSbox[58]\r
+ Xtime2Sbox[58] = _Xtime2Sbox[58]\r
+ Xtime3Sbox[58] = _Xtime3Sbox[58]\r
+ Xtime2[58] = _Xtime2[58]\r
+ Xtime9[58] = _Xtime9[58]\r
+ XtimeB[58] = _XtimeB[58]\r
+ XtimeD[58] = _XtimeD[58]\r
+ XtimeE[58] = _XtimeE[58]\r
+ Sbox[59] = _Sbox[59]\r
+ InvSbox[59] = _InvSbox[59]\r
+ Xtime2Sbox[59] = _Xtime2Sbox[59]\r
+ Xtime3Sbox[59] = _Xtime3Sbox[59]\r
+ Xtime2[59] = _Xtime2[59]\r
+ Xtime9[59] = _Xtime9[59]\r
+ XtimeB[59] = _XtimeB[59]\r
+ XtimeD[59] = _XtimeD[59]\r
+ XtimeE[59] = _XtimeE[59]\r
+ Sbox[60] = _Sbox[60]\r
+ InvSbox[60] = _InvSbox[60]\r
+ Xtime2Sbox[60] = _Xtime2Sbox[60]\r
+ Xtime3Sbox[60] = _Xtime3Sbox[60]\r
+ Xtime2[60] = _Xtime2[60]\r
+ Xtime9[60] = _Xtime9[60]\r
+ XtimeB[60] = _XtimeB[60]\r
+ XtimeD[60] = _XtimeD[60]\r
+ XtimeE[60] = _XtimeE[60]\r
+ Sbox[61] = _Sbox[61]\r
+ InvSbox[61] = _InvSbox[61]\r
+ Xtime2Sbox[61] = _Xtime2Sbox[61]\r
+ Xtime3Sbox[61] = _Xtime3Sbox[61]\r
+ Xtime2[61] = _Xtime2[61]\r
+ Xtime9[61] = _Xtime9[61]\r
+ XtimeB[61] = _XtimeB[61]\r
+ XtimeD[61] = _XtimeD[61]\r
+ XtimeE[61] = _XtimeE[61]\r
+ Sbox[62] = _Sbox[62]\r
+ InvSbox[62] = _InvSbox[62]\r
+ Xtime2Sbox[62] = _Xtime2Sbox[62]\r
+ Xtime3Sbox[62] = _Xtime3Sbox[62]\r
+ Xtime2[62] = _Xtime2[62]\r
+ Xtime9[62] = _Xtime9[62]\r
+ XtimeB[62] = _XtimeB[62]\r
+ XtimeD[62] = _XtimeD[62]\r
+ XtimeE[62] = _XtimeE[62]\r
+ Sbox[63] = _Sbox[63]\r
+ InvSbox[63] = _InvSbox[63]\r
+ Xtime2Sbox[63] = _Xtime2Sbox[63]\r
+ Xtime3Sbox[63] = _Xtime3Sbox[63]\r
+ Xtime2[63] = _Xtime2[63]\r
+ Xtime9[63] = _Xtime9[63]\r
+ XtimeB[63] = _XtimeB[63]\r
+ XtimeD[63] = _XtimeD[63]\r
+ XtimeE[63] = _XtimeE[63]\r
+ Sbox[64] = _Sbox[64]\r
+ InvSbox[64] = _InvSbox[64]\r
+ Xtime2Sbox[64] = _Xtime2Sbox[64]\r
+ Xtime3Sbox[64] = _Xtime3Sbox[64]\r
+ Xtime2[64] = _Xtime2[64]\r
+ Xtime9[64] = _Xtime9[64]\r
+ XtimeB[64] = _XtimeB[64]\r
+ XtimeD[64] = _XtimeD[64]\r
+ XtimeE[64] = _XtimeE[64]\r
+ Sbox[65] = _Sbox[65]\r
+ InvSbox[65] = _InvSbox[65]\r
+ Xtime2Sbox[65] = _Xtime2Sbox[65]\r
+ Xtime3Sbox[65] = _Xtime3Sbox[65]\r
+ Xtime2[65] = _Xtime2[65]\r
+ Xtime9[65] = _Xtime9[65]\r
+ XtimeB[65] = _XtimeB[65]\r
+ XtimeD[65] = _XtimeD[65]\r
+ XtimeE[65] = _XtimeE[65]\r
+ Sbox[66] = _Sbox[66]\r
+ InvSbox[66] = _InvSbox[66]\r
+ Xtime2Sbox[66] = _Xtime2Sbox[66]\r
+ Xtime3Sbox[66] = _Xtime3Sbox[66]\r
+ Xtime2[66] = _Xtime2[66]\r
+ Xtime9[66] = _Xtime9[66]\r
+ XtimeB[66] = _XtimeB[66]\r
+ XtimeD[66] = _XtimeD[66]\r
+ XtimeE[66] = _XtimeE[66]\r
+ Sbox[67] = _Sbox[67]\r
+ InvSbox[67] = _InvSbox[67]\r
+ Xtime2Sbox[67] = _Xtime2Sbox[67]\r
+ Xtime3Sbox[67] = _Xtime3Sbox[67]\r
+ Xtime2[67] = _Xtime2[67]\r
+ Xtime9[67] = _Xtime9[67]\r
+ XtimeB[67] = _XtimeB[67]\r
+ XtimeD[67] = _XtimeD[67]\r
+ XtimeE[67] = _XtimeE[67]\r
+ Sbox[68] = _Sbox[68]\r
+ InvSbox[68] = _InvSbox[68]\r
+ Xtime2Sbox[68] = _Xtime2Sbox[68]\r
+ Xtime3Sbox[68] = _Xtime3Sbox[68]\r
+ Xtime2[68] = _Xtime2[68]\r
+ Xtime9[68] = _Xtime9[68]\r
+ XtimeB[68] = _XtimeB[68]\r
+ XtimeD[68] = _XtimeD[68]\r
+ XtimeE[68] = _XtimeE[68]\r
+ Sbox[69] = _Sbox[69]\r
+ InvSbox[69] = _InvSbox[69]\r
+ Xtime2Sbox[69] = _Xtime2Sbox[69]\r
+ Xtime3Sbox[69] = _Xtime3Sbox[69]\r
+ Xtime2[69] = _Xtime2[69]\r
+ Xtime9[69] = _Xtime9[69]\r
+ XtimeB[69] = _XtimeB[69]\r
+ XtimeD[69] = _XtimeD[69]\r
+ XtimeE[69] = _XtimeE[69]\r
+ Sbox[70] = _Sbox[70]\r
+ InvSbox[70] = _InvSbox[70]\r
+ Xtime2Sbox[70] = _Xtime2Sbox[70]\r
+ Xtime3Sbox[70] = _Xtime3Sbox[70]\r
+ Xtime2[70] = _Xtime2[70]\r
+ Xtime9[70] = _Xtime9[70]\r
+ XtimeB[70] = _XtimeB[70]\r
+ XtimeD[70] = _XtimeD[70]\r
+ XtimeE[70] = _XtimeE[70]\r
+ Sbox[71] = _Sbox[71]\r
+ InvSbox[71] = _InvSbox[71]\r
+ Xtime2Sbox[71] = _Xtime2Sbox[71]\r
+ Xtime3Sbox[71] = _Xtime3Sbox[71]\r
+ Xtime2[71] = _Xtime2[71]\r
+ Xtime9[71] = _Xtime9[71]\r
+ XtimeB[71] = _XtimeB[71]\r
+ XtimeD[71] = _XtimeD[71]\r
+ XtimeE[71] = _XtimeE[71]\r
+ Sbox[72] = _Sbox[72]\r
+ InvSbox[72] = _InvSbox[72]\r
+ Xtime2Sbox[72] = _Xtime2Sbox[72]\r
+ Xtime3Sbox[72] = _Xtime3Sbox[72]\r
+ Xtime2[72] = _Xtime2[72]\r
+ Xtime9[72] = _Xtime9[72]\r
+ XtimeB[72] = _XtimeB[72]\r
+ XtimeD[72] = _XtimeD[72]\r
+ XtimeE[72] = _XtimeE[72]\r
+ Sbox[73] = _Sbox[73]\r
+ InvSbox[73] = _InvSbox[73]\r
+ Xtime2Sbox[73] = _Xtime2Sbox[73]\r
+ Xtime3Sbox[73] = _Xtime3Sbox[73]\r
+ Xtime2[73] = _Xtime2[73]\r
+ Xtime9[73] = _Xtime9[73]\r
+ XtimeB[73] = _XtimeB[73]\r
+ XtimeD[73] = _XtimeD[73]\r
+ XtimeE[73] = _XtimeE[73]\r
+ Sbox[74] = _Sbox[74]\r
+ InvSbox[74] = _InvSbox[74]\r
+ Xtime2Sbox[74] = _Xtime2Sbox[74]\r
+ Xtime3Sbox[74] = _Xtime3Sbox[74]\r
+ Xtime2[74] = _Xtime2[74]\r
+ Xtime9[74] = _Xtime9[74]\r
+ XtimeB[74] = _XtimeB[74]\r
+ XtimeD[74] = _XtimeD[74]\r
+ XtimeE[74] = _XtimeE[74]\r
+ Sbox[75] = _Sbox[75]\r
+ InvSbox[75] = _InvSbox[75]\r
+ Xtime2Sbox[75] = _Xtime2Sbox[75]\r
+ Xtime3Sbox[75] = _Xtime3Sbox[75]\r
+ Xtime2[75] = _Xtime2[75]\r
+ Xtime9[75] = _Xtime9[75]\r
+ XtimeB[75] = _XtimeB[75]\r
+ XtimeD[75] = _XtimeD[75]\r
+ XtimeE[75] = _XtimeE[75]\r
+ Sbox[76] = _Sbox[76]\r
+ InvSbox[76] = _InvSbox[76]\r
+ Xtime2Sbox[76] = _Xtime2Sbox[76]\r
+ Xtime3Sbox[76] = _Xtime3Sbox[76]\r
+ Xtime2[76] = _Xtime2[76]\r
+ Xtime9[76] = _Xtime9[76]\r
+ XtimeB[76] = _XtimeB[76]\r
+ XtimeD[76] = _XtimeD[76]\r
+ XtimeE[76] = _XtimeE[76]\r
+ Sbox[77] = _Sbox[77]\r
+ InvSbox[77] = _InvSbox[77]\r
+ Xtime2Sbox[77] = _Xtime2Sbox[77]\r
+ Xtime3Sbox[77] = _Xtime3Sbox[77]\r
+ Xtime2[77] = _Xtime2[77]\r
+ Xtime9[77] = _Xtime9[77]\r
+ XtimeB[77] = _XtimeB[77]\r
+ XtimeD[77] = _XtimeD[77]\r
+ XtimeE[77] = _XtimeE[77]\r
+ Sbox[78] = _Sbox[78]\r
+ InvSbox[78] = _InvSbox[78]\r
+ Xtime2Sbox[78] = _Xtime2Sbox[78]\r
+ Xtime3Sbox[78] = _Xtime3Sbox[78]\r
+ Xtime2[78] = _Xtime2[78]\r
+ Xtime9[78] = _Xtime9[78]\r
+ XtimeB[78] = _XtimeB[78]\r
+ XtimeD[78] = _XtimeD[78]\r
+ XtimeE[78] = _XtimeE[78]\r
+ Sbox[79] = _Sbox[79]\r
+ InvSbox[79] = _InvSbox[79]\r
+ Xtime2Sbox[79] = _Xtime2Sbox[79]\r
+ Xtime3Sbox[79] = _Xtime3Sbox[79]\r
+ Xtime2[79] = _Xtime2[79]\r
+ Xtime9[79] = _Xtime9[79]\r
+ XtimeB[79] = _XtimeB[79]\r
+ XtimeD[79] = _XtimeD[79]\r
+ XtimeE[79] = _XtimeE[79]\r
+ Sbox[80] = _Sbox[80]\r
+ InvSbox[80] = _InvSbox[80]\r
+ Xtime2Sbox[80] = _Xtime2Sbox[80]\r
+ Xtime3Sbox[80] = _Xtime3Sbox[80]\r
+ Xtime2[80] = _Xtime2[80]\r
+ Xtime9[80] = _Xtime9[80]\r
+ XtimeB[80] = _XtimeB[80]\r
+ XtimeD[80] = _XtimeD[80]\r
+ XtimeE[80] = _XtimeE[80]\r
+ Sbox[81] = _Sbox[81]\r
+ InvSbox[81] = _InvSbox[81]\r
+ Xtime2Sbox[81] = _Xtime2Sbox[81]\r
+ Xtime3Sbox[81] = _Xtime3Sbox[81]\r
+ Xtime2[81] = _Xtime2[81]\r
+ Xtime9[81] = _Xtime9[81]\r
+ XtimeB[81] = _XtimeB[81]\r
+ XtimeD[81] = _XtimeD[81]\r
+ XtimeE[81] = _XtimeE[81]\r
+ Sbox[82] = _Sbox[82]\r
+ InvSbox[82] = _InvSbox[82]\r
+ Xtime2Sbox[82] = _Xtime2Sbox[82]\r
+ Xtime3Sbox[82] = _Xtime3Sbox[82]\r
+ Xtime2[82] = _Xtime2[82]\r
+ Xtime9[82] = _Xtime9[82]\r
+ XtimeB[82] = _XtimeB[82]\r
+ XtimeD[82] = _XtimeD[82]\r
+ XtimeE[82] = _XtimeE[82]\r
+ Sbox[83] = _Sbox[83]\r
+ InvSbox[83] = _InvSbox[83]\r
+ Xtime2Sbox[83] = _Xtime2Sbox[83]\r
+ Xtime3Sbox[83] = _Xtime3Sbox[83]\r
+ Xtime2[83] = _Xtime2[83]\r
+ Xtime9[83] = _Xtime9[83]\r
+ XtimeB[83] = _XtimeB[83]\r
+ XtimeD[83] = _XtimeD[83]\r
+ XtimeE[83] = _XtimeE[83]\r
+ Sbox[84] = _Sbox[84]\r
+ InvSbox[84] = _InvSbox[84]\r
+ Xtime2Sbox[84] = _Xtime2Sbox[84]\r
+ Xtime3Sbox[84] = _Xtime3Sbox[84]\r
+ Xtime2[84] = _Xtime2[84]\r
+ Xtime9[84] = _Xtime9[84]\r
+ XtimeB[84] = _XtimeB[84]\r
+ XtimeD[84] = _XtimeD[84]\r
+ XtimeE[84] = _XtimeE[84]\r
+ Sbox[85] = _Sbox[85]\r
+ InvSbox[85] = _InvSbox[85]\r
+ Xtime2Sbox[85] = _Xtime2Sbox[85]\r
+ Xtime3Sbox[85] = _Xtime3Sbox[85]\r
+ Xtime2[85] = _Xtime2[85]\r
+ Xtime9[85] = _Xtime9[85]\r
+ XtimeB[85] = _XtimeB[85]\r
+ XtimeD[85] = _XtimeD[85]\r
+ XtimeE[85] = _XtimeE[85]\r
+ Sbox[86] = _Sbox[86]\r
+ InvSbox[86] = _InvSbox[86]\r
+ Xtime2Sbox[86] = _Xtime2Sbox[86]\r
+ Xtime3Sbox[86] = _Xtime3Sbox[86]\r
+ Xtime2[86] = _Xtime2[86]\r
+ Xtime9[86] = _Xtime9[86]\r
+ XtimeB[86] = _XtimeB[86]\r
+ XtimeD[86] = _XtimeD[86]\r
+ XtimeE[86] = _XtimeE[86]\r
+ Sbox[87] = _Sbox[87]\r
+ InvSbox[87] = _InvSbox[87]\r
+ Xtime2Sbox[87] = _Xtime2Sbox[87]\r
+ Xtime3Sbox[87] = _Xtime3Sbox[87]\r
+ Xtime2[87] = _Xtime2[87]\r
+ Xtime9[87] = _Xtime9[87]\r
+ XtimeB[87] = _XtimeB[87]\r
+ XtimeD[87] = _XtimeD[87]\r
+ XtimeE[87] = _XtimeE[87]\r
+ Sbox[88] = _Sbox[88]\r
+ InvSbox[88] = _InvSbox[88]\r
+ Xtime2Sbox[88] = _Xtime2Sbox[88]\r
+ Xtime3Sbox[88] = _Xtime3Sbox[88]\r
+ Xtime2[88] = _Xtime2[88]\r
+ Xtime9[88] = _Xtime9[88]\r
+ XtimeB[88] = _XtimeB[88]\r
+ XtimeD[88] = _XtimeD[88]\r
+ XtimeE[88] = _XtimeE[88]\r
+ Sbox[89] = _Sbox[89]\r
+ InvSbox[89] = _InvSbox[89]\r
+ Xtime2Sbox[89] = _Xtime2Sbox[89]\r
+ Xtime3Sbox[89] = _Xtime3Sbox[89]\r
+ Xtime2[89] = _Xtime2[89]\r
+ Xtime9[89] = _Xtime9[89]\r
+ XtimeB[89] = _XtimeB[89]\r
+ XtimeD[89] = _XtimeD[89]\r
+ XtimeE[89] = _XtimeE[89]\r
+ Sbox[90] = _Sbox[90]\r
+ InvSbox[90] = _InvSbox[90]\r
+ Xtime2Sbox[90] = _Xtime2Sbox[90]\r
+ Xtime3Sbox[90] = _Xtime3Sbox[90]\r
+ Xtime2[90] = _Xtime2[90]\r
+ Xtime9[90] = _Xtime9[90]\r
+ XtimeB[90] = _XtimeB[90]\r
+ XtimeD[90] = _XtimeD[90]\r
+ XtimeE[90] = _XtimeE[90]\r
+ Sbox[91] = _Sbox[91]\r
+ InvSbox[91] = _InvSbox[91]\r
+ Xtime2Sbox[91] = _Xtime2Sbox[91]\r
+ Xtime3Sbox[91] = _Xtime3Sbox[91]\r
+ Xtime2[91] = _Xtime2[91]\r
+ Xtime9[91] = _Xtime9[91]\r
+ XtimeB[91] = _XtimeB[91]\r
+ XtimeD[91] = _XtimeD[91]\r
+ XtimeE[91] = _XtimeE[91]\r
+ Sbox[92] = _Sbox[92]\r
+ InvSbox[92] = _InvSbox[92]\r
+ Xtime2Sbox[92] = _Xtime2Sbox[92]\r
+ Xtime3Sbox[92] = _Xtime3Sbox[92]\r
+ Xtime2[92] = _Xtime2[92]\r
+ Xtime9[92] = _Xtime9[92]\r
+ XtimeB[92] = _XtimeB[92]\r
+ XtimeD[92] = _XtimeD[92]\r
+ XtimeE[92] = _XtimeE[92]\r
+ Sbox[93] = _Sbox[93]\r
+ InvSbox[93] = _InvSbox[93]\r
+ Xtime2Sbox[93] = _Xtime2Sbox[93]\r
+ Xtime3Sbox[93] = _Xtime3Sbox[93]\r
+ Xtime2[93] = _Xtime2[93]\r
+ Xtime9[93] = _Xtime9[93]\r
+ XtimeB[93] = _XtimeB[93]\r
+ XtimeD[93] = _XtimeD[93]\r
+ XtimeE[93] = _XtimeE[93]\r
+ Sbox[94] = _Sbox[94]\r
+ InvSbox[94] = _InvSbox[94]\r
+ Xtime2Sbox[94] = _Xtime2Sbox[94]\r
+ Xtime3Sbox[94] = _Xtime3Sbox[94]\r
+ Xtime2[94] = _Xtime2[94]\r
+ Xtime9[94] = _Xtime9[94]\r
+ XtimeB[94] = _XtimeB[94]\r
+ XtimeD[94] = _XtimeD[94]\r
+ XtimeE[94] = _XtimeE[94]\r
+ Sbox[95] = _Sbox[95]\r
+ InvSbox[95] = _InvSbox[95]\r
+ Xtime2Sbox[95] = _Xtime2Sbox[95]\r
+ Xtime3Sbox[95] = _Xtime3Sbox[95]\r
+ Xtime2[95] = _Xtime2[95]\r
+ Xtime9[95] = _Xtime9[95]\r
+ XtimeB[95] = _XtimeB[95]\r
+ XtimeD[95] = _XtimeD[95]\r
+ XtimeE[95] = _XtimeE[95]\r
+ Sbox[96] = _Sbox[96]\r
+ InvSbox[96] = _InvSbox[96]\r
+ Xtime2Sbox[96] = _Xtime2Sbox[96]\r
+ Xtime3Sbox[96] = _Xtime3Sbox[96]\r
+ Xtime2[96] = _Xtime2[96]\r
+ Xtime9[96] = _Xtime9[96]\r
+ XtimeB[96] = _XtimeB[96]\r
+ XtimeD[96] = _XtimeD[96]\r
+ XtimeE[96] = _XtimeE[96]\r
+ Sbox[97] = _Sbox[97]\r
+ InvSbox[97] = _InvSbox[97]\r
+ Xtime2Sbox[97] = _Xtime2Sbox[97]\r
+ Xtime3Sbox[97] = _Xtime3Sbox[97]\r
+ Xtime2[97] = _Xtime2[97]\r
+ Xtime9[97] = _Xtime9[97]\r
+ XtimeB[97] = _XtimeB[97]\r
+ XtimeD[97] = _XtimeD[97]\r
+ XtimeE[97] = _XtimeE[97]\r
+ Sbox[98] = _Sbox[98]\r
+ InvSbox[98] = _InvSbox[98]\r
+ Xtime2Sbox[98] = _Xtime2Sbox[98]\r
+ Xtime3Sbox[98] = _Xtime3Sbox[98]\r
+ Xtime2[98] = _Xtime2[98]\r
+ Xtime9[98] = _Xtime9[98]\r
+ XtimeB[98] = _XtimeB[98]\r
+ XtimeD[98] = _XtimeD[98]\r
+ XtimeE[98] = _XtimeE[98]\r
+ Sbox[99] = _Sbox[99]\r
+ InvSbox[99] = _InvSbox[99]\r
+ Xtime2Sbox[99] = _Xtime2Sbox[99]\r
+ Xtime3Sbox[99] = _Xtime3Sbox[99]\r
+ Xtime2[99] = _Xtime2[99]\r
+ Xtime9[99] = _Xtime9[99]\r
+ XtimeB[99] = _XtimeB[99]\r
+ XtimeD[99] = _XtimeD[99]\r
+ XtimeE[99] = _XtimeE[99]\r
+ Sbox[100] = _Sbox[100]\r
+ InvSbox[100] = _InvSbox[100]\r
+ Xtime2Sbox[100] = _Xtime2Sbox[100]\r
+ Xtime3Sbox[100] = _Xtime3Sbox[100]\r
+ Xtime2[100] = _Xtime2[100]\r
+ Xtime9[100] = _Xtime9[100]\r
+ XtimeB[100] = _XtimeB[100]\r
+ XtimeD[100] = _XtimeD[100]\r
+ XtimeE[100] = _XtimeE[100]\r
+ Sbox[101] = _Sbox[101]\r
+ InvSbox[101] = _InvSbox[101]\r
+ Xtime2Sbox[101] = _Xtime2Sbox[101]\r
+ Xtime3Sbox[101] = _Xtime3Sbox[101]\r
+ Xtime2[101] = _Xtime2[101]\r
+ Xtime9[101] = _Xtime9[101]\r
+ XtimeB[101] = _XtimeB[101]\r
+ XtimeD[101] = _XtimeD[101]\r
+ XtimeE[101] = _XtimeE[101]\r
+ Sbox[102] = _Sbox[102]\r
+ InvSbox[102] = _InvSbox[102]\r
+ Xtime2Sbox[102] = _Xtime2Sbox[102]\r
+ Xtime3Sbox[102] = _Xtime3Sbox[102]\r
+ Xtime2[102] = _Xtime2[102]\r
+ Xtime9[102] = _Xtime9[102]\r
+ XtimeB[102] = _XtimeB[102]\r
+ XtimeD[102] = _XtimeD[102]\r
+ XtimeE[102] = _XtimeE[102]\r
+ Sbox[103] = _Sbox[103]\r
+ InvSbox[103] = _InvSbox[103]\r
+ Xtime2Sbox[103] = _Xtime2Sbox[103]\r
+ Xtime3Sbox[103] = _Xtime3Sbox[103]\r
+ Xtime2[103] = _Xtime2[103]\r
+ Xtime9[103] = _Xtime9[103]\r
+ XtimeB[103] = _XtimeB[103]\r
+ XtimeD[103] = _XtimeD[103]\r
+ XtimeE[103] = _XtimeE[103]\r
+ Sbox[104] = _Sbox[104]\r
+ InvSbox[104] = _InvSbox[104]\r
+ Xtime2Sbox[104] = _Xtime2Sbox[104]\r
+ Xtime3Sbox[104] = _Xtime3Sbox[104]\r
+ Xtime2[104] = _Xtime2[104]\r
+ Xtime9[104] = _Xtime9[104]\r
+ XtimeB[104] = _XtimeB[104]\r
+ XtimeD[104] = _XtimeD[104]\r
+ XtimeE[104] = _XtimeE[104]\r
+ Sbox[105] = _Sbox[105]\r
+ InvSbox[105] = _InvSbox[105]\r
+ Xtime2Sbox[105] = _Xtime2Sbox[105]\r
+ Xtime3Sbox[105] = _Xtime3Sbox[105]\r
+ Xtime2[105] = _Xtime2[105]\r
+ Xtime9[105] = _Xtime9[105]\r
+ XtimeB[105] = _XtimeB[105]\r
+ XtimeD[105] = _XtimeD[105]\r
+ XtimeE[105] = _XtimeE[105]\r
+ Sbox[106] = _Sbox[106]\r
+ InvSbox[106] = _InvSbox[106]\r
+ Xtime2Sbox[106] = _Xtime2Sbox[106]\r
+ Xtime3Sbox[106] = _Xtime3Sbox[106]\r
+ Xtime2[106] = _Xtime2[106]\r
+ Xtime9[106] = _Xtime9[106]\r
+ XtimeB[106] = _XtimeB[106]\r
+ XtimeD[106] = _XtimeD[106]\r
+ XtimeE[106] = _XtimeE[106]\r
+ Sbox[107] = _Sbox[107]\r
+ InvSbox[107] = _InvSbox[107]\r
+ Xtime2Sbox[107] = _Xtime2Sbox[107]\r
+ Xtime3Sbox[107] = _Xtime3Sbox[107]\r
+ Xtime2[107] = _Xtime2[107]\r
+ Xtime9[107] = _Xtime9[107]\r
+ XtimeB[107] = _XtimeB[107]\r
+ XtimeD[107] = _XtimeD[107]\r
+ XtimeE[107] = _XtimeE[107]\r
+ Sbox[108] = _Sbox[108]\r
+ InvSbox[108] = _InvSbox[108]\r
+ Xtime2Sbox[108] = _Xtime2Sbox[108]\r
+ Xtime3Sbox[108] = _Xtime3Sbox[108]\r
+ Xtime2[108] = _Xtime2[108]\r
+ Xtime9[108] = _Xtime9[108]\r
+ XtimeB[108] = _XtimeB[108]\r
+ XtimeD[108] = _XtimeD[108]\r
+ XtimeE[108] = _XtimeE[108]\r
+ Sbox[109] = _Sbox[109]\r
+ InvSbox[109] = _InvSbox[109]\r
+ Xtime2Sbox[109] = _Xtime2Sbox[109]\r
+ Xtime3Sbox[109] = _Xtime3Sbox[109]\r
+ Xtime2[109] = _Xtime2[109]\r
+ Xtime9[109] = _Xtime9[109]\r
+ XtimeB[109] = _XtimeB[109]\r
+ XtimeD[109] = _XtimeD[109]\r
+ XtimeE[109] = _XtimeE[109]\r
+ Sbox[110] = _Sbox[110]\r
+ InvSbox[110] = _InvSbox[110]\r
+ Xtime2Sbox[110] = _Xtime2Sbox[110]\r
+ Xtime3Sbox[110] = _Xtime3Sbox[110]\r
+ Xtime2[110] = _Xtime2[110]\r
+ Xtime9[110] = _Xtime9[110]\r
+ XtimeB[110] = _XtimeB[110]\r
+ XtimeD[110] = _XtimeD[110]\r
+ XtimeE[110] = _XtimeE[110]\r
+ Sbox[111] = _Sbox[111]\r
+ InvSbox[111] = _InvSbox[111]\r
+ Xtime2Sbox[111] = _Xtime2Sbox[111]\r
+ Xtime3Sbox[111] = _Xtime3Sbox[111]\r
+ Xtime2[111] = _Xtime2[111]\r
+ Xtime9[111] = _Xtime9[111]\r
+ XtimeB[111] = _XtimeB[111]\r
+ XtimeD[111] = _XtimeD[111]\r
+ XtimeE[111] = _XtimeE[111]\r
+ Sbox[112] = _Sbox[112]\r
+ InvSbox[112] = _InvSbox[112]\r
+ Xtime2Sbox[112] = _Xtime2Sbox[112]\r
+ Xtime3Sbox[112] = _Xtime3Sbox[112]\r
+ Xtime2[112] = _Xtime2[112]\r
+ Xtime9[112] = _Xtime9[112]\r
+ XtimeB[112] = _XtimeB[112]\r
+ XtimeD[112] = _XtimeD[112]\r
+ XtimeE[112] = _XtimeE[112]\r
+ Sbox[113] = _Sbox[113]\r
+ InvSbox[113] = _InvSbox[113]\r
+ Xtime2Sbox[113] = _Xtime2Sbox[113]\r
+ Xtime3Sbox[113] = _Xtime3Sbox[113]\r
+ Xtime2[113] = _Xtime2[113]\r
+ Xtime9[113] = _Xtime9[113]\r
+ XtimeB[113] = _XtimeB[113]\r
+ XtimeD[113] = _XtimeD[113]\r
+ XtimeE[113] = _XtimeE[113]\r
+ Sbox[114] = _Sbox[114]\r
+ InvSbox[114] = _InvSbox[114]\r
+ Xtime2Sbox[114] = _Xtime2Sbox[114]\r
+ Xtime3Sbox[114] = _Xtime3Sbox[114]\r
+ Xtime2[114] = _Xtime2[114]\r
+ Xtime9[114] = _Xtime9[114]\r
+ XtimeB[114] = _XtimeB[114]\r
+ XtimeD[114] = _XtimeD[114]\r
+ XtimeE[114] = _XtimeE[114]\r
+ Sbox[115] = _Sbox[115]\r
+ InvSbox[115] = _InvSbox[115]\r
+ Xtime2Sbox[115] = _Xtime2Sbox[115]\r
+ Xtime3Sbox[115] = _Xtime3Sbox[115]\r
+ Xtime2[115] = _Xtime2[115]\r
+ Xtime9[115] = _Xtime9[115]\r
+ XtimeB[115] = _XtimeB[115]\r
+ XtimeD[115] = _XtimeD[115]\r
+ XtimeE[115] = _XtimeE[115]\r
+ Sbox[116] = _Sbox[116]\r
+ InvSbox[116] = _InvSbox[116]\r
+ Xtime2Sbox[116] = _Xtime2Sbox[116]\r
+ Xtime3Sbox[116] = _Xtime3Sbox[116]\r
+ Xtime2[116] = _Xtime2[116]\r
+ Xtime9[116] = _Xtime9[116]\r
+ XtimeB[116] = _XtimeB[116]\r
+ XtimeD[116] = _XtimeD[116]\r
+ XtimeE[116] = _XtimeE[116]\r
+ Sbox[117] = _Sbox[117]\r
+ InvSbox[117] = _InvSbox[117]\r
+ Xtime2Sbox[117] = _Xtime2Sbox[117]\r
+ Xtime3Sbox[117] = _Xtime3Sbox[117]\r
+ Xtime2[117] = _Xtime2[117]\r
+ Xtime9[117] = _Xtime9[117]\r
+ XtimeB[117] = _XtimeB[117]\r
+ XtimeD[117] = _XtimeD[117]\r
+ XtimeE[117] = _XtimeE[117]\r
+ Sbox[118] = _Sbox[118]\r
+ InvSbox[118] = _InvSbox[118]\r
+ Xtime2Sbox[118] = _Xtime2Sbox[118]\r
+ Xtime3Sbox[118] = _Xtime3Sbox[118]\r
+ Xtime2[118] = _Xtime2[118]\r
+ Xtime9[118] = _Xtime9[118]\r
+ XtimeB[118] = _XtimeB[118]\r
+ XtimeD[118] = _XtimeD[118]\r
+ XtimeE[118] = _XtimeE[118]\r
+ Sbox[119] = _Sbox[119]\r
+ InvSbox[119] = _InvSbox[119]\r
+ Xtime2Sbox[119] = _Xtime2Sbox[119]\r
+ Xtime3Sbox[119] = _Xtime3Sbox[119]\r
+ Xtime2[119] = _Xtime2[119]\r
+ Xtime9[119] = _Xtime9[119]\r
+ XtimeB[119] = _XtimeB[119]\r
+ XtimeD[119] = _XtimeD[119]\r
+ XtimeE[119] = _XtimeE[119]\r
+ Sbox[120] = _Sbox[120]\r
+ InvSbox[120] = _InvSbox[120]\r
+ Xtime2Sbox[120] = _Xtime2Sbox[120]\r
+ Xtime3Sbox[120] = _Xtime3Sbox[120]\r
+ Xtime2[120] = _Xtime2[120]\r
+ Xtime9[120] = _Xtime9[120]\r
+ XtimeB[120] = _XtimeB[120]\r
+ XtimeD[120] = _XtimeD[120]\r
+ XtimeE[120] = _XtimeE[120]\r
+ Sbox[121] = _Sbox[121]\r
+ InvSbox[121] = _InvSbox[121]\r
+ Xtime2Sbox[121] = _Xtime2Sbox[121]\r
+ Xtime3Sbox[121] = _Xtime3Sbox[121]\r
+ Xtime2[121] = _Xtime2[121]\r
+ Xtime9[121] = _Xtime9[121]\r
+ XtimeB[121] = _XtimeB[121]\r
+ XtimeD[121] = _XtimeD[121]\r
+ XtimeE[121] = _XtimeE[121]\r
+ Sbox[122] = _Sbox[122]\r
+ InvSbox[122] = _InvSbox[122]\r
+ Xtime2Sbox[122] = _Xtime2Sbox[122]\r
+ Xtime3Sbox[122] = _Xtime3Sbox[122]\r
+ Xtime2[122] = _Xtime2[122]\r
+ Xtime9[122] = _Xtime9[122]\r
+ XtimeB[122] = _XtimeB[122]\r
+ XtimeD[122] = _XtimeD[122]\r
+ XtimeE[122] = _XtimeE[122]\r
+ Sbox[123] = _Sbox[123]\r
+ InvSbox[123] = _InvSbox[123]\r
+ Xtime2Sbox[123] = _Xtime2Sbox[123]\r
+ Xtime3Sbox[123] = _Xtime3Sbox[123]\r
+ Xtime2[123] = _Xtime2[123]\r
+ Xtime9[123] = _Xtime9[123]\r
+ XtimeB[123] = _XtimeB[123]\r
+ XtimeD[123] = _XtimeD[123]\r
+ XtimeE[123] = _XtimeE[123]\r
+ Sbox[124] = _Sbox[124]\r
+ InvSbox[124] = _InvSbox[124]\r
+ Xtime2Sbox[124] = _Xtime2Sbox[124]\r
+ Xtime3Sbox[124] = _Xtime3Sbox[124]\r
+ Xtime2[124] = _Xtime2[124]\r
+ Xtime9[124] = _Xtime9[124]\r
+ XtimeB[124] = _XtimeB[124]\r
+ XtimeD[124] = _XtimeD[124]\r
+ XtimeE[124] = _XtimeE[124]\r
+ Sbox[125] = _Sbox[125]\r
+ InvSbox[125] = _InvSbox[125]\r
+ Xtime2Sbox[125] = _Xtime2Sbox[125]\r
+ Xtime3Sbox[125] = _Xtime3Sbox[125]\r
+ Xtime2[125] = _Xtime2[125]\r
+ Xtime9[125] = _Xtime9[125]\r
+ XtimeB[125] = _XtimeB[125]\r
+ XtimeD[125] = _XtimeD[125]\r
+ XtimeE[125] = _XtimeE[125]\r
+ Sbox[126] = _Sbox[126]\r
+ InvSbox[126] = _InvSbox[126]\r
+ Xtime2Sbox[126] = _Xtime2Sbox[126]\r
+ Xtime3Sbox[126] = _Xtime3Sbox[126]\r
+ Xtime2[126] = _Xtime2[126]\r
+ Xtime9[126] = _Xtime9[126]\r
+ XtimeB[126] = _XtimeB[126]\r
+ XtimeD[126] = _XtimeD[126]\r
+ XtimeE[126] = _XtimeE[126]\r
+ Sbox[127] = _Sbox[127]\r
+ InvSbox[127] = _InvSbox[127]\r
+ Xtime2Sbox[127] = _Xtime2Sbox[127]\r
+ Xtime3Sbox[127] = _Xtime3Sbox[127]\r
+ Xtime2[127] = _Xtime2[127]\r
+ Xtime9[127] = _Xtime9[127]\r
+ XtimeB[127] = _XtimeB[127]\r
+ XtimeD[127] = _XtimeD[127]\r
+ XtimeE[127] = _XtimeE[127]\r
+ Sbox[128] = _Sbox[128]\r
+ InvSbox[128] = _InvSbox[128]\r
+ Xtime2Sbox[128] = _Xtime2Sbox[128]\r
+ Xtime3Sbox[128] = _Xtime3Sbox[128]\r
+ Xtime2[128] = _Xtime2[128]\r
+ Xtime9[128] = _Xtime9[128]\r
+ XtimeB[128] = _XtimeB[128]\r
+ XtimeD[128] = _XtimeD[128]\r
+ XtimeE[128] = _XtimeE[128]\r
+ Sbox[129] = _Sbox[129]\r
+ InvSbox[129] = _InvSbox[129]\r
+ Xtime2Sbox[129] = _Xtime2Sbox[129]\r
+ Xtime3Sbox[129] = _Xtime3Sbox[129]\r
+ Xtime2[129] = _Xtime2[129]\r
+ Xtime9[129] = _Xtime9[129]\r
+ XtimeB[129] = _XtimeB[129]\r
+ XtimeD[129] = _XtimeD[129]\r
+ XtimeE[129] = _XtimeE[129]\r
+ Sbox[130] = _Sbox[130]\r
+ InvSbox[130] = _InvSbox[130]\r
+ Xtime2Sbox[130] = _Xtime2Sbox[130]\r
+ Xtime3Sbox[130] = _Xtime3Sbox[130]\r
+ Xtime2[130] = _Xtime2[130]\r
+ Xtime9[130] = _Xtime9[130]\r
+ XtimeB[130] = _XtimeB[130]\r
+ XtimeD[130] = _XtimeD[130]\r
+ XtimeE[130] = _XtimeE[130]\r
+ Sbox[131] = _Sbox[131]\r
+ InvSbox[131] = _InvSbox[131]\r
+ Xtime2Sbox[131] = _Xtime2Sbox[131]\r
+ Xtime3Sbox[131] = _Xtime3Sbox[131]\r
+ Xtime2[131] = _Xtime2[131]\r
+ Xtime9[131] = _Xtime9[131]\r
+ XtimeB[131] = _XtimeB[131]\r
+ XtimeD[131] = _XtimeD[131]\r
+ XtimeE[131] = _XtimeE[131]\r
+ Sbox[132] = _Sbox[132]\r
+ InvSbox[132] = _InvSbox[132]\r
+ Xtime2Sbox[132] = _Xtime2Sbox[132]\r
+ Xtime3Sbox[132] = _Xtime3Sbox[132]\r
+ Xtime2[132] = _Xtime2[132]\r
+ Xtime9[132] = _Xtime9[132]\r
+ XtimeB[132] = _XtimeB[132]\r
+ XtimeD[132] = _XtimeD[132]\r
+ XtimeE[132] = _XtimeE[132]\r
+ Sbox[133] = _Sbox[133]\r
+ InvSbox[133] = _InvSbox[133]\r
+ Xtime2Sbox[133] = _Xtime2Sbox[133]\r
+ Xtime3Sbox[133] = _Xtime3Sbox[133]\r
+ Xtime2[133] = _Xtime2[133]\r
+ Xtime9[133] = _Xtime9[133]\r
+ XtimeB[133] = _XtimeB[133]\r
+ XtimeD[133] = _XtimeD[133]\r
+ XtimeE[133] = _XtimeE[133]\r
+ Sbox[134] = _Sbox[134]\r
+ InvSbox[134] = _InvSbox[134]\r
+ Xtime2Sbox[134] = _Xtime2Sbox[134]\r
+ Xtime3Sbox[134] = _Xtime3Sbox[134]\r
+ Xtime2[134] = _Xtime2[134]\r
+ Xtime9[134] = _Xtime9[134]\r
+ XtimeB[134] = _XtimeB[134]\r
+ XtimeD[134] = _XtimeD[134]\r
+ XtimeE[134] = _XtimeE[134]\r
+ Sbox[135] = _Sbox[135]\r
+ InvSbox[135] = _InvSbox[135]\r
+ Xtime2Sbox[135] = _Xtime2Sbox[135]\r
+ Xtime3Sbox[135] = _Xtime3Sbox[135]\r
+ Xtime2[135] = _Xtime2[135]\r
+ Xtime9[135] = _Xtime9[135]\r
+ XtimeB[135] = _XtimeB[135]\r
+ XtimeD[135] = _XtimeD[135]\r
+ XtimeE[135] = _XtimeE[135]\r
+ Sbox[136] = _Sbox[136]\r
+ InvSbox[136] = _InvSbox[136]\r
+ Xtime2Sbox[136] = _Xtime2Sbox[136]\r
+ Xtime3Sbox[136] = _Xtime3Sbox[136]\r
+ Xtime2[136] = _Xtime2[136]\r
+ Xtime9[136] = _Xtime9[136]\r
+ XtimeB[136] = _XtimeB[136]\r
+ XtimeD[136] = _XtimeD[136]\r
+ XtimeE[136] = _XtimeE[136]\r
+ Sbox[137] = _Sbox[137]\r
+ InvSbox[137] = _InvSbox[137]\r
+ Xtime2Sbox[137] = _Xtime2Sbox[137]\r
+ Xtime3Sbox[137] = _Xtime3Sbox[137]\r
+ Xtime2[137] = _Xtime2[137]\r
+ Xtime9[137] = _Xtime9[137]\r
+ XtimeB[137] = _XtimeB[137]\r
+ XtimeD[137] = _XtimeD[137]\r
+ XtimeE[137] = _XtimeE[137]\r
+ Sbox[138] = _Sbox[138]\r
+ InvSbox[138] = _InvSbox[138]\r
+ Xtime2Sbox[138] = _Xtime2Sbox[138]\r
+ Xtime3Sbox[138] = _Xtime3Sbox[138]\r
+ Xtime2[138] = _Xtime2[138]\r
+ Xtime9[138] = _Xtime9[138]\r
+ XtimeB[138] = _XtimeB[138]\r
+ XtimeD[138] = _XtimeD[138]\r
+ XtimeE[138] = _XtimeE[138]\r
+ Sbox[139] = _Sbox[139]\r
+ InvSbox[139] = _InvSbox[139]\r
+ Xtime2Sbox[139] = _Xtime2Sbox[139]\r
+ Xtime3Sbox[139] = _Xtime3Sbox[139]\r
+ Xtime2[139] = _Xtime2[139]\r
+ Xtime9[139] = _Xtime9[139]\r
+ XtimeB[139] = _XtimeB[139]\r
+ XtimeD[139] = _XtimeD[139]\r
+ XtimeE[139] = _XtimeE[139]\r
+ Sbox[140] = _Sbox[140]\r
+ InvSbox[140] = _InvSbox[140]\r
+ Xtime2Sbox[140] = _Xtime2Sbox[140]\r
+ Xtime3Sbox[140] = _Xtime3Sbox[140]\r
+ Xtime2[140] = _Xtime2[140]\r
+ Xtime9[140] = _Xtime9[140]\r
+ XtimeB[140] = _XtimeB[140]\r
+ XtimeD[140] = _XtimeD[140]\r
+ XtimeE[140] = _XtimeE[140]\r
+ Sbox[141] = _Sbox[141]\r
+ InvSbox[141] = _InvSbox[141]\r
+ Xtime2Sbox[141] = _Xtime2Sbox[141]\r
+ Xtime3Sbox[141] = _Xtime3Sbox[141]\r
+ Xtime2[141] = _Xtime2[141]\r
+ Xtime9[141] = _Xtime9[141]\r
+ XtimeB[141] = _XtimeB[141]\r
+ XtimeD[141] = _XtimeD[141]\r
+ XtimeE[141] = _XtimeE[141]\r
+ Sbox[142] = _Sbox[142]\r
+ InvSbox[142] = _InvSbox[142]\r
+ Xtime2Sbox[142] = _Xtime2Sbox[142]\r
+ Xtime3Sbox[142] = _Xtime3Sbox[142]\r
+ Xtime2[142] = _Xtime2[142]\r
+ Xtime9[142] = _Xtime9[142]\r
+ XtimeB[142] = _XtimeB[142]\r
+ XtimeD[142] = _XtimeD[142]\r
+ XtimeE[142] = _XtimeE[142]\r
+ Sbox[143] = _Sbox[143]\r
+ InvSbox[143] = _InvSbox[143]\r
+ Xtime2Sbox[143] = _Xtime2Sbox[143]\r
+ Xtime3Sbox[143] = _Xtime3Sbox[143]\r
+ Xtime2[143] = _Xtime2[143]\r
+ Xtime9[143] = _Xtime9[143]\r
+ XtimeB[143] = _XtimeB[143]\r
+ XtimeD[143] = _XtimeD[143]\r
+ XtimeE[143] = _XtimeE[143]\r
+ Sbox[144] = _Sbox[144]\r
+ InvSbox[144] = _InvSbox[144]\r
+ Xtime2Sbox[144] = _Xtime2Sbox[144]\r
+ Xtime3Sbox[144] = _Xtime3Sbox[144]\r
+ Xtime2[144] = _Xtime2[144]\r
+ Xtime9[144] = _Xtime9[144]\r
+ XtimeB[144] = _XtimeB[144]\r
+ XtimeD[144] = _XtimeD[144]\r
+ XtimeE[144] = _XtimeE[144]\r
+ Sbox[145] = _Sbox[145]\r
+ InvSbox[145] = _InvSbox[145]\r
+ Xtime2Sbox[145] = _Xtime2Sbox[145]\r
+ Xtime3Sbox[145] = _Xtime3Sbox[145]\r
+ Xtime2[145] = _Xtime2[145]\r
+ Xtime9[145] = _Xtime9[145]\r
+ XtimeB[145] = _XtimeB[145]\r
+ XtimeD[145] = _XtimeD[145]\r
+ XtimeE[145] = _XtimeE[145]\r
+ Sbox[146] = _Sbox[146]\r
+ InvSbox[146] = _InvSbox[146]\r
+ Xtime2Sbox[146] = _Xtime2Sbox[146]\r
+ Xtime3Sbox[146] = _Xtime3Sbox[146]\r
+ Xtime2[146] = _Xtime2[146]\r
+ Xtime9[146] = _Xtime9[146]\r
+ XtimeB[146] = _XtimeB[146]\r
+ XtimeD[146] = _XtimeD[146]\r
+ XtimeE[146] = _XtimeE[146]\r
+ Sbox[147] = _Sbox[147]\r
+ InvSbox[147] = _InvSbox[147]\r
+ Xtime2Sbox[147] = _Xtime2Sbox[147]\r
+ Xtime3Sbox[147] = _Xtime3Sbox[147]\r
+ Xtime2[147] = _Xtime2[147]\r
+ Xtime9[147] = _Xtime9[147]\r
+ XtimeB[147] = _XtimeB[147]\r
+ XtimeD[147] = _XtimeD[147]\r
+ XtimeE[147] = _XtimeE[147]\r
+ Sbox[148] = _Sbox[148]\r
+ InvSbox[148] = _InvSbox[148]\r
+ Xtime2Sbox[148] = _Xtime2Sbox[148]\r
+ Xtime3Sbox[148] = _Xtime3Sbox[148]\r
+ Xtime2[148] = _Xtime2[148]\r
+ Xtime9[148] = _Xtime9[148]\r
+ XtimeB[148] = _XtimeB[148]\r
+ XtimeD[148] = _XtimeD[148]\r
+ XtimeE[148] = _XtimeE[148]\r
+ Sbox[149] = _Sbox[149]\r
+ InvSbox[149] = _InvSbox[149]\r
+ Xtime2Sbox[149] = _Xtime2Sbox[149]\r
+ Xtime3Sbox[149] = _Xtime3Sbox[149]\r
+ Xtime2[149] = _Xtime2[149]\r
+ Xtime9[149] = _Xtime9[149]\r
+ XtimeB[149] = _XtimeB[149]\r
+ XtimeD[149] = _XtimeD[149]\r
+ XtimeE[149] = _XtimeE[149]\r
+ Sbox[150] = _Sbox[150]\r
+ InvSbox[150] = _InvSbox[150]\r
+ Xtime2Sbox[150] = _Xtime2Sbox[150]\r
+ Xtime3Sbox[150] = _Xtime3Sbox[150]\r
+ Xtime2[150] = _Xtime2[150]\r
+ Xtime9[150] = _Xtime9[150]\r
+ XtimeB[150] = _XtimeB[150]\r
+ XtimeD[150] = _XtimeD[150]\r
+ XtimeE[150] = _XtimeE[150]\r
+ Sbox[151] = _Sbox[151]\r
+ InvSbox[151] = _InvSbox[151]\r
+ Xtime2Sbox[151] = _Xtime2Sbox[151]\r
+ Xtime3Sbox[151] = _Xtime3Sbox[151]\r
+ Xtime2[151] = _Xtime2[151]\r
+ Xtime9[151] = _Xtime9[151]\r
+ XtimeB[151] = _XtimeB[151]\r
+ XtimeD[151] = _XtimeD[151]\r
+ XtimeE[151] = _XtimeE[151]\r
+ Sbox[152] = _Sbox[152]\r
+ InvSbox[152] = _InvSbox[152]\r
+ Xtime2Sbox[152] = _Xtime2Sbox[152]\r
+ Xtime3Sbox[152] = _Xtime3Sbox[152]\r
+ Xtime2[152] = _Xtime2[152]\r
+ Xtime9[152] = _Xtime9[152]\r
+ XtimeB[152] = _XtimeB[152]\r
+ XtimeD[152] = _XtimeD[152]\r
+ XtimeE[152] = _XtimeE[152]\r
+ Sbox[153] = _Sbox[153]\r
+ InvSbox[153] = _InvSbox[153]\r
+ Xtime2Sbox[153] = _Xtime2Sbox[153]\r
+ Xtime3Sbox[153] = _Xtime3Sbox[153]\r
+ Xtime2[153] = _Xtime2[153]\r
+ Xtime9[153] = _Xtime9[153]\r
+ XtimeB[153] = _XtimeB[153]\r
+ XtimeD[153] = _XtimeD[153]\r
+ XtimeE[153] = _XtimeE[153]\r
+ Sbox[154] = _Sbox[154]\r
+ InvSbox[154] = _InvSbox[154]\r
+ Xtime2Sbox[154] = _Xtime2Sbox[154]\r
+ Xtime3Sbox[154] = _Xtime3Sbox[154]\r
+ Xtime2[154] = _Xtime2[154]\r
+ Xtime9[154] = _Xtime9[154]\r
+ XtimeB[154] = _XtimeB[154]\r
+ XtimeD[154] = _XtimeD[154]\r
+ XtimeE[154] = _XtimeE[154]\r
+ Sbox[155] = _Sbox[155]\r
+ InvSbox[155] = _InvSbox[155]\r
+ Xtime2Sbox[155] = _Xtime2Sbox[155]\r
+ Xtime3Sbox[155] = _Xtime3Sbox[155]\r
+ Xtime2[155] = _Xtime2[155]\r
+ Xtime9[155] = _Xtime9[155]\r
+ XtimeB[155] = _XtimeB[155]\r
+ XtimeD[155] = _XtimeD[155]\r
+ XtimeE[155] = _XtimeE[155]\r
+ Sbox[156] = _Sbox[156]\r
+ InvSbox[156] = _InvSbox[156]\r
+ Xtime2Sbox[156] = _Xtime2Sbox[156]\r
+ Xtime3Sbox[156] = _Xtime3Sbox[156]\r
+ Xtime2[156] = _Xtime2[156]\r
+ Xtime9[156] = _Xtime9[156]\r
+ XtimeB[156] = _XtimeB[156]\r
+ XtimeD[156] = _XtimeD[156]\r
+ XtimeE[156] = _XtimeE[156]\r
+ Sbox[157] = _Sbox[157]\r
+ InvSbox[157] = _InvSbox[157]\r
+ Xtime2Sbox[157] = _Xtime2Sbox[157]\r
+ Xtime3Sbox[157] = _Xtime3Sbox[157]\r
+ Xtime2[157] = _Xtime2[157]\r
+ Xtime9[157] = _Xtime9[157]\r
+ XtimeB[157] = _XtimeB[157]\r
+ XtimeD[157] = _XtimeD[157]\r
+ XtimeE[157] = _XtimeE[157]\r
+ Sbox[158] = _Sbox[158]\r
+ InvSbox[158] = _InvSbox[158]\r
+ Xtime2Sbox[158] = _Xtime2Sbox[158]\r
+ Xtime3Sbox[158] = _Xtime3Sbox[158]\r
+ Xtime2[158] = _Xtime2[158]\r
+ Xtime9[158] = _Xtime9[158]\r
+ XtimeB[158] = _XtimeB[158]\r
+ XtimeD[158] = _XtimeD[158]\r
+ XtimeE[158] = _XtimeE[158]\r
+ Sbox[159] = _Sbox[159]\r
+ InvSbox[159] = _InvSbox[159]\r
+ Xtime2Sbox[159] = _Xtime2Sbox[159]\r
+ Xtime3Sbox[159] = _Xtime3Sbox[159]\r
+ Xtime2[159] = _Xtime2[159]\r
+ Xtime9[159] = _Xtime9[159]\r
+ XtimeB[159] = _XtimeB[159]\r
+ XtimeD[159] = _XtimeD[159]\r
+ XtimeE[159] = _XtimeE[159]\r
+ Sbox[160] = _Sbox[160]\r
+ InvSbox[160] = _InvSbox[160]\r
+ Xtime2Sbox[160] = _Xtime2Sbox[160]\r
+ Xtime3Sbox[160] = _Xtime3Sbox[160]\r
+ Xtime2[160] = _Xtime2[160]\r
+ Xtime9[160] = _Xtime9[160]\r
+ XtimeB[160] = _XtimeB[160]\r
+ XtimeD[160] = _XtimeD[160]\r
+ XtimeE[160] = _XtimeE[160]\r
+ Sbox[161] = _Sbox[161]\r
+ InvSbox[161] = _InvSbox[161]\r
+ Xtime2Sbox[161] = _Xtime2Sbox[161]\r
+ Xtime3Sbox[161] = _Xtime3Sbox[161]\r
+ Xtime2[161] = _Xtime2[161]\r
+ Xtime9[161] = _Xtime9[161]\r
+ XtimeB[161] = _XtimeB[161]\r
+ XtimeD[161] = _XtimeD[161]\r
+ XtimeE[161] = _XtimeE[161]\r
+ Sbox[162] = _Sbox[162]\r
+ InvSbox[162] = _InvSbox[162]\r
+ Xtime2Sbox[162] = _Xtime2Sbox[162]\r
+ Xtime3Sbox[162] = _Xtime3Sbox[162]\r
+ Xtime2[162] = _Xtime2[162]\r
+ Xtime9[162] = _Xtime9[162]\r
+ XtimeB[162] = _XtimeB[162]\r
+ XtimeD[162] = _XtimeD[162]\r
+ XtimeE[162] = _XtimeE[162]\r
+ Sbox[163] = _Sbox[163]\r
+ InvSbox[163] = _InvSbox[163]\r
+ Xtime2Sbox[163] = _Xtime2Sbox[163]\r
+ Xtime3Sbox[163] = _Xtime3Sbox[163]\r
+ Xtime2[163] = _Xtime2[163]\r
+ Xtime9[163] = _Xtime9[163]\r
+ XtimeB[163] = _XtimeB[163]\r
+ XtimeD[163] = _XtimeD[163]\r
+ XtimeE[163] = _XtimeE[163]\r
+ Sbox[164] = _Sbox[164]\r
+ InvSbox[164] = _InvSbox[164]\r
+ Xtime2Sbox[164] = _Xtime2Sbox[164]\r
+ Xtime3Sbox[164] = _Xtime3Sbox[164]\r
+ Xtime2[164] = _Xtime2[164]\r
+ Xtime9[164] = _Xtime9[164]\r
+ XtimeB[164] = _XtimeB[164]\r
+ XtimeD[164] = _XtimeD[164]\r
+ XtimeE[164] = _XtimeE[164]\r
+ Sbox[165] = _Sbox[165]\r
+ InvSbox[165] = _InvSbox[165]\r
+ Xtime2Sbox[165] = _Xtime2Sbox[165]\r
+ Xtime3Sbox[165] = _Xtime3Sbox[165]\r
+ Xtime2[165] = _Xtime2[165]\r
+ Xtime9[165] = _Xtime9[165]\r
+ XtimeB[165] = _XtimeB[165]\r
+ XtimeD[165] = _XtimeD[165]\r
+ XtimeE[165] = _XtimeE[165]\r
+ Sbox[166] = _Sbox[166]\r
+ InvSbox[166] = _InvSbox[166]\r
+ Xtime2Sbox[166] = _Xtime2Sbox[166]\r
+ Xtime3Sbox[166] = _Xtime3Sbox[166]\r
+ Xtime2[166] = _Xtime2[166]\r
+ Xtime9[166] = _Xtime9[166]\r
+ XtimeB[166] = _XtimeB[166]\r
+ XtimeD[166] = _XtimeD[166]\r
+ XtimeE[166] = _XtimeE[166]\r
+ Sbox[167] = _Sbox[167]\r
+ InvSbox[167] = _InvSbox[167]\r
+ Xtime2Sbox[167] = _Xtime2Sbox[167]\r
+ Xtime3Sbox[167] = _Xtime3Sbox[167]\r
+ Xtime2[167] = _Xtime2[167]\r
+ Xtime9[167] = _Xtime9[167]\r
+ XtimeB[167] = _XtimeB[167]\r
+ XtimeD[167] = _XtimeD[167]\r
+ XtimeE[167] = _XtimeE[167]\r
+ Sbox[168] = _Sbox[168]\r
+ InvSbox[168] = _InvSbox[168]\r
+ Xtime2Sbox[168] = _Xtime2Sbox[168]\r
+ Xtime3Sbox[168] = _Xtime3Sbox[168]\r
+ Xtime2[168] = _Xtime2[168]\r
+ Xtime9[168] = _Xtime9[168]\r
+ XtimeB[168] = _XtimeB[168]\r
+ XtimeD[168] = _XtimeD[168]\r
+ XtimeE[168] = _XtimeE[168]\r
+ Sbox[169] = _Sbox[169]\r
+ InvSbox[169] = _InvSbox[169]\r
+ Xtime2Sbox[169] = _Xtime2Sbox[169]\r
+ Xtime3Sbox[169] = _Xtime3Sbox[169]\r
+ Xtime2[169] = _Xtime2[169]\r
+ Xtime9[169] = _Xtime9[169]\r
+ XtimeB[169] = _XtimeB[169]\r
+ XtimeD[169] = _XtimeD[169]\r
+ XtimeE[169] = _XtimeE[169]\r
+ Sbox[170] = _Sbox[170]\r
+ InvSbox[170] = _InvSbox[170]\r
+ Xtime2Sbox[170] = _Xtime2Sbox[170]\r
+ Xtime3Sbox[170] = _Xtime3Sbox[170]\r
+ Xtime2[170] = _Xtime2[170]\r
+ Xtime9[170] = _Xtime9[170]\r
+ XtimeB[170] = _XtimeB[170]\r
+ XtimeD[170] = _XtimeD[170]\r
+ XtimeE[170] = _XtimeE[170]\r
+ Sbox[171] = _Sbox[171]\r
+ InvSbox[171] = _InvSbox[171]\r
+ Xtime2Sbox[171] = _Xtime2Sbox[171]\r
+ Xtime3Sbox[171] = _Xtime3Sbox[171]\r
+ Xtime2[171] = _Xtime2[171]\r
+ Xtime9[171] = _Xtime9[171]\r
+ XtimeB[171] = _XtimeB[171]\r
+ XtimeD[171] = _XtimeD[171]\r
+ XtimeE[171] = _XtimeE[171]\r
+ Sbox[172] = _Sbox[172]\r
+ InvSbox[172] = _InvSbox[172]\r
+ Xtime2Sbox[172] = _Xtime2Sbox[172]\r
+ Xtime3Sbox[172] = _Xtime3Sbox[172]\r
+ Xtime2[172] = _Xtime2[172]\r
+ Xtime9[172] = _Xtime9[172]\r
+ XtimeB[172] = _XtimeB[172]\r
+ XtimeD[172] = _XtimeD[172]\r
+ XtimeE[172] = _XtimeE[172]\r
+ Sbox[173] = _Sbox[173]\r
+ InvSbox[173] = _InvSbox[173]\r
+ Xtime2Sbox[173] = _Xtime2Sbox[173]\r
+ Xtime3Sbox[173] = _Xtime3Sbox[173]\r
+ Xtime2[173] = _Xtime2[173]\r
+ Xtime9[173] = _Xtime9[173]\r
+ XtimeB[173] = _XtimeB[173]\r
+ XtimeD[173] = _XtimeD[173]\r
+ XtimeE[173] = _XtimeE[173]\r
+ Sbox[174] = _Sbox[174]\r
+ InvSbox[174] = _InvSbox[174]\r
+ Xtime2Sbox[174] = _Xtime2Sbox[174]\r
+ Xtime3Sbox[174] = _Xtime3Sbox[174]\r
+ Xtime2[174] = _Xtime2[174]\r
+ Xtime9[174] = _Xtime9[174]\r
+ XtimeB[174] = _XtimeB[174]\r
+ XtimeD[174] = _XtimeD[174]\r
+ XtimeE[174] = _XtimeE[174]\r
+ Sbox[175] = _Sbox[175]\r
+ InvSbox[175] = _InvSbox[175]\r
+ Xtime2Sbox[175] = _Xtime2Sbox[175]\r
+ Xtime3Sbox[175] = _Xtime3Sbox[175]\r
+ Xtime2[175] = _Xtime2[175]\r
+ Xtime9[175] = _Xtime9[175]\r
+ XtimeB[175] = _XtimeB[175]\r
+ XtimeD[175] = _XtimeD[175]\r
+ XtimeE[175] = _XtimeE[175]\r
+ Sbox[176] = _Sbox[176]\r
+ InvSbox[176] = _InvSbox[176]\r
+ Xtime2Sbox[176] = _Xtime2Sbox[176]\r
+ Xtime3Sbox[176] = _Xtime3Sbox[176]\r
+ Xtime2[176] = _Xtime2[176]\r
+ Xtime9[176] = _Xtime9[176]\r
+ XtimeB[176] = _XtimeB[176]\r
+ XtimeD[176] = _XtimeD[176]\r
+ XtimeE[176] = _XtimeE[176]\r
+ Sbox[177] = _Sbox[177]\r
+ InvSbox[177] = _InvSbox[177]\r
+ Xtime2Sbox[177] = _Xtime2Sbox[177]\r
+ Xtime3Sbox[177] = _Xtime3Sbox[177]\r
+ Xtime2[177] = _Xtime2[177]\r
+ Xtime9[177] = _Xtime9[177]\r
+ XtimeB[177] = _XtimeB[177]\r
+ XtimeD[177] = _XtimeD[177]\r
+ XtimeE[177] = _XtimeE[177]\r
+ Sbox[178] = _Sbox[178]\r
+ InvSbox[178] = _InvSbox[178]\r
+ Xtime2Sbox[178] = _Xtime2Sbox[178]\r
+ Xtime3Sbox[178] = _Xtime3Sbox[178]\r
+ Xtime2[178] = _Xtime2[178]\r
+ Xtime9[178] = _Xtime9[178]\r
+ XtimeB[178] = _XtimeB[178]\r
+ XtimeD[178] = _XtimeD[178]\r
+ XtimeE[178] = _XtimeE[178]\r
+ Sbox[179] = _Sbox[179]\r
+ InvSbox[179] = _InvSbox[179]\r
+ Xtime2Sbox[179] = _Xtime2Sbox[179]\r
+ Xtime3Sbox[179] = _Xtime3Sbox[179]\r
+ Xtime2[179] = _Xtime2[179]\r
+ Xtime9[179] = _Xtime9[179]\r
+ XtimeB[179] = _XtimeB[179]\r
+ XtimeD[179] = _XtimeD[179]\r
+ XtimeE[179] = _XtimeE[179]\r
+ Sbox[180] = _Sbox[180]\r
+ InvSbox[180] = _InvSbox[180]\r
+ Xtime2Sbox[180] = _Xtime2Sbox[180]\r
+ Xtime3Sbox[180] = _Xtime3Sbox[180]\r
+ Xtime2[180] = _Xtime2[180]\r
+ Xtime9[180] = _Xtime9[180]\r
+ XtimeB[180] = _XtimeB[180]\r
+ XtimeD[180] = _XtimeD[180]\r
+ XtimeE[180] = _XtimeE[180]\r
+ Sbox[181] = _Sbox[181]\r
+ InvSbox[181] = _InvSbox[181]\r
+ Xtime2Sbox[181] = _Xtime2Sbox[181]\r
+ Xtime3Sbox[181] = _Xtime3Sbox[181]\r
+ Xtime2[181] = _Xtime2[181]\r
+ Xtime9[181] = _Xtime9[181]\r
+ XtimeB[181] = _XtimeB[181]\r
+ XtimeD[181] = _XtimeD[181]\r
+ XtimeE[181] = _XtimeE[181]\r
+ Sbox[182] = _Sbox[182]\r
+ InvSbox[182] = _InvSbox[182]\r
+ Xtime2Sbox[182] = _Xtime2Sbox[182]\r
+ Xtime3Sbox[182] = _Xtime3Sbox[182]\r
+ Xtime2[182] = _Xtime2[182]\r
+ Xtime9[182] = _Xtime9[182]\r
+ XtimeB[182] = _XtimeB[182]\r
+ XtimeD[182] = _XtimeD[182]\r
+ XtimeE[182] = _XtimeE[182]\r
+ Sbox[183] = _Sbox[183]\r
+ InvSbox[183] = _InvSbox[183]\r
+ Xtime2Sbox[183] = _Xtime2Sbox[183]\r
+ Xtime3Sbox[183] = _Xtime3Sbox[183]\r
+ Xtime2[183] = _Xtime2[183]\r
+ Xtime9[183] = _Xtime9[183]\r
+ XtimeB[183] = _XtimeB[183]\r
+ XtimeD[183] = _XtimeD[183]\r
+ XtimeE[183] = _XtimeE[183]\r
+ Sbox[184] = _Sbox[184]\r
+ InvSbox[184] = _InvSbox[184]\r
+ Xtime2Sbox[184] = _Xtime2Sbox[184]\r
+ Xtime3Sbox[184] = _Xtime3Sbox[184]\r
+ Xtime2[184] = _Xtime2[184]\r
+ Xtime9[184] = _Xtime9[184]\r
+ XtimeB[184] = _XtimeB[184]\r
+ XtimeD[184] = _XtimeD[184]\r
+ XtimeE[184] = _XtimeE[184]\r
+ Sbox[185] = _Sbox[185]\r
+ InvSbox[185] = _InvSbox[185]\r
+ Xtime2Sbox[185] = _Xtime2Sbox[185]\r
+ Xtime3Sbox[185] = _Xtime3Sbox[185]\r
+ Xtime2[185] = _Xtime2[185]\r
+ Xtime9[185] = _Xtime9[185]\r
+ XtimeB[185] = _XtimeB[185]\r
+ XtimeD[185] = _XtimeD[185]\r
+ XtimeE[185] = _XtimeE[185]\r
+ Sbox[186] = _Sbox[186]\r
+ InvSbox[186] = _InvSbox[186]\r
+ Xtime2Sbox[186] = _Xtime2Sbox[186]\r
+ Xtime3Sbox[186] = _Xtime3Sbox[186]\r
+ Xtime2[186] = _Xtime2[186]\r
+ Xtime9[186] = _Xtime9[186]\r
+ XtimeB[186] = _XtimeB[186]\r
+ XtimeD[186] = _XtimeD[186]\r
+ XtimeE[186] = _XtimeE[186]\r
+ Sbox[187] = _Sbox[187]\r
+ InvSbox[187] = _InvSbox[187]\r
+ Xtime2Sbox[187] = _Xtime2Sbox[187]\r
+ Xtime3Sbox[187] = _Xtime3Sbox[187]\r
+ Xtime2[187] = _Xtime2[187]\r
+ Xtime9[187] = _Xtime9[187]\r
+ XtimeB[187] = _XtimeB[187]\r
+ XtimeD[187] = _XtimeD[187]\r
+ XtimeE[187] = _XtimeE[187]\r
+ Sbox[188] = _Sbox[188]\r
+ InvSbox[188] = _InvSbox[188]\r
+ Xtime2Sbox[188] = _Xtime2Sbox[188]\r
+ Xtime3Sbox[188] = _Xtime3Sbox[188]\r
+ Xtime2[188] = _Xtime2[188]\r
+ Xtime9[188] = _Xtime9[188]\r
+ XtimeB[188] = _XtimeB[188]\r
+ XtimeD[188] = _XtimeD[188]\r
+ XtimeE[188] = _XtimeE[188]\r
+ Sbox[189] = _Sbox[189]\r
+ InvSbox[189] = _InvSbox[189]\r
+ Xtime2Sbox[189] = _Xtime2Sbox[189]\r
+ Xtime3Sbox[189] = _Xtime3Sbox[189]\r
+ Xtime2[189] = _Xtime2[189]\r
+ Xtime9[189] = _Xtime9[189]\r
+ XtimeB[189] = _XtimeB[189]\r
+ XtimeD[189] = _XtimeD[189]\r
+ XtimeE[189] = _XtimeE[189]\r
+ Sbox[190] = _Sbox[190]\r
+ InvSbox[190] = _InvSbox[190]\r
+ Xtime2Sbox[190] = _Xtime2Sbox[190]\r
+ Xtime3Sbox[190] = _Xtime3Sbox[190]\r
+ Xtime2[190] = _Xtime2[190]\r
+ Xtime9[190] = _Xtime9[190]\r
+ XtimeB[190] = _XtimeB[190]\r
+ XtimeD[190] = _XtimeD[190]\r
+ XtimeE[190] = _XtimeE[190]\r
+ Sbox[191] = _Sbox[191]\r
+ InvSbox[191] = _InvSbox[191]\r
+ Xtime2Sbox[191] = _Xtime2Sbox[191]\r
+ Xtime3Sbox[191] = _Xtime3Sbox[191]\r
+ Xtime2[191] = _Xtime2[191]\r
+ Xtime9[191] = _Xtime9[191]\r
+ XtimeB[191] = _XtimeB[191]\r
+ XtimeD[191] = _XtimeD[191]\r
+ XtimeE[191] = _XtimeE[191]\r
+ Sbox[192] = _Sbox[192]\r
+ InvSbox[192] = _InvSbox[192]\r
+ Xtime2Sbox[192] = _Xtime2Sbox[192]\r
+ Xtime3Sbox[192] = _Xtime3Sbox[192]\r
+ Xtime2[192] = _Xtime2[192]\r
+ Xtime9[192] = _Xtime9[192]\r
+ XtimeB[192] = _XtimeB[192]\r
+ XtimeD[192] = _XtimeD[192]\r
+ XtimeE[192] = _XtimeE[192]\r
+ Sbox[193] = _Sbox[193]\r
+ InvSbox[193] = _InvSbox[193]\r
+ Xtime2Sbox[193] = _Xtime2Sbox[193]\r
+ Xtime3Sbox[193] = _Xtime3Sbox[193]\r
+ Xtime2[193] = _Xtime2[193]\r
+ Xtime9[193] = _Xtime9[193]\r
+ XtimeB[193] = _XtimeB[193]\r
+ XtimeD[193] = _XtimeD[193]\r
+ XtimeE[193] = _XtimeE[193]\r
+ Sbox[194] = _Sbox[194]\r
+ InvSbox[194] = _InvSbox[194]\r
+ Xtime2Sbox[194] = _Xtime2Sbox[194]\r
+ Xtime3Sbox[194] = _Xtime3Sbox[194]\r
+ Xtime2[194] = _Xtime2[194]\r
+ Xtime9[194] = _Xtime9[194]\r
+ XtimeB[194] = _XtimeB[194]\r
+ XtimeD[194] = _XtimeD[194]\r
+ XtimeE[194] = _XtimeE[194]\r
+ Sbox[195] = _Sbox[195]\r
+ InvSbox[195] = _InvSbox[195]\r
+ Xtime2Sbox[195] = _Xtime2Sbox[195]\r
+ Xtime3Sbox[195] = _Xtime3Sbox[195]\r
+ Xtime2[195] = _Xtime2[195]\r
+ Xtime9[195] = _Xtime9[195]\r
+ XtimeB[195] = _XtimeB[195]\r
+ XtimeD[195] = _XtimeD[195]\r
+ XtimeE[195] = _XtimeE[195]\r
+ Sbox[196] = _Sbox[196]\r
+ InvSbox[196] = _InvSbox[196]\r
+ Xtime2Sbox[196] = _Xtime2Sbox[196]\r
+ Xtime3Sbox[196] = _Xtime3Sbox[196]\r
+ Xtime2[196] = _Xtime2[196]\r
+ Xtime9[196] = _Xtime9[196]\r
+ XtimeB[196] = _XtimeB[196]\r
+ XtimeD[196] = _XtimeD[196]\r
+ XtimeE[196] = _XtimeE[196]\r
+ Sbox[197] = _Sbox[197]\r
+ InvSbox[197] = _InvSbox[197]\r
+ Xtime2Sbox[197] = _Xtime2Sbox[197]\r
+ Xtime3Sbox[197] = _Xtime3Sbox[197]\r
+ Xtime2[197] = _Xtime2[197]\r
+ Xtime9[197] = _Xtime9[197]\r
+ XtimeB[197] = _XtimeB[197]\r
+ XtimeD[197] = _XtimeD[197]\r
+ XtimeE[197] = _XtimeE[197]\r
+ Sbox[198] = _Sbox[198]\r
+ InvSbox[198] = _InvSbox[198]\r
+ Xtime2Sbox[198] = _Xtime2Sbox[198]\r
+ Xtime3Sbox[198] = _Xtime3Sbox[198]\r
+ Xtime2[198] = _Xtime2[198]\r
+ Xtime9[198] = _Xtime9[198]\r
+ XtimeB[198] = _XtimeB[198]\r
+ XtimeD[198] = _XtimeD[198]\r
+ XtimeE[198] = _XtimeE[198]\r
+ Sbox[199] = _Sbox[199]\r
+ InvSbox[199] = _InvSbox[199]\r
+ Xtime2Sbox[199] = _Xtime2Sbox[199]\r
+ Xtime3Sbox[199] = _Xtime3Sbox[199]\r
+ Xtime2[199] = _Xtime2[199]\r
+ Xtime9[199] = _Xtime9[199]\r
+ XtimeB[199] = _XtimeB[199]\r
+ XtimeD[199] = _XtimeD[199]\r
+ XtimeE[199] = _XtimeE[199]\r
+ Sbox[200] = _Sbox[200]\r
+ InvSbox[200] = _InvSbox[200]\r
+ Xtime2Sbox[200] = _Xtime2Sbox[200]\r
+ Xtime3Sbox[200] = _Xtime3Sbox[200]\r
+ Xtime2[200] = _Xtime2[200]\r
+ Xtime9[200] = _Xtime9[200]\r
+ XtimeB[200] = _XtimeB[200]\r
+ XtimeD[200] = _XtimeD[200]\r
+ XtimeE[200] = _XtimeE[200]\r
+ Sbox[201] = _Sbox[201]\r
+ InvSbox[201] = _InvSbox[201]\r
+ Xtime2Sbox[201] = _Xtime2Sbox[201]\r
+ Xtime3Sbox[201] = _Xtime3Sbox[201]\r
+ Xtime2[201] = _Xtime2[201]\r
+ Xtime9[201] = _Xtime9[201]\r
+ XtimeB[201] = _XtimeB[201]\r
+ XtimeD[201] = _XtimeD[201]\r
+ XtimeE[201] = _XtimeE[201]\r
+ Sbox[202] = _Sbox[202]\r
+ InvSbox[202] = _InvSbox[202]\r
+ Xtime2Sbox[202] = _Xtime2Sbox[202]\r
+ Xtime3Sbox[202] = _Xtime3Sbox[202]\r
+ Xtime2[202] = _Xtime2[202]\r
+ Xtime9[202] = _Xtime9[202]\r
+ XtimeB[202] = _XtimeB[202]\r
+ XtimeD[202] = _XtimeD[202]\r
+ XtimeE[202] = _XtimeE[202]\r
+ Sbox[203] = _Sbox[203]\r
+ InvSbox[203] = _InvSbox[203]\r
+ Xtime2Sbox[203] = _Xtime2Sbox[203]\r
+ Xtime3Sbox[203] = _Xtime3Sbox[203]\r
+ Xtime2[203] = _Xtime2[203]\r
+ Xtime9[203] = _Xtime9[203]\r
+ XtimeB[203] = _XtimeB[203]\r
+ XtimeD[203] = _XtimeD[203]\r
+ XtimeE[203] = _XtimeE[203]\r
+ Sbox[204] = _Sbox[204]\r
+ InvSbox[204] = _InvSbox[204]\r
+ Xtime2Sbox[204] = _Xtime2Sbox[204]\r
+ Xtime3Sbox[204] = _Xtime3Sbox[204]\r
+ Xtime2[204] = _Xtime2[204]\r
+ Xtime9[204] = _Xtime9[204]\r
+ XtimeB[204] = _XtimeB[204]\r
+ XtimeD[204] = _XtimeD[204]\r
+ XtimeE[204] = _XtimeE[204]\r
+ Sbox[205] = _Sbox[205]\r
+ InvSbox[205] = _InvSbox[205]\r
+ Xtime2Sbox[205] = _Xtime2Sbox[205]\r
+ Xtime3Sbox[205] = _Xtime3Sbox[205]\r
+ Xtime2[205] = _Xtime2[205]\r
+ Xtime9[205] = _Xtime9[205]\r
+ XtimeB[205] = _XtimeB[205]\r
+ XtimeD[205] = _XtimeD[205]\r
+ XtimeE[205] = _XtimeE[205]\r
+ Sbox[206] = _Sbox[206]\r
+ InvSbox[206] = _InvSbox[206]\r
+ Xtime2Sbox[206] = _Xtime2Sbox[206]\r
+ Xtime3Sbox[206] = _Xtime3Sbox[206]\r
+ Xtime2[206] = _Xtime2[206]\r
+ Xtime9[206] = _Xtime9[206]\r
+ XtimeB[206] = _XtimeB[206]\r
+ XtimeD[206] = _XtimeD[206]\r
+ XtimeE[206] = _XtimeE[206]\r
+ Sbox[207] = _Sbox[207]\r
+ InvSbox[207] = _InvSbox[207]\r
+ Xtime2Sbox[207] = _Xtime2Sbox[207]\r
+ Xtime3Sbox[207] = _Xtime3Sbox[207]\r
+ Xtime2[207] = _Xtime2[207]\r
+ Xtime9[207] = _Xtime9[207]\r
+ XtimeB[207] = _XtimeB[207]\r
+ XtimeD[207] = _XtimeD[207]\r
+ XtimeE[207] = _XtimeE[207]\r
+ Sbox[208] = _Sbox[208]\r
+ InvSbox[208] = _InvSbox[208]\r
+ Xtime2Sbox[208] = _Xtime2Sbox[208]\r
+ Xtime3Sbox[208] = _Xtime3Sbox[208]\r
+ Xtime2[208] = _Xtime2[208]\r
+ Xtime9[208] = _Xtime9[208]\r
+ XtimeB[208] = _XtimeB[208]\r
+ XtimeD[208] = _XtimeD[208]\r
+ XtimeE[208] = _XtimeE[208]\r
+ Sbox[209] = _Sbox[209]\r
+ InvSbox[209] = _InvSbox[209]\r
+ Xtime2Sbox[209] = _Xtime2Sbox[209]\r
+ Xtime3Sbox[209] = _Xtime3Sbox[209]\r
+ Xtime2[209] = _Xtime2[209]\r
+ Xtime9[209] = _Xtime9[209]\r
+ XtimeB[209] = _XtimeB[209]\r
+ XtimeD[209] = _XtimeD[209]\r
+ XtimeE[209] = _XtimeE[209]\r
+ Sbox[210] = _Sbox[210]\r
+ InvSbox[210] = _InvSbox[210]\r
+ Xtime2Sbox[210] = _Xtime2Sbox[210]\r
+ Xtime3Sbox[210] = _Xtime3Sbox[210]\r
+ Xtime2[210] = _Xtime2[210]\r
+ Xtime9[210] = _Xtime9[210]\r
+ XtimeB[210] = _XtimeB[210]\r
+ XtimeD[210] = _XtimeD[210]\r
+ XtimeE[210] = _XtimeE[210]\r
+ Sbox[211] = _Sbox[211]\r
+ InvSbox[211] = _InvSbox[211]\r
+ Xtime2Sbox[211] = _Xtime2Sbox[211]\r
+ Xtime3Sbox[211] = _Xtime3Sbox[211]\r
+ Xtime2[211] = _Xtime2[211]\r
+ Xtime9[211] = _Xtime9[211]\r
+ XtimeB[211] = _XtimeB[211]\r
+ XtimeD[211] = _XtimeD[211]\r
+ XtimeE[211] = _XtimeE[211]\r
+ Sbox[212] = _Sbox[212]\r
+ InvSbox[212] = _InvSbox[212]\r
+ Xtime2Sbox[212] = _Xtime2Sbox[212]\r
+ Xtime3Sbox[212] = _Xtime3Sbox[212]\r
+ Xtime2[212] = _Xtime2[212]\r
+ Xtime9[212] = _Xtime9[212]\r
+ XtimeB[212] = _XtimeB[212]\r
+ XtimeD[212] = _XtimeD[212]\r
+ XtimeE[212] = _XtimeE[212]\r
+ Sbox[213] = _Sbox[213]\r
+ InvSbox[213] = _InvSbox[213]\r
+ Xtime2Sbox[213] = _Xtime2Sbox[213]\r
+ Xtime3Sbox[213] = _Xtime3Sbox[213]\r
+ Xtime2[213] = _Xtime2[213]\r
+ Xtime9[213] = _Xtime9[213]\r
+ XtimeB[213] = _XtimeB[213]\r
+ XtimeD[213] = _XtimeD[213]\r
+ XtimeE[213] = _XtimeE[213]\r
+ Sbox[214] = _Sbox[214]\r
+ InvSbox[214] = _InvSbox[214]\r
+ Xtime2Sbox[214] = _Xtime2Sbox[214]\r
+ Xtime3Sbox[214] = _Xtime3Sbox[214]\r
+ Xtime2[214] = _Xtime2[214]\r
+ Xtime9[214] = _Xtime9[214]\r
+ XtimeB[214] = _XtimeB[214]\r
+ XtimeD[214] = _XtimeD[214]\r
+ XtimeE[214] = _XtimeE[214]\r
+ Sbox[215] = _Sbox[215]\r
+ InvSbox[215] = _InvSbox[215]\r
+ Xtime2Sbox[215] = _Xtime2Sbox[215]\r
+ Xtime3Sbox[215] = _Xtime3Sbox[215]\r
+ Xtime2[215] = _Xtime2[215]\r
+ Xtime9[215] = _Xtime9[215]\r
+ XtimeB[215] = _XtimeB[215]\r
+ XtimeD[215] = _XtimeD[215]\r
+ XtimeE[215] = _XtimeE[215]\r
+ Sbox[216] = _Sbox[216]\r
+ InvSbox[216] = _InvSbox[216]\r
+ Xtime2Sbox[216] = _Xtime2Sbox[216]\r
+ Xtime3Sbox[216] = _Xtime3Sbox[216]\r
+ Xtime2[216] = _Xtime2[216]\r
+ Xtime9[216] = _Xtime9[216]\r
+ XtimeB[216] = _XtimeB[216]\r
+ XtimeD[216] = _XtimeD[216]\r
+ XtimeE[216] = _XtimeE[216]\r
+ Sbox[217] = _Sbox[217]\r
+ InvSbox[217] = _InvSbox[217]\r
+ Xtime2Sbox[217] = _Xtime2Sbox[217]\r
+ Xtime3Sbox[217] = _Xtime3Sbox[217]\r
+ Xtime2[217] = _Xtime2[217]\r
+ Xtime9[217] = _Xtime9[217]\r
+ XtimeB[217] = _XtimeB[217]\r
+ XtimeD[217] = _XtimeD[217]\r
+ XtimeE[217] = _XtimeE[217]\r
+ Sbox[218] = _Sbox[218]\r
+ InvSbox[218] = _InvSbox[218]\r
+ Xtime2Sbox[218] = _Xtime2Sbox[218]\r
+ Xtime3Sbox[218] = _Xtime3Sbox[218]\r
+ Xtime2[218] = _Xtime2[218]\r
+ Xtime9[218] = _Xtime9[218]\r
+ XtimeB[218] = _XtimeB[218]\r
+ XtimeD[218] = _XtimeD[218]\r
+ XtimeE[218] = _XtimeE[218]\r
+ Sbox[219] = _Sbox[219]\r
+ InvSbox[219] = _InvSbox[219]\r
+ Xtime2Sbox[219] = _Xtime2Sbox[219]\r
+ Xtime3Sbox[219] = _Xtime3Sbox[219]\r
+ Xtime2[219] = _Xtime2[219]\r
+ Xtime9[219] = _Xtime9[219]\r
+ XtimeB[219] = _XtimeB[219]\r
+ XtimeD[219] = _XtimeD[219]\r
+ XtimeE[219] = _XtimeE[219]\r
+ Sbox[220] = _Sbox[220]\r
+ InvSbox[220] = _InvSbox[220]\r
+ Xtime2Sbox[220] = _Xtime2Sbox[220]\r
+ Xtime3Sbox[220] = _Xtime3Sbox[220]\r
+ Xtime2[220] = _Xtime2[220]\r
+ Xtime9[220] = _Xtime9[220]\r
+ XtimeB[220] = _XtimeB[220]\r
+ XtimeD[220] = _XtimeD[220]\r
+ XtimeE[220] = _XtimeE[220]\r
+ Sbox[221] = _Sbox[221]\r
+ InvSbox[221] = _InvSbox[221]\r
+ Xtime2Sbox[221] = _Xtime2Sbox[221]\r
+ Xtime3Sbox[221] = _Xtime3Sbox[221]\r
+ Xtime2[221] = _Xtime2[221]\r
+ Xtime9[221] = _Xtime9[221]\r
+ XtimeB[221] = _XtimeB[221]\r
+ XtimeD[221] = _XtimeD[221]\r
+ XtimeE[221] = _XtimeE[221]\r
+ Sbox[222] = _Sbox[222]\r
+ InvSbox[222] = _InvSbox[222]\r
+ Xtime2Sbox[222] = _Xtime2Sbox[222]\r
+ Xtime3Sbox[222] = _Xtime3Sbox[222]\r
+ Xtime2[222] = _Xtime2[222]\r
+ Xtime9[222] = _Xtime9[222]\r
+ XtimeB[222] = _XtimeB[222]\r
+ XtimeD[222] = _XtimeD[222]\r
+ XtimeE[222] = _XtimeE[222]\r
+ Sbox[223] = _Sbox[223]\r
+ InvSbox[223] = _InvSbox[223]\r
+ Xtime2Sbox[223] = _Xtime2Sbox[223]\r
+ Xtime3Sbox[223] = _Xtime3Sbox[223]\r
+ Xtime2[223] = _Xtime2[223]\r
+ Xtime9[223] = _Xtime9[223]\r
+ XtimeB[223] = _XtimeB[223]\r
+ XtimeD[223] = _XtimeD[223]\r
+ XtimeE[223] = _XtimeE[223]\r
+ Sbox[224] = _Sbox[224]\r
+ InvSbox[224] = _InvSbox[224]\r
+ Xtime2Sbox[224] = _Xtime2Sbox[224]\r
+ Xtime3Sbox[224] = _Xtime3Sbox[224]\r
+ Xtime2[224] = _Xtime2[224]\r
+ Xtime9[224] = _Xtime9[224]\r
+ XtimeB[224] = _XtimeB[224]\r
+ XtimeD[224] = _XtimeD[224]\r
+ XtimeE[224] = _XtimeE[224]\r
+ Sbox[225] = _Sbox[225]\r
+ InvSbox[225] = _InvSbox[225]\r
+ Xtime2Sbox[225] = _Xtime2Sbox[225]\r
+ Xtime3Sbox[225] = _Xtime3Sbox[225]\r
+ Xtime2[225] = _Xtime2[225]\r
+ Xtime9[225] = _Xtime9[225]\r
+ XtimeB[225] = _XtimeB[225]\r
+ XtimeD[225] = _XtimeD[225]\r
+ XtimeE[225] = _XtimeE[225]\r
+ Sbox[226] = _Sbox[226]\r
+ InvSbox[226] = _InvSbox[226]\r
+ Xtime2Sbox[226] = _Xtime2Sbox[226]\r
+ Xtime3Sbox[226] = _Xtime3Sbox[226]\r
+ Xtime2[226] = _Xtime2[226]\r
+ Xtime9[226] = _Xtime9[226]\r
+ XtimeB[226] = _XtimeB[226]\r
+ XtimeD[226] = _XtimeD[226]\r
+ XtimeE[226] = _XtimeE[226]\r
+ Sbox[227] = _Sbox[227]\r
+ InvSbox[227] = _InvSbox[227]\r
+ Xtime2Sbox[227] = _Xtime2Sbox[227]\r
+ Xtime3Sbox[227] = _Xtime3Sbox[227]\r
+ Xtime2[227] = _Xtime2[227]\r
+ Xtime9[227] = _Xtime9[227]\r
+ XtimeB[227] = _XtimeB[227]\r
+ XtimeD[227] = _XtimeD[227]\r
+ XtimeE[227] = _XtimeE[227]\r
+ Sbox[228] = _Sbox[228]\r
+ InvSbox[228] = _InvSbox[228]\r
+ Xtime2Sbox[228] = _Xtime2Sbox[228]\r
+ Xtime3Sbox[228] = _Xtime3Sbox[228]\r
+ Xtime2[228] = _Xtime2[228]\r
+ Xtime9[228] = _Xtime9[228]\r
+ XtimeB[228] = _XtimeB[228]\r
+ XtimeD[228] = _XtimeD[228]\r
+ XtimeE[228] = _XtimeE[228]\r
+ Sbox[229] = _Sbox[229]\r
+ InvSbox[229] = _InvSbox[229]\r
+ Xtime2Sbox[229] = _Xtime2Sbox[229]\r
+ Xtime3Sbox[229] = _Xtime3Sbox[229]\r
+ Xtime2[229] = _Xtime2[229]\r
+ Xtime9[229] = _Xtime9[229]\r
+ XtimeB[229] = _XtimeB[229]\r
+ XtimeD[229] = _XtimeD[229]\r
+ XtimeE[229] = _XtimeE[229]\r
+ Sbox[230] = _Sbox[230]\r
+ InvSbox[230] = _InvSbox[230]\r
+ Xtime2Sbox[230] = _Xtime2Sbox[230]\r
+ Xtime3Sbox[230] = _Xtime3Sbox[230]\r
+ Xtime2[230] = _Xtime2[230]\r
+ Xtime9[230] = _Xtime9[230]\r
+ XtimeB[230] = _XtimeB[230]\r
+ XtimeD[230] = _XtimeD[230]\r
+ XtimeE[230] = _XtimeE[230]\r
+ Sbox[231] = _Sbox[231]\r
+ InvSbox[231] = _InvSbox[231]\r
+ Xtime2Sbox[231] = _Xtime2Sbox[231]\r
+ Xtime3Sbox[231] = _Xtime3Sbox[231]\r
+ Xtime2[231] = _Xtime2[231]\r
+ Xtime9[231] = _Xtime9[231]\r
+ XtimeB[231] = _XtimeB[231]\r
+ XtimeD[231] = _XtimeD[231]\r
+ XtimeE[231] = _XtimeE[231]\r
+ Sbox[232] = _Sbox[232]\r
+ InvSbox[232] = _InvSbox[232]\r
+ Xtime2Sbox[232] = _Xtime2Sbox[232]\r
+ Xtime3Sbox[232] = _Xtime3Sbox[232]\r
+ Xtime2[232] = _Xtime2[232]\r
+ Xtime9[232] = _Xtime9[232]\r
+ XtimeB[232] = _XtimeB[232]\r
+ XtimeD[232] = _XtimeD[232]\r
+ XtimeE[232] = _XtimeE[232]\r
+ Sbox[233] = _Sbox[233]\r
+ InvSbox[233] = _InvSbox[233]\r
+ Xtime2Sbox[233] = _Xtime2Sbox[233]\r
+ Xtime3Sbox[233] = _Xtime3Sbox[233]\r
+ Xtime2[233] = _Xtime2[233]\r
+ Xtime9[233] = _Xtime9[233]\r
+ XtimeB[233] = _XtimeB[233]\r
+ XtimeD[233] = _XtimeD[233]\r
+ XtimeE[233] = _XtimeE[233]\r
+ Sbox[234] = _Sbox[234]\r
+ InvSbox[234] = _InvSbox[234]\r
+ Xtime2Sbox[234] = _Xtime2Sbox[234]\r
+ Xtime3Sbox[234] = _Xtime3Sbox[234]\r
+ Xtime2[234] = _Xtime2[234]\r
+ Xtime9[234] = _Xtime9[234]\r
+ XtimeB[234] = _XtimeB[234]\r
+ XtimeD[234] = _XtimeD[234]\r
+ XtimeE[234] = _XtimeE[234]\r
+ Sbox[235] = _Sbox[235]\r
+ InvSbox[235] = _InvSbox[235]\r
+ Xtime2Sbox[235] = _Xtime2Sbox[235]\r
+ Xtime3Sbox[235] = _Xtime3Sbox[235]\r
+ Xtime2[235] = _Xtime2[235]\r
+ Xtime9[235] = _Xtime9[235]\r
+ XtimeB[235] = _XtimeB[235]\r
+ XtimeD[235] = _XtimeD[235]\r
+ XtimeE[235] = _XtimeE[235]\r
+ Sbox[236] = _Sbox[236]\r
+ InvSbox[236] = _InvSbox[236]\r
+ Xtime2Sbox[236] = _Xtime2Sbox[236]\r
+ Xtime3Sbox[236] = _Xtime3Sbox[236]\r
+ Xtime2[236] = _Xtime2[236]\r
+ Xtime9[236] = _Xtime9[236]\r
+ XtimeB[236] = _XtimeB[236]\r
+ XtimeD[236] = _XtimeD[236]\r
+ XtimeE[236] = _XtimeE[236]\r
+ Sbox[237] = _Sbox[237]\r
+ InvSbox[237] = _InvSbox[237]\r
+ Xtime2Sbox[237] = _Xtime2Sbox[237]\r
+ Xtime3Sbox[237] = _Xtime3Sbox[237]\r
+ Xtime2[237] = _Xtime2[237]\r
+ Xtime9[237] = _Xtime9[237]\r
+ XtimeB[237] = _XtimeB[237]\r
+ XtimeD[237] = _XtimeD[237]\r
+ XtimeE[237] = _XtimeE[237]\r
+ Sbox[238] = _Sbox[238]\r
+ InvSbox[238] = _InvSbox[238]\r
+ Xtime2Sbox[238] = _Xtime2Sbox[238]\r
+ Xtime3Sbox[238] = _Xtime3Sbox[238]\r
+ Xtime2[238] = _Xtime2[238]\r
+ Xtime9[238] = _Xtime9[238]\r
+ XtimeB[238] = _XtimeB[238]\r
+ XtimeD[238] = _XtimeD[238]\r
+ XtimeE[238] = _XtimeE[238]\r
+ Sbox[239] = _Sbox[239]\r
+ InvSbox[239] = _InvSbox[239]\r
+ Xtime2Sbox[239] = _Xtime2Sbox[239]\r
+ Xtime3Sbox[239] = _Xtime3Sbox[239]\r
+ Xtime2[239] = _Xtime2[239]\r
+ Xtime9[239] = _Xtime9[239]\r
+ XtimeB[239] = _XtimeB[239]\r
+ XtimeD[239] = _XtimeD[239]\r
+ XtimeE[239] = _XtimeE[239]\r
+ Sbox[240] = _Sbox[240]\r
+ InvSbox[240] = _InvSbox[240]\r
+ Xtime2Sbox[240] = _Xtime2Sbox[240]\r
+ Xtime3Sbox[240] = _Xtime3Sbox[240]\r
+ Xtime2[240] = _Xtime2[240]\r
+ Xtime9[240] = _Xtime9[240]\r
+ XtimeB[240] = _XtimeB[240]\r
+ XtimeD[240] = _XtimeD[240]\r
+ XtimeE[240] = _XtimeE[240]\r
+ Sbox[241] = _Sbox[241]\r
+ InvSbox[241] = _InvSbox[241]\r
+ Xtime2Sbox[241] = _Xtime2Sbox[241]\r
+ Xtime3Sbox[241] = _Xtime3Sbox[241]\r
+ Xtime2[241] = _Xtime2[241]\r
+ Xtime9[241] = _Xtime9[241]\r
+ XtimeB[241] = _XtimeB[241]\r
+ XtimeD[241] = _XtimeD[241]\r
+ XtimeE[241] = _XtimeE[241]\r
+ Sbox[242] = _Sbox[242]\r
+ InvSbox[242] = _InvSbox[242]\r
+ Xtime2Sbox[242] = _Xtime2Sbox[242]\r
+ Xtime3Sbox[242] = _Xtime3Sbox[242]\r
+ Xtime2[242] = _Xtime2[242]\r
+ Xtime9[242] = _Xtime9[242]\r
+ XtimeB[242] = _XtimeB[242]\r
+ XtimeD[242] = _XtimeD[242]\r
+ XtimeE[242] = _XtimeE[242]\r
+ Sbox[243] = _Sbox[243]\r
+ InvSbox[243] = _InvSbox[243]\r
+ Xtime2Sbox[243] = _Xtime2Sbox[243]\r
+ Xtime3Sbox[243] = _Xtime3Sbox[243]\r
+ Xtime2[243] = _Xtime2[243]\r
+ Xtime9[243] = _Xtime9[243]\r
+ XtimeB[243] = _XtimeB[243]\r
+ XtimeD[243] = _XtimeD[243]\r
+ XtimeE[243] = _XtimeE[243]\r
+ Sbox[244] = _Sbox[244]\r
+ InvSbox[244] = _InvSbox[244]\r
+ Xtime2Sbox[244] = _Xtime2Sbox[244]\r
+ Xtime3Sbox[244] = _Xtime3Sbox[244]\r
+ Xtime2[244] = _Xtime2[244]\r
+ Xtime9[244] = _Xtime9[244]\r
+ XtimeB[244] = _XtimeB[244]\r
+ XtimeD[244] = _XtimeD[244]\r
+ XtimeE[244] = _XtimeE[244]\r
+ Sbox[245] = _Sbox[245]\r
+ InvSbox[245] = _InvSbox[245]\r
+ Xtime2Sbox[245] = _Xtime2Sbox[245]\r
+ Xtime3Sbox[245] = _Xtime3Sbox[245]\r
+ Xtime2[245] = _Xtime2[245]\r
+ Xtime9[245] = _Xtime9[245]\r
+ XtimeB[245] = _XtimeB[245]\r
+ XtimeD[245] = _XtimeD[245]\r
+ XtimeE[245] = _XtimeE[245]\r
+ Sbox[246] = _Sbox[246]\r
+ InvSbox[246] = _InvSbox[246]\r
+ Xtime2Sbox[246] = _Xtime2Sbox[246]\r
+ Xtime3Sbox[246] = _Xtime3Sbox[246]\r
+ Xtime2[246] = _Xtime2[246]\r
+ Xtime9[246] = _Xtime9[246]\r
+ XtimeB[246] = _XtimeB[246]\r
+ XtimeD[246] = _XtimeD[246]\r
+ XtimeE[246] = _XtimeE[246]\r
+ Sbox[247] = _Sbox[247]\r
+ InvSbox[247] = _InvSbox[247]\r
+ Xtime2Sbox[247] = _Xtime2Sbox[247]\r
+ Xtime3Sbox[247] = _Xtime3Sbox[247]\r
+ Xtime2[247] = _Xtime2[247]\r
+ Xtime9[247] = _Xtime9[247]\r
+ XtimeB[247] = _XtimeB[247]\r
+ XtimeD[247] = _XtimeD[247]\r
+ XtimeE[247] = _XtimeE[247]\r
+ Sbox[248] = _Sbox[248]\r
+ InvSbox[248] = _InvSbox[248]\r
+ Xtime2Sbox[248] = _Xtime2Sbox[248]\r
+ Xtime3Sbox[248] = _Xtime3Sbox[248]\r
+ Xtime2[248] = _Xtime2[248]\r
+ Xtime9[248] = _Xtime9[248]\r
+ XtimeB[248] = _XtimeB[248]\r
+ XtimeD[248] = _XtimeD[248]\r
+ XtimeE[248] = _XtimeE[248]\r
+ Sbox[249] = _Sbox[249]\r
+ InvSbox[249] = _InvSbox[249]\r
+ Xtime2Sbox[249] = _Xtime2Sbox[249]\r
+ Xtime3Sbox[249] = _Xtime3Sbox[249]\r
+ Xtime2[249] = _Xtime2[249]\r
+ Xtime9[249] = _Xtime9[249]\r
+ XtimeB[249] = _XtimeB[249]\r
+ XtimeD[249] = _XtimeD[249]\r
+ XtimeE[249] = _XtimeE[249]\r
+ Sbox[250] = _Sbox[250]\r
+ InvSbox[250] = _InvSbox[250]\r
+ Xtime2Sbox[250] = _Xtime2Sbox[250]\r
+ Xtime3Sbox[250] = _Xtime3Sbox[250]\r
+ Xtime2[250] = _Xtime2[250]\r
+ Xtime9[250] = _Xtime9[250]\r
+ XtimeB[250] = _XtimeB[250]\r
+ XtimeD[250] = _XtimeD[250]\r
+ XtimeE[250] = _XtimeE[250]\r
+ Sbox[251] = _Sbox[251]\r
+ InvSbox[251] = _InvSbox[251]\r
+ Xtime2Sbox[251] = _Xtime2Sbox[251]\r
+ Xtime3Sbox[251] = _Xtime3Sbox[251]\r
+ Xtime2[251] = _Xtime2[251]\r
+ Xtime9[251] = _Xtime9[251]\r
+ XtimeB[251] = _XtimeB[251]\r
+ XtimeD[251] = _XtimeD[251]\r
+ XtimeE[251] = _XtimeE[251]\r
+ Sbox[252] = _Sbox[252]\r
+ InvSbox[252] = _InvSbox[252]\r
+ Xtime2Sbox[252] = _Xtime2Sbox[252]\r
+ Xtime3Sbox[252] = _Xtime3Sbox[252]\r
+ Xtime2[252] = _Xtime2[252]\r
+ Xtime9[252] = _Xtime9[252]\r
+ XtimeB[252] = _XtimeB[252]\r
+ XtimeD[252] = _XtimeD[252]\r
+ XtimeE[252] = _XtimeE[252]\r
+ Sbox[253] = _Sbox[253]\r
+ InvSbox[253] = _InvSbox[253]\r
+ Xtime2Sbox[253] = _Xtime2Sbox[253]\r
+ Xtime3Sbox[253] = _Xtime3Sbox[253]\r
+ Xtime2[253] = _Xtime2[253]\r
+ Xtime9[253] = _Xtime9[253]\r
+ XtimeB[253] = _XtimeB[253]\r
+ XtimeD[253] = _XtimeD[253]\r
+ XtimeE[253] = _XtimeE[253]\r
+ Sbox[254] = _Sbox[254]\r
+ InvSbox[254] = _InvSbox[254]\r
+ Xtime2Sbox[254] = _Xtime2Sbox[254]\r
+ Xtime3Sbox[254] = _Xtime3Sbox[254]\r
+ Xtime2[254] = _Xtime2[254]\r
+ Xtime9[254] = _Xtime9[254]\r
+ XtimeB[254] = _XtimeB[254]\r
+ XtimeD[254] = _XtimeD[254]\r
+ XtimeE[254] = _XtimeE[254]\r
+ Sbox[255] = _Sbox[255]\r
+ InvSbox[255] = _InvSbox[255]\r
+ Xtime2Sbox[255] = _Xtime2Sbox[255]\r
+ Xtime3Sbox[255] = _Xtime3Sbox[255]\r
+ Xtime2[255] = _Xtime2[255]\r
+ Xtime9[255] = _Xtime9[255]\r
+ XtimeB[255] = _XtimeB[255]\r
+ XtimeD[255] = _XtimeD[255]\r
+ XtimeE[255] = _XtimeE[255]\r
+ Rcon = new ByteArray;\r
+ /*\r
+ for (i=0;i<_Rcon.length;i++) {\r
+ Rcon[i] = _Rcon[i];\r
+ }\r
+ */\r
+ Rcon[0] = _Rcon[0];\r
+ Rcon[1] = _Rcon[1];\r
+ Rcon[2] = _Rcon[2];\r
+ Rcon[3] = _Rcon[3];\r
+ Rcon[4] = _Rcon[4];\r
+ Rcon[5] = _Rcon[5];\r
+ Rcon[6] = _Rcon[6];\r
+ Rcon[7] = _Rcon[7];\r
+ Rcon[8] = _Rcon[8];\r
+ Rcon[9] = _Rcon[9];\r
+ Rcon[10] = _Rcon[10];\r
+ Rcon[11] = _Rcon[11];\r
+ }\r
+ \r
+ private var key:ByteArray;\r
+ private var keyLength:uint;\r
+ private var Nr:uint;\r
+ private var state:ByteArray;\r
+ private var tmp:ByteArray;\r
+\r
+ public function AESKey(key:ByteArray) {\r
+ tmp = new ByteArray;\r
+ state = new ByteArray;\r
+ keyLength = key.length;\r
+ this.key = new ByteArray;\r
+ this.key.writeBytes(key);\r
+ expandKey();\r
+ }\r
+ \r
+ // produce Nb bytes for each round\r
+ private function expandKey():void {\r
+ var tmp0:uint, tmp1:uint, tmp2:uint, tmp3:uint, tmp4:uint;\r
+ var idx:uint;\r
+ var Nk:uint = key.length/4;\r
+ Nr = Nk+6;\r
+ \r
+ for( idx = Nk; idx < Nb * (Nr + 1); idx++ ) {\r
+ tmp0 = key[4*idx - 4];\r
+ tmp1 = key[4*idx - 3];\r
+ tmp2 = key[4*idx - 2];\r
+ tmp3 = key[4*idx - 1];\r
+ if( !(idx % Nk) ) {\r
+ tmp4 = tmp3;\r
+ tmp3 = Sbox[tmp0];\r
+ tmp0 = Sbox[tmp1] ^ Rcon[idx/Nk];\r
+ tmp1 = Sbox[tmp2];\r
+ tmp2 = Sbox[tmp4];\r
+ } else if( Nk > 6 && idx % Nk == 4 ) {\r
+ tmp0 = Sbox[tmp0];\r
+ tmp1 = Sbox[tmp1];\r
+ tmp2 = Sbox[tmp2];\r
+ tmp3 = Sbox[tmp3];\r
+ }\r
+ \r
+ key[4*idx+0] = key[4*idx - 4*Nk + 0] ^ tmp0;\r
+ key[4*idx+1] = key[4*idx - 4*Nk + 1] ^ tmp1;\r
+ key[4*idx+2] = key[4*idx - 4*Nk + 2] ^ tmp2;\r
+ key[4*idx+3] = key[4*idx - 4*Nk + 3] ^ tmp3;\r
+ }\r
+ }\r
+\r
+\r
+ public function getBlockSize():uint\r
+ {\r
+ return 16;\r
+ }\r
+ \r
+ // encrypt one 128 bit block\r
+ public function encrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ var round:uint;\r
+ state.position=0;\r
+ state.writeBytes(block, index, Nb*4);\r
+\r
+ addRoundKey(key, 0);\r
+ for ( round = 1; round < Nr + 1; round++ ) {\r
+ if (round < Nr) {\r
+ mixSubColumns();\r
+ } else {\r
+ shiftRows();\r
+ }\r
+ addRoundKey(key, round * Nb * 4);\r
+ }\r
+\r
+ block.position=index;\r
+ block.writeBytes(state);\r
+ }\r
+ \r
+ public function decrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ var round:uint;\r
+ state.position=0;\r
+ state.writeBytes(block, index, Nb*4);\r
+\r
+ addRoundKey(key, Nr*Nb*4);\r
+ invShiftRows();\r
+ for( round = Nr; round--; )\r
+ {\r
+ addRoundKey( key, round*Nb*4);\r
+ if (round) {\r
+ invMixSubColumns();\r
+ }\r
+ }\r
+ \r
+ block.position=index;\r
+ block.writeBytes(state);\r
+ }\r
+ \r
+ public function dispose():void {\r
+ var i:uint;\r
+ var r:Random = new Random;\r
+ for (i=0;i<key.length;i++) {\r
+ key[i] = r.nextByte();\r
+ }\r
+ Nr = r.nextByte();\r
+ for (i=0;i<state.length;i++) {\r
+ state[i] = r.nextByte();\r
+ }\r
+ for (i=0;i<tmp.length;i++) {\r
+ tmp[i] = r.nextByte();\r
+ }\r
+ key.length=0;\r
+ keyLength=0;\r
+ state.length=0;\r
+ tmp.length=0;\r
+ key = null;\r
+ state = null;\r
+ tmp = null;\r
+ Nr = 0;\r
+ Memory.gc();\r
+ }\r
+\r
+ // exchanges columns in each of 4 rows\r
+ // row0 - unchanged, row1- shifted left 1, \r
+ // row2 - shifted left 2 and row3 - shifted left 3\r
+ protected function shiftRows():void\r
+ {\r
+ var tmp:uint;\r
+ \r
+ // just substitute row 0\r
+ state[0] = Sbox[state[0]]; state[4] = Sbox[state[4]];\r
+ state[8] = Sbox[state[8]]; state[12] = Sbox[state[12]];\r
+ \r
+ // rotate row 1\r
+ tmp = Sbox[state[1]]; state[1] = Sbox[state[5]];\r
+ state[5] = Sbox[state[9]]; state[9] = Sbox[state[13]]; state[13] = tmp;\r
+ \r
+ // rotate row 2\r
+ tmp = Sbox[state[2]]; state[2] = Sbox[state[10]]; state[10] = tmp;\r
+ tmp = Sbox[state[6]]; state[6] = Sbox[state[14]]; state[14] = tmp;\r
+ \r
+ // rotate row 3\r
+ tmp = Sbox[state[15]]; state[15] = Sbox[state[11]];\r
+ state[11] = Sbox[state[7]]; state[7] = Sbox[state[3]]; state[3] = tmp;\r
+ }\r
+ \r
+ // restores columns in each of 4 rows\r
+ // row0 - unchanged, row1- shifted right 1, \r
+ // row2 - shifted right 2 and row3 - shifted right 3\r
+ protected function invShiftRows ():void\r
+ {\r
+ var tmp:uint;\r
+ \r
+ // restore row 0\r
+ state[0] = InvSbox[state[0]]; state[4] = InvSbox[state[4]];\r
+ state[8] = InvSbox[state[8]]; state[12] = InvSbox[state[12]];\r
+ \r
+ // restore row 1\r
+ tmp = InvSbox[state[13]]; state[13] = InvSbox[state[9]];\r
+ state[9] = InvSbox[state[5]]; state[5] = InvSbox[state[1]]; state[1] = tmp;\r
+ \r
+ // restore row 2\r
+ tmp = InvSbox[state[2]]; state[2] = InvSbox[state[10]]; state[10] = tmp;\r
+ tmp = InvSbox[state[6]]; state[6] = InvSbox[state[14]]; state[14] = tmp;\r
+ \r
+ // restore row 3\r
+ tmp = InvSbox[state[3]]; state[3] = InvSbox[state[7]];\r
+ state[7] = InvSbox[state[11]]; state[11] = InvSbox[state[15]]; state[15] = tmp;\r
+ }\r
+ \r
+ // recombine and mix each row in a column\r
+ protected function mixSubColumns ():void\r
+ {\r
+ tmp.length=0;\r
+ \r
+ // mixing column 0\r
+ tmp[0] = Xtime2Sbox[state[0]] ^ Xtime3Sbox[state[5]] ^ Sbox[state[10]] ^ Sbox[state[15]];\r
+ tmp[1] = Sbox[state[0]] ^ Xtime2Sbox[state[5]] ^ Xtime3Sbox[state[10]] ^ Sbox[state[15]];\r
+ tmp[2] = Sbox[state[0]] ^ Sbox[state[5]] ^ Xtime2Sbox[state[10]] ^ Xtime3Sbox[state[15]];\r
+ tmp[3] = Xtime3Sbox[state[0]] ^ Sbox[state[5]] ^ Sbox[state[10]] ^ Xtime2Sbox[state[15]];\r
+ \r
+ // mixing column 1\r
+ tmp[4] = Xtime2Sbox[state[4]] ^ Xtime3Sbox[state[9]] ^ Sbox[state[14]] ^ Sbox[state[3]];\r
+ tmp[5] = Sbox[state[4]] ^ Xtime2Sbox[state[9]] ^ Xtime3Sbox[state[14]] ^ Sbox[state[3]];\r
+ tmp[6] = Sbox[state[4]] ^ Sbox[state[9]] ^ Xtime2Sbox[state[14]] ^ Xtime3Sbox[state[3]];\r
+ tmp[7] = Xtime3Sbox[state[4]] ^ Sbox[state[9]] ^ Sbox[state[14]] ^ Xtime2Sbox[state[3]];\r
+ \r
+ // mixing column 2\r
+ tmp[8] = Xtime2Sbox[state[8]] ^ Xtime3Sbox[state[13]] ^ Sbox[state[2]] ^ Sbox[state[7]];\r
+ tmp[9] = Sbox[state[8]] ^ Xtime2Sbox[state[13]] ^ Xtime3Sbox[state[2]] ^ Sbox[state[7]];\r
+ tmp[10] = Sbox[state[8]] ^ Sbox[state[13]] ^ Xtime2Sbox[state[2]] ^ Xtime3Sbox[state[7]];\r
+ tmp[11] = Xtime3Sbox[state[8]] ^ Sbox[state[13]] ^ Sbox[state[2]] ^ Xtime2Sbox[state[7]];\r
+ \r
+ // mixing column 3\r
+ tmp[12] = Xtime2Sbox[state[12]] ^ Xtime3Sbox[state[1]] ^ Sbox[state[6]] ^ Sbox[state[11]];\r
+ tmp[13] = Sbox[state[12]] ^ Xtime2Sbox[state[1]] ^ Xtime3Sbox[state[6]] ^ Sbox[state[11]];\r
+ tmp[14] = Sbox[state[12]] ^ Sbox[state[1]] ^ Xtime2Sbox[state[6]] ^ Xtime3Sbox[state[11]];\r
+ tmp[15] = Xtime3Sbox[state[12]] ^ Sbox[state[1]] ^ Sbox[state[6]] ^ Xtime2Sbox[state[11]];\r
+ \r
+ state.position=0;\r
+ state.writeBytes(tmp, 0, Nb*4);\r
+ }\r
+ \r
+ // restore and un-mix each row in a column\r
+ protected function invMixSubColumns ():void\r
+ {\r
+ tmp.length=0;\r
+ var i:uint;\r
+ \r
+ // restore column 0\r
+ tmp[0] = XtimeE[state[0]] ^ XtimeB[state[1]] ^ XtimeD[state[2]] ^ Xtime9[state[3]];\r
+ tmp[5] = Xtime9[state[0]] ^ XtimeE[state[1]] ^ XtimeB[state[2]] ^ XtimeD[state[3]];\r
+ tmp[10] = XtimeD[state[0]] ^ Xtime9[state[1]] ^ XtimeE[state[2]] ^ XtimeB[state[3]];\r
+ tmp[15] = XtimeB[state[0]] ^ XtimeD[state[1]] ^ Xtime9[state[2]] ^ XtimeE[state[3]];\r
+ \r
+ // restore column 1\r
+ tmp[4] = XtimeE[state[4]] ^ XtimeB[state[5]] ^ XtimeD[state[6]] ^ Xtime9[state[7]];\r
+ tmp[9] = Xtime9[state[4]] ^ XtimeE[state[5]] ^ XtimeB[state[6]] ^ XtimeD[state[7]];\r
+ tmp[14] = XtimeD[state[4]] ^ Xtime9[state[5]] ^ XtimeE[state[6]] ^ XtimeB[state[7]];\r
+ tmp[3] = XtimeB[state[4]] ^ XtimeD[state[5]] ^ Xtime9[state[6]] ^ XtimeE[state[7]];\r
+ \r
+ // restore column 2\r
+ tmp[8] = XtimeE[state[8]] ^ XtimeB[state[9]] ^ XtimeD[state[10]] ^ Xtime9[state[11]];\r
+ tmp[13] = Xtime9[state[8]] ^ XtimeE[state[9]] ^ XtimeB[state[10]] ^ XtimeD[state[11]];\r
+ tmp[2] = XtimeD[state[8]] ^ Xtime9[state[9]] ^ XtimeE[state[10]] ^ XtimeB[state[11]];\r
+ tmp[7] = XtimeB[state[8]] ^ XtimeD[state[9]] ^ Xtime9[state[10]] ^ XtimeE[state[11]];\r
+ \r
+ // restore column 3\r
+ tmp[12] = XtimeE[state[12]] ^ XtimeB[state[13]] ^ XtimeD[state[14]] ^ Xtime9[state[15]];\r
+ tmp[1] = Xtime9[state[12]] ^ XtimeE[state[13]] ^ XtimeB[state[14]] ^ XtimeD[state[15]];\r
+ tmp[6] = XtimeD[state[12]] ^ Xtime9[state[13]] ^ XtimeE[state[14]] ^ XtimeB[state[15]];\r
+ tmp[11] = XtimeB[state[12]] ^ XtimeD[state[13]] ^ Xtime9[state[14]] ^ XtimeE[state[15]];\r
+ \r
+ for( i=0; i < 4 * Nb; i++ )\r
+ state[i] = InvSbox[tmp[i]];\r
+ }\r
+ \r
+ // encrypt/decrypt columns of the key\r
+ protected function addRoundKey (key:ByteArray, offset:uint):void\r
+ {\r
+ var idx:uint;\r
+ \r
+ for( idx = 0; idx < 16; idx++ )\r
+ state[idx] ^= key[idx+offset];\r
+ }\r
+\r
+ public function toString():String {\r
+ return "aes"+(8*keyLength);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * BlowFishKey\r
+ * \r
+ * An Actionscript 3 implementation of the BlowFish encryption algorithm,\r
+ * as documented at http://www.schneier.com/blowfish.html\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * The Bouncy Castle Crypto package, \r
+ * Copyright (c) 2000-2004 The Legion Of The Bouncy Castle\r
+ * (http://www.bouncycastle.org)\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Memory;\r
+\r
+ public class BlowFishKey implements ISymmetricKey\r
+ {\r
+\r
+ private static const KP:Array = [ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,\r
+ 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5,\r
+ 0xB5470917, 0x9216D5D9, 0x8979FB1B ];\r
+\r
+ private static const KS0:Array = [ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947,\r
+ 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658,\r
+ 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918,\r
+ 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,\r
+ 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF,\r
+ 0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C,\r
+ 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60,\r
+ 0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,\r
+ 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2,\r
+ 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176,\r
+ 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F,\r
+ 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,\r
+ 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6,\r
+ 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C,\r
+ 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39,\r
+ 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,\r
+ 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB,\r
+ 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8,\r
+ 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC,\r
+ 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,\r
+ 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB,\r
+ 0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777,\r
+ 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81,\r
+ 0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,\r
+ 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B,\r
+ 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9,\r
+ 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476,\r
+ 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,\r
+ 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A ];\r
+\r
+ private static const KS1:Array = [ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71,\r
+ 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65,\r
+ 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6,\r
+ 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,\r
+ 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A,\r
+ 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC,\r
+ 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1,\r
+ 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,\r
+ 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718,\r
+ 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908,\r
+ 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6,\r
+ 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,\r
+ 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6,\r
+ 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D,\r
+ 0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1,\r
+ 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,\r
+ 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90,\r
+ 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA,\r
+ 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E,\r
+ 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,\r
+ 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF,\r
+ 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA,\r
+ 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A,\r
+ 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,\r
+ 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092,\r
+ 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E,\r
+ 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705,\r
+ 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,\r
+ 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 ];\r
+\r
+ private static const KS2:Array = [ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471,\r
+ 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF,\r
+ 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6,\r
+ 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,\r
+ 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35,\r
+ 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332,\r
+ 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7,\r
+ 0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,\r
+ 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE,\r
+ 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60,\r
+ 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62,\r
+ 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,\r
+ 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60,\r
+ 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3,\r
+ 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF,\r
+ 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,\r
+ 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659,\r
+ 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086,\r
+ 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187,\r
+ 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,\r
+ 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E,\r
+ 0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09,\r
+ 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F,\r
+ 0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,\r
+ 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7,\r
+ 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188,\r
+ 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3,\r
+ 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,\r
+ 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 ];\r
+\r
+ private static const KS3:Array = [ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D,\r
+ 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79,\r
+ 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8,\r
+ 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,\r
+ 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3,\r
+ 0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797,\r
+ 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472,\r
+ 0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,\r
+ 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15,\r
+ 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5,\r
+ 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862,\r
+ 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,\r
+ 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD,\r
+ 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB,\r
+ 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671,\r
+ 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,\r
+ 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1,\r
+ 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A,\r
+ 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF,\r
+ 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,\r
+ 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532,\r
+ 0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E,\r
+ 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5,\r
+ 0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,\r
+ 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD,\r
+ 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3,\r
+ 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0,\r
+ 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,\r
+ 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 ];\r
+\r
+ // ====================================\r
+ // Useful constants\r
+ // ====================================\r
+ \r
+ private static const ROUNDS:uint = 16;\r
+ private static const BLOCK_SIZE:uint = 8; // bytes = 64 bits\r
+ private static const SBOX_SK:uint = 256;\r
+ private static const P_SZ:uint = ROUNDS + 2;\r
+ \r
+ private var S0:Array;\r
+ private var S1:Array;\r
+ private var S2:Array;\r
+ private var S3:Array; // the s-boxes\r
+ private var P:Array; // the p-array\r
+ \r
+ private var key:ByteArray = null;\r
+\r
+ public function BlowFishKey(key:ByteArray) {\r
+ this.key = key;\r
+ setKey(key);\r
+ }\r
+\r
+ public function getBlockSize():uint\r
+ {\r
+ return BLOCK_SIZE;\r
+ }\r
+ \r
+ public function decrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ decryptBlock(block, index, block, index);\r
+ }\r
+ \r
+ public function dispose():void\r
+ {\r
+ var i:uint=0;\r
+ for (i=0;i<S0.length;i++) { S0[i]=0; }\r
+ for (i=0;i<S1.length;i++) { S1[i]=0; }\r
+ for (i=0;i<S2.length;i++) { S2[i]=0; }\r
+ for (i=0;i<S3.length;i++) { S3[i]=0; }\r
+ for (i=0;i<P.length;i++) { P[i]=0; }\r
+ S0 = null;\r
+ S1 = null;\r
+ S2 = null;\r
+ S3 = null;\r
+ P = null;\r
+ for (i=0;i<key.length;i++) {\r
+ key[i]=0;\r
+ }\r
+ key.length = 0;\r
+ key = null;\r
+ Memory.gc();\r
+ }\r
+ \r
+ public function encrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ encryptBlock(block, index, block, index);\r
+ }\r
+\r
+ // ==================================\r
+ // Private Implementation\r
+ // ==================================\r
+ \r
+ private function F(x:uint):uint\r
+ {\r
+ return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff]) ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]);\r
+ }\r
+\r
+ /**\r
+ * apply the encryption cycle to each value pair in the table.\r
+ */\r
+ private function processTable(xl:uint, xr:uint, table:Array):void\r
+ {\r
+ var size:uint = table.length;\r
+ \r
+ for (var s:uint = 0; s < size; s += 2)\r
+ {\r
+ xl ^= P[0];\r
+ \r
+ for (var i:uint = 1; i < ROUNDS; i += 2)\r
+ {\r
+ xr ^= F(xl) ^ P[i];\r
+ xl ^= F(xr) ^ P[i + 1];\r
+ }\r
+ \r
+ xr ^= P[ROUNDS + 1];\r
+ \r
+ table[s] = xr;\r
+ table[s + 1] = xl;\r
+ \r
+ xr = xl; // end of cycle swap\r
+ xl = table[s];\r
+ }\r
+ }\r
+ \r
+ private function setKey(key:ByteArray):void\r
+ {\r
+ /*\r
+ * - comments are from _Applied Crypto_, Schneier, p338 please be\r
+ * careful comparing the two, AC numbers the arrays from 1, the enclosed\r
+ * code from 0.\r
+ * \r
+ * (1) Initialise the S-boxes and the P-array, with a fixed string This\r
+ * string contains the hexadecimal digits of pi (3.141...)\r
+ */\r
+ S0 = KS0.concat();\r
+ S1 = KS1.concat();\r
+ S2 = KS2.concat();\r
+ S3 = KS3.concat();\r
+ P = KP.concat();\r
+ \r
+ /*\r
+ * (2) Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with\r
+ * the second 32-bits of the key, and so on for all bits of the key (up\r
+ * to P[17]). Repeatedly cycle through the key bits until the entire\r
+ * P-array has been XOR-ed with the key bits\r
+ */\r
+ var keyLength:uint= key.length;\r
+ var keyIndex:uint = 0;\r
+ \r
+ for (var i:uint = 0; i < P_SZ; i++)\r
+ {\r
+ // get the 32 bits of the key, in 4 * 8 bit chunks\r
+ var data:uint = 0x0000000;\r
+ for (var j:uint = 0; j < 4; j++)\r
+ {\r
+ // create a 32 bit block\r
+ data = (data << 8) | (key[keyIndex++] & 0xff);\r
+ \r
+ // wrap when we get to the end of the key\r
+ if (keyIndex >= keyLength)\r
+ {\r
+ keyIndex = 0;\r
+ }\r
+ }\r
+ // XOR the newly created 32 bit chunk onto the P-array\r
+ P[i] ^= data;\r
+ }\r
+ \r
+ /*\r
+ * (3) Encrypt the all-zero string with the Blowfish algorithm, using\r
+ * the subkeys described in (1) and (2)\r
+ * \r
+ * (4) Replace P1 and P2 with the output of step (3)\r
+ * \r
+ * (5) Encrypt the output of step(3) using the Blowfish algorithm, with\r
+ * the modified subkeys.\r
+ * \r
+ * (6) Replace P3 and P4 with the output of step (5)\r
+ * \r
+ * (7) Continue the process, replacing all elements of the P-array and\r
+ * then all four S-boxes in order, with the output of the continuously\r
+ * changing Blowfish algorithm\r
+ */\r
+ \r
+ processTable(0, 0, P);\r
+ processTable(P[P_SZ - 2], P[P_SZ - 1], S0);\r
+ processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);\r
+ processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);\r
+ processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);\r
+ }\r
+ \r
+ /**\r
+ * Encrypt the given input starting at the given offset and place the result\r
+ * in the provided buffer starting at the given offset. The input will be an\r
+ * exact multiple of our blocksize.\r
+ */\r
+ private function encryptBlock(src:ByteArray, srcIndex:uint, dst:ByteArray, dstIndex:uint):void\r
+ {\r
+ var xl:uint = BytesTo32bits(src, srcIndex);\r
+ var xr:uint = BytesTo32bits(src, srcIndex + 4);\r
+ \r
+ xl ^= P[0];\r
+ \r
+ for (var i:uint = 1; i < ROUNDS; i += 2)\r
+ {\r
+ xr ^= F(xl) ^ P[i];\r
+ xl ^= F(xr) ^ P[i + 1];\r
+ }\r
+ \r
+ xr ^= P[ROUNDS + 1];\r
+ \r
+ Bits32ToBytes(xr, dst, dstIndex);\r
+ Bits32ToBytes(xl, dst, dstIndex + 4);\r
+ }\r
+ \r
+ /**\r
+ * Decrypt the given input starting at the given offset and place the result\r
+ * in the provided buffer starting at the given offset. The input will be an\r
+ * exact multiple of our blocksize.\r
+ */\r
+ private function decryptBlock(src:ByteArray, srcIndex:uint, dst:ByteArray, dstIndex:uint):void\r
+ {\r
+ var xl:uint = BytesTo32bits(src, srcIndex);\r
+ var xr:uint = BytesTo32bits(src, srcIndex + 4);\r
+ \r
+ xl ^= P[ROUNDS + 1];\r
+ \r
+ for (var i:uint = ROUNDS; i > 0; i -= 2)\r
+ {\r
+ xr ^= F(xl) ^ P[i];\r
+ xl ^= F(xr) ^ P[i - 1];\r
+ }\r
+ \r
+ xr ^= P[0];\r
+ \r
+ Bits32ToBytes(xr, dst, dstIndex);\r
+ Bits32ToBytes(xl, dst, dstIndex + 4);\r
+ }\r
+ \r
+ private function BytesTo32bits(b:ByteArray, i:uint):uint\r
+ {\r
+ return ((b[i] & 0xff) << 24) | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | ((b[i + 3] & 0xff));\r
+ }\r
+ \r
+ private function Bits32ToBytes(i:uint, b:ByteArray, offset:uint):void\r
+ {\r
+ b[offset + 3] = i;\r
+ b[offset + 2] = (i >> 8);\r
+ b[offset + 1] = (i >> 16);\r
+ b[offset] = (i >> 24);\r
+ }\r
+ \r
+ public function toString():String {\r
+ return "blowfish";\r
+ }\r
+ \r
+ }\r
+ \r
+}\r
--- /dev/null
+/**\r
+ * CBCMode\r
+ * \r
+ * An ActionScript 3 implementation of the CBC confidentiality mode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ /**\r
+ * CBC confidentiality mode. why not.\r
+ */\r
+ public class CBCMode extends IVMode implements IMode\r
+ {\r
+ \r
+ public function CBCMode(key:ISymmetricKey, padding:IPad = null) {\r
+ super(key, padding);\r
+ }\r
+\r
+ public function encrypt(src:ByteArray):void {\r
+ padding.pad(src);\r
+ var vector:ByteArray = getIV4e();\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ for (var j:uint=0;j<blockSize;j++) {\r
+ src[i+j] ^= vector[j];\r
+ }\r
+ key.encrypt(src, i);\r
+ vector.position=0;\r
+ vector.writeBytes(src, i, blockSize);\r
+ }\r
+ }\r
+ public function decrypt(src:ByteArray):void {\r
+ var vector:ByteArray = getIV4d();\r
+ var tmp:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ tmp.position=0;\r
+ tmp.writeBytes(src, i, blockSize);\r
+ key.decrypt(src, i);\r
+ for (var j:uint=0;j<blockSize;j++) {\r
+ src[i+j] ^= vector[j];\r
+ }\r
+ vector.position=0;\r
+ vector.writeBytes(tmp, 0, blockSize);\r
+ }\r
+ padding.unpad(src);\r
+ }\r
+ \r
+ public function toString():String {\r
+ return key.toString()+"-cbc";\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * CFB8Mode\r
+ * \r
+ * An ActionScript 3 implementation of the CFB-8 confidentiality mode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import com.hurlant.crypto.tests.TestCase;\r
+ import flash.utils.ByteArray;\r
+\r
+ /**\r
+ * \r
+ * Note: The constructor accepts an optional padding argument, but ignores it otherwise.\r
+ */\r
+ public class CFB8Mode extends IVMode implements IMode\r
+ {\r
+ public function CFB8Mode(key:ISymmetricKey, padding:IPad = null) {\r
+ super(key, null);\r
+ }\r
+ \r
+ public function encrypt(src:ByteArray):void {\r
+ var vector:ByteArray = getIV4e();\r
+ var tmp:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<src.length;i++) {\r
+ tmp.position = 0;\r
+ tmp.writeBytes(vector);\r
+ key.encrypt(vector);\r
+ src[i] ^= vector[0];\r
+ // rotate\r
+ for (var j:uint=0;j<blockSize-1;j++) {\r
+ vector[j] = tmp[j+1];\r
+ }\r
+ vector[blockSize-1] = src[i];\r
+ }\r
+ }\r
+ \r
+ public function decrypt(src:ByteArray):void {\r
+ var vector:ByteArray = getIV4d();\r
+ var tmp:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<src.length;i++) {\r
+ var c:uint = src[i];\r
+ tmp.position = 0;\r
+ tmp.writeBytes(vector); // I <- tmp\r
+ key.encrypt(vector); // O <- vector\r
+ src[i] ^= vector[0];\r
+ // rotate\r
+ for (var j:uint=0;j<blockSize-1;j++) {\r
+ vector[j] = tmp[j+1];\r
+ }\r
+ vector[blockSize-1] = c;\r
+ }\r
+\r
+ }\r
+ public function toString():String {\r
+ return key.toString()+"-cfb8";\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * CFBMode\r
+ * \r
+ * An ActionScript 3 implementation of the CFB confidentiality mode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+\r
+ /**\r
+ * This is the "full" CFB.\r
+ * CFB1 and CFB8 are hiding somewhere else.\r
+ * \r
+ * Note: The constructor accepts an optional padding argument, but ignores it otherwise.\r
+ */\r
+ public class CFBMode extends IVMode implements IMode\r
+ {\r
+ \r
+ public function CFBMode(key:ISymmetricKey, padding:IPad = null) {\r
+ super(key,null);\r
+ }\r
+\r
+ public function encrypt(src:ByteArray):void\r
+ {\r
+ var l:uint = src.length;\r
+ var vector:ByteArray = getIV4e();\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ key.encrypt(vector);\r
+ var chunk:uint = (i+blockSize<l)?blockSize:l-i;\r
+ for (var j:uint=0;j<chunk;j++) {\r
+ src[i+j] ^= vector[j];\r
+ }\r
+ vector.position=0;\r
+ vector.writeBytes(src, i, chunk);\r
+ }\r
+ }\r
+ \r
+ public function decrypt(src:ByteArray):void\r
+ {\r
+ var l:uint = src.length;\r
+ var vector:ByteArray = getIV4d();\r
+ var tmp:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ key.encrypt(vector);\r
+ var chunk:uint = (i+blockSize<l)?blockSize:l-i;\r
+ tmp.position=0;\r
+ tmp.writeBytes(src, i, chunk);\r
+ for (var j:uint=0;j<chunk;j++) {\r
+ src[i+j] ^= vector[j];\r
+ }\r
+ vector.position=0;\r
+ vector.writeBytes(tmp);\r
+ }\r
+ }\r
+ \r
+ public function toString():String {\r
+ return key.toString()+"-cfb";\r
+ }\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * CTRMode\r
+ * \r
+ * An ActionScript 3 implementation of the counter confidentiality mode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+\r
+ public class CTRMode extends IVMode implements IMode\r
+ {\r
+\r
+ public function CTRMode(key:ISymmetricKey, padding:IPad = null) {\r
+ super(key, padding);\r
+ }\r
+ \r
+ public function encrypt(src:ByteArray):void\r
+ {\r
+ padding.pad(src);\r
+ var vector:ByteArray = getIV4e();\r
+ core(src, vector);\r
+ }\r
+ \r
+ public function decrypt(src:ByteArray):void\r
+ {\r
+ var vector:ByteArray = getIV4d();\r
+ core(src, vector);\r
+ padding.unpad(src);\r
+ }\r
+ \r
+ private function core(src:ByteArray, iv:ByteArray):void {\r
+ var X:ByteArray = new ByteArray;\r
+ var Xenc:ByteArray = new ByteArray;\r
+ X.writeBytes(iv);\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ Xenc.position=0;\r
+ Xenc.writeBytes(X);\r
+ key.encrypt(Xenc);\r
+ for (var j:uint=0;j<blockSize;j++) {\r
+ src[i+j] ^= Xenc[j];\r
+ }\r
+ \r
+ for (j=blockSize-1;j>=0;--j) {\r
+ X[j]++;\r
+ if (X[j]!=0)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ public function toString():String {\r
+ return key.toString()+"-ctr";\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * DESKey\r
+ * \r
+ * An Actionscript 3 implementation of the Data Encryption Standard (DES)\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * The Bouncy Castle Crypto package, \r
+ * Copyright (c) 2000-2004 The Legion Of The Bouncy Castle\r
+ * (http://www.bouncycastle.org)\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.util.Memory;\r
+\r
+ public class DESKey implements ISymmetricKey\r
+ {\r
+ /**\r
+ * what follows is mainly taken from "Applied Cryptography", by Bruce\r
+ * Schneier, however it also bears great resemblance to Richard\r
+ * Outerbridge's D3DES...\r
+ */\r
+ \r
+ private static const Df_Key:Array = [ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,\r
+ 0x10, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 ];\r
+ \r
+ private static const bytebit:Array = [ 128, 64, 32, 16, 8, 4, 2, 1 ];\r
+ \r
+ private static const bigbyte:Array = [ 0x800000, 0x400000, 0x200000, 0x100000, 0x80000, 0x40000, 0x20000, 0x10000, 0x8000,\r
+ 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 ];\r
+ \r
+ /*\r
+ * Use the key schedule specified in the Standard (ANSI X3.92-1981).\r
+ */\r
+ \r
+ private static const pc1:Array = [ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2,\r
+ 59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12,\r
+ 4, 27, 19, 11, 3 ];\r
+ \r
+ private static const totrot:Array = [ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 ];\r
+ \r
+ private static const pc2:Array = [ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40,\r
+ 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 ];\r
+ \r
+ private static const SP1:Array = [ 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004,\r
+ 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,\r
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004,\r
+ 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404,\r
+ 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400,\r
+ 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404,\r
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004,\r
+ 0x00010400, 0x00000000, 0x01010004 ];\r
+ \r
+ private static const SP2:Array = [ 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020,\r
+ 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,\r
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020,\r
+ 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020,\r
+ 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020,\r
+ 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020,\r
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000,\r
+ 0x80100020, 0x80108020, 0x00108000 ];\r
+ \r
+ private static const SP3:Array = [ 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208,\r
+ 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,\r
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208,\r
+ 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000,\r
+ 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208,\r
+ 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208,\r
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208,\r
+ 0x00000008, 0x08020008, 0x00020200 ];\r
+ \r
+ private static const SP4:Array = [ 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001,\r
+ 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,\r
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081,\r
+ 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001,\r
+ 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081,\r
+ 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000,\r
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080,\r
+ 0x00800000, 0x00002000, 0x00802080 ];\r
+ \r
+ private static const SP5:Array = [ 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000,\r
+ 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,\r
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000,\r
+ 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100,\r
+ 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000,\r
+ 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100,\r
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000,\r
+ 0x40080000, 0x02080100, 0x40000100 ];\r
+ \r
+ private static const SP6:Array = [ 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010,\r
+ 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,\r
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010,\r
+ 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010,\r
+ 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000,\r
+ 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010,\r
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000,\r
+ 0x20000000, 0x00400010, 0x20004010 ];\r
+ \r
+ private static const SP7:Array = [ 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802,\r
+ 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,\r
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000,\r
+ 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800,\r
+ 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800,\r
+ 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000,\r
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002,\r
+ 0x04000800, 0x00000800, 0x00200002 ];\r
+ \r
+ private static const SP8:Array = [ 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040,\r
+ 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,\r
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040,\r
+ 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000,\r
+ 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040,\r
+ 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040,\r
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040,\r
+ 0x00040040, 0x10000000, 0x10041000 ];\r
+\r
+ \r
+ protected var key:ByteArray;\r
+ protected var encKey:Array;\r
+ protected var decKey:Array;\r
+ \r
+\r
+ public function DESKey(key:ByteArray) {\r
+ this.key = key;\r
+ this.encKey = generateWorkingKey(true, key, 0);\r
+ this.decKey = generateWorkingKey(false, key, 0);\r
+ }\r
+\r
+ public function getBlockSize():uint\r
+ {\r
+ return 8;\r
+ }\r
+ \r
+ public function decrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ desFunc(decKey, block, index, block, index);\r
+ }\r
+ \r
+ public function dispose():void\r
+ {\r
+ var i:uint=0;\r
+ for (i=0;i<encKey.length;i++) { encKey[i]=0; }\r
+ for (i=0;i<decKey.length;i++) { decKey[i]=0; }\r
+ encKey=null;\r
+ decKey=null;\r
+ for (i=0;i<key.length;i++) { key[i]=0; }\r
+ key.length = 0;\r
+ key = null;\r
+ Memory.gc();\r
+ }\r
+ \r
+ public function encrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ desFunc(encKey, block, index, block, index);\r
+ }\r
+ \r
+ \r
+ /**\r
+ * generate an integer based working key based on our secret key and what we\r
+ * processing we are planning to do.\r
+ * \r
+ * Acknowledgements for this routine go to James Gillogly & Phil Karn.\r
+ */\r
+ protected function generateWorkingKey(encrypting:Boolean, key:ByteArray, off:uint):Array\r
+ {\r
+ //int[] newKey = new int[32];\r
+ var newKey:Array = [];\r
+ //boolean[] pc1m = new boolean[56], pcr = new boolean[56];\r
+ var pc1m:ByteArray = new ByteArray;\r
+ var pcr:ByteArray = new ByteArray;\r
+ \r
+ var l:uint;\r
+ \r
+ for (var j:uint = 0; j < 56; j++)\r
+ {\r
+ l = pc1[j];\r
+ \r
+ pc1m[j] = ((key[off + (l >>> 3)] & bytebit[l & 07]) != 0);\r
+ }\r
+ \r
+ for (var i:uint = 0; i < 16; i++)\r
+ {\r
+ var m:uint;\r
+ var n:uint;\r
+ \r
+ if (encrypting)\r
+ {\r
+ m = i << 1;\r
+ }\r
+ else\r
+ {\r
+ m = (15 - i) << 1;\r
+ }\r
+ \r
+ n = m + 1;\r
+ newKey[m] = newKey[n] = 0;\r
+ \r
+ for (j = 0; j < 28; j++)\r
+ {\r
+ l = j + totrot[i];\r
+ if (l < 28)\r
+ {\r
+ pcr[j] = pc1m[l];\r
+ }\r
+ else\r
+ {\r
+ pcr[j] = pc1m[l - 28];\r
+ }\r
+ }\r
+ \r
+ for (j = 28; j < 56; j++)\r
+ {\r
+ l = j + totrot[i];\r
+ if (l < 56)\r
+ {\r
+ pcr[j] = pc1m[l];\r
+ }\r
+ else\r
+ {\r
+ pcr[j] = pc1m[l - 28];\r
+ }\r
+ }\r
+ \r
+ for (j = 0; j < 24; j++)\r
+ {\r
+ if (pcr[pc2[j]])\r
+ {\r
+ newKey[m] |= bigbyte[j];\r
+ }\r
+ \r
+ if (pcr[pc2[j + 24]])\r
+ {\r
+ newKey[n] |= bigbyte[j];\r
+ }\r
+ }\r
+ }\r
+ \r
+ //\r
+ // store the processed key\r
+ //\r
+ for (i = 0; i != 32; i += 2)\r
+ {\r
+ var i1:uint;\r
+ var i2:uint;\r
+ \r
+ i1 = newKey[i];\r
+ i2 = newKey[i + 1];\r
+ \r
+ newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10) | ((i2 & 0x00fc0000) >>> 10)\r
+ | ((i2 & 0x00000fc0) >>> 6);\r
+ \r
+ newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16) | ((i2 & 0x0003f000) >>> 4)\r
+ | (i2 & 0x0000003f);\r
+ }\r
+ return newKey;\r
+ }\r
+ \r
+ /**\r
+ * the DES engine.\r
+ */\r
+ protected function desFunc(wKey:Array, inp:ByteArray, inOff:uint, out:ByteArray, outOff:uint):void\r
+ {\r
+ var work:uint;\r
+ var right:uint;\r
+ var left:uint;\r
+ \r
+ left = (inp[inOff + 0] & 0xff) << 24;\r
+ left |= (inp[inOff + 1] & 0xff) << 16;\r
+ left |= (inp[inOff + 2] & 0xff) << 8;\r
+ left |= (inp[inOff + 3] & 0xff);\r
+ \r
+ right = (inp[inOff + 4] & 0xff) << 24;\r
+ right |= (inp[inOff + 5] & 0xff) << 16;\r
+ right |= (inp[inOff + 6] & 0xff) << 8;\r
+ right |= (inp[inOff + 7] & 0xff);\r
+\r
+ work = ((left >>> 4) ^ right) & 0x0f0f0f0f;\r
+ right ^= work;\r
+ left ^= (work << 4);\r
+ work = ((left >>> 16) ^ right) & 0x0000ffff;\r
+ right ^= work;\r
+ left ^= (work << 16);\r
+ work = ((right >>> 2) ^ left) & 0x33333333;\r
+ left ^= work;\r
+ right ^= (work << 2);\r
+ work = ((right >>> 8) ^ left) & 0x00ff00ff;\r
+ left ^= work;\r
+ right ^= (work << 8);\r
+ right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff;\r
+ work = (left ^ right) & 0xaaaaaaaa;\r
+ left ^= work;\r
+ right ^= work;\r
+ left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff;\r
+\r
+ for (var round:uint = 0; round < 8; round++)\r
+ {\r
+ var fval:uint;\r
+ \r
+ work = (right << 28) | (right >>> 4);\r
+ work ^= wKey[round * 4 + 0];\r
+ fval = SP7[work & 0x3f];\r
+ fval |= SP5[(work >>> 8) & 0x3f];\r
+ fval |= SP3[(work >>> 16) & 0x3f];\r
+ fval |= SP1[(work >>> 24) & 0x3f];\r
+ work = right ^ wKey[round * 4 + 1];\r
+ fval |= SP8[work & 0x3f];\r
+ fval |= SP6[(work >>> 8) & 0x3f];\r
+ fval |= SP4[(work >>> 16) & 0x3f];\r
+ fval |= SP2[(work >>> 24) & 0x3f];\r
+ left ^= fval;\r
+ work = (left << 28) | (left >>> 4);\r
+ work ^= wKey[round * 4 + 2];\r
+ fval = SP7[work & 0x3f];\r
+ fval |= SP5[(work >>> 8) & 0x3f];\r
+ fval |= SP3[(work >>> 16) & 0x3f];\r
+ fval |= SP1[(work >>> 24) & 0x3f];\r
+ work = left ^ wKey[round * 4 + 3];\r
+ fval |= SP8[work & 0x3f];\r
+ fval |= SP6[(work >>> 8) & 0x3f];\r
+ fval |= SP4[(work >>> 16) & 0x3f];\r
+ fval |= SP2[(work >>> 24) & 0x3f];\r
+ right ^= fval;\r
+ }\r
+ \r
+ right = (right << 31) | (right >>> 1);\r
+ work = (left ^ right) & 0xaaaaaaaa;\r
+ left ^= work;\r
+ right ^= work;\r
+ left = (left << 31) | (left >>> 1);\r
+ work = ((left >>> 8) ^ right) & 0x00ff00ff;\r
+ right ^= work;\r
+ left ^= (work << 8);\r
+ work = ((left >>> 2) ^ right) & 0x33333333;\r
+ right ^= work;\r
+ left ^= (work << 2);\r
+ work = ((right >>> 16) ^ left) & 0x0000ffff;\r
+ left ^= work;\r
+ right ^= (work << 16);\r
+ work = ((right >>> 4) ^ left) & 0x0f0f0f0f;\r
+ left ^= work;\r
+ right ^= (work << 4);\r
+ \r
+ out[outOff + 0] = ((right >>> 24) & 0xff);\r
+ out[outOff + 1] = ((right >>> 16) & 0xff);\r
+ out[outOff + 2] = ((right >>> 8) & 0xff);\r
+ out[outOff + 3] = (right & 0xff);\r
+ out[outOff + 4] = ((left >>> 24) & 0xff);\r
+ out[outOff + 5] = ((left >>> 16) & 0xff);\r
+ out[outOff + 6] = ((left >>> 8) & 0xff);\r
+ out[outOff + 7] = (left & 0xff);\r
+ }\r
+ \r
+ \r
+ public function toString():String {\r
+ return "des";\r
+ }\r
+ \r
+ \r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ECBMode\r
+ * \r
+ * An ActionScript 3 implementation of the ECB confidentiality mode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Memory;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ /**\r
+ * ECB mode.\r
+ * This uses a padding and a symmetric key.\r
+ * If no padding is given, PKCS#5 is used.\r
+ */\r
+ public class ECBMode implements IMode, ICipher\r
+ {\r
+ private var key:ISymmetricKey;\r
+ private var padding:IPad;\r
+ \r
+ public function ECBMode(key:ISymmetricKey, padding:IPad = null) {\r
+ this.key = key;\r
+ if (padding == null) {\r
+ padding = new PKCS5(key.getBlockSize());\r
+ } else {\r
+ padding.setBlockSize(key.getBlockSize());\r
+ }\r
+ this.padding = padding;\r
+ }\r
+ \r
+ public function getBlockSize():uint {\r
+ return key.getBlockSize();\r
+ }\r
+ \r
+ public function encrypt(src:ByteArray):void {\r
+ padding.pad(src);\r
+ src.position = 0;\r
+ var blockSize:uint = key.getBlockSize();\r
+ var tmp:ByteArray = new ByteArray;\r
+ var dst:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ tmp.length=0;\r
+ src.readBytes(tmp, 0, blockSize);\r
+ key.encrypt(tmp);\r
+ dst.writeBytes(tmp);\r
+ }\r
+ src.length=0;\r
+ src.writeBytes(dst);\r
+ }\r
+ public function decrypt(src:ByteArray):void {\r
+ src.position = 0;\r
+ var blockSize:uint = key.getBlockSize();\r
+ \r
+ // sanity check.\r
+ if (src.length%blockSize!=0) {\r
+ throw new Error("ECB mode cipher length must be a multiple of blocksize "+blockSize);\r
+ }\r
+ \r
+ var tmp:ByteArray = new ByteArray;\r
+ var dst:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ tmp.length=0;\r
+ src.readBytes(tmp, 0, blockSize);\r
+ \r
+ key.decrypt(tmp);\r
+ dst.writeBytes(tmp);\r
+ }\r
+ padding.unpad(dst);\r
+ src.length=0;\r
+ src.writeBytes(dst);\r
+ }\r
+ public function dispose():void {\r
+ key.dispose();\r
+ key = null;\r
+ padding = null;\r
+ Memory.gc();\r
+ }\r
+ public function toString():String {\r
+ return key.toString()+"-ecb";\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ICipher\r
+ * \r
+ * A generic interface to use symmetric ciphers\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public interface ICipher\r
+ {\r
+ function getBlockSize():uint;\r
+ function encrypt(src:ByteArray):void;\r
+ function decrypt(src:ByteArray):void;\r
+ function dispose():void;\r
+ function toString():String;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * IMode\r
+ * \r
+ * An interface for confidentiality modes to implement\r
+ * This could become deprecated at some point.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric \r
+{\r
+ public interface IMode extends ICipher\r
+ {\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * IPad\r
+ * \r
+ * An interface for padding mechanisms to implement.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ /**\r
+ * Tiny interface that represents a padding mechanism.\r
+ */\r
+ public interface IPad\r
+ {\r
+ /**\r
+ * Add padding to the array\r
+ */\r
+ function pad(a:ByteArray):void;\r
+ /**\r
+ * Remove padding from the array.\r
+ * @throws Error if the padding is invalid.\r
+ */\r
+ function unpad(a:ByteArray):void;\r
+ /**\r
+ * Set the blockSize to work on\r
+ */\r
+ function setBlockSize(bs:uint):void;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * IStreamCipher\r
+ * \r
+ * A "marker" interface for stream ciphers.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric {\r
+ \r
+ /**\r
+ * A marker to indicate how this cipher works.\r
+ * A stream cipher:\r
+ * - does not use initialization vector\r
+ * - keeps some internal state between calls to encrypt() and decrypt()\r
+ * \r
+ */\r
+ public interface IStreamCipher extends ICipher {\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ISymmetricKey\r
+ * \r
+ * An interface for symmetric encryption keys to implement.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public interface ISymmetricKey\r
+ {\r
+ /**\r
+ * Returns the block size used by this particular encryption algorithm\r
+ */\r
+ function getBlockSize():uint;\r
+ /**\r
+ * Encrypt one block of data in "block", starting at "index", of length "getBlockSize()"\r
+ */\r
+ function encrypt(block:ByteArray, index:uint=0):void;\r
+ /**\r
+ * Decrypt one block of data in "block", starting at "index", of length "getBlockSize()"\r
+ */\r
+ function decrypt(block:ByteArray, index:uint=0):void;\r
+ /**\r
+ * Attempts to destroy sensitive information from memory, such as encryption keys.\r
+ * Note: This is not guaranteed to work given the Flash sandbox model.\r
+ */\r
+ function dispose():void;\r
+ \r
+ function toString():String;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * IVMode\r
+ * \r
+ * An abstract class for confidentialy modes that rely on an initialization vector.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import com.hurlant.crypto.prng.Random;\r
+ import com.hurlant.crypto.tests.TestCase;\r
+ import com.hurlant.util.Memory;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ /**\r
+ * An "abtract" class to avoid redundant code in subclasses\r
+ */\r
+ public class IVMode\r
+ {\r
+ protected var key:ISymmetricKey;\r
+ protected var padding:IPad;\r
+ // random generator used to generate IVs\r
+ protected var prng:Random;\r
+ // optional static IV. used for testing only.\r
+ protected var iv:ByteArray;\r
+ // generated IV is stored here.\r
+ protected var lastIV:ByteArray;\r
+ protected var blockSize:uint;\r
+ \r
+ \r
+ public function IVMode(key:ISymmetricKey, padding:IPad = null) {\r
+ this.key = key;\r
+ blockSize = key.getBlockSize();\r
+ if (padding == null) {\r
+ padding = new PKCS5(blockSize);\r
+ } else {\r
+ padding.setBlockSize(blockSize);\r
+ }\r
+ this.padding = padding;\r
+ \r
+ prng = new Random;\r
+ iv = null;\r
+ lastIV = new ByteArray;\r
+ }\r
+ \r
+ public function getBlockSize():uint {\r
+ return key.getBlockSize();\r
+ }\r
+ public function dispose():void {\r
+ var i:uint;\r
+ if (iv != null) {\r
+ for (i=0;i<iv.length;i++) {\r
+ iv[i] = prng.nextByte();\r
+ }\r
+ iv.length=0;\r
+ iv = null;\r
+ }\r
+ if (lastIV != null) {\r
+ for (i=0;i<iv.length;i++) {\r
+ lastIV[i] = prng.nextByte();\r
+ }\r
+ lastIV.length=0;\r
+ lastIV=null;\r
+ }\r
+ key.dispose();\r
+ key = null;\r
+ padding = null;\r
+ prng.dispose();\r
+ prng = null;\r
+ Memory.gc();\r
+ }\r
+ /**\r
+ * Optional function to force the IV value.\r
+ * Normally, an IV gets generated randomly at every encrypt() call.\r
+ * Also, use this to set the IV before calling decrypt()\r
+ * (if not set before decrypt(), the IV is read from the beginning of the stream.)\r
+ */\r
+ public function set IV(value:ByteArray):void {\r
+ iv = value;\r
+ lastIV.length=0;\r
+ lastIV.writeBytes(iv);\r
+ }\r
+ public function get IV():ByteArray {\r
+ return lastIV;\r
+ }\r
+ \r
+ protected function getIV4e():ByteArray {\r
+ var vec:ByteArray = new ByteArray;\r
+ if (iv) {\r
+ vec.writeBytes(iv);\r
+ } else {\r
+ prng.nextBytes(vec, blockSize);\r
+ }\r
+ lastIV.length=0;\r
+ lastIV.writeBytes(vec);\r
+ return vec;\r
+ }\r
+ protected function getIV4d():ByteArray {\r
+ var vec:ByteArray = new ByteArray;\r
+ if (iv) {\r
+ vec.writeBytes(iv);\r
+ } else {\r
+ throw new Error("an IV must be set before calling decrypt()");\r
+ }\r
+ return vec;\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * NullPad\r
+ * \r
+ * A padding class that doesn't pad.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+\r
+ /**\r
+ * A pad that does nothing.\r
+ * Useful when you don't want padding in your Mode.\r
+ */\r
+ public class NullPad implements IPad\r
+ {\r
+ public function unpad(a:ByteArray):void\r
+ {\r
+ return;\r
+ }\r
+ \r
+ public function pad(a:ByteArray):void\r
+ {\r
+ return;\r
+ }\r
+\r
+ public function setBlockSize(bs:uint):void {\r
+ return;\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * OFBMode\r
+ * \r
+ * An ActionScript 3 implementation of the OFB confidentiality mode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+\r
+ public class OFBMode extends IVMode implements IMode\r
+ {\r
+ public function OFBMode(key:ISymmetricKey, padding:IPad=null)\r
+ {\r
+ super(key, null);\r
+ }\r
+ \r
+ public function encrypt(src:ByteArray):void\r
+ {\r
+ var vector:ByteArray = getIV4e();\r
+ core(src, vector);\r
+ }\r
+ \r
+ public function decrypt(src:ByteArray):void\r
+ {\r
+ var vector:ByteArray = getIV4d();\r
+ core(src, vector);\r
+ }\r
+ \r
+ private function core(src:ByteArray, iv:ByteArray):void { \r
+ var l:uint = src.length;\r
+ var tmp:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<src.length;i+=blockSize) {\r
+ key.encrypt(iv);\r
+ tmp.position=0;\r
+ tmp.writeBytes(iv);\r
+ var chunk:uint = (i+blockSize<l)?blockSize:l-i;\r
+ for (var j:uint=0;j<chunk;j++) {\r
+ src[i+j] ^= iv[j];\r
+ }\r
+ iv.position=0;\r
+ iv.writeBytes(tmp);\r
+ }\r
+ }\r
+ public function toString():String {\r
+ return key.toString()+"-ofb";\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * PKCS5\r
+ * \r
+ * A padding implementation of PKCS5.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class PKCS5 implements IPad\r
+ {\r
+ private var blockSize:uint;\r
+ \r
+ public function PKCS5(blockSize:uint=0) {\r
+ this.blockSize = blockSize;\r
+ }\r
+ \r
+ public function pad(a:ByteArray):void {\r
+ var c:uint = blockSize-a.length%blockSize;\r
+ for (var i:uint=0;i<c;i++){\r
+ a[a.length] = c;\r
+ }\r
+ }\r
+ public function unpad(a:ByteArray):void {\r
+ var c:uint = a.length%blockSize;\r
+ if (c!=0) throw new Error("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");\r
+ c = a[a.length-1];\r
+ for (var i:uint=c;i>0;i--) {\r
+ var v:uint = a[a.length-1];\r
+ a.length--;\r
+ if (c!=v) throw new Error("PKCS#5:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]");\r
+ }\r
+ // that is all.\r
+ }\r
+\r
+ public function setBlockSize(bs:uint):void {\r
+ blockSize = bs;\r
+ }\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**
+ * TLSPad
+ *
+ * A padding implementation used by TLS
+ * Copyright (c) 2007 Henri Torgemane
+ *
+ * See LICENSE.txt for full license information.
+ */
+package com.hurlant.crypto.symmetric {
+ import flash.utils.ByteArray;
+ import com.hurlant.util.Hex;
+ import com.hurlant.crypto.tls.TLSError;
+
+ public class SSLPad implements IPad {
+ private var blockSize:uint;
+
+ public function SSLPad(blockSize:uint=0) {
+ this.blockSize = blockSize;
+ }
+ public function pad(a:ByteArray):void {
+ var c:uint = blockSize - (a.length+1)%blockSize;
+ for (var i:uint=0;i<=c;i++) {
+ a[a.length] = c;
+ }
+
+ }
+ public function unpad(a:ByteArray):void {
+ var c:uint = a.length%blockSize;
+ if (c!=0) throw new TLSError("SSLPad::unpad: ByteArray.length isn't a multiple of the blockSize", TLSError.bad_record_mac);
+ c = a[a.length-1];
+ for (var i:uint=c;i>0;i--) {
+ var v:uint = a[a.length-1];
+ a.length--;
+ // But LOOK! SSL 3.0 doesn't care about this, bytes are arbitrary!
+ // if (c!=v) throw new TLSError("SSLPad:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]", TLSError.bad_record_mac);
+ }
+ a.length--;
+
+ }
+ public function setBlockSize(bs:uint):void {
+ blockSize = bs;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * SimpleIVMode\r
+ * \r
+ * A convenience class that automatically places the IV\r
+ * at the beginning of the encrypted stream, so it doesn't have to\r
+ * be handled explicitely.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Memory;\r
+ \r
+ public class SimpleIVMode implements IMode, ICipher\r
+ {\r
+ protected var mode:IVMode;\r
+ protected var cipher:ICipher;\r
+ \r
+ public function SimpleIVMode(mode:IVMode) {\r
+ this.mode = mode;\r
+ cipher = mode as ICipher;\r
+ }\r
+ \r
+ public function getBlockSize():uint {\r
+ return mode.getBlockSize();\r
+ }\r
+ \r
+ public function dispose():void {\r
+ mode.dispose();\r
+ mode = null;\r
+ cipher = null;\r
+ Memory.gc();\r
+ }\r
+ \r
+ public function encrypt(src:ByteArray):void {\r
+ cipher.encrypt(src);\r
+ var tmp:ByteArray = new ByteArray;\r
+ tmp.writeBytes(mode.IV);\r
+ tmp.writeBytes(src);\r
+ src.position=0;\r
+ src.writeBytes(tmp);\r
+ }\r
+ \r
+ public function decrypt(src:ByteArray):void {\r
+ var tmp:ByteArray = new ByteArray;\r
+ tmp.writeBytes(src, 0, getBlockSize());\r
+ mode.IV = tmp;\r
+ tmp = new ByteArray;\r
+ tmp.writeBytes(src, getBlockSize());\r
+ cipher.decrypt(tmp);\r
+ src.length=0;\r
+ src.writeBytes(tmp);\r
+ }\r
+ public function toString():String {\r
+ return "simple-"+cipher.toString();\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TLSPad\r
+ * \r
+ * A padding implementation used by TLS\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric {\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.crypto.tls.TLSError;\r
+ \r
+ public class TLSPad implements IPad {\r
+ private var blockSize:uint;\r
+ \r
+ public function TLSPad(blockSize:uint=0) {\r
+ this.blockSize = blockSize;\r
+ }\r
+ public function pad(a:ByteArray):void {\r
+ var c:uint = blockSize - (a.length+1)%blockSize;\r
+ for (var i:uint=0;i<=c;i++) {\r
+ a[a.length] = c;\r
+ }\r
+ }\r
+ public function unpad(a:ByteArray):void {\r
+ var c:uint = a.length%blockSize;\r
+ if (c!=0) throw new TLSError("TLSPad::unpad: ByteArray.length isn't a multiple of the blockSize", TLSError.bad_record_mac);\r
+ c = a[a.length-1];\r
+ for (var i:uint=c;i>0;i--) {\r
+ var v:uint = a[a.length-1];\r
+ a.length--;\r
+ if (c!=v) throw new TLSError("TLSPad:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]", TLSError.bad_record_mac);\r
+ }\r
+ a.length--;\r
+ // mostly ripped off from PKCS5.as, but with subtle differences\r
+ }\r
+ public function setBlockSize(bs:uint):void {\r
+ blockSize = bs;\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TripleDESKey\r
+ * \r
+ * An Actionscript 3 implementation of Triple DES\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * The Bouncy Castle Crypto package, \r
+ * Copyright (c) 2000-2004 The Legion Of The Bouncy Castle\r
+ * (http://www.bouncycastle.org)\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Memory;\r
+ import com.hurlant.util.Hex;\r
+\r
+ public class TripleDESKey extends DESKey\r
+ {\r
+ protected var encKey2:Array;\r
+ protected var encKey3:Array;\r
+ protected var decKey2:Array;\r
+ protected var decKey3:Array;\r
+ \r
+ /**\r
+ * This supports 2TDES and 3TDES.\r
+ * If the key passed is 128 bits, 2TDES is used.\r
+ * If the key has 192 bits, 3TDES is used.\r
+ * Other key lengths give "undefined" results.\r
+ */\r
+ public function TripleDESKey(key:ByteArray)\r
+ {\r
+ super(key);\r
+ encKey2 = generateWorkingKey(false, key, 8);\r
+ decKey2 = generateWorkingKey(true, key, 8);\r
+ if (key.length>16) {\r
+ encKey3 = generateWorkingKey(true, key, 16);\r
+ decKey3 = generateWorkingKey(false, key, 16);\r
+ } else {\r
+ encKey3 = encKey;\r
+ decKey3 = decKey;\r
+ }\r
+ }\r
+\r
+ public override function dispose():void\r
+ {\r
+ super.dispose();\r
+ var i:uint = 0;\r
+ if (encKey2!=null) {\r
+ for (i=0;i<encKey2.length;i++) { encKey2[i]=0; }\r
+ encKey2=null;\r
+ }\r
+ if (encKey3!=null) {\r
+ for (i=0;i<encKey3.length;i++) { encKey3[i]=0; }\r
+ encKey3=null;\r
+ }\r
+ if (decKey2!=null) {\r
+ for (i=0;i<decKey2.length;i++) { decKey2[i]=0; }\r
+ decKey2=null\r
+ }\r
+ if (decKey3!=null) {\r
+ for (i=0;i<decKey3.length;i++) { decKey3[i]=0; }\r
+ decKey3=null;\r
+ }\r
+ Memory.gc();\r
+ }\r
+ \r
+ public override function encrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ desFunc(encKey, block,index, block,index);\r
+ desFunc(encKey2, block,index, block,index);\r
+ desFunc(encKey3, block,index, block,index);\r
+ }\r
+ \r
+ public override function decrypt(block:ByteArray, index:uint=0):void\r
+ {\r
+ desFunc(decKey3, block, index, block, index);\r
+ desFunc(decKey2, block, index, block, index);\r
+ desFunc(decKey, block, index, block, index);\r
+ }\r
+ \r
+ public override function toString():String {\r
+ return "3des";\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * XTeaKey\r
+ * \r
+ * An ActionScript 3 implementation of the XTea algorithm\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.symmetric\r
+{\r
+ import com.hurlant.crypto.prng.Random;\r
+ import com.hurlant.util.Memory;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ \r
+ public class XTeaKey implements ISymmetricKey\r
+ {\r
+ public const NUM_ROUNDS:uint = 64; \r
+ private var k:Array;\r
+\r
+ public function XTeaKey(a:ByteArray) {\r
+ a.position=0;\r
+ k = [a.readUnsignedInt(),a.readUnsignedInt(),a.readUnsignedInt(),a.readUnsignedInt()];\r
+ }\r
+ /**\r
+ * K is an hex string with 32 digits.\r
+ */\r
+ public static function parseKey(K:String):XTeaKey {\r
+ var a:ByteArray = new ByteArray;\r
+ a.writeUnsignedInt(parseInt(K.substr(0,8),16));\r
+ a.writeUnsignedInt(parseInt(K.substr(8,8),16));\r
+ a.writeUnsignedInt(parseInt(K.substr(16,8),16));\r
+ a.writeUnsignedInt(parseInt(K.substr(24,8),16));\r
+ a.position = 0;\r
+ return new XTeaKey(a);\r
+ }\r
+ \r
+ public function getBlockSize():uint {\r
+ return 8;\r
+ }\r
+\r
+ public function encrypt(block:ByteArray, index:uint=0):void {\r
+ block.position = index;\r
+ var v0:uint = block.readUnsignedInt();\r
+ var v1:uint = block.readUnsignedInt();\r
+ var i:uint;\r
+ var sum:uint =0;\r
+ var delta:uint = 0x9E3779B9;\r
+ for (i=0; i<NUM_ROUNDS; i++) {\r
+ v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);\r
+ sum += delta;\r
+ v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);\r
+ }\r
+ block.position-=8;\r
+ block.writeUnsignedInt(v0);\r
+ block.writeUnsignedInt(v1);\r
+ }\r
+ \r
+ public function decrypt(block:ByteArray, index:uint=0):void {\r
+ block.position = index;\r
+ var v0:uint = block.readUnsignedInt();\r
+ var v1:uint = block.readUnsignedInt();\r
+ var i:uint;\r
+ var delta:uint = 0x9E3779B9;\r
+ var sum:uint = delta*NUM_ROUNDS;\r
+ for (i=0; i<NUM_ROUNDS; i++) {\r
+ v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);\r
+ sum -= delta;\r
+ v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);\r
+ }\r
+ block.position-=8;\r
+ block.writeUnsignedInt(v0);\r
+ block.writeUnsignedInt(v1);\r
+ }\r
+\r
+ public function dispose():void {\r
+ //private var k:Array;\r
+ var r:Random = new Random;\r
+ for (var i:uint=0;i<k.length;i++) {\r
+ k[i] = r.nextByte();\r
+ delete k[i];\r
+ }\r
+ k = null;\r
+ Memory.gc();\r
+ }\r
+\r
+ public function toString():String {\r
+ return "xtea";\r
+ }\r
+ }\r
+ \r
+\r
+}
\ No newline at end of file
--- /dev/null
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+sub say {
+ my $w = shift;
+ print $w;
+ print "\n";
+}
+
+sub dump {
+ my $i = shift;
+ &say(sprintf("Sbox[%d] = _Sbox[%d]", $i, $i));
+ &say(sprintf("InvSbox[%d] = _InvSbox[%d]", $i, $i));
+ &say(sprintf("Xtime2Sbox[%d] = _Xtime2Sbox[%d]", $i, $i));
+ &say(sprintf("Xtime3Sbox[%d] = _Xtime3Sbox[%d]", $i, $i));
+ &say(sprintf("Xtime2[%d] = _Xtime2[%d]", $i, $i));
+ &say(sprintf("Xtime9[%d] = _Xtime9[%d]", $i, $i));
+ &say(sprintf("XtimeB[%d] = _XtimeB[%d]", $i, $i));
+ &say(sprintf("XtimeD[%d] = _XtimeD[%d]", $i, $i));
+ &say(sprintf("XtimeE[%d] = _XtimeE[%d]", $i, $i));
+}
+
+for (my $i=0;$i<256;$i++) {
+ &dump($i);
+}
+
+
+
--- /dev/null
+Sbox[0] = _Sbox[0]
+InvSbox[0] = _InvSbox[0]
+Xtime2Sbox[0] = _Xtime2Sbox[0]
+Xtime3Sbox[0] = _Xtime3Sbox[0]
+Xtime2[0] = _Xtime2[0]
+Xtime9[0] = _Xtime9[0]
+XtimeB[0] = _XtimeB[0]
+XtimeD[0] = _XtimeD[0]
+XtimeE[0] = _XtimeE[0]
+Sbox[1] = _Sbox[1]
+InvSbox[1] = _InvSbox[1]
+Xtime2Sbox[1] = _Xtime2Sbox[1]
+Xtime3Sbox[1] = _Xtime3Sbox[1]
+Xtime2[1] = _Xtime2[1]
+Xtime9[1] = _Xtime9[1]
+XtimeB[1] = _XtimeB[1]
+XtimeD[1] = _XtimeD[1]
+XtimeE[1] = _XtimeE[1]
+Sbox[2] = _Sbox[2]
+InvSbox[2] = _InvSbox[2]
+Xtime2Sbox[2] = _Xtime2Sbox[2]
+Xtime3Sbox[2] = _Xtime3Sbox[2]
+Xtime2[2] = _Xtime2[2]
+Xtime9[2] = _Xtime9[2]
+XtimeB[2] = _XtimeB[2]
+XtimeD[2] = _XtimeD[2]
+XtimeE[2] = _XtimeE[2]
+Sbox[3] = _Sbox[3]
+InvSbox[3] = _InvSbox[3]
+Xtime2Sbox[3] = _Xtime2Sbox[3]
+Xtime3Sbox[3] = _Xtime3Sbox[3]
+Xtime2[3] = _Xtime2[3]
+Xtime9[3] = _Xtime9[3]
+XtimeB[3] = _XtimeB[3]
+XtimeD[3] = _XtimeD[3]
+XtimeE[3] = _XtimeE[3]
+Sbox[4] = _Sbox[4]
+InvSbox[4] = _InvSbox[4]
+Xtime2Sbox[4] = _Xtime2Sbox[4]
+Xtime3Sbox[4] = _Xtime3Sbox[4]
+Xtime2[4] = _Xtime2[4]
+Xtime9[4] = _Xtime9[4]
+XtimeB[4] = _XtimeB[4]
+XtimeD[4] = _XtimeD[4]
+XtimeE[4] = _XtimeE[4]
+Sbox[5] = _Sbox[5]
+InvSbox[5] = _InvSbox[5]
+Xtime2Sbox[5] = _Xtime2Sbox[5]
+Xtime3Sbox[5] = _Xtime3Sbox[5]
+Xtime2[5] = _Xtime2[5]
+Xtime9[5] = _Xtime9[5]
+XtimeB[5] = _XtimeB[5]
+XtimeD[5] = _XtimeD[5]
+XtimeE[5] = _XtimeE[5]
+Sbox[6] = _Sbox[6]
+InvSbox[6] = _InvSbox[6]
+Xtime2Sbox[6] = _Xtime2Sbox[6]
+Xtime3Sbox[6] = _Xtime3Sbox[6]
+Xtime2[6] = _Xtime2[6]
+Xtime9[6] = _Xtime9[6]
+XtimeB[6] = _XtimeB[6]
+XtimeD[6] = _XtimeD[6]
+XtimeE[6] = _XtimeE[6]
+Sbox[7] = _Sbox[7]
+InvSbox[7] = _InvSbox[7]
+Xtime2Sbox[7] = _Xtime2Sbox[7]
+Xtime3Sbox[7] = _Xtime3Sbox[7]
+Xtime2[7] = _Xtime2[7]
+Xtime9[7] = _Xtime9[7]
+XtimeB[7] = _XtimeB[7]
+XtimeD[7] = _XtimeD[7]
+XtimeE[7] = _XtimeE[7]
+Sbox[8] = _Sbox[8]
+InvSbox[8] = _InvSbox[8]
+Xtime2Sbox[8] = _Xtime2Sbox[8]
+Xtime3Sbox[8] = _Xtime3Sbox[8]
+Xtime2[8] = _Xtime2[8]
+Xtime9[8] = _Xtime9[8]
+XtimeB[8] = _XtimeB[8]
+XtimeD[8] = _XtimeD[8]
+XtimeE[8] = _XtimeE[8]
+Sbox[9] = _Sbox[9]
+InvSbox[9] = _InvSbox[9]
+Xtime2Sbox[9] = _Xtime2Sbox[9]
+Xtime3Sbox[9] = _Xtime3Sbox[9]
+Xtime2[9] = _Xtime2[9]
+Xtime9[9] = _Xtime9[9]
+XtimeB[9] = _XtimeB[9]
+XtimeD[9] = _XtimeD[9]
+XtimeE[9] = _XtimeE[9]
+Sbox[10] = _Sbox[10]
+InvSbox[10] = _InvSbox[10]
+Xtime2Sbox[10] = _Xtime2Sbox[10]
+Xtime3Sbox[10] = _Xtime3Sbox[10]
+Xtime2[10] = _Xtime2[10]
+Xtime9[10] = _Xtime9[10]
+XtimeB[10] = _XtimeB[10]
+XtimeD[10] = _XtimeD[10]
+XtimeE[10] = _XtimeE[10]
+Sbox[11] = _Sbox[11]
+InvSbox[11] = _InvSbox[11]
+Xtime2Sbox[11] = _Xtime2Sbox[11]
+Xtime3Sbox[11] = _Xtime3Sbox[11]
+Xtime2[11] = _Xtime2[11]
+Xtime9[11] = _Xtime9[11]
+XtimeB[11] = _XtimeB[11]
+XtimeD[11] = _XtimeD[11]
+XtimeE[11] = _XtimeE[11]
+Sbox[12] = _Sbox[12]
+InvSbox[12] = _InvSbox[12]
+Xtime2Sbox[12] = _Xtime2Sbox[12]
+Xtime3Sbox[12] = _Xtime3Sbox[12]
+Xtime2[12] = _Xtime2[12]
+Xtime9[12] = _Xtime9[12]
+XtimeB[12] = _XtimeB[12]
+XtimeD[12] = _XtimeD[12]
+XtimeE[12] = _XtimeE[12]
+Sbox[13] = _Sbox[13]
+InvSbox[13] = _InvSbox[13]
+Xtime2Sbox[13] = _Xtime2Sbox[13]
+Xtime3Sbox[13] = _Xtime3Sbox[13]
+Xtime2[13] = _Xtime2[13]
+Xtime9[13] = _Xtime9[13]
+XtimeB[13] = _XtimeB[13]
+XtimeD[13] = _XtimeD[13]
+XtimeE[13] = _XtimeE[13]
+Sbox[14] = _Sbox[14]
+InvSbox[14] = _InvSbox[14]
+Xtime2Sbox[14] = _Xtime2Sbox[14]
+Xtime3Sbox[14] = _Xtime3Sbox[14]
+Xtime2[14] = _Xtime2[14]
+Xtime9[14] = _Xtime9[14]
+XtimeB[14] = _XtimeB[14]
+XtimeD[14] = _XtimeD[14]
+XtimeE[14] = _XtimeE[14]
+Sbox[15] = _Sbox[15]
+InvSbox[15] = _InvSbox[15]
+Xtime2Sbox[15] = _Xtime2Sbox[15]
+Xtime3Sbox[15] = _Xtime3Sbox[15]
+Xtime2[15] = _Xtime2[15]
+Xtime9[15] = _Xtime9[15]
+XtimeB[15] = _XtimeB[15]
+XtimeD[15] = _XtimeD[15]
+XtimeE[15] = _XtimeE[15]
+Sbox[16] = _Sbox[16]
+InvSbox[16] = _InvSbox[16]
+Xtime2Sbox[16] = _Xtime2Sbox[16]
+Xtime3Sbox[16] = _Xtime3Sbox[16]
+Xtime2[16] = _Xtime2[16]
+Xtime9[16] = _Xtime9[16]
+XtimeB[16] = _XtimeB[16]
+XtimeD[16] = _XtimeD[16]
+XtimeE[16] = _XtimeE[16]
+Sbox[17] = _Sbox[17]
+InvSbox[17] = _InvSbox[17]
+Xtime2Sbox[17] = _Xtime2Sbox[17]
+Xtime3Sbox[17] = _Xtime3Sbox[17]
+Xtime2[17] = _Xtime2[17]
+Xtime9[17] = _Xtime9[17]
+XtimeB[17] = _XtimeB[17]
+XtimeD[17] = _XtimeD[17]
+XtimeE[17] = _XtimeE[17]
+Sbox[18] = _Sbox[18]
+InvSbox[18] = _InvSbox[18]
+Xtime2Sbox[18] = _Xtime2Sbox[18]
+Xtime3Sbox[18] = _Xtime3Sbox[18]
+Xtime2[18] = _Xtime2[18]
+Xtime9[18] = _Xtime9[18]
+XtimeB[18] = _XtimeB[18]
+XtimeD[18] = _XtimeD[18]
+XtimeE[18] = _XtimeE[18]
+Sbox[19] = _Sbox[19]
+InvSbox[19] = _InvSbox[19]
+Xtime2Sbox[19] = _Xtime2Sbox[19]
+Xtime3Sbox[19] = _Xtime3Sbox[19]
+Xtime2[19] = _Xtime2[19]
+Xtime9[19] = _Xtime9[19]
+XtimeB[19] = _XtimeB[19]
+XtimeD[19] = _XtimeD[19]
+XtimeE[19] = _XtimeE[19]
+Sbox[20] = _Sbox[20]
+InvSbox[20] = _InvSbox[20]
+Xtime2Sbox[20] = _Xtime2Sbox[20]
+Xtime3Sbox[20] = _Xtime3Sbox[20]
+Xtime2[20] = _Xtime2[20]
+Xtime9[20] = _Xtime9[20]
+XtimeB[20] = _XtimeB[20]
+XtimeD[20] = _XtimeD[20]
+XtimeE[20] = _XtimeE[20]
+Sbox[21] = _Sbox[21]
+InvSbox[21] = _InvSbox[21]
+Xtime2Sbox[21] = _Xtime2Sbox[21]
+Xtime3Sbox[21] = _Xtime3Sbox[21]
+Xtime2[21] = _Xtime2[21]
+Xtime9[21] = _Xtime9[21]
+XtimeB[21] = _XtimeB[21]
+XtimeD[21] = _XtimeD[21]
+XtimeE[21] = _XtimeE[21]
+Sbox[22] = _Sbox[22]
+InvSbox[22] = _InvSbox[22]
+Xtime2Sbox[22] = _Xtime2Sbox[22]
+Xtime3Sbox[22] = _Xtime3Sbox[22]
+Xtime2[22] = _Xtime2[22]
+Xtime9[22] = _Xtime9[22]
+XtimeB[22] = _XtimeB[22]
+XtimeD[22] = _XtimeD[22]
+XtimeE[22] = _XtimeE[22]
+Sbox[23] = _Sbox[23]
+InvSbox[23] = _InvSbox[23]
+Xtime2Sbox[23] = _Xtime2Sbox[23]
+Xtime3Sbox[23] = _Xtime3Sbox[23]
+Xtime2[23] = _Xtime2[23]
+Xtime9[23] = _Xtime9[23]
+XtimeB[23] = _XtimeB[23]
+XtimeD[23] = _XtimeD[23]
+XtimeE[23] = _XtimeE[23]
+Sbox[24] = _Sbox[24]
+InvSbox[24] = _InvSbox[24]
+Xtime2Sbox[24] = _Xtime2Sbox[24]
+Xtime3Sbox[24] = _Xtime3Sbox[24]
+Xtime2[24] = _Xtime2[24]
+Xtime9[24] = _Xtime9[24]
+XtimeB[24] = _XtimeB[24]
+XtimeD[24] = _XtimeD[24]
+XtimeE[24] = _XtimeE[24]
+Sbox[25] = _Sbox[25]
+InvSbox[25] = _InvSbox[25]
+Xtime2Sbox[25] = _Xtime2Sbox[25]
+Xtime3Sbox[25] = _Xtime3Sbox[25]
+Xtime2[25] = _Xtime2[25]
+Xtime9[25] = _Xtime9[25]
+XtimeB[25] = _XtimeB[25]
+XtimeD[25] = _XtimeD[25]
+XtimeE[25] = _XtimeE[25]
+Sbox[26] = _Sbox[26]
+InvSbox[26] = _InvSbox[26]
+Xtime2Sbox[26] = _Xtime2Sbox[26]
+Xtime3Sbox[26] = _Xtime3Sbox[26]
+Xtime2[26] = _Xtime2[26]
+Xtime9[26] = _Xtime9[26]
+XtimeB[26] = _XtimeB[26]
+XtimeD[26] = _XtimeD[26]
+XtimeE[26] = _XtimeE[26]
+Sbox[27] = _Sbox[27]
+InvSbox[27] = _InvSbox[27]
+Xtime2Sbox[27] = _Xtime2Sbox[27]
+Xtime3Sbox[27] = _Xtime3Sbox[27]
+Xtime2[27] = _Xtime2[27]
+Xtime9[27] = _Xtime9[27]
+XtimeB[27] = _XtimeB[27]
+XtimeD[27] = _XtimeD[27]
+XtimeE[27] = _XtimeE[27]
+Sbox[28] = _Sbox[28]
+InvSbox[28] = _InvSbox[28]
+Xtime2Sbox[28] = _Xtime2Sbox[28]
+Xtime3Sbox[28] = _Xtime3Sbox[28]
+Xtime2[28] = _Xtime2[28]
+Xtime9[28] = _Xtime9[28]
+XtimeB[28] = _XtimeB[28]
+XtimeD[28] = _XtimeD[28]
+XtimeE[28] = _XtimeE[28]
+Sbox[29] = _Sbox[29]
+InvSbox[29] = _InvSbox[29]
+Xtime2Sbox[29] = _Xtime2Sbox[29]
+Xtime3Sbox[29] = _Xtime3Sbox[29]
+Xtime2[29] = _Xtime2[29]
+Xtime9[29] = _Xtime9[29]
+XtimeB[29] = _XtimeB[29]
+XtimeD[29] = _XtimeD[29]
+XtimeE[29] = _XtimeE[29]
+Sbox[30] = _Sbox[30]
+InvSbox[30] = _InvSbox[30]
+Xtime2Sbox[30] = _Xtime2Sbox[30]
+Xtime3Sbox[30] = _Xtime3Sbox[30]
+Xtime2[30] = _Xtime2[30]
+Xtime9[30] = _Xtime9[30]
+XtimeB[30] = _XtimeB[30]
+XtimeD[30] = _XtimeD[30]
+XtimeE[30] = _XtimeE[30]
+Sbox[31] = _Sbox[31]
+InvSbox[31] = _InvSbox[31]
+Xtime2Sbox[31] = _Xtime2Sbox[31]
+Xtime3Sbox[31] = _Xtime3Sbox[31]
+Xtime2[31] = _Xtime2[31]
+Xtime9[31] = _Xtime9[31]
+XtimeB[31] = _XtimeB[31]
+XtimeD[31] = _XtimeD[31]
+XtimeE[31] = _XtimeE[31]
+Sbox[32] = _Sbox[32]
+InvSbox[32] = _InvSbox[32]
+Xtime2Sbox[32] = _Xtime2Sbox[32]
+Xtime3Sbox[32] = _Xtime3Sbox[32]
+Xtime2[32] = _Xtime2[32]
+Xtime9[32] = _Xtime9[32]
+XtimeB[32] = _XtimeB[32]
+XtimeD[32] = _XtimeD[32]
+XtimeE[32] = _XtimeE[32]
+Sbox[33] = _Sbox[33]
+InvSbox[33] = _InvSbox[33]
+Xtime2Sbox[33] = _Xtime2Sbox[33]
+Xtime3Sbox[33] = _Xtime3Sbox[33]
+Xtime2[33] = _Xtime2[33]
+Xtime9[33] = _Xtime9[33]
+XtimeB[33] = _XtimeB[33]
+XtimeD[33] = _XtimeD[33]
+XtimeE[33] = _XtimeE[33]
+Sbox[34] = _Sbox[34]
+InvSbox[34] = _InvSbox[34]
+Xtime2Sbox[34] = _Xtime2Sbox[34]
+Xtime3Sbox[34] = _Xtime3Sbox[34]
+Xtime2[34] = _Xtime2[34]
+Xtime9[34] = _Xtime9[34]
+XtimeB[34] = _XtimeB[34]
+XtimeD[34] = _XtimeD[34]
+XtimeE[34] = _XtimeE[34]
+Sbox[35] = _Sbox[35]
+InvSbox[35] = _InvSbox[35]
+Xtime2Sbox[35] = _Xtime2Sbox[35]
+Xtime3Sbox[35] = _Xtime3Sbox[35]
+Xtime2[35] = _Xtime2[35]
+Xtime9[35] = _Xtime9[35]
+XtimeB[35] = _XtimeB[35]
+XtimeD[35] = _XtimeD[35]
+XtimeE[35] = _XtimeE[35]
+Sbox[36] = _Sbox[36]
+InvSbox[36] = _InvSbox[36]
+Xtime2Sbox[36] = _Xtime2Sbox[36]
+Xtime3Sbox[36] = _Xtime3Sbox[36]
+Xtime2[36] = _Xtime2[36]
+Xtime9[36] = _Xtime9[36]
+XtimeB[36] = _XtimeB[36]
+XtimeD[36] = _XtimeD[36]
+XtimeE[36] = _XtimeE[36]
+Sbox[37] = _Sbox[37]
+InvSbox[37] = _InvSbox[37]
+Xtime2Sbox[37] = _Xtime2Sbox[37]
+Xtime3Sbox[37] = _Xtime3Sbox[37]
+Xtime2[37] = _Xtime2[37]
+Xtime9[37] = _Xtime9[37]
+XtimeB[37] = _XtimeB[37]
+XtimeD[37] = _XtimeD[37]
+XtimeE[37] = _XtimeE[37]
+Sbox[38] = _Sbox[38]
+InvSbox[38] = _InvSbox[38]
+Xtime2Sbox[38] = _Xtime2Sbox[38]
+Xtime3Sbox[38] = _Xtime3Sbox[38]
+Xtime2[38] = _Xtime2[38]
+Xtime9[38] = _Xtime9[38]
+XtimeB[38] = _XtimeB[38]
+XtimeD[38] = _XtimeD[38]
+XtimeE[38] = _XtimeE[38]
+Sbox[39] = _Sbox[39]
+InvSbox[39] = _InvSbox[39]
+Xtime2Sbox[39] = _Xtime2Sbox[39]
+Xtime3Sbox[39] = _Xtime3Sbox[39]
+Xtime2[39] = _Xtime2[39]
+Xtime9[39] = _Xtime9[39]
+XtimeB[39] = _XtimeB[39]
+XtimeD[39] = _XtimeD[39]
+XtimeE[39] = _XtimeE[39]
+Sbox[40] = _Sbox[40]
+InvSbox[40] = _InvSbox[40]
+Xtime2Sbox[40] = _Xtime2Sbox[40]
+Xtime3Sbox[40] = _Xtime3Sbox[40]
+Xtime2[40] = _Xtime2[40]
+Xtime9[40] = _Xtime9[40]
+XtimeB[40] = _XtimeB[40]
+XtimeD[40] = _XtimeD[40]
+XtimeE[40] = _XtimeE[40]
+Sbox[41] = _Sbox[41]
+InvSbox[41] = _InvSbox[41]
+Xtime2Sbox[41] = _Xtime2Sbox[41]
+Xtime3Sbox[41] = _Xtime3Sbox[41]
+Xtime2[41] = _Xtime2[41]
+Xtime9[41] = _Xtime9[41]
+XtimeB[41] = _XtimeB[41]
+XtimeD[41] = _XtimeD[41]
+XtimeE[41] = _XtimeE[41]
+Sbox[42] = _Sbox[42]
+InvSbox[42] = _InvSbox[42]
+Xtime2Sbox[42] = _Xtime2Sbox[42]
+Xtime3Sbox[42] = _Xtime3Sbox[42]
+Xtime2[42] = _Xtime2[42]
+Xtime9[42] = _Xtime9[42]
+XtimeB[42] = _XtimeB[42]
+XtimeD[42] = _XtimeD[42]
+XtimeE[42] = _XtimeE[42]
+Sbox[43] = _Sbox[43]
+InvSbox[43] = _InvSbox[43]
+Xtime2Sbox[43] = _Xtime2Sbox[43]
+Xtime3Sbox[43] = _Xtime3Sbox[43]
+Xtime2[43] = _Xtime2[43]
+Xtime9[43] = _Xtime9[43]
+XtimeB[43] = _XtimeB[43]
+XtimeD[43] = _XtimeD[43]
+XtimeE[43] = _XtimeE[43]
+Sbox[44] = _Sbox[44]
+InvSbox[44] = _InvSbox[44]
+Xtime2Sbox[44] = _Xtime2Sbox[44]
+Xtime3Sbox[44] = _Xtime3Sbox[44]
+Xtime2[44] = _Xtime2[44]
+Xtime9[44] = _Xtime9[44]
+XtimeB[44] = _XtimeB[44]
+XtimeD[44] = _XtimeD[44]
+XtimeE[44] = _XtimeE[44]
+Sbox[45] = _Sbox[45]
+InvSbox[45] = _InvSbox[45]
+Xtime2Sbox[45] = _Xtime2Sbox[45]
+Xtime3Sbox[45] = _Xtime3Sbox[45]
+Xtime2[45] = _Xtime2[45]
+Xtime9[45] = _Xtime9[45]
+XtimeB[45] = _XtimeB[45]
+XtimeD[45] = _XtimeD[45]
+XtimeE[45] = _XtimeE[45]
+Sbox[46] = _Sbox[46]
+InvSbox[46] = _InvSbox[46]
+Xtime2Sbox[46] = _Xtime2Sbox[46]
+Xtime3Sbox[46] = _Xtime3Sbox[46]
+Xtime2[46] = _Xtime2[46]
+Xtime9[46] = _Xtime9[46]
+XtimeB[46] = _XtimeB[46]
+XtimeD[46] = _XtimeD[46]
+XtimeE[46] = _XtimeE[46]
+Sbox[47] = _Sbox[47]
+InvSbox[47] = _InvSbox[47]
+Xtime2Sbox[47] = _Xtime2Sbox[47]
+Xtime3Sbox[47] = _Xtime3Sbox[47]
+Xtime2[47] = _Xtime2[47]
+Xtime9[47] = _Xtime9[47]
+XtimeB[47] = _XtimeB[47]
+XtimeD[47] = _XtimeD[47]
+XtimeE[47] = _XtimeE[47]
+Sbox[48] = _Sbox[48]
+InvSbox[48] = _InvSbox[48]
+Xtime2Sbox[48] = _Xtime2Sbox[48]
+Xtime3Sbox[48] = _Xtime3Sbox[48]
+Xtime2[48] = _Xtime2[48]
+Xtime9[48] = _Xtime9[48]
+XtimeB[48] = _XtimeB[48]
+XtimeD[48] = _XtimeD[48]
+XtimeE[48] = _XtimeE[48]
+Sbox[49] = _Sbox[49]
+InvSbox[49] = _InvSbox[49]
+Xtime2Sbox[49] = _Xtime2Sbox[49]
+Xtime3Sbox[49] = _Xtime3Sbox[49]
+Xtime2[49] = _Xtime2[49]
+Xtime9[49] = _Xtime9[49]
+XtimeB[49] = _XtimeB[49]
+XtimeD[49] = _XtimeD[49]
+XtimeE[49] = _XtimeE[49]
+Sbox[50] = _Sbox[50]
+InvSbox[50] = _InvSbox[50]
+Xtime2Sbox[50] = _Xtime2Sbox[50]
+Xtime3Sbox[50] = _Xtime3Sbox[50]
+Xtime2[50] = _Xtime2[50]
+Xtime9[50] = _Xtime9[50]
+XtimeB[50] = _XtimeB[50]
+XtimeD[50] = _XtimeD[50]
+XtimeE[50] = _XtimeE[50]
+Sbox[51] = _Sbox[51]
+InvSbox[51] = _InvSbox[51]
+Xtime2Sbox[51] = _Xtime2Sbox[51]
+Xtime3Sbox[51] = _Xtime3Sbox[51]
+Xtime2[51] = _Xtime2[51]
+Xtime9[51] = _Xtime9[51]
+XtimeB[51] = _XtimeB[51]
+XtimeD[51] = _XtimeD[51]
+XtimeE[51] = _XtimeE[51]
+Sbox[52] = _Sbox[52]
+InvSbox[52] = _InvSbox[52]
+Xtime2Sbox[52] = _Xtime2Sbox[52]
+Xtime3Sbox[52] = _Xtime3Sbox[52]
+Xtime2[52] = _Xtime2[52]
+Xtime9[52] = _Xtime9[52]
+XtimeB[52] = _XtimeB[52]
+XtimeD[52] = _XtimeD[52]
+XtimeE[52] = _XtimeE[52]
+Sbox[53] = _Sbox[53]
+InvSbox[53] = _InvSbox[53]
+Xtime2Sbox[53] = _Xtime2Sbox[53]
+Xtime3Sbox[53] = _Xtime3Sbox[53]
+Xtime2[53] = _Xtime2[53]
+Xtime9[53] = _Xtime9[53]
+XtimeB[53] = _XtimeB[53]
+XtimeD[53] = _XtimeD[53]
+XtimeE[53] = _XtimeE[53]
+Sbox[54] = _Sbox[54]
+InvSbox[54] = _InvSbox[54]
+Xtime2Sbox[54] = _Xtime2Sbox[54]
+Xtime3Sbox[54] = _Xtime3Sbox[54]
+Xtime2[54] = _Xtime2[54]
+Xtime9[54] = _Xtime9[54]
+XtimeB[54] = _XtimeB[54]
+XtimeD[54] = _XtimeD[54]
+XtimeE[54] = _XtimeE[54]
+Sbox[55] = _Sbox[55]
+InvSbox[55] = _InvSbox[55]
+Xtime2Sbox[55] = _Xtime2Sbox[55]
+Xtime3Sbox[55] = _Xtime3Sbox[55]
+Xtime2[55] = _Xtime2[55]
+Xtime9[55] = _Xtime9[55]
+XtimeB[55] = _XtimeB[55]
+XtimeD[55] = _XtimeD[55]
+XtimeE[55] = _XtimeE[55]
+Sbox[56] = _Sbox[56]
+InvSbox[56] = _InvSbox[56]
+Xtime2Sbox[56] = _Xtime2Sbox[56]
+Xtime3Sbox[56] = _Xtime3Sbox[56]
+Xtime2[56] = _Xtime2[56]
+Xtime9[56] = _Xtime9[56]
+XtimeB[56] = _XtimeB[56]
+XtimeD[56] = _XtimeD[56]
+XtimeE[56] = _XtimeE[56]
+Sbox[57] = _Sbox[57]
+InvSbox[57] = _InvSbox[57]
+Xtime2Sbox[57] = _Xtime2Sbox[57]
+Xtime3Sbox[57] = _Xtime3Sbox[57]
+Xtime2[57] = _Xtime2[57]
+Xtime9[57] = _Xtime9[57]
+XtimeB[57] = _XtimeB[57]
+XtimeD[57] = _XtimeD[57]
+XtimeE[57] = _XtimeE[57]
+Sbox[58] = _Sbox[58]
+InvSbox[58] = _InvSbox[58]
+Xtime2Sbox[58] = _Xtime2Sbox[58]
+Xtime3Sbox[58] = _Xtime3Sbox[58]
+Xtime2[58] = _Xtime2[58]
+Xtime9[58] = _Xtime9[58]
+XtimeB[58] = _XtimeB[58]
+XtimeD[58] = _XtimeD[58]
+XtimeE[58] = _XtimeE[58]
+Sbox[59] = _Sbox[59]
+InvSbox[59] = _InvSbox[59]
+Xtime2Sbox[59] = _Xtime2Sbox[59]
+Xtime3Sbox[59] = _Xtime3Sbox[59]
+Xtime2[59] = _Xtime2[59]
+Xtime9[59] = _Xtime9[59]
+XtimeB[59] = _XtimeB[59]
+XtimeD[59] = _XtimeD[59]
+XtimeE[59] = _XtimeE[59]
+Sbox[60] = _Sbox[60]
+InvSbox[60] = _InvSbox[60]
+Xtime2Sbox[60] = _Xtime2Sbox[60]
+Xtime3Sbox[60] = _Xtime3Sbox[60]
+Xtime2[60] = _Xtime2[60]
+Xtime9[60] = _Xtime9[60]
+XtimeB[60] = _XtimeB[60]
+XtimeD[60] = _XtimeD[60]
+XtimeE[60] = _XtimeE[60]
+Sbox[61] = _Sbox[61]
+InvSbox[61] = _InvSbox[61]
+Xtime2Sbox[61] = _Xtime2Sbox[61]
+Xtime3Sbox[61] = _Xtime3Sbox[61]
+Xtime2[61] = _Xtime2[61]
+Xtime9[61] = _Xtime9[61]
+XtimeB[61] = _XtimeB[61]
+XtimeD[61] = _XtimeD[61]
+XtimeE[61] = _XtimeE[61]
+Sbox[62] = _Sbox[62]
+InvSbox[62] = _InvSbox[62]
+Xtime2Sbox[62] = _Xtime2Sbox[62]
+Xtime3Sbox[62] = _Xtime3Sbox[62]
+Xtime2[62] = _Xtime2[62]
+Xtime9[62] = _Xtime9[62]
+XtimeB[62] = _XtimeB[62]
+XtimeD[62] = _XtimeD[62]
+XtimeE[62] = _XtimeE[62]
+Sbox[63] = _Sbox[63]
+InvSbox[63] = _InvSbox[63]
+Xtime2Sbox[63] = _Xtime2Sbox[63]
+Xtime3Sbox[63] = _Xtime3Sbox[63]
+Xtime2[63] = _Xtime2[63]
+Xtime9[63] = _Xtime9[63]
+XtimeB[63] = _XtimeB[63]
+XtimeD[63] = _XtimeD[63]
+XtimeE[63] = _XtimeE[63]
+Sbox[64] = _Sbox[64]
+InvSbox[64] = _InvSbox[64]
+Xtime2Sbox[64] = _Xtime2Sbox[64]
+Xtime3Sbox[64] = _Xtime3Sbox[64]
+Xtime2[64] = _Xtime2[64]
+Xtime9[64] = _Xtime9[64]
+XtimeB[64] = _XtimeB[64]
+XtimeD[64] = _XtimeD[64]
+XtimeE[64] = _XtimeE[64]
+Sbox[65] = _Sbox[65]
+InvSbox[65] = _InvSbox[65]
+Xtime2Sbox[65] = _Xtime2Sbox[65]
+Xtime3Sbox[65] = _Xtime3Sbox[65]
+Xtime2[65] = _Xtime2[65]
+Xtime9[65] = _Xtime9[65]
+XtimeB[65] = _XtimeB[65]
+XtimeD[65] = _XtimeD[65]
+XtimeE[65] = _XtimeE[65]
+Sbox[66] = _Sbox[66]
+InvSbox[66] = _InvSbox[66]
+Xtime2Sbox[66] = _Xtime2Sbox[66]
+Xtime3Sbox[66] = _Xtime3Sbox[66]
+Xtime2[66] = _Xtime2[66]
+Xtime9[66] = _Xtime9[66]
+XtimeB[66] = _XtimeB[66]
+XtimeD[66] = _XtimeD[66]
+XtimeE[66] = _XtimeE[66]
+Sbox[67] = _Sbox[67]
+InvSbox[67] = _InvSbox[67]
+Xtime2Sbox[67] = _Xtime2Sbox[67]
+Xtime3Sbox[67] = _Xtime3Sbox[67]
+Xtime2[67] = _Xtime2[67]
+Xtime9[67] = _Xtime9[67]
+XtimeB[67] = _XtimeB[67]
+XtimeD[67] = _XtimeD[67]
+XtimeE[67] = _XtimeE[67]
+Sbox[68] = _Sbox[68]
+InvSbox[68] = _InvSbox[68]
+Xtime2Sbox[68] = _Xtime2Sbox[68]
+Xtime3Sbox[68] = _Xtime3Sbox[68]
+Xtime2[68] = _Xtime2[68]
+Xtime9[68] = _Xtime9[68]
+XtimeB[68] = _XtimeB[68]
+XtimeD[68] = _XtimeD[68]
+XtimeE[68] = _XtimeE[68]
+Sbox[69] = _Sbox[69]
+InvSbox[69] = _InvSbox[69]
+Xtime2Sbox[69] = _Xtime2Sbox[69]
+Xtime3Sbox[69] = _Xtime3Sbox[69]
+Xtime2[69] = _Xtime2[69]
+Xtime9[69] = _Xtime9[69]
+XtimeB[69] = _XtimeB[69]
+XtimeD[69] = _XtimeD[69]
+XtimeE[69] = _XtimeE[69]
+Sbox[70] = _Sbox[70]
+InvSbox[70] = _InvSbox[70]
+Xtime2Sbox[70] = _Xtime2Sbox[70]
+Xtime3Sbox[70] = _Xtime3Sbox[70]
+Xtime2[70] = _Xtime2[70]
+Xtime9[70] = _Xtime9[70]
+XtimeB[70] = _XtimeB[70]
+XtimeD[70] = _XtimeD[70]
+XtimeE[70] = _XtimeE[70]
+Sbox[71] = _Sbox[71]
+InvSbox[71] = _InvSbox[71]
+Xtime2Sbox[71] = _Xtime2Sbox[71]
+Xtime3Sbox[71] = _Xtime3Sbox[71]
+Xtime2[71] = _Xtime2[71]
+Xtime9[71] = _Xtime9[71]
+XtimeB[71] = _XtimeB[71]
+XtimeD[71] = _XtimeD[71]
+XtimeE[71] = _XtimeE[71]
+Sbox[72] = _Sbox[72]
+InvSbox[72] = _InvSbox[72]
+Xtime2Sbox[72] = _Xtime2Sbox[72]
+Xtime3Sbox[72] = _Xtime3Sbox[72]
+Xtime2[72] = _Xtime2[72]
+Xtime9[72] = _Xtime9[72]
+XtimeB[72] = _XtimeB[72]
+XtimeD[72] = _XtimeD[72]
+XtimeE[72] = _XtimeE[72]
+Sbox[73] = _Sbox[73]
+InvSbox[73] = _InvSbox[73]
+Xtime2Sbox[73] = _Xtime2Sbox[73]
+Xtime3Sbox[73] = _Xtime3Sbox[73]
+Xtime2[73] = _Xtime2[73]
+Xtime9[73] = _Xtime9[73]
+XtimeB[73] = _XtimeB[73]
+XtimeD[73] = _XtimeD[73]
+XtimeE[73] = _XtimeE[73]
+Sbox[74] = _Sbox[74]
+InvSbox[74] = _InvSbox[74]
+Xtime2Sbox[74] = _Xtime2Sbox[74]
+Xtime3Sbox[74] = _Xtime3Sbox[74]
+Xtime2[74] = _Xtime2[74]
+Xtime9[74] = _Xtime9[74]
+XtimeB[74] = _XtimeB[74]
+XtimeD[74] = _XtimeD[74]
+XtimeE[74] = _XtimeE[74]
+Sbox[75] = _Sbox[75]
+InvSbox[75] = _InvSbox[75]
+Xtime2Sbox[75] = _Xtime2Sbox[75]
+Xtime3Sbox[75] = _Xtime3Sbox[75]
+Xtime2[75] = _Xtime2[75]
+Xtime9[75] = _Xtime9[75]
+XtimeB[75] = _XtimeB[75]
+XtimeD[75] = _XtimeD[75]
+XtimeE[75] = _XtimeE[75]
+Sbox[76] = _Sbox[76]
+InvSbox[76] = _InvSbox[76]
+Xtime2Sbox[76] = _Xtime2Sbox[76]
+Xtime3Sbox[76] = _Xtime3Sbox[76]
+Xtime2[76] = _Xtime2[76]
+Xtime9[76] = _Xtime9[76]
+XtimeB[76] = _XtimeB[76]
+XtimeD[76] = _XtimeD[76]
+XtimeE[76] = _XtimeE[76]
+Sbox[77] = _Sbox[77]
+InvSbox[77] = _InvSbox[77]
+Xtime2Sbox[77] = _Xtime2Sbox[77]
+Xtime3Sbox[77] = _Xtime3Sbox[77]
+Xtime2[77] = _Xtime2[77]
+Xtime9[77] = _Xtime9[77]
+XtimeB[77] = _XtimeB[77]
+XtimeD[77] = _XtimeD[77]
+XtimeE[77] = _XtimeE[77]
+Sbox[78] = _Sbox[78]
+InvSbox[78] = _InvSbox[78]
+Xtime2Sbox[78] = _Xtime2Sbox[78]
+Xtime3Sbox[78] = _Xtime3Sbox[78]
+Xtime2[78] = _Xtime2[78]
+Xtime9[78] = _Xtime9[78]
+XtimeB[78] = _XtimeB[78]
+XtimeD[78] = _XtimeD[78]
+XtimeE[78] = _XtimeE[78]
+Sbox[79] = _Sbox[79]
+InvSbox[79] = _InvSbox[79]
+Xtime2Sbox[79] = _Xtime2Sbox[79]
+Xtime3Sbox[79] = _Xtime3Sbox[79]
+Xtime2[79] = _Xtime2[79]
+Xtime9[79] = _Xtime9[79]
+XtimeB[79] = _XtimeB[79]
+XtimeD[79] = _XtimeD[79]
+XtimeE[79] = _XtimeE[79]
+Sbox[80] = _Sbox[80]
+InvSbox[80] = _InvSbox[80]
+Xtime2Sbox[80] = _Xtime2Sbox[80]
+Xtime3Sbox[80] = _Xtime3Sbox[80]
+Xtime2[80] = _Xtime2[80]
+Xtime9[80] = _Xtime9[80]
+XtimeB[80] = _XtimeB[80]
+XtimeD[80] = _XtimeD[80]
+XtimeE[80] = _XtimeE[80]
+Sbox[81] = _Sbox[81]
+InvSbox[81] = _InvSbox[81]
+Xtime2Sbox[81] = _Xtime2Sbox[81]
+Xtime3Sbox[81] = _Xtime3Sbox[81]
+Xtime2[81] = _Xtime2[81]
+Xtime9[81] = _Xtime9[81]
+XtimeB[81] = _XtimeB[81]
+XtimeD[81] = _XtimeD[81]
+XtimeE[81] = _XtimeE[81]
+Sbox[82] = _Sbox[82]
+InvSbox[82] = _InvSbox[82]
+Xtime2Sbox[82] = _Xtime2Sbox[82]
+Xtime3Sbox[82] = _Xtime3Sbox[82]
+Xtime2[82] = _Xtime2[82]
+Xtime9[82] = _Xtime9[82]
+XtimeB[82] = _XtimeB[82]
+XtimeD[82] = _XtimeD[82]
+XtimeE[82] = _XtimeE[82]
+Sbox[83] = _Sbox[83]
+InvSbox[83] = _InvSbox[83]
+Xtime2Sbox[83] = _Xtime2Sbox[83]
+Xtime3Sbox[83] = _Xtime3Sbox[83]
+Xtime2[83] = _Xtime2[83]
+Xtime9[83] = _Xtime9[83]
+XtimeB[83] = _XtimeB[83]
+XtimeD[83] = _XtimeD[83]
+XtimeE[83] = _XtimeE[83]
+Sbox[84] = _Sbox[84]
+InvSbox[84] = _InvSbox[84]
+Xtime2Sbox[84] = _Xtime2Sbox[84]
+Xtime3Sbox[84] = _Xtime3Sbox[84]
+Xtime2[84] = _Xtime2[84]
+Xtime9[84] = _Xtime9[84]
+XtimeB[84] = _XtimeB[84]
+XtimeD[84] = _XtimeD[84]
+XtimeE[84] = _XtimeE[84]
+Sbox[85] = _Sbox[85]
+InvSbox[85] = _InvSbox[85]
+Xtime2Sbox[85] = _Xtime2Sbox[85]
+Xtime3Sbox[85] = _Xtime3Sbox[85]
+Xtime2[85] = _Xtime2[85]
+Xtime9[85] = _Xtime9[85]
+XtimeB[85] = _XtimeB[85]
+XtimeD[85] = _XtimeD[85]
+XtimeE[85] = _XtimeE[85]
+Sbox[86] = _Sbox[86]
+InvSbox[86] = _InvSbox[86]
+Xtime2Sbox[86] = _Xtime2Sbox[86]
+Xtime3Sbox[86] = _Xtime3Sbox[86]
+Xtime2[86] = _Xtime2[86]
+Xtime9[86] = _Xtime9[86]
+XtimeB[86] = _XtimeB[86]
+XtimeD[86] = _XtimeD[86]
+XtimeE[86] = _XtimeE[86]
+Sbox[87] = _Sbox[87]
+InvSbox[87] = _InvSbox[87]
+Xtime2Sbox[87] = _Xtime2Sbox[87]
+Xtime3Sbox[87] = _Xtime3Sbox[87]
+Xtime2[87] = _Xtime2[87]
+Xtime9[87] = _Xtime9[87]
+XtimeB[87] = _XtimeB[87]
+XtimeD[87] = _XtimeD[87]
+XtimeE[87] = _XtimeE[87]
+Sbox[88] = _Sbox[88]
+InvSbox[88] = _InvSbox[88]
+Xtime2Sbox[88] = _Xtime2Sbox[88]
+Xtime3Sbox[88] = _Xtime3Sbox[88]
+Xtime2[88] = _Xtime2[88]
+Xtime9[88] = _Xtime9[88]
+XtimeB[88] = _XtimeB[88]
+XtimeD[88] = _XtimeD[88]
+XtimeE[88] = _XtimeE[88]
+Sbox[89] = _Sbox[89]
+InvSbox[89] = _InvSbox[89]
+Xtime2Sbox[89] = _Xtime2Sbox[89]
+Xtime3Sbox[89] = _Xtime3Sbox[89]
+Xtime2[89] = _Xtime2[89]
+Xtime9[89] = _Xtime9[89]
+XtimeB[89] = _XtimeB[89]
+XtimeD[89] = _XtimeD[89]
+XtimeE[89] = _XtimeE[89]
+Sbox[90] = _Sbox[90]
+InvSbox[90] = _InvSbox[90]
+Xtime2Sbox[90] = _Xtime2Sbox[90]
+Xtime3Sbox[90] = _Xtime3Sbox[90]
+Xtime2[90] = _Xtime2[90]
+Xtime9[90] = _Xtime9[90]
+XtimeB[90] = _XtimeB[90]
+XtimeD[90] = _XtimeD[90]
+XtimeE[90] = _XtimeE[90]
+Sbox[91] = _Sbox[91]
+InvSbox[91] = _InvSbox[91]
+Xtime2Sbox[91] = _Xtime2Sbox[91]
+Xtime3Sbox[91] = _Xtime3Sbox[91]
+Xtime2[91] = _Xtime2[91]
+Xtime9[91] = _Xtime9[91]
+XtimeB[91] = _XtimeB[91]
+XtimeD[91] = _XtimeD[91]
+XtimeE[91] = _XtimeE[91]
+Sbox[92] = _Sbox[92]
+InvSbox[92] = _InvSbox[92]
+Xtime2Sbox[92] = _Xtime2Sbox[92]
+Xtime3Sbox[92] = _Xtime3Sbox[92]
+Xtime2[92] = _Xtime2[92]
+Xtime9[92] = _Xtime9[92]
+XtimeB[92] = _XtimeB[92]
+XtimeD[92] = _XtimeD[92]
+XtimeE[92] = _XtimeE[92]
+Sbox[93] = _Sbox[93]
+InvSbox[93] = _InvSbox[93]
+Xtime2Sbox[93] = _Xtime2Sbox[93]
+Xtime3Sbox[93] = _Xtime3Sbox[93]
+Xtime2[93] = _Xtime2[93]
+Xtime9[93] = _Xtime9[93]
+XtimeB[93] = _XtimeB[93]
+XtimeD[93] = _XtimeD[93]
+XtimeE[93] = _XtimeE[93]
+Sbox[94] = _Sbox[94]
+InvSbox[94] = _InvSbox[94]
+Xtime2Sbox[94] = _Xtime2Sbox[94]
+Xtime3Sbox[94] = _Xtime3Sbox[94]
+Xtime2[94] = _Xtime2[94]
+Xtime9[94] = _Xtime9[94]
+XtimeB[94] = _XtimeB[94]
+XtimeD[94] = _XtimeD[94]
+XtimeE[94] = _XtimeE[94]
+Sbox[95] = _Sbox[95]
+InvSbox[95] = _InvSbox[95]
+Xtime2Sbox[95] = _Xtime2Sbox[95]
+Xtime3Sbox[95] = _Xtime3Sbox[95]
+Xtime2[95] = _Xtime2[95]
+Xtime9[95] = _Xtime9[95]
+XtimeB[95] = _XtimeB[95]
+XtimeD[95] = _XtimeD[95]
+XtimeE[95] = _XtimeE[95]
+Sbox[96] = _Sbox[96]
+InvSbox[96] = _InvSbox[96]
+Xtime2Sbox[96] = _Xtime2Sbox[96]
+Xtime3Sbox[96] = _Xtime3Sbox[96]
+Xtime2[96] = _Xtime2[96]
+Xtime9[96] = _Xtime9[96]
+XtimeB[96] = _XtimeB[96]
+XtimeD[96] = _XtimeD[96]
+XtimeE[96] = _XtimeE[96]
+Sbox[97] = _Sbox[97]
+InvSbox[97] = _InvSbox[97]
+Xtime2Sbox[97] = _Xtime2Sbox[97]
+Xtime3Sbox[97] = _Xtime3Sbox[97]
+Xtime2[97] = _Xtime2[97]
+Xtime9[97] = _Xtime9[97]
+XtimeB[97] = _XtimeB[97]
+XtimeD[97] = _XtimeD[97]
+XtimeE[97] = _XtimeE[97]
+Sbox[98] = _Sbox[98]
+InvSbox[98] = _InvSbox[98]
+Xtime2Sbox[98] = _Xtime2Sbox[98]
+Xtime3Sbox[98] = _Xtime3Sbox[98]
+Xtime2[98] = _Xtime2[98]
+Xtime9[98] = _Xtime9[98]
+XtimeB[98] = _XtimeB[98]
+XtimeD[98] = _XtimeD[98]
+XtimeE[98] = _XtimeE[98]
+Sbox[99] = _Sbox[99]
+InvSbox[99] = _InvSbox[99]
+Xtime2Sbox[99] = _Xtime2Sbox[99]
+Xtime3Sbox[99] = _Xtime3Sbox[99]
+Xtime2[99] = _Xtime2[99]
+Xtime9[99] = _Xtime9[99]
+XtimeB[99] = _XtimeB[99]
+XtimeD[99] = _XtimeD[99]
+XtimeE[99] = _XtimeE[99]
+Sbox[100] = _Sbox[100]
+InvSbox[100] = _InvSbox[100]
+Xtime2Sbox[100] = _Xtime2Sbox[100]
+Xtime3Sbox[100] = _Xtime3Sbox[100]
+Xtime2[100] = _Xtime2[100]
+Xtime9[100] = _Xtime9[100]
+XtimeB[100] = _XtimeB[100]
+XtimeD[100] = _XtimeD[100]
+XtimeE[100] = _XtimeE[100]
+Sbox[101] = _Sbox[101]
+InvSbox[101] = _InvSbox[101]
+Xtime2Sbox[101] = _Xtime2Sbox[101]
+Xtime3Sbox[101] = _Xtime3Sbox[101]
+Xtime2[101] = _Xtime2[101]
+Xtime9[101] = _Xtime9[101]
+XtimeB[101] = _XtimeB[101]
+XtimeD[101] = _XtimeD[101]
+XtimeE[101] = _XtimeE[101]
+Sbox[102] = _Sbox[102]
+InvSbox[102] = _InvSbox[102]
+Xtime2Sbox[102] = _Xtime2Sbox[102]
+Xtime3Sbox[102] = _Xtime3Sbox[102]
+Xtime2[102] = _Xtime2[102]
+Xtime9[102] = _Xtime9[102]
+XtimeB[102] = _XtimeB[102]
+XtimeD[102] = _XtimeD[102]
+XtimeE[102] = _XtimeE[102]
+Sbox[103] = _Sbox[103]
+InvSbox[103] = _InvSbox[103]
+Xtime2Sbox[103] = _Xtime2Sbox[103]
+Xtime3Sbox[103] = _Xtime3Sbox[103]
+Xtime2[103] = _Xtime2[103]
+Xtime9[103] = _Xtime9[103]
+XtimeB[103] = _XtimeB[103]
+XtimeD[103] = _XtimeD[103]
+XtimeE[103] = _XtimeE[103]
+Sbox[104] = _Sbox[104]
+InvSbox[104] = _InvSbox[104]
+Xtime2Sbox[104] = _Xtime2Sbox[104]
+Xtime3Sbox[104] = _Xtime3Sbox[104]
+Xtime2[104] = _Xtime2[104]
+Xtime9[104] = _Xtime9[104]
+XtimeB[104] = _XtimeB[104]
+XtimeD[104] = _XtimeD[104]
+XtimeE[104] = _XtimeE[104]
+Sbox[105] = _Sbox[105]
+InvSbox[105] = _InvSbox[105]
+Xtime2Sbox[105] = _Xtime2Sbox[105]
+Xtime3Sbox[105] = _Xtime3Sbox[105]
+Xtime2[105] = _Xtime2[105]
+Xtime9[105] = _Xtime9[105]
+XtimeB[105] = _XtimeB[105]
+XtimeD[105] = _XtimeD[105]
+XtimeE[105] = _XtimeE[105]
+Sbox[106] = _Sbox[106]
+InvSbox[106] = _InvSbox[106]
+Xtime2Sbox[106] = _Xtime2Sbox[106]
+Xtime3Sbox[106] = _Xtime3Sbox[106]
+Xtime2[106] = _Xtime2[106]
+Xtime9[106] = _Xtime9[106]
+XtimeB[106] = _XtimeB[106]
+XtimeD[106] = _XtimeD[106]
+XtimeE[106] = _XtimeE[106]
+Sbox[107] = _Sbox[107]
+InvSbox[107] = _InvSbox[107]
+Xtime2Sbox[107] = _Xtime2Sbox[107]
+Xtime3Sbox[107] = _Xtime3Sbox[107]
+Xtime2[107] = _Xtime2[107]
+Xtime9[107] = _Xtime9[107]
+XtimeB[107] = _XtimeB[107]
+XtimeD[107] = _XtimeD[107]
+XtimeE[107] = _XtimeE[107]
+Sbox[108] = _Sbox[108]
+InvSbox[108] = _InvSbox[108]
+Xtime2Sbox[108] = _Xtime2Sbox[108]
+Xtime3Sbox[108] = _Xtime3Sbox[108]
+Xtime2[108] = _Xtime2[108]
+Xtime9[108] = _Xtime9[108]
+XtimeB[108] = _XtimeB[108]
+XtimeD[108] = _XtimeD[108]
+XtimeE[108] = _XtimeE[108]
+Sbox[109] = _Sbox[109]
+InvSbox[109] = _InvSbox[109]
+Xtime2Sbox[109] = _Xtime2Sbox[109]
+Xtime3Sbox[109] = _Xtime3Sbox[109]
+Xtime2[109] = _Xtime2[109]
+Xtime9[109] = _Xtime9[109]
+XtimeB[109] = _XtimeB[109]
+XtimeD[109] = _XtimeD[109]
+XtimeE[109] = _XtimeE[109]
+Sbox[110] = _Sbox[110]
+InvSbox[110] = _InvSbox[110]
+Xtime2Sbox[110] = _Xtime2Sbox[110]
+Xtime3Sbox[110] = _Xtime3Sbox[110]
+Xtime2[110] = _Xtime2[110]
+Xtime9[110] = _Xtime9[110]
+XtimeB[110] = _XtimeB[110]
+XtimeD[110] = _XtimeD[110]
+XtimeE[110] = _XtimeE[110]
+Sbox[111] = _Sbox[111]
+InvSbox[111] = _InvSbox[111]
+Xtime2Sbox[111] = _Xtime2Sbox[111]
+Xtime3Sbox[111] = _Xtime3Sbox[111]
+Xtime2[111] = _Xtime2[111]
+Xtime9[111] = _Xtime9[111]
+XtimeB[111] = _XtimeB[111]
+XtimeD[111] = _XtimeD[111]
+XtimeE[111] = _XtimeE[111]
+Sbox[112] = _Sbox[112]
+InvSbox[112] = _InvSbox[112]
+Xtime2Sbox[112] = _Xtime2Sbox[112]
+Xtime3Sbox[112] = _Xtime3Sbox[112]
+Xtime2[112] = _Xtime2[112]
+Xtime9[112] = _Xtime9[112]
+XtimeB[112] = _XtimeB[112]
+XtimeD[112] = _XtimeD[112]
+XtimeE[112] = _XtimeE[112]
+Sbox[113] = _Sbox[113]
+InvSbox[113] = _InvSbox[113]
+Xtime2Sbox[113] = _Xtime2Sbox[113]
+Xtime3Sbox[113] = _Xtime3Sbox[113]
+Xtime2[113] = _Xtime2[113]
+Xtime9[113] = _Xtime9[113]
+XtimeB[113] = _XtimeB[113]
+XtimeD[113] = _XtimeD[113]
+XtimeE[113] = _XtimeE[113]
+Sbox[114] = _Sbox[114]
+InvSbox[114] = _InvSbox[114]
+Xtime2Sbox[114] = _Xtime2Sbox[114]
+Xtime3Sbox[114] = _Xtime3Sbox[114]
+Xtime2[114] = _Xtime2[114]
+Xtime9[114] = _Xtime9[114]
+XtimeB[114] = _XtimeB[114]
+XtimeD[114] = _XtimeD[114]
+XtimeE[114] = _XtimeE[114]
+Sbox[115] = _Sbox[115]
+InvSbox[115] = _InvSbox[115]
+Xtime2Sbox[115] = _Xtime2Sbox[115]
+Xtime3Sbox[115] = _Xtime3Sbox[115]
+Xtime2[115] = _Xtime2[115]
+Xtime9[115] = _Xtime9[115]
+XtimeB[115] = _XtimeB[115]
+XtimeD[115] = _XtimeD[115]
+XtimeE[115] = _XtimeE[115]
+Sbox[116] = _Sbox[116]
+InvSbox[116] = _InvSbox[116]
+Xtime2Sbox[116] = _Xtime2Sbox[116]
+Xtime3Sbox[116] = _Xtime3Sbox[116]
+Xtime2[116] = _Xtime2[116]
+Xtime9[116] = _Xtime9[116]
+XtimeB[116] = _XtimeB[116]
+XtimeD[116] = _XtimeD[116]
+XtimeE[116] = _XtimeE[116]
+Sbox[117] = _Sbox[117]
+InvSbox[117] = _InvSbox[117]
+Xtime2Sbox[117] = _Xtime2Sbox[117]
+Xtime3Sbox[117] = _Xtime3Sbox[117]
+Xtime2[117] = _Xtime2[117]
+Xtime9[117] = _Xtime9[117]
+XtimeB[117] = _XtimeB[117]
+XtimeD[117] = _XtimeD[117]
+XtimeE[117] = _XtimeE[117]
+Sbox[118] = _Sbox[118]
+InvSbox[118] = _InvSbox[118]
+Xtime2Sbox[118] = _Xtime2Sbox[118]
+Xtime3Sbox[118] = _Xtime3Sbox[118]
+Xtime2[118] = _Xtime2[118]
+Xtime9[118] = _Xtime9[118]
+XtimeB[118] = _XtimeB[118]
+XtimeD[118] = _XtimeD[118]
+XtimeE[118] = _XtimeE[118]
+Sbox[119] = _Sbox[119]
+InvSbox[119] = _InvSbox[119]
+Xtime2Sbox[119] = _Xtime2Sbox[119]
+Xtime3Sbox[119] = _Xtime3Sbox[119]
+Xtime2[119] = _Xtime2[119]
+Xtime9[119] = _Xtime9[119]
+XtimeB[119] = _XtimeB[119]
+XtimeD[119] = _XtimeD[119]
+XtimeE[119] = _XtimeE[119]
+Sbox[120] = _Sbox[120]
+InvSbox[120] = _InvSbox[120]
+Xtime2Sbox[120] = _Xtime2Sbox[120]
+Xtime3Sbox[120] = _Xtime3Sbox[120]
+Xtime2[120] = _Xtime2[120]
+Xtime9[120] = _Xtime9[120]
+XtimeB[120] = _XtimeB[120]
+XtimeD[120] = _XtimeD[120]
+XtimeE[120] = _XtimeE[120]
+Sbox[121] = _Sbox[121]
+InvSbox[121] = _InvSbox[121]
+Xtime2Sbox[121] = _Xtime2Sbox[121]
+Xtime3Sbox[121] = _Xtime3Sbox[121]
+Xtime2[121] = _Xtime2[121]
+Xtime9[121] = _Xtime9[121]
+XtimeB[121] = _XtimeB[121]
+XtimeD[121] = _XtimeD[121]
+XtimeE[121] = _XtimeE[121]
+Sbox[122] = _Sbox[122]
+InvSbox[122] = _InvSbox[122]
+Xtime2Sbox[122] = _Xtime2Sbox[122]
+Xtime3Sbox[122] = _Xtime3Sbox[122]
+Xtime2[122] = _Xtime2[122]
+Xtime9[122] = _Xtime9[122]
+XtimeB[122] = _XtimeB[122]
+XtimeD[122] = _XtimeD[122]
+XtimeE[122] = _XtimeE[122]
+Sbox[123] = _Sbox[123]
+InvSbox[123] = _InvSbox[123]
+Xtime2Sbox[123] = _Xtime2Sbox[123]
+Xtime3Sbox[123] = _Xtime3Sbox[123]
+Xtime2[123] = _Xtime2[123]
+Xtime9[123] = _Xtime9[123]
+XtimeB[123] = _XtimeB[123]
+XtimeD[123] = _XtimeD[123]
+XtimeE[123] = _XtimeE[123]
+Sbox[124] = _Sbox[124]
+InvSbox[124] = _InvSbox[124]
+Xtime2Sbox[124] = _Xtime2Sbox[124]
+Xtime3Sbox[124] = _Xtime3Sbox[124]
+Xtime2[124] = _Xtime2[124]
+Xtime9[124] = _Xtime9[124]
+XtimeB[124] = _XtimeB[124]
+XtimeD[124] = _XtimeD[124]
+XtimeE[124] = _XtimeE[124]
+Sbox[125] = _Sbox[125]
+InvSbox[125] = _InvSbox[125]
+Xtime2Sbox[125] = _Xtime2Sbox[125]
+Xtime3Sbox[125] = _Xtime3Sbox[125]
+Xtime2[125] = _Xtime2[125]
+Xtime9[125] = _Xtime9[125]
+XtimeB[125] = _XtimeB[125]
+XtimeD[125] = _XtimeD[125]
+XtimeE[125] = _XtimeE[125]
+Sbox[126] = _Sbox[126]
+InvSbox[126] = _InvSbox[126]
+Xtime2Sbox[126] = _Xtime2Sbox[126]
+Xtime3Sbox[126] = _Xtime3Sbox[126]
+Xtime2[126] = _Xtime2[126]
+Xtime9[126] = _Xtime9[126]
+XtimeB[126] = _XtimeB[126]
+XtimeD[126] = _XtimeD[126]
+XtimeE[126] = _XtimeE[126]
+Sbox[127] = _Sbox[127]
+InvSbox[127] = _InvSbox[127]
+Xtime2Sbox[127] = _Xtime2Sbox[127]
+Xtime3Sbox[127] = _Xtime3Sbox[127]
+Xtime2[127] = _Xtime2[127]
+Xtime9[127] = _Xtime9[127]
+XtimeB[127] = _XtimeB[127]
+XtimeD[127] = _XtimeD[127]
+XtimeE[127] = _XtimeE[127]
+Sbox[128] = _Sbox[128]
+InvSbox[128] = _InvSbox[128]
+Xtime2Sbox[128] = _Xtime2Sbox[128]
+Xtime3Sbox[128] = _Xtime3Sbox[128]
+Xtime2[128] = _Xtime2[128]
+Xtime9[128] = _Xtime9[128]
+XtimeB[128] = _XtimeB[128]
+XtimeD[128] = _XtimeD[128]
+XtimeE[128] = _XtimeE[128]
+Sbox[129] = _Sbox[129]
+InvSbox[129] = _InvSbox[129]
+Xtime2Sbox[129] = _Xtime2Sbox[129]
+Xtime3Sbox[129] = _Xtime3Sbox[129]
+Xtime2[129] = _Xtime2[129]
+Xtime9[129] = _Xtime9[129]
+XtimeB[129] = _XtimeB[129]
+XtimeD[129] = _XtimeD[129]
+XtimeE[129] = _XtimeE[129]
+Sbox[130] = _Sbox[130]
+InvSbox[130] = _InvSbox[130]
+Xtime2Sbox[130] = _Xtime2Sbox[130]
+Xtime3Sbox[130] = _Xtime3Sbox[130]
+Xtime2[130] = _Xtime2[130]
+Xtime9[130] = _Xtime9[130]
+XtimeB[130] = _XtimeB[130]
+XtimeD[130] = _XtimeD[130]
+XtimeE[130] = _XtimeE[130]
+Sbox[131] = _Sbox[131]
+InvSbox[131] = _InvSbox[131]
+Xtime2Sbox[131] = _Xtime2Sbox[131]
+Xtime3Sbox[131] = _Xtime3Sbox[131]
+Xtime2[131] = _Xtime2[131]
+Xtime9[131] = _Xtime9[131]
+XtimeB[131] = _XtimeB[131]
+XtimeD[131] = _XtimeD[131]
+XtimeE[131] = _XtimeE[131]
+Sbox[132] = _Sbox[132]
+InvSbox[132] = _InvSbox[132]
+Xtime2Sbox[132] = _Xtime2Sbox[132]
+Xtime3Sbox[132] = _Xtime3Sbox[132]
+Xtime2[132] = _Xtime2[132]
+Xtime9[132] = _Xtime9[132]
+XtimeB[132] = _XtimeB[132]
+XtimeD[132] = _XtimeD[132]
+XtimeE[132] = _XtimeE[132]
+Sbox[133] = _Sbox[133]
+InvSbox[133] = _InvSbox[133]
+Xtime2Sbox[133] = _Xtime2Sbox[133]
+Xtime3Sbox[133] = _Xtime3Sbox[133]
+Xtime2[133] = _Xtime2[133]
+Xtime9[133] = _Xtime9[133]
+XtimeB[133] = _XtimeB[133]
+XtimeD[133] = _XtimeD[133]
+XtimeE[133] = _XtimeE[133]
+Sbox[134] = _Sbox[134]
+InvSbox[134] = _InvSbox[134]
+Xtime2Sbox[134] = _Xtime2Sbox[134]
+Xtime3Sbox[134] = _Xtime3Sbox[134]
+Xtime2[134] = _Xtime2[134]
+Xtime9[134] = _Xtime9[134]
+XtimeB[134] = _XtimeB[134]
+XtimeD[134] = _XtimeD[134]
+XtimeE[134] = _XtimeE[134]
+Sbox[135] = _Sbox[135]
+InvSbox[135] = _InvSbox[135]
+Xtime2Sbox[135] = _Xtime2Sbox[135]
+Xtime3Sbox[135] = _Xtime3Sbox[135]
+Xtime2[135] = _Xtime2[135]
+Xtime9[135] = _Xtime9[135]
+XtimeB[135] = _XtimeB[135]
+XtimeD[135] = _XtimeD[135]
+XtimeE[135] = _XtimeE[135]
+Sbox[136] = _Sbox[136]
+InvSbox[136] = _InvSbox[136]
+Xtime2Sbox[136] = _Xtime2Sbox[136]
+Xtime3Sbox[136] = _Xtime3Sbox[136]
+Xtime2[136] = _Xtime2[136]
+Xtime9[136] = _Xtime9[136]
+XtimeB[136] = _XtimeB[136]
+XtimeD[136] = _XtimeD[136]
+XtimeE[136] = _XtimeE[136]
+Sbox[137] = _Sbox[137]
+InvSbox[137] = _InvSbox[137]
+Xtime2Sbox[137] = _Xtime2Sbox[137]
+Xtime3Sbox[137] = _Xtime3Sbox[137]
+Xtime2[137] = _Xtime2[137]
+Xtime9[137] = _Xtime9[137]
+XtimeB[137] = _XtimeB[137]
+XtimeD[137] = _XtimeD[137]
+XtimeE[137] = _XtimeE[137]
+Sbox[138] = _Sbox[138]
+InvSbox[138] = _InvSbox[138]
+Xtime2Sbox[138] = _Xtime2Sbox[138]
+Xtime3Sbox[138] = _Xtime3Sbox[138]
+Xtime2[138] = _Xtime2[138]
+Xtime9[138] = _Xtime9[138]
+XtimeB[138] = _XtimeB[138]
+XtimeD[138] = _XtimeD[138]
+XtimeE[138] = _XtimeE[138]
+Sbox[139] = _Sbox[139]
+InvSbox[139] = _InvSbox[139]
+Xtime2Sbox[139] = _Xtime2Sbox[139]
+Xtime3Sbox[139] = _Xtime3Sbox[139]
+Xtime2[139] = _Xtime2[139]
+Xtime9[139] = _Xtime9[139]
+XtimeB[139] = _XtimeB[139]
+XtimeD[139] = _XtimeD[139]
+XtimeE[139] = _XtimeE[139]
+Sbox[140] = _Sbox[140]
+InvSbox[140] = _InvSbox[140]
+Xtime2Sbox[140] = _Xtime2Sbox[140]
+Xtime3Sbox[140] = _Xtime3Sbox[140]
+Xtime2[140] = _Xtime2[140]
+Xtime9[140] = _Xtime9[140]
+XtimeB[140] = _XtimeB[140]
+XtimeD[140] = _XtimeD[140]
+XtimeE[140] = _XtimeE[140]
+Sbox[141] = _Sbox[141]
+InvSbox[141] = _InvSbox[141]
+Xtime2Sbox[141] = _Xtime2Sbox[141]
+Xtime3Sbox[141] = _Xtime3Sbox[141]
+Xtime2[141] = _Xtime2[141]
+Xtime9[141] = _Xtime9[141]
+XtimeB[141] = _XtimeB[141]
+XtimeD[141] = _XtimeD[141]
+XtimeE[141] = _XtimeE[141]
+Sbox[142] = _Sbox[142]
+InvSbox[142] = _InvSbox[142]
+Xtime2Sbox[142] = _Xtime2Sbox[142]
+Xtime3Sbox[142] = _Xtime3Sbox[142]
+Xtime2[142] = _Xtime2[142]
+Xtime9[142] = _Xtime9[142]
+XtimeB[142] = _XtimeB[142]
+XtimeD[142] = _XtimeD[142]
+XtimeE[142] = _XtimeE[142]
+Sbox[143] = _Sbox[143]
+InvSbox[143] = _InvSbox[143]
+Xtime2Sbox[143] = _Xtime2Sbox[143]
+Xtime3Sbox[143] = _Xtime3Sbox[143]
+Xtime2[143] = _Xtime2[143]
+Xtime9[143] = _Xtime9[143]
+XtimeB[143] = _XtimeB[143]
+XtimeD[143] = _XtimeD[143]
+XtimeE[143] = _XtimeE[143]
+Sbox[144] = _Sbox[144]
+InvSbox[144] = _InvSbox[144]
+Xtime2Sbox[144] = _Xtime2Sbox[144]
+Xtime3Sbox[144] = _Xtime3Sbox[144]
+Xtime2[144] = _Xtime2[144]
+Xtime9[144] = _Xtime9[144]
+XtimeB[144] = _XtimeB[144]
+XtimeD[144] = _XtimeD[144]
+XtimeE[144] = _XtimeE[144]
+Sbox[145] = _Sbox[145]
+InvSbox[145] = _InvSbox[145]
+Xtime2Sbox[145] = _Xtime2Sbox[145]
+Xtime3Sbox[145] = _Xtime3Sbox[145]
+Xtime2[145] = _Xtime2[145]
+Xtime9[145] = _Xtime9[145]
+XtimeB[145] = _XtimeB[145]
+XtimeD[145] = _XtimeD[145]
+XtimeE[145] = _XtimeE[145]
+Sbox[146] = _Sbox[146]
+InvSbox[146] = _InvSbox[146]
+Xtime2Sbox[146] = _Xtime2Sbox[146]
+Xtime3Sbox[146] = _Xtime3Sbox[146]
+Xtime2[146] = _Xtime2[146]
+Xtime9[146] = _Xtime9[146]
+XtimeB[146] = _XtimeB[146]
+XtimeD[146] = _XtimeD[146]
+XtimeE[146] = _XtimeE[146]
+Sbox[147] = _Sbox[147]
+InvSbox[147] = _InvSbox[147]
+Xtime2Sbox[147] = _Xtime2Sbox[147]
+Xtime3Sbox[147] = _Xtime3Sbox[147]
+Xtime2[147] = _Xtime2[147]
+Xtime9[147] = _Xtime9[147]
+XtimeB[147] = _XtimeB[147]
+XtimeD[147] = _XtimeD[147]
+XtimeE[147] = _XtimeE[147]
+Sbox[148] = _Sbox[148]
+InvSbox[148] = _InvSbox[148]
+Xtime2Sbox[148] = _Xtime2Sbox[148]
+Xtime3Sbox[148] = _Xtime3Sbox[148]
+Xtime2[148] = _Xtime2[148]
+Xtime9[148] = _Xtime9[148]
+XtimeB[148] = _XtimeB[148]
+XtimeD[148] = _XtimeD[148]
+XtimeE[148] = _XtimeE[148]
+Sbox[149] = _Sbox[149]
+InvSbox[149] = _InvSbox[149]
+Xtime2Sbox[149] = _Xtime2Sbox[149]
+Xtime3Sbox[149] = _Xtime3Sbox[149]
+Xtime2[149] = _Xtime2[149]
+Xtime9[149] = _Xtime9[149]
+XtimeB[149] = _XtimeB[149]
+XtimeD[149] = _XtimeD[149]
+XtimeE[149] = _XtimeE[149]
+Sbox[150] = _Sbox[150]
+InvSbox[150] = _InvSbox[150]
+Xtime2Sbox[150] = _Xtime2Sbox[150]
+Xtime3Sbox[150] = _Xtime3Sbox[150]
+Xtime2[150] = _Xtime2[150]
+Xtime9[150] = _Xtime9[150]
+XtimeB[150] = _XtimeB[150]
+XtimeD[150] = _XtimeD[150]
+XtimeE[150] = _XtimeE[150]
+Sbox[151] = _Sbox[151]
+InvSbox[151] = _InvSbox[151]
+Xtime2Sbox[151] = _Xtime2Sbox[151]
+Xtime3Sbox[151] = _Xtime3Sbox[151]
+Xtime2[151] = _Xtime2[151]
+Xtime9[151] = _Xtime9[151]
+XtimeB[151] = _XtimeB[151]
+XtimeD[151] = _XtimeD[151]
+XtimeE[151] = _XtimeE[151]
+Sbox[152] = _Sbox[152]
+InvSbox[152] = _InvSbox[152]
+Xtime2Sbox[152] = _Xtime2Sbox[152]
+Xtime3Sbox[152] = _Xtime3Sbox[152]
+Xtime2[152] = _Xtime2[152]
+Xtime9[152] = _Xtime9[152]
+XtimeB[152] = _XtimeB[152]
+XtimeD[152] = _XtimeD[152]
+XtimeE[152] = _XtimeE[152]
+Sbox[153] = _Sbox[153]
+InvSbox[153] = _InvSbox[153]
+Xtime2Sbox[153] = _Xtime2Sbox[153]
+Xtime3Sbox[153] = _Xtime3Sbox[153]
+Xtime2[153] = _Xtime2[153]
+Xtime9[153] = _Xtime9[153]
+XtimeB[153] = _XtimeB[153]
+XtimeD[153] = _XtimeD[153]
+XtimeE[153] = _XtimeE[153]
+Sbox[154] = _Sbox[154]
+InvSbox[154] = _InvSbox[154]
+Xtime2Sbox[154] = _Xtime2Sbox[154]
+Xtime3Sbox[154] = _Xtime3Sbox[154]
+Xtime2[154] = _Xtime2[154]
+Xtime9[154] = _Xtime9[154]
+XtimeB[154] = _XtimeB[154]
+XtimeD[154] = _XtimeD[154]
+XtimeE[154] = _XtimeE[154]
+Sbox[155] = _Sbox[155]
+InvSbox[155] = _InvSbox[155]
+Xtime2Sbox[155] = _Xtime2Sbox[155]
+Xtime3Sbox[155] = _Xtime3Sbox[155]
+Xtime2[155] = _Xtime2[155]
+Xtime9[155] = _Xtime9[155]
+XtimeB[155] = _XtimeB[155]
+XtimeD[155] = _XtimeD[155]
+XtimeE[155] = _XtimeE[155]
+Sbox[156] = _Sbox[156]
+InvSbox[156] = _InvSbox[156]
+Xtime2Sbox[156] = _Xtime2Sbox[156]
+Xtime3Sbox[156] = _Xtime3Sbox[156]
+Xtime2[156] = _Xtime2[156]
+Xtime9[156] = _Xtime9[156]
+XtimeB[156] = _XtimeB[156]
+XtimeD[156] = _XtimeD[156]
+XtimeE[156] = _XtimeE[156]
+Sbox[157] = _Sbox[157]
+InvSbox[157] = _InvSbox[157]
+Xtime2Sbox[157] = _Xtime2Sbox[157]
+Xtime3Sbox[157] = _Xtime3Sbox[157]
+Xtime2[157] = _Xtime2[157]
+Xtime9[157] = _Xtime9[157]
+XtimeB[157] = _XtimeB[157]
+XtimeD[157] = _XtimeD[157]
+XtimeE[157] = _XtimeE[157]
+Sbox[158] = _Sbox[158]
+InvSbox[158] = _InvSbox[158]
+Xtime2Sbox[158] = _Xtime2Sbox[158]
+Xtime3Sbox[158] = _Xtime3Sbox[158]
+Xtime2[158] = _Xtime2[158]
+Xtime9[158] = _Xtime9[158]
+XtimeB[158] = _XtimeB[158]
+XtimeD[158] = _XtimeD[158]
+XtimeE[158] = _XtimeE[158]
+Sbox[159] = _Sbox[159]
+InvSbox[159] = _InvSbox[159]
+Xtime2Sbox[159] = _Xtime2Sbox[159]
+Xtime3Sbox[159] = _Xtime3Sbox[159]
+Xtime2[159] = _Xtime2[159]
+Xtime9[159] = _Xtime9[159]
+XtimeB[159] = _XtimeB[159]
+XtimeD[159] = _XtimeD[159]
+XtimeE[159] = _XtimeE[159]
+Sbox[160] = _Sbox[160]
+InvSbox[160] = _InvSbox[160]
+Xtime2Sbox[160] = _Xtime2Sbox[160]
+Xtime3Sbox[160] = _Xtime3Sbox[160]
+Xtime2[160] = _Xtime2[160]
+Xtime9[160] = _Xtime9[160]
+XtimeB[160] = _XtimeB[160]
+XtimeD[160] = _XtimeD[160]
+XtimeE[160] = _XtimeE[160]
+Sbox[161] = _Sbox[161]
+InvSbox[161] = _InvSbox[161]
+Xtime2Sbox[161] = _Xtime2Sbox[161]
+Xtime3Sbox[161] = _Xtime3Sbox[161]
+Xtime2[161] = _Xtime2[161]
+Xtime9[161] = _Xtime9[161]
+XtimeB[161] = _XtimeB[161]
+XtimeD[161] = _XtimeD[161]
+XtimeE[161] = _XtimeE[161]
+Sbox[162] = _Sbox[162]
+InvSbox[162] = _InvSbox[162]
+Xtime2Sbox[162] = _Xtime2Sbox[162]
+Xtime3Sbox[162] = _Xtime3Sbox[162]
+Xtime2[162] = _Xtime2[162]
+Xtime9[162] = _Xtime9[162]
+XtimeB[162] = _XtimeB[162]
+XtimeD[162] = _XtimeD[162]
+XtimeE[162] = _XtimeE[162]
+Sbox[163] = _Sbox[163]
+InvSbox[163] = _InvSbox[163]
+Xtime2Sbox[163] = _Xtime2Sbox[163]
+Xtime3Sbox[163] = _Xtime3Sbox[163]
+Xtime2[163] = _Xtime2[163]
+Xtime9[163] = _Xtime9[163]
+XtimeB[163] = _XtimeB[163]
+XtimeD[163] = _XtimeD[163]
+XtimeE[163] = _XtimeE[163]
+Sbox[164] = _Sbox[164]
+InvSbox[164] = _InvSbox[164]
+Xtime2Sbox[164] = _Xtime2Sbox[164]
+Xtime3Sbox[164] = _Xtime3Sbox[164]
+Xtime2[164] = _Xtime2[164]
+Xtime9[164] = _Xtime9[164]
+XtimeB[164] = _XtimeB[164]
+XtimeD[164] = _XtimeD[164]
+XtimeE[164] = _XtimeE[164]
+Sbox[165] = _Sbox[165]
+InvSbox[165] = _InvSbox[165]
+Xtime2Sbox[165] = _Xtime2Sbox[165]
+Xtime3Sbox[165] = _Xtime3Sbox[165]
+Xtime2[165] = _Xtime2[165]
+Xtime9[165] = _Xtime9[165]
+XtimeB[165] = _XtimeB[165]
+XtimeD[165] = _XtimeD[165]
+XtimeE[165] = _XtimeE[165]
+Sbox[166] = _Sbox[166]
+InvSbox[166] = _InvSbox[166]
+Xtime2Sbox[166] = _Xtime2Sbox[166]
+Xtime3Sbox[166] = _Xtime3Sbox[166]
+Xtime2[166] = _Xtime2[166]
+Xtime9[166] = _Xtime9[166]
+XtimeB[166] = _XtimeB[166]
+XtimeD[166] = _XtimeD[166]
+XtimeE[166] = _XtimeE[166]
+Sbox[167] = _Sbox[167]
+InvSbox[167] = _InvSbox[167]
+Xtime2Sbox[167] = _Xtime2Sbox[167]
+Xtime3Sbox[167] = _Xtime3Sbox[167]
+Xtime2[167] = _Xtime2[167]
+Xtime9[167] = _Xtime9[167]
+XtimeB[167] = _XtimeB[167]
+XtimeD[167] = _XtimeD[167]
+XtimeE[167] = _XtimeE[167]
+Sbox[168] = _Sbox[168]
+InvSbox[168] = _InvSbox[168]
+Xtime2Sbox[168] = _Xtime2Sbox[168]
+Xtime3Sbox[168] = _Xtime3Sbox[168]
+Xtime2[168] = _Xtime2[168]
+Xtime9[168] = _Xtime9[168]
+XtimeB[168] = _XtimeB[168]
+XtimeD[168] = _XtimeD[168]
+XtimeE[168] = _XtimeE[168]
+Sbox[169] = _Sbox[169]
+InvSbox[169] = _InvSbox[169]
+Xtime2Sbox[169] = _Xtime2Sbox[169]
+Xtime3Sbox[169] = _Xtime3Sbox[169]
+Xtime2[169] = _Xtime2[169]
+Xtime9[169] = _Xtime9[169]
+XtimeB[169] = _XtimeB[169]
+XtimeD[169] = _XtimeD[169]
+XtimeE[169] = _XtimeE[169]
+Sbox[170] = _Sbox[170]
+InvSbox[170] = _InvSbox[170]
+Xtime2Sbox[170] = _Xtime2Sbox[170]
+Xtime3Sbox[170] = _Xtime3Sbox[170]
+Xtime2[170] = _Xtime2[170]
+Xtime9[170] = _Xtime9[170]
+XtimeB[170] = _XtimeB[170]
+XtimeD[170] = _XtimeD[170]
+XtimeE[170] = _XtimeE[170]
+Sbox[171] = _Sbox[171]
+InvSbox[171] = _InvSbox[171]
+Xtime2Sbox[171] = _Xtime2Sbox[171]
+Xtime3Sbox[171] = _Xtime3Sbox[171]
+Xtime2[171] = _Xtime2[171]
+Xtime9[171] = _Xtime9[171]
+XtimeB[171] = _XtimeB[171]
+XtimeD[171] = _XtimeD[171]
+XtimeE[171] = _XtimeE[171]
+Sbox[172] = _Sbox[172]
+InvSbox[172] = _InvSbox[172]
+Xtime2Sbox[172] = _Xtime2Sbox[172]
+Xtime3Sbox[172] = _Xtime3Sbox[172]
+Xtime2[172] = _Xtime2[172]
+Xtime9[172] = _Xtime9[172]
+XtimeB[172] = _XtimeB[172]
+XtimeD[172] = _XtimeD[172]
+XtimeE[172] = _XtimeE[172]
+Sbox[173] = _Sbox[173]
+InvSbox[173] = _InvSbox[173]
+Xtime2Sbox[173] = _Xtime2Sbox[173]
+Xtime3Sbox[173] = _Xtime3Sbox[173]
+Xtime2[173] = _Xtime2[173]
+Xtime9[173] = _Xtime9[173]
+XtimeB[173] = _XtimeB[173]
+XtimeD[173] = _XtimeD[173]
+XtimeE[173] = _XtimeE[173]
+Sbox[174] = _Sbox[174]
+InvSbox[174] = _InvSbox[174]
+Xtime2Sbox[174] = _Xtime2Sbox[174]
+Xtime3Sbox[174] = _Xtime3Sbox[174]
+Xtime2[174] = _Xtime2[174]
+Xtime9[174] = _Xtime9[174]
+XtimeB[174] = _XtimeB[174]
+XtimeD[174] = _XtimeD[174]
+XtimeE[174] = _XtimeE[174]
+Sbox[175] = _Sbox[175]
+InvSbox[175] = _InvSbox[175]
+Xtime2Sbox[175] = _Xtime2Sbox[175]
+Xtime3Sbox[175] = _Xtime3Sbox[175]
+Xtime2[175] = _Xtime2[175]
+Xtime9[175] = _Xtime9[175]
+XtimeB[175] = _XtimeB[175]
+XtimeD[175] = _XtimeD[175]
+XtimeE[175] = _XtimeE[175]
+Sbox[176] = _Sbox[176]
+InvSbox[176] = _InvSbox[176]
+Xtime2Sbox[176] = _Xtime2Sbox[176]
+Xtime3Sbox[176] = _Xtime3Sbox[176]
+Xtime2[176] = _Xtime2[176]
+Xtime9[176] = _Xtime9[176]
+XtimeB[176] = _XtimeB[176]
+XtimeD[176] = _XtimeD[176]
+XtimeE[176] = _XtimeE[176]
+Sbox[177] = _Sbox[177]
+InvSbox[177] = _InvSbox[177]
+Xtime2Sbox[177] = _Xtime2Sbox[177]
+Xtime3Sbox[177] = _Xtime3Sbox[177]
+Xtime2[177] = _Xtime2[177]
+Xtime9[177] = _Xtime9[177]
+XtimeB[177] = _XtimeB[177]
+XtimeD[177] = _XtimeD[177]
+XtimeE[177] = _XtimeE[177]
+Sbox[178] = _Sbox[178]
+InvSbox[178] = _InvSbox[178]
+Xtime2Sbox[178] = _Xtime2Sbox[178]
+Xtime3Sbox[178] = _Xtime3Sbox[178]
+Xtime2[178] = _Xtime2[178]
+Xtime9[178] = _Xtime9[178]
+XtimeB[178] = _XtimeB[178]
+XtimeD[178] = _XtimeD[178]
+XtimeE[178] = _XtimeE[178]
+Sbox[179] = _Sbox[179]
+InvSbox[179] = _InvSbox[179]
+Xtime2Sbox[179] = _Xtime2Sbox[179]
+Xtime3Sbox[179] = _Xtime3Sbox[179]
+Xtime2[179] = _Xtime2[179]
+Xtime9[179] = _Xtime9[179]
+XtimeB[179] = _XtimeB[179]
+XtimeD[179] = _XtimeD[179]
+XtimeE[179] = _XtimeE[179]
+Sbox[180] = _Sbox[180]
+InvSbox[180] = _InvSbox[180]
+Xtime2Sbox[180] = _Xtime2Sbox[180]
+Xtime3Sbox[180] = _Xtime3Sbox[180]
+Xtime2[180] = _Xtime2[180]
+Xtime9[180] = _Xtime9[180]
+XtimeB[180] = _XtimeB[180]
+XtimeD[180] = _XtimeD[180]
+XtimeE[180] = _XtimeE[180]
+Sbox[181] = _Sbox[181]
+InvSbox[181] = _InvSbox[181]
+Xtime2Sbox[181] = _Xtime2Sbox[181]
+Xtime3Sbox[181] = _Xtime3Sbox[181]
+Xtime2[181] = _Xtime2[181]
+Xtime9[181] = _Xtime9[181]
+XtimeB[181] = _XtimeB[181]
+XtimeD[181] = _XtimeD[181]
+XtimeE[181] = _XtimeE[181]
+Sbox[182] = _Sbox[182]
+InvSbox[182] = _InvSbox[182]
+Xtime2Sbox[182] = _Xtime2Sbox[182]
+Xtime3Sbox[182] = _Xtime3Sbox[182]
+Xtime2[182] = _Xtime2[182]
+Xtime9[182] = _Xtime9[182]
+XtimeB[182] = _XtimeB[182]
+XtimeD[182] = _XtimeD[182]
+XtimeE[182] = _XtimeE[182]
+Sbox[183] = _Sbox[183]
+InvSbox[183] = _InvSbox[183]
+Xtime2Sbox[183] = _Xtime2Sbox[183]
+Xtime3Sbox[183] = _Xtime3Sbox[183]
+Xtime2[183] = _Xtime2[183]
+Xtime9[183] = _Xtime9[183]
+XtimeB[183] = _XtimeB[183]
+XtimeD[183] = _XtimeD[183]
+XtimeE[183] = _XtimeE[183]
+Sbox[184] = _Sbox[184]
+InvSbox[184] = _InvSbox[184]
+Xtime2Sbox[184] = _Xtime2Sbox[184]
+Xtime3Sbox[184] = _Xtime3Sbox[184]
+Xtime2[184] = _Xtime2[184]
+Xtime9[184] = _Xtime9[184]
+XtimeB[184] = _XtimeB[184]
+XtimeD[184] = _XtimeD[184]
+XtimeE[184] = _XtimeE[184]
+Sbox[185] = _Sbox[185]
+InvSbox[185] = _InvSbox[185]
+Xtime2Sbox[185] = _Xtime2Sbox[185]
+Xtime3Sbox[185] = _Xtime3Sbox[185]
+Xtime2[185] = _Xtime2[185]
+Xtime9[185] = _Xtime9[185]
+XtimeB[185] = _XtimeB[185]
+XtimeD[185] = _XtimeD[185]
+XtimeE[185] = _XtimeE[185]
+Sbox[186] = _Sbox[186]
+InvSbox[186] = _InvSbox[186]
+Xtime2Sbox[186] = _Xtime2Sbox[186]
+Xtime3Sbox[186] = _Xtime3Sbox[186]
+Xtime2[186] = _Xtime2[186]
+Xtime9[186] = _Xtime9[186]
+XtimeB[186] = _XtimeB[186]
+XtimeD[186] = _XtimeD[186]
+XtimeE[186] = _XtimeE[186]
+Sbox[187] = _Sbox[187]
+InvSbox[187] = _InvSbox[187]
+Xtime2Sbox[187] = _Xtime2Sbox[187]
+Xtime3Sbox[187] = _Xtime3Sbox[187]
+Xtime2[187] = _Xtime2[187]
+Xtime9[187] = _Xtime9[187]
+XtimeB[187] = _XtimeB[187]
+XtimeD[187] = _XtimeD[187]
+XtimeE[187] = _XtimeE[187]
+Sbox[188] = _Sbox[188]
+InvSbox[188] = _InvSbox[188]
+Xtime2Sbox[188] = _Xtime2Sbox[188]
+Xtime3Sbox[188] = _Xtime3Sbox[188]
+Xtime2[188] = _Xtime2[188]
+Xtime9[188] = _Xtime9[188]
+XtimeB[188] = _XtimeB[188]
+XtimeD[188] = _XtimeD[188]
+XtimeE[188] = _XtimeE[188]
+Sbox[189] = _Sbox[189]
+InvSbox[189] = _InvSbox[189]
+Xtime2Sbox[189] = _Xtime2Sbox[189]
+Xtime3Sbox[189] = _Xtime3Sbox[189]
+Xtime2[189] = _Xtime2[189]
+Xtime9[189] = _Xtime9[189]
+XtimeB[189] = _XtimeB[189]
+XtimeD[189] = _XtimeD[189]
+XtimeE[189] = _XtimeE[189]
+Sbox[190] = _Sbox[190]
+InvSbox[190] = _InvSbox[190]
+Xtime2Sbox[190] = _Xtime2Sbox[190]
+Xtime3Sbox[190] = _Xtime3Sbox[190]
+Xtime2[190] = _Xtime2[190]
+Xtime9[190] = _Xtime9[190]
+XtimeB[190] = _XtimeB[190]
+XtimeD[190] = _XtimeD[190]
+XtimeE[190] = _XtimeE[190]
+Sbox[191] = _Sbox[191]
+InvSbox[191] = _InvSbox[191]
+Xtime2Sbox[191] = _Xtime2Sbox[191]
+Xtime3Sbox[191] = _Xtime3Sbox[191]
+Xtime2[191] = _Xtime2[191]
+Xtime9[191] = _Xtime9[191]
+XtimeB[191] = _XtimeB[191]
+XtimeD[191] = _XtimeD[191]
+XtimeE[191] = _XtimeE[191]
+Sbox[192] = _Sbox[192]
+InvSbox[192] = _InvSbox[192]
+Xtime2Sbox[192] = _Xtime2Sbox[192]
+Xtime3Sbox[192] = _Xtime3Sbox[192]
+Xtime2[192] = _Xtime2[192]
+Xtime9[192] = _Xtime9[192]
+XtimeB[192] = _XtimeB[192]
+XtimeD[192] = _XtimeD[192]
+XtimeE[192] = _XtimeE[192]
+Sbox[193] = _Sbox[193]
+InvSbox[193] = _InvSbox[193]
+Xtime2Sbox[193] = _Xtime2Sbox[193]
+Xtime3Sbox[193] = _Xtime3Sbox[193]
+Xtime2[193] = _Xtime2[193]
+Xtime9[193] = _Xtime9[193]
+XtimeB[193] = _XtimeB[193]
+XtimeD[193] = _XtimeD[193]
+XtimeE[193] = _XtimeE[193]
+Sbox[194] = _Sbox[194]
+InvSbox[194] = _InvSbox[194]
+Xtime2Sbox[194] = _Xtime2Sbox[194]
+Xtime3Sbox[194] = _Xtime3Sbox[194]
+Xtime2[194] = _Xtime2[194]
+Xtime9[194] = _Xtime9[194]
+XtimeB[194] = _XtimeB[194]
+XtimeD[194] = _XtimeD[194]
+XtimeE[194] = _XtimeE[194]
+Sbox[195] = _Sbox[195]
+InvSbox[195] = _InvSbox[195]
+Xtime2Sbox[195] = _Xtime2Sbox[195]
+Xtime3Sbox[195] = _Xtime3Sbox[195]
+Xtime2[195] = _Xtime2[195]
+Xtime9[195] = _Xtime9[195]
+XtimeB[195] = _XtimeB[195]
+XtimeD[195] = _XtimeD[195]
+XtimeE[195] = _XtimeE[195]
+Sbox[196] = _Sbox[196]
+InvSbox[196] = _InvSbox[196]
+Xtime2Sbox[196] = _Xtime2Sbox[196]
+Xtime3Sbox[196] = _Xtime3Sbox[196]
+Xtime2[196] = _Xtime2[196]
+Xtime9[196] = _Xtime9[196]
+XtimeB[196] = _XtimeB[196]
+XtimeD[196] = _XtimeD[196]
+XtimeE[196] = _XtimeE[196]
+Sbox[197] = _Sbox[197]
+InvSbox[197] = _InvSbox[197]
+Xtime2Sbox[197] = _Xtime2Sbox[197]
+Xtime3Sbox[197] = _Xtime3Sbox[197]
+Xtime2[197] = _Xtime2[197]
+Xtime9[197] = _Xtime9[197]
+XtimeB[197] = _XtimeB[197]
+XtimeD[197] = _XtimeD[197]
+XtimeE[197] = _XtimeE[197]
+Sbox[198] = _Sbox[198]
+InvSbox[198] = _InvSbox[198]
+Xtime2Sbox[198] = _Xtime2Sbox[198]
+Xtime3Sbox[198] = _Xtime3Sbox[198]
+Xtime2[198] = _Xtime2[198]
+Xtime9[198] = _Xtime9[198]
+XtimeB[198] = _XtimeB[198]
+XtimeD[198] = _XtimeD[198]
+XtimeE[198] = _XtimeE[198]
+Sbox[199] = _Sbox[199]
+InvSbox[199] = _InvSbox[199]
+Xtime2Sbox[199] = _Xtime2Sbox[199]
+Xtime3Sbox[199] = _Xtime3Sbox[199]
+Xtime2[199] = _Xtime2[199]
+Xtime9[199] = _Xtime9[199]
+XtimeB[199] = _XtimeB[199]
+XtimeD[199] = _XtimeD[199]
+XtimeE[199] = _XtimeE[199]
+Sbox[200] = _Sbox[200]
+InvSbox[200] = _InvSbox[200]
+Xtime2Sbox[200] = _Xtime2Sbox[200]
+Xtime3Sbox[200] = _Xtime3Sbox[200]
+Xtime2[200] = _Xtime2[200]
+Xtime9[200] = _Xtime9[200]
+XtimeB[200] = _XtimeB[200]
+XtimeD[200] = _XtimeD[200]
+XtimeE[200] = _XtimeE[200]
+Sbox[201] = _Sbox[201]
+InvSbox[201] = _InvSbox[201]
+Xtime2Sbox[201] = _Xtime2Sbox[201]
+Xtime3Sbox[201] = _Xtime3Sbox[201]
+Xtime2[201] = _Xtime2[201]
+Xtime9[201] = _Xtime9[201]
+XtimeB[201] = _XtimeB[201]
+XtimeD[201] = _XtimeD[201]
+XtimeE[201] = _XtimeE[201]
+Sbox[202] = _Sbox[202]
+InvSbox[202] = _InvSbox[202]
+Xtime2Sbox[202] = _Xtime2Sbox[202]
+Xtime3Sbox[202] = _Xtime3Sbox[202]
+Xtime2[202] = _Xtime2[202]
+Xtime9[202] = _Xtime9[202]
+XtimeB[202] = _XtimeB[202]
+XtimeD[202] = _XtimeD[202]
+XtimeE[202] = _XtimeE[202]
+Sbox[203] = _Sbox[203]
+InvSbox[203] = _InvSbox[203]
+Xtime2Sbox[203] = _Xtime2Sbox[203]
+Xtime3Sbox[203] = _Xtime3Sbox[203]
+Xtime2[203] = _Xtime2[203]
+Xtime9[203] = _Xtime9[203]
+XtimeB[203] = _XtimeB[203]
+XtimeD[203] = _XtimeD[203]
+XtimeE[203] = _XtimeE[203]
+Sbox[204] = _Sbox[204]
+InvSbox[204] = _InvSbox[204]
+Xtime2Sbox[204] = _Xtime2Sbox[204]
+Xtime3Sbox[204] = _Xtime3Sbox[204]
+Xtime2[204] = _Xtime2[204]
+Xtime9[204] = _Xtime9[204]
+XtimeB[204] = _XtimeB[204]
+XtimeD[204] = _XtimeD[204]
+XtimeE[204] = _XtimeE[204]
+Sbox[205] = _Sbox[205]
+InvSbox[205] = _InvSbox[205]
+Xtime2Sbox[205] = _Xtime2Sbox[205]
+Xtime3Sbox[205] = _Xtime3Sbox[205]
+Xtime2[205] = _Xtime2[205]
+Xtime9[205] = _Xtime9[205]
+XtimeB[205] = _XtimeB[205]
+XtimeD[205] = _XtimeD[205]
+XtimeE[205] = _XtimeE[205]
+Sbox[206] = _Sbox[206]
+InvSbox[206] = _InvSbox[206]
+Xtime2Sbox[206] = _Xtime2Sbox[206]
+Xtime3Sbox[206] = _Xtime3Sbox[206]
+Xtime2[206] = _Xtime2[206]
+Xtime9[206] = _Xtime9[206]
+XtimeB[206] = _XtimeB[206]
+XtimeD[206] = _XtimeD[206]
+XtimeE[206] = _XtimeE[206]
+Sbox[207] = _Sbox[207]
+InvSbox[207] = _InvSbox[207]
+Xtime2Sbox[207] = _Xtime2Sbox[207]
+Xtime3Sbox[207] = _Xtime3Sbox[207]
+Xtime2[207] = _Xtime2[207]
+Xtime9[207] = _Xtime9[207]
+XtimeB[207] = _XtimeB[207]
+XtimeD[207] = _XtimeD[207]
+XtimeE[207] = _XtimeE[207]
+Sbox[208] = _Sbox[208]
+InvSbox[208] = _InvSbox[208]
+Xtime2Sbox[208] = _Xtime2Sbox[208]
+Xtime3Sbox[208] = _Xtime3Sbox[208]
+Xtime2[208] = _Xtime2[208]
+Xtime9[208] = _Xtime9[208]
+XtimeB[208] = _XtimeB[208]
+XtimeD[208] = _XtimeD[208]
+XtimeE[208] = _XtimeE[208]
+Sbox[209] = _Sbox[209]
+InvSbox[209] = _InvSbox[209]
+Xtime2Sbox[209] = _Xtime2Sbox[209]
+Xtime3Sbox[209] = _Xtime3Sbox[209]
+Xtime2[209] = _Xtime2[209]
+Xtime9[209] = _Xtime9[209]
+XtimeB[209] = _XtimeB[209]
+XtimeD[209] = _XtimeD[209]
+XtimeE[209] = _XtimeE[209]
+Sbox[210] = _Sbox[210]
+InvSbox[210] = _InvSbox[210]
+Xtime2Sbox[210] = _Xtime2Sbox[210]
+Xtime3Sbox[210] = _Xtime3Sbox[210]
+Xtime2[210] = _Xtime2[210]
+Xtime9[210] = _Xtime9[210]
+XtimeB[210] = _XtimeB[210]
+XtimeD[210] = _XtimeD[210]
+XtimeE[210] = _XtimeE[210]
+Sbox[211] = _Sbox[211]
+InvSbox[211] = _InvSbox[211]
+Xtime2Sbox[211] = _Xtime2Sbox[211]
+Xtime3Sbox[211] = _Xtime3Sbox[211]
+Xtime2[211] = _Xtime2[211]
+Xtime9[211] = _Xtime9[211]
+XtimeB[211] = _XtimeB[211]
+XtimeD[211] = _XtimeD[211]
+XtimeE[211] = _XtimeE[211]
+Sbox[212] = _Sbox[212]
+InvSbox[212] = _InvSbox[212]
+Xtime2Sbox[212] = _Xtime2Sbox[212]
+Xtime3Sbox[212] = _Xtime3Sbox[212]
+Xtime2[212] = _Xtime2[212]
+Xtime9[212] = _Xtime9[212]
+XtimeB[212] = _XtimeB[212]
+XtimeD[212] = _XtimeD[212]
+XtimeE[212] = _XtimeE[212]
+Sbox[213] = _Sbox[213]
+InvSbox[213] = _InvSbox[213]
+Xtime2Sbox[213] = _Xtime2Sbox[213]
+Xtime3Sbox[213] = _Xtime3Sbox[213]
+Xtime2[213] = _Xtime2[213]
+Xtime9[213] = _Xtime9[213]
+XtimeB[213] = _XtimeB[213]
+XtimeD[213] = _XtimeD[213]
+XtimeE[213] = _XtimeE[213]
+Sbox[214] = _Sbox[214]
+InvSbox[214] = _InvSbox[214]
+Xtime2Sbox[214] = _Xtime2Sbox[214]
+Xtime3Sbox[214] = _Xtime3Sbox[214]
+Xtime2[214] = _Xtime2[214]
+Xtime9[214] = _Xtime9[214]
+XtimeB[214] = _XtimeB[214]
+XtimeD[214] = _XtimeD[214]
+XtimeE[214] = _XtimeE[214]
+Sbox[215] = _Sbox[215]
+InvSbox[215] = _InvSbox[215]
+Xtime2Sbox[215] = _Xtime2Sbox[215]
+Xtime3Sbox[215] = _Xtime3Sbox[215]
+Xtime2[215] = _Xtime2[215]
+Xtime9[215] = _Xtime9[215]
+XtimeB[215] = _XtimeB[215]
+XtimeD[215] = _XtimeD[215]
+XtimeE[215] = _XtimeE[215]
+Sbox[216] = _Sbox[216]
+InvSbox[216] = _InvSbox[216]
+Xtime2Sbox[216] = _Xtime2Sbox[216]
+Xtime3Sbox[216] = _Xtime3Sbox[216]
+Xtime2[216] = _Xtime2[216]
+Xtime9[216] = _Xtime9[216]
+XtimeB[216] = _XtimeB[216]
+XtimeD[216] = _XtimeD[216]
+XtimeE[216] = _XtimeE[216]
+Sbox[217] = _Sbox[217]
+InvSbox[217] = _InvSbox[217]
+Xtime2Sbox[217] = _Xtime2Sbox[217]
+Xtime3Sbox[217] = _Xtime3Sbox[217]
+Xtime2[217] = _Xtime2[217]
+Xtime9[217] = _Xtime9[217]
+XtimeB[217] = _XtimeB[217]
+XtimeD[217] = _XtimeD[217]
+XtimeE[217] = _XtimeE[217]
+Sbox[218] = _Sbox[218]
+InvSbox[218] = _InvSbox[218]
+Xtime2Sbox[218] = _Xtime2Sbox[218]
+Xtime3Sbox[218] = _Xtime3Sbox[218]
+Xtime2[218] = _Xtime2[218]
+Xtime9[218] = _Xtime9[218]
+XtimeB[218] = _XtimeB[218]
+XtimeD[218] = _XtimeD[218]
+XtimeE[218] = _XtimeE[218]
+Sbox[219] = _Sbox[219]
+InvSbox[219] = _InvSbox[219]
+Xtime2Sbox[219] = _Xtime2Sbox[219]
+Xtime3Sbox[219] = _Xtime3Sbox[219]
+Xtime2[219] = _Xtime2[219]
+Xtime9[219] = _Xtime9[219]
+XtimeB[219] = _XtimeB[219]
+XtimeD[219] = _XtimeD[219]
+XtimeE[219] = _XtimeE[219]
+Sbox[220] = _Sbox[220]
+InvSbox[220] = _InvSbox[220]
+Xtime2Sbox[220] = _Xtime2Sbox[220]
+Xtime3Sbox[220] = _Xtime3Sbox[220]
+Xtime2[220] = _Xtime2[220]
+Xtime9[220] = _Xtime9[220]
+XtimeB[220] = _XtimeB[220]
+XtimeD[220] = _XtimeD[220]
+XtimeE[220] = _XtimeE[220]
+Sbox[221] = _Sbox[221]
+InvSbox[221] = _InvSbox[221]
+Xtime2Sbox[221] = _Xtime2Sbox[221]
+Xtime3Sbox[221] = _Xtime3Sbox[221]
+Xtime2[221] = _Xtime2[221]
+Xtime9[221] = _Xtime9[221]
+XtimeB[221] = _XtimeB[221]
+XtimeD[221] = _XtimeD[221]
+XtimeE[221] = _XtimeE[221]
+Sbox[222] = _Sbox[222]
+InvSbox[222] = _InvSbox[222]
+Xtime2Sbox[222] = _Xtime2Sbox[222]
+Xtime3Sbox[222] = _Xtime3Sbox[222]
+Xtime2[222] = _Xtime2[222]
+Xtime9[222] = _Xtime9[222]
+XtimeB[222] = _XtimeB[222]
+XtimeD[222] = _XtimeD[222]
+XtimeE[222] = _XtimeE[222]
+Sbox[223] = _Sbox[223]
+InvSbox[223] = _InvSbox[223]
+Xtime2Sbox[223] = _Xtime2Sbox[223]
+Xtime3Sbox[223] = _Xtime3Sbox[223]
+Xtime2[223] = _Xtime2[223]
+Xtime9[223] = _Xtime9[223]
+XtimeB[223] = _XtimeB[223]
+XtimeD[223] = _XtimeD[223]
+XtimeE[223] = _XtimeE[223]
+Sbox[224] = _Sbox[224]
+InvSbox[224] = _InvSbox[224]
+Xtime2Sbox[224] = _Xtime2Sbox[224]
+Xtime3Sbox[224] = _Xtime3Sbox[224]
+Xtime2[224] = _Xtime2[224]
+Xtime9[224] = _Xtime9[224]
+XtimeB[224] = _XtimeB[224]
+XtimeD[224] = _XtimeD[224]
+XtimeE[224] = _XtimeE[224]
+Sbox[225] = _Sbox[225]
+InvSbox[225] = _InvSbox[225]
+Xtime2Sbox[225] = _Xtime2Sbox[225]
+Xtime3Sbox[225] = _Xtime3Sbox[225]
+Xtime2[225] = _Xtime2[225]
+Xtime9[225] = _Xtime9[225]
+XtimeB[225] = _XtimeB[225]
+XtimeD[225] = _XtimeD[225]
+XtimeE[225] = _XtimeE[225]
+Sbox[226] = _Sbox[226]
+InvSbox[226] = _InvSbox[226]
+Xtime2Sbox[226] = _Xtime2Sbox[226]
+Xtime3Sbox[226] = _Xtime3Sbox[226]
+Xtime2[226] = _Xtime2[226]
+Xtime9[226] = _Xtime9[226]
+XtimeB[226] = _XtimeB[226]
+XtimeD[226] = _XtimeD[226]
+XtimeE[226] = _XtimeE[226]
+Sbox[227] = _Sbox[227]
+InvSbox[227] = _InvSbox[227]
+Xtime2Sbox[227] = _Xtime2Sbox[227]
+Xtime3Sbox[227] = _Xtime3Sbox[227]
+Xtime2[227] = _Xtime2[227]
+Xtime9[227] = _Xtime9[227]
+XtimeB[227] = _XtimeB[227]
+XtimeD[227] = _XtimeD[227]
+XtimeE[227] = _XtimeE[227]
+Sbox[228] = _Sbox[228]
+InvSbox[228] = _InvSbox[228]
+Xtime2Sbox[228] = _Xtime2Sbox[228]
+Xtime3Sbox[228] = _Xtime3Sbox[228]
+Xtime2[228] = _Xtime2[228]
+Xtime9[228] = _Xtime9[228]
+XtimeB[228] = _XtimeB[228]
+XtimeD[228] = _XtimeD[228]
+XtimeE[228] = _XtimeE[228]
+Sbox[229] = _Sbox[229]
+InvSbox[229] = _InvSbox[229]
+Xtime2Sbox[229] = _Xtime2Sbox[229]
+Xtime3Sbox[229] = _Xtime3Sbox[229]
+Xtime2[229] = _Xtime2[229]
+Xtime9[229] = _Xtime9[229]
+XtimeB[229] = _XtimeB[229]
+XtimeD[229] = _XtimeD[229]
+XtimeE[229] = _XtimeE[229]
+Sbox[230] = _Sbox[230]
+InvSbox[230] = _InvSbox[230]
+Xtime2Sbox[230] = _Xtime2Sbox[230]
+Xtime3Sbox[230] = _Xtime3Sbox[230]
+Xtime2[230] = _Xtime2[230]
+Xtime9[230] = _Xtime9[230]
+XtimeB[230] = _XtimeB[230]
+XtimeD[230] = _XtimeD[230]
+XtimeE[230] = _XtimeE[230]
+Sbox[231] = _Sbox[231]
+InvSbox[231] = _InvSbox[231]
+Xtime2Sbox[231] = _Xtime2Sbox[231]
+Xtime3Sbox[231] = _Xtime3Sbox[231]
+Xtime2[231] = _Xtime2[231]
+Xtime9[231] = _Xtime9[231]
+XtimeB[231] = _XtimeB[231]
+XtimeD[231] = _XtimeD[231]
+XtimeE[231] = _XtimeE[231]
+Sbox[232] = _Sbox[232]
+InvSbox[232] = _InvSbox[232]
+Xtime2Sbox[232] = _Xtime2Sbox[232]
+Xtime3Sbox[232] = _Xtime3Sbox[232]
+Xtime2[232] = _Xtime2[232]
+Xtime9[232] = _Xtime9[232]
+XtimeB[232] = _XtimeB[232]
+XtimeD[232] = _XtimeD[232]
+XtimeE[232] = _XtimeE[232]
+Sbox[233] = _Sbox[233]
+InvSbox[233] = _InvSbox[233]
+Xtime2Sbox[233] = _Xtime2Sbox[233]
+Xtime3Sbox[233] = _Xtime3Sbox[233]
+Xtime2[233] = _Xtime2[233]
+Xtime9[233] = _Xtime9[233]
+XtimeB[233] = _XtimeB[233]
+XtimeD[233] = _XtimeD[233]
+XtimeE[233] = _XtimeE[233]
+Sbox[234] = _Sbox[234]
+InvSbox[234] = _InvSbox[234]
+Xtime2Sbox[234] = _Xtime2Sbox[234]
+Xtime3Sbox[234] = _Xtime3Sbox[234]
+Xtime2[234] = _Xtime2[234]
+Xtime9[234] = _Xtime9[234]
+XtimeB[234] = _XtimeB[234]
+XtimeD[234] = _XtimeD[234]
+XtimeE[234] = _XtimeE[234]
+Sbox[235] = _Sbox[235]
+InvSbox[235] = _InvSbox[235]
+Xtime2Sbox[235] = _Xtime2Sbox[235]
+Xtime3Sbox[235] = _Xtime3Sbox[235]
+Xtime2[235] = _Xtime2[235]
+Xtime9[235] = _Xtime9[235]
+XtimeB[235] = _XtimeB[235]
+XtimeD[235] = _XtimeD[235]
+XtimeE[235] = _XtimeE[235]
+Sbox[236] = _Sbox[236]
+InvSbox[236] = _InvSbox[236]
+Xtime2Sbox[236] = _Xtime2Sbox[236]
+Xtime3Sbox[236] = _Xtime3Sbox[236]
+Xtime2[236] = _Xtime2[236]
+Xtime9[236] = _Xtime9[236]
+XtimeB[236] = _XtimeB[236]
+XtimeD[236] = _XtimeD[236]
+XtimeE[236] = _XtimeE[236]
+Sbox[237] = _Sbox[237]
+InvSbox[237] = _InvSbox[237]
+Xtime2Sbox[237] = _Xtime2Sbox[237]
+Xtime3Sbox[237] = _Xtime3Sbox[237]
+Xtime2[237] = _Xtime2[237]
+Xtime9[237] = _Xtime9[237]
+XtimeB[237] = _XtimeB[237]
+XtimeD[237] = _XtimeD[237]
+XtimeE[237] = _XtimeE[237]
+Sbox[238] = _Sbox[238]
+InvSbox[238] = _InvSbox[238]
+Xtime2Sbox[238] = _Xtime2Sbox[238]
+Xtime3Sbox[238] = _Xtime3Sbox[238]
+Xtime2[238] = _Xtime2[238]
+Xtime9[238] = _Xtime9[238]
+XtimeB[238] = _XtimeB[238]
+XtimeD[238] = _XtimeD[238]
+XtimeE[238] = _XtimeE[238]
+Sbox[239] = _Sbox[239]
+InvSbox[239] = _InvSbox[239]
+Xtime2Sbox[239] = _Xtime2Sbox[239]
+Xtime3Sbox[239] = _Xtime3Sbox[239]
+Xtime2[239] = _Xtime2[239]
+Xtime9[239] = _Xtime9[239]
+XtimeB[239] = _XtimeB[239]
+XtimeD[239] = _XtimeD[239]
+XtimeE[239] = _XtimeE[239]
+Sbox[240] = _Sbox[240]
+InvSbox[240] = _InvSbox[240]
+Xtime2Sbox[240] = _Xtime2Sbox[240]
+Xtime3Sbox[240] = _Xtime3Sbox[240]
+Xtime2[240] = _Xtime2[240]
+Xtime9[240] = _Xtime9[240]
+XtimeB[240] = _XtimeB[240]
+XtimeD[240] = _XtimeD[240]
+XtimeE[240] = _XtimeE[240]
+Sbox[241] = _Sbox[241]
+InvSbox[241] = _InvSbox[241]
+Xtime2Sbox[241] = _Xtime2Sbox[241]
+Xtime3Sbox[241] = _Xtime3Sbox[241]
+Xtime2[241] = _Xtime2[241]
+Xtime9[241] = _Xtime9[241]
+XtimeB[241] = _XtimeB[241]
+XtimeD[241] = _XtimeD[241]
+XtimeE[241] = _XtimeE[241]
+Sbox[242] = _Sbox[242]
+InvSbox[242] = _InvSbox[242]
+Xtime2Sbox[242] = _Xtime2Sbox[242]
+Xtime3Sbox[242] = _Xtime3Sbox[242]
+Xtime2[242] = _Xtime2[242]
+Xtime9[242] = _Xtime9[242]
+XtimeB[242] = _XtimeB[242]
+XtimeD[242] = _XtimeD[242]
+XtimeE[242] = _XtimeE[242]
+Sbox[243] = _Sbox[243]
+InvSbox[243] = _InvSbox[243]
+Xtime2Sbox[243] = _Xtime2Sbox[243]
+Xtime3Sbox[243] = _Xtime3Sbox[243]
+Xtime2[243] = _Xtime2[243]
+Xtime9[243] = _Xtime9[243]
+XtimeB[243] = _XtimeB[243]
+XtimeD[243] = _XtimeD[243]
+XtimeE[243] = _XtimeE[243]
+Sbox[244] = _Sbox[244]
+InvSbox[244] = _InvSbox[244]
+Xtime2Sbox[244] = _Xtime2Sbox[244]
+Xtime3Sbox[244] = _Xtime3Sbox[244]
+Xtime2[244] = _Xtime2[244]
+Xtime9[244] = _Xtime9[244]
+XtimeB[244] = _XtimeB[244]
+XtimeD[244] = _XtimeD[244]
+XtimeE[244] = _XtimeE[244]
+Sbox[245] = _Sbox[245]
+InvSbox[245] = _InvSbox[245]
+Xtime2Sbox[245] = _Xtime2Sbox[245]
+Xtime3Sbox[245] = _Xtime3Sbox[245]
+Xtime2[245] = _Xtime2[245]
+Xtime9[245] = _Xtime9[245]
+XtimeB[245] = _XtimeB[245]
+XtimeD[245] = _XtimeD[245]
+XtimeE[245] = _XtimeE[245]
+Sbox[246] = _Sbox[246]
+InvSbox[246] = _InvSbox[246]
+Xtime2Sbox[246] = _Xtime2Sbox[246]
+Xtime3Sbox[246] = _Xtime3Sbox[246]
+Xtime2[246] = _Xtime2[246]
+Xtime9[246] = _Xtime9[246]
+XtimeB[246] = _XtimeB[246]
+XtimeD[246] = _XtimeD[246]
+XtimeE[246] = _XtimeE[246]
+Sbox[247] = _Sbox[247]
+InvSbox[247] = _InvSbox[247]
+Xtime2Sbox[247] = _Xtime2Sbox[247]
+Xtime3Sbox[247] = _Xtime3Sbox[247]
+Xtime2[247] = _Xtime2[247]
+Xtime9[247] = _Xtime9[247]
+XtimeB[247] = _XtimeB[247]
+XtimeD[247] = _XtimeD[247]
+XtimeE[247] = _XtimeE[247]
+Sbox[248] = _Sbox[248]
+InvSbox[248] = _InvSbox[248]
+Xtime2Sbox[248] = _Xtime2Sbox[248]
+Xtime3Sbox[248] = _Xtime3Sbox[248]
+Xtime2[248] = _Xtime2[248]
+Xtime9[248] = _Xtime9[248]
+XtimeB[248] = _XtimeB[248]
+XtimeD[248] = _XtimeD[248]
+XtimeE[248] = _XtimeE[248]
+Sbox[249] = _Sbox[249]
+InvSbox[249] = _InvSbox[249]
+Xtime2Sbox[249] = _Xtime2Sbox[249]
+Xtime3Sbox[249] = _Xtime3Sbox[249]
+Xtime2[249] = _Xtime2[249]
+Xtime9[249] = _Xtime9[249]
+XtimeB[249] = _XtimeB[249]
+XtimeD[249] = _XtimeD[249]
+XtimeE[249] = _XtimeE[249]
+Sbox[250] = _Sbox[250]
+InvSbox[250] = _InvSbox[250]
+Xtime2Sbox[250] = _Xtime2Sbox[250]
+Xtime3Sbox[250] = _Xtime3Sbox[250]
+Xtime2[250] = _Xtime2[250]
+Xtime9[250] = _Xtime9[250]
+XtimeB[250] = _XtimeB[250]
+XtimeD[250] = _XtimeD[250]
+XtimeE[250] = _XtimeE[250]
+Sbox[251] = _Sbox[251]
+InvSbox[251] = _InvSbox[251]
+Xtime2Sbox[251] = _Xtime2Sbox[251]
+Xtime3Sbox[251] = _Xtime3Sbox[251]
+Xtime2[251] = _Xtime2[251]
+Xtime9[251] = _Xtime9[251]
+XtimeB[251] = _XtimeB[251]
+XtimeD[251] = _XtimeD[251]
+XtimeE[251] = _XtimeE[251]
+Sbox[252] = _Sbox[252]
+InvSbox[252] = _InvSbox[252]
+Xtime2Sbox[252] = _Xtime2Sbox[252]
+Xtime3Sbox[252] = _Xtime3Sbox[252]
+Xtime2[252] = _Xtime2[252]
+Xtime9[252] = _Xtime9[252]
+XtimeB[252] = _XtimeB[252]
+XtimeD[252] = _XtimeD[252]
+XtimeE[252] = _XtimeE[252]
+Sbox[253] = _Sbox[253]
+InvSbox[253] = _InvSbox[253]
+Xtime2Sbox[253] = _Xtime2Sbox[253]
+Xtime3Sbox[253] = _Xtime3Sbox[253]
+Xtime2[253] = _Xtime2[253]
+Xtime9[253] = _Xtime9[253]
+XtimeB[253] = _XtimeB[253]
+XtimeD[253] = _XtimeD[253]
+XtimeE[253] = _XtimeE[253]
+Sbox[254] = _Sbox[254]
+InvSbox[254] = _InvSbox[254]
+Xtime2Sbox[254] = _Xtime2Sbox[254]
+Xtime3Sbox[254] = _Xtime3Sbox[254]
+Xtime2[254] = _Xtime2[254]
+Xtime9[254] = _Xtime9[254]
+XtimeB[254] = _XtimeB[254]
+XtimeD[254] = _XtimeD[254]
+XtimeE[254] = _XtimeE[254]
+Sbox[255] = _Sbox[255]
+InvSbox[255] = _InvSbox[255]
+Xtime2Sbox[255] = _Xtime2Sbox[255]
+Xtime3Sbox[255] = _Xtime3Sbox[255]
+Xtime2[255] = _Xtime2[255]
+Xtime9[255] = _Xtime9[255]
+XtimeB[255] = _XtimeB[255]
+XtimeD[255] = _XtimeD[255]
+XtimeE[255] = _XtimeE[255]
--- /dev/null
+/**\r
+ * AESKeyTest\r
+ * \r
+ * A test class for AESKey\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.prng.Random;\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.ECBMode;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ import flash.utils.getTimer;\r
+ \r
+ public class AESKeyTest extends TestCase\r
+ {\r
+ public function AESKeyTest(h:ITestHarness) {\r
+ super(h, "AESKey Test");\r
+ \r
+ runTest(testGetBlockSize, "AES Block Size");\r
+ runTest(testECB_TBL, "AES ECB Test Vectors");\r
+\r
+ h.endTestCase();\r
+ }\r
+ \r
+ \r
+ public function testGetBlockSize():void {\r
+ var key:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<32;i++) {\r
+ key[i]=i;\r
+ }\r
+ var k:AESKey = new AESKey(key);\r
+ assert("128bit block size", k.getBlockSize()==16);\r
+ }\r
+ \r
+ /**\r
+ * http://csrc.nist.gov/encryption/aes/rijndael/rijndael-vals.zip\r
+ * this uses ecb_tbl.txt\r
+ * we test encryption and decryption with keys of length 128,192,256 bits.\r
+ */\r
+ public function testECB_TBL():void {\r
+ var keys:Array = [\r
+ "00010203050607080A0B0C0D0F101112",\r
+ "14151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A",\r
+ "3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F606162",\r
+ "64656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A",\r
+ "8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2",\r
+ "B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",\r
+ "C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA",\r
+ "DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE010002",\r
+ "04050607090A0B0C0E0F101113141516",\r
+ "2C2D2E2F31323334363738393B3C3D3E",\r
+ "40414243454647484A4B4C4D4F505152",\r
+ "54555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A",\r
+ "7C7D7E7F81828384868788898B8C8D8E",\r
+ "A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",\r
+ "E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2",\r
+ "08090A0B0D0E0F10121314151718191A",\r
+ "6C6D6E6F71727374767778797B7C7D7E",\r
+ "80818283858687888A8B8C8D8F909192",\r
+ "94959697999A9B9C9E9FA0A1A3A4A5A6",\r
+ "A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA",\r
+ "BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",\r
+ "D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2",\r
+ "E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",\r
+ "F8F9FAFBFDFEFE00020304050708090A",\r
+ "0C0D0E0F11121314161718191B1C1D1E",\r
+ "20212223252627282A2B2C2D2F303132",\r
+ "34353637393A3B3C3E3F404143444546",\r
+ "48494A4B4D4E4F50525354555758595A",\r
+ "5C5D5E5F61626364666768696B6C6D6E",\r
+ "70717273757677787A7B7C7D7F808182",\r
+ "84858687898A8B8C8E8F909193949596",\r
+ "98999A9B9D9E9FA0A2A3A4A5A7A8A9AA",\r
+ "ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",\r
+ "C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2",\r
+ "D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",\r
+ "E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA",\r
+ "FCFDFEFF01020304060708090B0C0D0E",\r
+ "10111213151617181A1B1C1D1F202122",\r
+ "24252627292A2B2C2E2F303133343536",\r
+ "38393A3B3D3E3F40424344454748494A",\r
+ "4C4D4E4F51525354565758595B5C5D5E",\r
+ "60616263656667686A6B6C6D6F707172",\r
+ "74757677797A7B7C7E7F808183848586",\r
+ "88898A8B8D8E8F90929394959798999A",\r
+ "9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",\r
+ "B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2",\r
+ "C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",\r
+ "D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EA",\r
+ "ECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",\r
+ "00010203050607080A0B0C0D0F101112",\r
+ "14151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A",\r
+ "3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F606162",\r
+ "64656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A",\r
+ "8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2",\r
+ "B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",\r
+ "C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA",\r
+ "DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE010002",\r
+ "04050607090A0B0C0E0F101113141516",\r
+ "18191A1B1D1E1F20222324252728292A",\r
+ "2C2D2E2F31323334363738393B3C3D3E",\r
+ "40414243454647484A4B4C4D4F505152",\r
+ "54555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A",\r
+ "7C7D7E7F81828384868788898B8C8D8E",\r
+ "90919293959697989A9B9C9D9FA0A1A2",\r
+ "A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",\r
+ "B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CA",\r
+ "CCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",\r
+ "E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2",\r
+ "F4F5F6F7F9FAFBFCFEFE010103040506",\r
+ "08090A0B0D0E0F10121314151718191A",\r
+ "1C1D1E1F21222324262728292B2C2D2E",\r
+ "30313233353637383A3B3C3D3F404142",\r
+ "44454647494A4B4C4E4F505153545556",\r
+ "58595A5B5D5E5F60626364656768696A",\r
+ "6C6D6E6F71727374767778797B7C7D7E",\r
+ "80818283858687888A8B8C8D8F909192",\r
+ "94959697999A9B9C9E9FA0A1A3A4A5A6",\r
+ "A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA",\r
+ "BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",\r
+ "D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2",\r
+ "E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",\r
+ "F8F9FAFBFDFEFE00020304050708090A",\r
+ "0C0D0E0F11121314161718191B1C1D1E",\r
+ "20212223252627282A2B2C2D2F303132",\r
+ "34353637393A3B3C3E3F404143444546",\r
+ "48494A4B4D4E4F50525354555758595A",\r
+ "5C5D5E5F61626364666768696B6C6D6E",\r
+ "70717273757677787A7B7C7D7F808182",\r
+ "84858687898A8B8C8E8F909193949596",\r
+ "98999A9B9D9E9FA0A2A3A4A5A7A8A9AA",\r
+ "ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",\r
+ "C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2",\r
+ "D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",\r
+ "E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA",\r
+ "FCFDFEFF01020304060708090B0C0D0E",\r
+ "10111213151617181A1B1C1D1F202122",\r
+ "24252627292A2B2C2E2F303133343536",\r
+ "38393A3B3D3E3F40424344454748494A",\r
+ "4C4D4E4F51525354565758595B5C5D5E",\r
+ "60616263656667686A6B6C6D6F707172",\r
+ "74757677797A7B7C7E7F808183848586",\r
+ "88898A8B8D8E8F90929394959798999A",\r
+ "9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",\r
+ "B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2",\r
+ "C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",\r
+ "D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EA",\r
+ "ECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",\r
+ "00010203050607080A0B0C0D0F101112",\r
+ "14151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A",\r
+ "3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F606162",\r
+ "64656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A",\r
+ "8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2",\r
+ "00010203050607080A0B0C0D0F10111214151617191A1B1C",\r
+ "1E1F20212324252628292A2B2D2E2F30323334353738393A",\r
+ "3C3D3E3F41424344464748494B4C4D4E5051525355565758",\r
+ "5A5B5C5D5F60616264656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A8C8D8E8F91929394",\r
+ "969798999B9C9D9EA0A1A2A3A5A6A7A8AAABACADAFB0B1B2",\r
+ "B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6C8C9CACBCDCECFD0",\r
+ "D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C",\r
+ "0E0F10111314151618191A1B1D1E1F20222324252728292A",\r
+ "2C2D2E2F31323334363738393B3C3D3E4041424345464748",\r
+ "4A4B4C4D4F50515254555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A7C7D7E7F81828384",\r
+ "868788898B8C8D8E90919293959697989A9B9C9D9FA0A1A2",\r
+ "A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6B8B9BABBBDBEBFC0",\r
+ "C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",\r
+ "E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFC",\r
+ "FEFE01010304050608090A0B0D0E0F10121314151718191A",\r
+ "1C1D1E1F21222324262728292B2C2D2E3031323335363738",\r
+ "3A3B3C3D3F40414244454647494A4B4C4E4F505153545556",\r
+ "58595A5B5D5E5F60626364656768696A6C6D6E6F71727374",\r
+ "767778797B7C7D7E80818283858687888A8B8C8D8F909192",\r
+ "94959697999A9B9C9E9FA0A1A3A4A5A6A8A9AAABADAEAFB0",\r
+ "D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBEC",\r
+ "2A2B2C2D2F30313234353637393A3B3C3E3F404143444546",\r
+ "48494A4B4D4E4F50525354555758595A5C5D5E5F61626364",\r
+ "84858687898A8B8C8E8F90919394959698999A9B9D9E9FA0",\r
+ "A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",\r
+ "C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDC",\r
+ "1A1B1C1D1F20212224252627292A2B2C2E2F303133343536",\r
+ "38393A3B3D3E3F40424344454748494A4C4D4E4F51525354",\r
+ "929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",\r
+ "464748494B4C4D4E50515253555657585A5B5C5D5F606162",\r
+ "828384858788898A8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBC",\r
+ "BEBFC0C1C3C4C5C6C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA",\r
+ "DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEEF0F1F2F3F5F6F7F8",\r
+ "FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",\r
+ "18191A1B1D1E1F20222324252728292A2C2D2E2F31323334",\r
+ "363738393B3C3D3E40414243454647484A4B4C4D4F505152",\r
+ "54555657595A5B5C5E5F60616364656668696A6B6D6E6F70",\r
+ "727374757778797A7C7D7E7F81828384868788898B8C8D8E",\r
+ "90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABAC",\r
+ "AEAFB0B1B3B4B5B6B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CA",\r
+ "CCCDCECFD1D2D3D4D6D7D8D9DBDCDDDEE0E1E2E3E5E6E7E8",\r
+ "EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",\r
+ "08090A0B0D0E0F10121314151718191A1C1D1E1F21222324",\r
+ "262728292B2C2D2E30313233353637383A3B3C3D3F404142",\r
+ "44454647494A4B4C4E4F50515354555658595A5B5D5E5F60",\r
+ "626364656768696A6C6D6E6F71727374767778797B7C7D7E",\r
+ "80818283858687888A8B8C8D8F90919294959697999A9B9C",\r
+ "9E9FA0A1A3A4A5A6A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA",\r
+ "BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCED0D1D2D3D5D6D7D8",\r
+ "DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",\r
+ "F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314",\r
+ "161718191B1C1D1E20212223252627282A2B2C2D2F303132",\r
+ "34353637393A3B3C3E3F40414344454648494A4B4D4E4F50",\r
+ "525354555758595A5C5D5E5F61626364666768696B6C6D6E",\r
+ "70717273757677787A7B7C7D7F80818284858687898A8B8C",\r
+ "8E8F90919394959698999A9B9D9E9FA0A2A3A4A5A7A8A9AA",\r
+ "ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBEC0C1C2C3C5C6C7C8",\r
+ "CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",\r
+ "E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304",\r
+ "060708090B0C0D0E10111213151617181A1B1C1D1F202122",\r
+ "24252627292A2B2C2E2F30313334353638393A3B3D3E3F40",\r
+ "424344454748494A4C4D4E4F51525354565758595B5C5D5E",\r
+ "60616263656667686A6B6C6D6F70717274757677797A7B7C",\r
+ "7E7F80818384858688898A8B8D8E8F90929394959798999A",\r
+ "9C9D9E9FA1A2A3A4A6A7A8A9ABACADAEB0B1B2B3B5B6B7B8",\r
+ "BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",\r
+ "D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4",\r
+ "F6F7F8F9FBFCFDFE00010203050607080A0B0C0D0F101112",\r
+ "14151617191A1B1C1E1F20212324252628292A2B2D2E2F30",\r
+ "323334353738393A3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F60616264656667696A6B6C",\r
+ "6E6F70717374757678797A7B7D7E7F80828384858788898A",\r
+ "8C8D8E8F91929394969798999B9C9D9EA0A1A2A3A5A6A7A8",\r
+ "AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",\r
+ "C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4",\r
+ "E6E7E8E9EBECEDEEF0F1F2F3F5F6F7F8FAFBFCFDFE010002",\r
+ "04050607090A0B0C0E0F10111314151618191A1B1D1E1F20",\r
+ "222324252728292A2C2D2E2F31323334363738393B3C3D3E",\r
+ "40414243454647484A4B4C4D4F50515254555657595A5B5C",\r
+ "5E5F60616364656668696A6B6D6E6F70727374757778797A",\r
+ "7C7D7E7F81828384868788898B8C8D8E9091929395969798",\r
+ "9A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",\r
+ "B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4",\r
+ "D6D7D8D9DBDCDDDEE0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2",\r
+ "F4F5F6F7F9FAFBFCFEFE01010304050608090A0B0D0E0F10",\r
+ "121314151718191A1C1D1E1F21222324262728292B2C2D2E",\r
+ "30313233353637383A3B3C3D3F40414244454647494A4B4C",\r
+ "4E4F50515354555658595A5B5D5E5F60626364656768696A",\r
+ "6C6D6E6F71727374767778797B7C7D7E8081828385868788",\r
+ "8A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",\r
+ "A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4",\r
+ "C6C7C8C9CBCCCDCED0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2",\r
+ "E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6F8F9FAFBFDFEFE00",\r
+ "020304050708090A0C0D0E0F11121314161718191B1C1D1E",\r
+ "20212223252627282A2B2C2D2F30313234353637393A3B3C",\r
+ "3E3F40414344454648494A4B4D4E4F50525354555758595A",\r
+ "5C5D5E5F61626364666768696B6C6D6E7071727375767778",\r
+ "7A7B7C7D7F80818284858687898A8B8C8E8F909193949596",\r
+ "98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4",\r
+ "B6B7B8B9BBBCBDBEC0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2",\r
+ "D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6E8E9EAEBEDEEEFF0",\r
+ "F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",\r
+ "10111213151617181A1B1C1D1F20212224252627292A2B2C",\r
+ "2E2F30313334353638393A3B3D3E3F40424344454748494A",\r
+ "4C4D4E4F51525354565758595B5C5D5E6061626365666768",\r
+ "6A6B6C6D6F70717274757677797A7B7C7E7F808183848586",\r
+ "88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4",\r
+ "A6A7A8A9ABACADAEB0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2",\r
+ "C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6D8D9DADBDDDEDFE0",\r
+ "E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",\r
+ "00010203050607080A0B0C0D0F10111214151617191A1B1C",\r
+ "1E1F20212324252628292A2B2D2E2F30323334353738393A",\r
+ "3C3D3E3F41424344464748494B4C4D4E5051525355565758",\r
+ "5A5B5C5D5F60616264656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A8C8D8E8F91929394",\r
+ "969798999B9C9D9EA0A1A2A3A5A6A7A8AAABACADAFB0B1B2",\r
+ "B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6C8C9CACBCDCECFD0",\r
+ "D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C",\r
+ "0E0F10111314151618191A1B1D1E1F20222324252728292A",\r
+ "2C2D2E2F31323334363738393B3C3D3E4041424345464748",\r
+ "4A4B4C4D4F50515254555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A7C7D7E7F81828384",\r
+ "868788898B8C8D8E90919293959697989A9B9C9D9FA0A1A2",\r
+ "00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",\r
+ "C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",\r
+ "18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",\r
+ "40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",\r
+ "90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",\r
+ "B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",\r
+ "E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",\r
+ "08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",\r
+ "30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",\r
+ "58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",\r
+ "80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",\r
+ "A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",\r
+ "D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",\r
+ "70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",\r
+ "98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",\r
+ "C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",\r
+ "E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",\r
+ "10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",\r
+ "38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",\r
+ "60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",\r
+ "88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",\r
+ "B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",\r
+ "D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",\r
+ "00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",\r
+ "C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",\r
+ "18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",\r
+ "40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",\r
+ "90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",\r
+ "B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",\r
+ "E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",\r
+ "08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",\r
+ "30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",\r
+ "58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",\r
+ "80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",\r
+ "A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",\r
+ "D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",\r
+ "F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E",\r
+ "20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546",\r
+ "48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E",\r
+ "70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",\r
+ "98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",\r
+ "C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",\r
+ "E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",\r
+ "10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",\r
+ "38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",\r
+ "60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",\r
+ "88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",\r
+ "B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",\r
+ "D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",\r
+ "00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",\r
+ "C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",\r
+ "18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",\r
+ "40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",\r
+ "90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",\r
+ "B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",\r
+ "E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",\r
+ "08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",\r
+ "30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",\r
+ "58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",\r
+ "80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",\r
+ "A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",\r
+ "D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",\r
+ "F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E",\r
+ "20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546",\r
+ "48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E",\r
+ "70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",\r
+ "98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",\r
+ "C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",\r
+ "E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",\r
+ "10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",\r
+ "38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",\r
+ "60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",\r
+ "88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",\r
+ "B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",\r
+ "D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",\r
+ "00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",\r
+ "78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",\r
+ "A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",\r
+ "C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",\r
+ "F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",\r
+ "18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",\r
+ "40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",\r
+ "68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",\r
+ "90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",\r
+ "B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",\r
+ "E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",\r
+ "08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",\r
+ "30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",\r
+ "58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",\r
+ "80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",\r
+ "A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",\r
+ "D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",\r
+ "F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E",\r
+ "20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546",\r
+ "48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E",\r
+ "70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",\r
+ "98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",\r
+ "C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",\r
+ "E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",\r
+ "10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",\r
+ "38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",\r
+ "60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",\r
+ "88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",\r
+ "B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",\r
+ "D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",\r
+ "00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",\r
+ "28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",\r
+ "50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576"];\r
+ \r
+ var pts:Array = [\r
+ "506812A45F08C889B97F5980038B8359",\r
+ "5C6D71CA30DE8B8B00549984D2EC7D4B",\r
+ "53F3F4C64F8616E4E7C56199F48F21F6",\r
+ "A1EB65A3487165FB0F1C27FF9959F703",\r
+ "3553ECF0B1739558B08E350A98A39BFA",\r
+ "67429969490B9711AE2B01DC497AFDE8",\r
+ "93385C1F2AEC8BED192F5A8E161DD508",\r
+ "B5BF946BE19BEB8DB3983B5F4C6E8DDB",\r
+ "41321EE10E21BD907227C4450FF42324",\r
+ "00A82F59C91C8486D12C0A80124F6089",\r
+ "7CE0FD076754691B4BBD9FAF8A1372FE",\r
+ "23605A8243D07764541BC5AD355B3129",\r
+ "12A8CFA23EA764FD876232B4E842BC44",\r
+ "BCAF32415E8308B3723E5FDD853CCC80",\r
+ "89AFAE685D801AD747ACE91FC49ADDE0",\r
+ "F521D07B484357C4A69E76124A634216",\r
+ "3E23B3BC065BCC152407E23896D77783",\r
+ "79F0FBA002BE1744670E7E99290D8F52",\r
+ "DA23FE9D5BD63E1D72E3DAFBE21A6C2A",\r
+ "E3F5698BA90B6A022EFD7DB2C7E6C823",\r
+ "BDC2691D4F1B73D2700679C3BCBF9C6E",\r
+ "BA74E02093217EE1BA1B42BD5624349A",\r
+ "B5C593B5851C57FBF8B3F57715E8F680",\r
+ "3DA9BD9CEC072381788F9387C3BBF4EE",\r
+ "4197F3051121702AB65D316B3C637374",\r
+ "9F46C62EC4F6EE3F6E8C62554BC48AB7",\r
+ "0220673FE9E699A4EBC8E0DBEB6979C8",\r
+ "B2B99171337DED9BC8C2C23FF6F18867",\r
+ "A7FACF4E301E984E5EFEEFD645B23505",\r
+ "F7C762E4A9819160FD7ACFB6C4EEDCDD",\r
+ "9B64FC21EA08709F4915436FAA70F1BE",\r
+ "52AF2C3DE07EE6777F55A4ABFC100B3F",\r
+ "2FCA001224386C57AA3F968CBE2C816F",\r
+ "4149C73658A4A9C564342755EE2C132F",\r
+ "AF60005A00A1772F7C07A48A923C23D2",\r
+ "6FCCBC28363759914B6F0280AFAF20C6",\r
+ "7D82A43DDF4FEFA2FC5947499884D386",\r
+ "5D5A990EAAB9093AFE4CE254DFA49EF9",\r
+ "4CD1E2FD3F4434B553AAE453F0ED1A02",\r
+ "5A2C9A9641D4299125FA1B9363104B5E",\r
+ "B517FE34C0FA217D341740BFD4FE8DD4",\r
+ "014BAF2278A69D331D5180103643E99A",\r
+ "B529BD8164F20D0AA443D4932116841C",\r
+ "2E596DCBB2F33D4216A1176D5BD1E456",\r
+ "7274A1EA2B7EE2424E9A0E4673689143",\r
+ "AE20020BD4F13E9D90140BEE3B5D26AF",\r
+ "BAAC065DA7AC26E855E79C8849D75A02",\r
+ "7C917D8D1D45FAB9E2540E28832540CC",\r
+ "BDE6F89E16DAADB0E847A2A614566A91",\r
+ "C9DE163725F1F5BE44EBB1DB51D07FBC",\r
+ "3AF57A58F0C07DFFA669572B521E2B92",\r
+ "3D5EBAC306DDE4604F1B4FBBBFCDAE55",\r
+ "C2DFA91BCEB76A1183C995020AC0B556",\r
+ "C70F54305885E9A0746D01EC56C8596B",\r
+ "C4F81B610E98012CE000182050C0C2B2",\r
+ "EAAB86B1D02A95D7404EFF67489F97D4",\r
+ "7C55BDB40B88870B52BEC3738DE82886",\r
+ "BA6EAA88371FF0A3BD875E3F2A975CE0",\r
+ "08059130C4C24BD30CF0575E4E0373DC",\r
+ "9A8EAB004EF53093DFCF96F57E7EDA82",\r
+ "0745B589E2400C25F117B1D796C28129",\r
+ "2F1777781216CEC3F044F134B1B92BBE",\r
+ "353A779FFC541B3A3805D90CE17580FC",\r
+ "1A1EAE4415CEFCF08C4AC1C8F68BEA8F",\r
+ "E6E7E4E5B0B3B2B5D4D5AAAB16111013",\r
+ "F8F9FAFBFBF8F9E677767170EFE0E1E2",\r
+ "63626160A1A2A3A445444B4A75727370",\r
+ "717073720605040B2D2C2B2A05FAFBF9",\r
+ "78797A7BEAE9E8EF3736292891969794",\r
+ "838281803231300FDDDCDBDAA0AFAEAD",\r
+ "18191A1BBFBCBDBA75747B7A7F78797A",\r
+ "848586879B989996A3A2A5A4849B9A99",\r
+ "0001020322212027CACBF4F551565754",\r
+ "CECFCCCDAFACADB2515057564A454447",\r
+ "92939091CDCECFC813121D1C80878685",\r
+ "D2D3D0D16F6C6D6259585F5ED1EEEFEC",\r
+ "ACADAEAF878485820F0E1110D5D2D3D0",\r
+ "9091929364676619E6E7E0E1757A7B78",\r
+ "BABBB8B98A89888F74757A7B92959497",\r
+ "8D8C8F8E6E6D6C633B3A3D3CCAD5D4D7",\r
+ "86878485010203040808F7F767606162",\r
+ "8E8F8C8D656667788A8B8C8D010E0F0C",\r
+ "C8C9CACB858687807A7B7475E7E0E1E2",\r
+ "6D6C6F6E5053525D8C8D8A8BADD2D3D0",\r
+ "28292A2B393A3B3C0607181903040506",\r
+ "A5A4A7A6B0B3B28DDBDADDDCBDB2B3B0",\r
+ "323330316467666130313E3F2C2B2A29",\r
+ "27262524080B0A05171611100B141516",\r
+ "040506074142434435340B0AA3A4A5A6",\r
+ "242526271112130C61606766BDB2B3B0",\r
+ "4B4A4948252627209E9F9091CEC9C8CB",\r
+ "68696A6B6665646B9F9E9998D9E6E7E4",\r
+ "34353637C5C6C7C0F0F1EEEF7C7B7A79",\r
+ "32333031C2C1C13F0D0C0B0A050A0B08",\r
+ "CDCCCFCEBEBDBCBBABAAA5A4181F1E1D",\r
+ "212023223635343BA0A1A6A7445B5A59",\r
+ "0E0F0C0DA8ABAAAD2F2E515002050407",\r
+ "070605042A2928378E8F8889BDB2B3B0",\r
+ "CBCAC9C893909196A9A8A7A6A5A2A3A0",\r
+ "80818283C1C2C3CC9C9D9A9B0CF3F2F1",\r
+ "1213101125262720FAFBE4E5B1B6B7B4",\r
+ "7F7E7D7C3033320D97969190222D2C2F",\r
+ "4E4F4C4D484B4A4D81808F8E53545556",\r
+ "DCDDDEDFB0B3B2BD15141312A1BEBFBC",\r
+ "93929190282B2A2DC4C5FAFB92959497",\r
+ "F5F4F7F6C4C7C6D9373631307E717073",\r
+ "93929190B6B5B4B364656A6B05020300",\r
+ "BABBB8B90D0E0F00A4A5A2A3043B3A39",\r
+ "D8D9DADB7F7C7D7A10110E0F787F7E7D",\r
+ "FEFFFCFDEFECED923B3A3D3C6768696A",\r
+ "D6D7D4D58A89888F96979899A5A2A3A0",\r
+ "18191A1BA8ABAAA5303136379B848586",\r
+ "6B6A6968A4A7A6A1D6D72829B0B7B6B5",\r
+ "000102038A89889755545352A6A9A8AB",\r
+ "2D2C2F2EB3B0B1B6B6B7B8B9F2F5F4F7",\r
+ "979695943536373856575051E09F9E9D",\r
+ "A4A5A6A7989B9A9DB1B0AFAE7A7D7C7F",\r
+ "C1C0C3C2686B6A55A8A9AEAFEAE5E4E7",\r
+ "C1C0C3C2141716118C8D828364636261",\r
+ "93929190CCCFCEC196979091E0FFFEFD",\r
+ "B4B5B6B7F9FAFBFC25241B1A6E69686B",\r
+ "868784850704051AC7C6C1C08788898A",\r
+ "F4F5F6F7AAA9A8AFFDFCF3F277707172",\r
+ "D3D2D1D00605040BC3C2C5C43E010003",\r
+ "73727170424140476A6B74750D0A0B08",\r
+ "C2C3C0C10A0908F754555253A1AEAFAC",\r
+ "6D6C6F6EF8FBFAFD82838C8DF8FFFEFD",\r
+ "F5F4F7F684878689A6A7A0A1D2CDCCCF",\r
+ "2D33EEF2C0430A8A9EBF45E809C40BB6",\r
+ "6AA375D1FA155A61FB72353E0A5A8756",\r
+ "BC3736518B9490DCB8ED60EB26758ED4",\r
+ "AA214402B46CFFB9F761EC11263A311E",\r
+ "02AEA86E572EEAB66B2C3AF5E9A46FD6",\r
+ "E2AEF6ACC33B965C4FA1F91C75FF6F36",\r
+ "0659DF46427162B9434865DD9499F91D",\r
+ "49A44239C748FEB456F59C276A5658DF",\r
+ "66208F6E9D04525BDEDB2733B6A6BE37",\r
+ "3393F8DFC729C97F5480B950BC9666B0",\r
+ "606834C8CE063F3234CF1145325DBD71",\r
+ "FEC1C04F529BBD17D8CECFCC4718B17F",\r
+ "32DF99B431ED5DC5ACF8CAF6DC6CE475",\r
+ "7FDC2B746F3F665296943B83710D1F82",\r
+ "8FBA1510A3C5B87E2EAA3F7A91455CA2",\r
+ "2C9B468B1C2EED92578D41B0716B223B",\r
+ "0A2BBF0EFC6BC0034F8A03433FCA1B1A",\r
+ "25260E1F31F4104D387222E70632504B",\r
+ "C527D25A49F08A5228D338642AE65137",\r
+ "3B49FC081432F5890D0E3D87E884A69E",\r
+ "D173F9ED1E57597E166931DF2754A083",\r
+ "8C2B7CAFA5AFE7F13562DAEAE1ADEDE0",\r
+ "AAF4EC8C1A815AEB826CAB741339532C",\r
+ "40BE8C5D9108E663F38F1A2395279ECF",\r
+ "0C8AD9BC32D43E04716753AA4CFBE351",\r
+ "1407B1D5F87D63357C8DC7EBBAEBBFEE",\r
+ "E62734D1AE3378C4549E939E6F123416",\r
+ "5A752CFF2A176DB1A1DE77F2D2CDEE41",\r
+ "A9C8C3A4EABEDC80C64730DDD018CD88",\r
+ "EE9B3DBBDB86180072130834D305999A",\r
+ "A7FA8C3586B8EBDE7568EAD6F634A879",\r
+ "37E0F4A87F127D45AC936FE7AD88C10A",\r
+ "3F77D8B5D92BAC148E4E46F697A535C5",\r
+ "D25EBB686C40F7E2C4DA1014936571CA",\r
+ "4F1C769D1E5B0552C7ECA84DEA26A549",\r
+ "8548E2F882D7584D0FAFC54372B6633A",\r
+ "87D7A336CB476F177CD2A51AF2A62CDF",\r
+ "03B1FEAC668C4E485C1065DFC22B44EE",\r
+ "BDA15E66819FA72D653A6866AA287962",\r
+ "4D0C7A0D2505B80BF8B62CEB12467F0A",\r
+ "626D34C9429B37211330986466B94E5F",\r
+ "333C3E6BF00656B088A17E5FF0E7F60A",\r
+ "687ED0CDC0D2A2BC8C466D05EF9D2891",\r
+ "487830E78CC56C1693E64B2A6660C7B6",\r
+ "7A48D6B7B52B29392AA2072A32B66160",\r
+ "907320E64C8C5314D10F8D7A11C8618D",\r
+ "B561F2CA2D6E65A4A98341F3ED9FF533",\r
+ "DF769380D212792D026F049E2E3E48EF",\r
+ "79F374BC445BDABF8FCCB8843D6054C6",\r
+ "4E02F1242FA56B05C68DBAE8FE44C9D6",\r
+ "CF73C93CBFF57AC635A6F4AD2A4A1545",\r
+ "9923548E2875750725B886566784C625",\r
+ "4888336B723A022C9545320F836A4207",\r
+ "F84D9A5561B0608B1160DEE000C41BA8",\r
+ "C23192A0418E30A19B45AE3E3625BF22",\r
+ "B84E0690B28B0025381AD82A15E501A7",\r
+ "ACEF5E5C108876C4F06269F865B8F0B0",\r
+ "0F1B3603E0F5DDEA4548246153A5E064",\r
+ "FBB63893450D42B58C6D88CD3C1809E3",\r
+ "4BEF736DF150259DAE0C91354E8A5F92",\r
+ "7D2D46242056EF13D3C3FC93C128F4C7",\r
+ "E9C1BA2DF415657A256EDB33934680FD",\r
+ "E23EE277B0AA0A1DFB81F7527C3514F1",\r
+ "3E7445B0B63CAAF75E4A911E12106B4C",\r
+ "767774752023222544455A5BE6E1E0E3",\r
+ "72737475717E7F7CE9E8EBEA696A6B6C",\r
+ "DFDEDDDC25262728C9C8CFCEF1EEEFEC",\r
+ "FFFE0100707776755F5E5D5C7675746B",\r
+ "E0E1E2E3424140479F9E9190292E2F2C",\r
+ "2120272690EFEEED3B3A39384E4D4C4B",\r
+ "ECEDEEEF5350516EA1A0A7A6A3ACADAE",\r
+ "32333C3D25222320E9E8EBEACECDCCC3",\r
+ "40414243626160678A8BB4B511161714",\r
+ "94959293F5FAFBF81F1E1D1C7C7F7E79",\r
+ "BEBFBCBD191A1B14CFCEC9C8546B6A69",\r
+ "2C2D3233898E8F8CBBBAB9B8333031CE",\r
+ "84858687BFBCBDBA37363938FDFAFBF8",\r
+ "828384857669686B909192930B08090E",\r
+ "BEBFBCBD9695948B707176779E919093",\r
+ "8B8A85846067666521202322D0D3D2DD",\r
+ "76777475F1F2F3F4F8F9E6E777707172",\r
+ "A4A5A2A34F404142B4B5B6B727242522",\r
+ "94959697E1E2E3EC16171011839C9D9E",\r
+ "03023D3C06010003DEDFDCDDFFFCFDE2",\r
+ "10111213F1F2F3F4CECFC0C1DBDCDDDE",\r
+ "67666160724D4C4F1D1C1F1E73707176",\r
+ "E6E7E4E5A8ABAAD584858283909F9E9D",\r
+ "71707F7E565150537D7C7F7E6162636C",\r
+ "64656667212223245555AAAA03040506",\r
+ "9E9F9899ABA4A5A6CFCECDCC2B28292E",\r
+ "C7C6C5C4D1D2D3DC626364653A454447",\r
+ "F6F7E8E9E0E7E6E51D1C1F1E5B585966",\r
+ "BCBDBEBF5D5E5F5868696667F4F3F2F1",\r
+ "40414647B0AFAEAD9B9A99989B98999E",\r
+ "69686B6A0201001F0F0E0908B4BBBAB9",\r
+ "C7C6C9C8D8DFDEDD5A5B5859BEBDBCB3",\r
+ "DEDFDCDD787B7A7DFFFEE1E0B2B5B4B7",\r
+ "4D4C4B4A606F6E6DD0D1D2D3FBF8F9FE",\r
+ "B7B6B5B4D7D4D5DAE5E4E3E2E1FEFFFC",\r
+ "CECFB0B1F7F0F1F2AEAFACAD3E3D3C23",\r
+ "CACBC8C9CDCECFC812131C1D494E4F4C",\r
+ "9D9C9B9AD22D2C2FB1B0B3B20C0F0E09",\r
+ "7A7B787964676659959493924F404142",\r
+ "AAABA4A5CEC9C8CB1F1E1D1CABA8A9A6",\r
+ "93929190282B2A2DC4C5FAFB92959497",\r
+ "EFEEE9E8DED1D0D339383B3A888B8A8D",\r
+ "7F7E7D7CA2A1A0AF78797E7F112E2F2C",\r
+ "84859A9B2B2C2D2E868784852625245B",\r
+ "B0B1B2B3070405026869666710171615",\r
+ "ACADAAABBDA2A3A00D0C0F0E595A5B5C",\r
+ "121310115655544B5253545569666764",\r
+ "DEDFD0D166616063EAEBE8E94142434C",\r
+ "DBDAD9D81417161166677879E0E7E6E5",\r
+ "6A6B6C6DE0EFEEED2B2A2928C0C3C2C5",\r
+ "B1B0B3B21714151A1A1B1C1D5649484B",\r
+ "39380706A3A4A5A6C4C5C6C77271706F",\r
+ "5C5D5E5F1013121539383736E2E5E4E7",\r
+ "43424544EAD5D4D72E2F2C2D64676661",\r
+ "55545756989B9A65F8F9FEFF18171615",\r
+ "05040B0A525554573C3D3E3F4A494847",\r
+ "14151617595A5B5C8584FBFA8E89888B",\r
+ "7C7D7A7BFDF2F3F029282B2A51525354",\r
+ "38393A3B1E1D1C1341404746C23D3C3E",\r
+ "8D8C939240474645818083827C7F7E41",\r
+ "3B3A39381A19181F32333C3D45424340",\r
+ "F0F1F6F738272625828380817F7C7D7A",\r
+ "89888B8A0407061966676061141B1A19",\r
+ "D3D2DDDCAAADACAF9C9D9E9FE8EBEAE5",\r
+ "834EADFCCAC7E1B30664B1ABA44815AB",\r
+ "D9DC4DBA3021B05D67C0518F72B62BF1",\r
+ "A291D86301A4A739F7392173AA3C604C",\r
+ "4264B2696498DE4DF79788A9F83E9390",\r
+ "EE9932B3721804D5A83EF5949245B6F6",\r
+ "E6248F55C5FDCBCA9CBBB01C88A2EA77",\r
+ "B8358E41B9DFF65FD461D55A99266247",\r
+ "F0E2D72260AF58E21E015AB3A4C0D906",\r
+ "475B8B823CE8893DB3C44A9F2A379FF7",\r
+ "688F5281945812862F5F3076CF80412F",\r
+ "08D1D2BC750AF553365D35E75AFACEAA",\r
+ "8707121F47CC3EFCECA5F9A8474950A1",\r
+ "E51AA0B135DBA566939C3B6359A980C5",\r
+ "069A007FC76A459F98BAF917FEDF9521",\r
+ "726165C1723FBCF6C026D7D00B091027",\r
+ "D7C544DE91D55CFCDE1F84CA382200CE",\r
+ "FED3C9A161B9B5B2BD611B41DC9DA357",\r
+ "4F634CDC6551043409F30B635832CF82",\r
+ "109CE98DB0DFB36734D9F3394711B4E6",\r
+ "4EA6DFABA2D8A02FFDFFA89835987242",\r
+ "5AE094F54AF58E6E3CDBF976DAC6D9EF",\r
+ "764D8E8E0F29926DBE5122E66354FDBE",\r
+ "3F0418F888CDF29A982BF6B75410D6A9",\r
+ "E4A3E7CB12CDD56AA4A75197A9530220",\r
+ "211677684AAC1EC1A160F44C4EBF3F26",\r
+ "D21E439FF749AC8F18D6D4B105E03895",\r
+ "D9F6FF44646C4725BD4C0103FF5552A7",\r
+ "0B1256C2A00B976250CFC5B0C37ED382",\r
+ "B056447FFC6DC4523A36CC2E972A3A79",\r
+ "5E25CA78F0DE55802524D38DA3FE4456",\r
+ "A5BCF4728FA5EAAD8567C0DC24675F83",\r
+ "814E59F97ED84646B78B2CA022E9CA43",\r
+ "15478BEEC58F4775C7A7F5D4395514D7",\r
+ "253548FFCA461C67C8CBC78CD59F4756",\r
+ "FD7AD8D73B9B0F8CC41600640F503D65",\r
+ "06199DE52C6CBF8AF954CD65830BCD56",\r
+ "F17C4FFE48E44C61BD891E257E725794",\r
+ "9A5B4A402A3E8A59BE6BF5CD8154F029",\r
+ "79BD40B91A7E07DC939D441782AE6B17",\r
+ "D8CEAAF8976E5FBE1012D8C84F323799",\r
+ "3316E2751E2E388B083DA23DD6AC3FBE",\r
+ "8B7CFBE37DE7DCA793521819242C5816",\r
+ "F23F033C0EEBF8EC55752662FD58CE68",\r
+ "59EB34F6C8BDBACC5FC6AD73A59A1301",\r
+ "DCDE8B6BD5CF7CC22D9505E3CE81261A",\r
+ "E33CF7E524FED781E7042FF9F4B35DC7",\r
+ "27963C8FACDF73062867D164DF6D064C",\r
+ "77B1CE386B551B995F2F2A1DA994EEF8",\r
+ "F083388B013679EFCF0BB9B15D52AE5C",\r
+ "C5009E0DAB55DB0ABDB636F2600290C8",\r
+ "7804881E26CD532D8514D3683F00F1B9",\r
+ "46CDDCD73D1EB53E675CA012870A92A3",\r
+ "A9FB44062BB07FE130A8E8299EACB1AB",\r
+ "2B6FF8D7A5CC3A28A22D5A6F221AF26B",\r
+ "1A9527C29B8ADD4B0E3E656DBB2AF8B4",\r
+ "7F99CF2C75244DF015EB4B0C1050AEAE",\r
+ "E84FF85B0D9454071909C1381646C4ED",\r
+ "89AFD40F99521280D5399B12404F6DB4",\r
+ "A09EF32DBC5119A35AB7FA38656F0329",\r
+ "61773457F068C376C7829B93E696E716",\r
+ "A34F0CAE726CCE41DD498747D891B967",\r
+ "856F59496C7388EE2D2B1A27B7697847",\r
+ "CB090C593EF7720BD95908FB93B49DF4",\r
+ "A0AC75CD2F1923D460FC4D457AD95BAF",\r
+ "2A2B282974777689E8E9EEEF525D5C5F",\r
+ "909192939390919E0F0E09089788898A",\r
+ "777675748D8E8F907170777649464744",\r
+ "717073720605040B2D2C2B2A05FAFBF9",\r
+ "64656667FEFDFCC31B1A1D1CA5AAABA8",\r
+ "DBDAD9D86A696867B5B4B3B2C8D7D6D5",\r
+ "5C5D5E5FE3E0E1FE31303736333C3D3E",\r
+ "545556574B48494673727574546B6A69",\r
+ "ECEDEEEFC6C5C4BB56575051F5FAFBF8",\r
+ "464744452724252AC9C8CFCED2CDCCCF",\r
+ "E6E7E4E54142435C878681801C131211",\r
+ "72737071CFCCCDC2F9F8FFFE710E0F0C",\r
+ "505152537370714EC3C2C5C4010E0F0C",\r
+ "A8A9AAAB5C5F5E51AEAFA8A93D222320",\r
+ "DEDFDCDDF6F5F4EB10111617FEF1F0F3",\r
+ "BDBCBFBE5E5D5C530B0A0D0CFAC5C4C7",\r
+ "8A8B8889050606F8F4F5F2F3636C6D6E",\r
+ "A6A7A4A54D4E4F40B2B3B4B539262724",\r
+ "9C9D9E9FE9EAEBF40E0F08099B949596",\r
+ "2D2C2F2E1013121DCCCDCACBED121310",\r
+ "F4F5F6F7EDEEEFD0EAEBECEDF7F8F9FA",\r
+ "3D3C3F3E282B2A2573727574150A0B08",\r
+ "B6B7B4B5F8FBFAE5B4B5B2B3A0AFAEAD",\r
+ "B7B6B5B4989B9A95878681809BA4A5A6",\r
+ "A8A9AAABE5E6E798E9E8EFEE4748494A",\r
+ "ECEDEEEFD9DADBD4B9B8BFBE657A7B78",\r
+ "7F7E7D7C696A6B74CACBCCCD929D9C9F",\r
+ "08090A0B0605040BFFFEF9F8B9C6C7C4",\r
+ "08090A0BF1F2F3CCFCFDFAFB68676665",\r
+ "CACBC8C93A393837050403020D121310",\r
+ "E9E8EBEA8281809F8F8E8988343B3A39",\r
+ "515053524645444BD0D1D6D7340B0A09",\r
+ "42434041ECEFEE1193929594C6C9C8CB",\r
+ "EFEEEDECC2C1C0CF76777071455A5B58",\r
+ "5F5E5D5C3F3C3D221D1C1B1A19161714",\r
+ "000102034142434C1C1D1A1B8D727371",\r
+ "8E8F8C8DB1B2B38C56575051050A0B08",\r
+ "A7A6A5A4E8EBEAE57F7E7978CAD5D4D7",\r
+ "8A8B888994979689454443429F909192",\r
+ "8C8D8E8FE0E3E2ED45444342F1CECFCC",\r
+ "FFFEFDFC4C4F4E31D8D9DEDFB6B9B8BB",\r
+ "FDFCFFFECCCFCEC12F2E29286679787B",\r
+ "67666564BAB9B8A77071767719161714",\r
+ "9A9B98992D2E2F2084858283245B5A59",\r
+ "A4A5A6A70B0809365C5D5A5B2C232221",\r
+ "464744455754555AF3F2F5F4AFB0B1B2",\r
+ "323330317675746B7273747549464744",\r
+ "A8A9AAAB181B1A15808186872B141516",\r
+ "E7E6E5E4202323DDAAABACAD343B3A39",\r
+ "A8A9AAAB2221202FEDECEBEA1E010003",\r
+ "F9F8FBFA5F5C5D42424344450E010003",\r
+ "57565554F5F6F7F89697909120DFDEDD",\r
+ "F8F9FAFBCCCFCEF1DDDCDBDA0E010003",\r
+ "D9D8DBDA7073727D80818687C2DDDCDF",\r
+ "C5C4C7C6080B0A1588898E8F68676665",\r
+ "83828180DCDFDED186878081F0CFCECD",\r
+ "98999A9BDDDEDFA079787F7E0A050407",\r
+ "CECFCCCD4F4C4D429F9E9998DFC0C1C2",\r
+ "404142436665647B29282F2EABA4A5A6",\r
+ "33323130E6E5E4EB23222524DEA1A0A3",\r
+ "CFCECDCCF6F5F4CBE6E7E0E199969794",\r
+ "BABBB8B97271707FDCDDDADB29363734",\r
+ "C9C8CBCA4447465926272021545B5A59",\r
+ "050407067477767956575051221D1C1F"];\r
+ \r
+ var cts:Array = [\r
+ "D8F532538289EF7D06B506A4FD5BE9C9",\r
+ "59AB30F4D4EE6E4FF9907EF65B1FB68C",\r
+ "BF1ED2FCB2AF3FD41443B56D85025CB1",\r
+ "7316632D5C32233EDCB0780560EAE8B2",\r
+ "408C073E3E2538072B72625E68B8364B",\r
+ "E1F94DFA776597BEACA262F2F6366FEA",\r
+ "F29E986C6A1C27D7B29FFD7EE92B75F1",\r
+ "131C886A57F8C2E713ABA6955E2B55B5",\r
+ "D2AB7662DF9B8C740210E5EEB61C199D",\r
+ "14C10554B2859C484CAB5869BBE7C470",\r
+ "DB4D498F0A49CF55445D502C1F9AB3B5",\r
+ "6D96FEF7D66590A77A77BB2056667F7F",\r
+ "316FB68EDBA736C53E78477BF913725C",\r
+ "6936F2B93AF8397FD3A771FC011C8C37",\r
+ "F3F92F7A9C59179C1FCC2C2BA0B082CD",\r
+ "6A95EA659EE3889158E7A9152FF04EBC",\r
+ "1959338344E945670678A5D432C90B93",\r
+ "E49BDDD2369B83EE66E6C75A1161B394",\r
+ "D3388F19057FF704B70784164A74867D",\r
+ "23AA03E2D5E4CD24F3217E596480D1E1",\r
+ "C84113D68B666AB2A50A8BDB222E91B9",\r
+ "AC02403981CD4340B507963DB65CB7B6",\r
+ "8D1299236223359474011F6BF5088414",\r
+ "5A1D6AB8605505F7977E55B9A54D9B90",\r
+ "72E9C2D519CF555E4208805AABE3B258",\r
+ "A8F3E81C4A23A39EF4D745DFFE026E80",\r
+ "546F646449D31458F9EB4EF5483AEE6C",\r
+ "4DBE4BC84AC797C0EE4EFB7F1A07401C",\r
+ "25E10BFB411BBD4D625AC8795C8CA3B3",\r
+ "315637405054EC803614E43DEF177579",\r
+ "60C5BC8A1410247295C6386C59E572A8",\r
+ "01366FC8CA52DFE055D6A00A76471BA6",\r
+ "ECC46595516EC612449C3F581E7D42FF",\r
+ "6B7FFE4C602A154B06EE9C7DAB5331C9",\r
+ "7DA234C14039A240DD02DD0FBF84EB67",\r
+ "C7DC217D9E3604FFE7E91F080ECD5A3A",\r
+ "37785901863F5C81260EA41E7580CDA5",\r
+ "A07B9338E92ED105E6AD720FCCCE9FE4",\r
+ "AE0FB9722418CC21A7DA816BBC61322C",\r
+ "C826A193080FF91FFB21F71D3373C877",\r
+ "1181B11B0E494E8D8B0AA6B1D5AC2C48",\r
+ "6743C3D1519AB4F2CD9A78AB09A511BD",\r
+ "DC55C076D52BACDF2EEFD952946A439D",\r
+ "711B17B590FFC72B5C8E342B601E8003",\r
+ "19983BB0950783A537E1339F4AA21C75",\r
+ "3BA7762E15554169C0F4FA39164C410C",\r
+ "A0564C41245AFCA7AF8AA2E0E588EA89",\r
+ "5E36A42A2E099F54AE85ECD92E2381ED",\r
+ "770036F878CD0F6CA2268172F106F2FE",\r
+ "7E4E03908B716116443CCF7C94E7C259",\r
+ "482735A48C30613A242DD494C7F9185D",\r
+ "B4C0F6C9D4D7079ADDF9369FC081061D",\r
+ "D5810FE0509AC53EDCD74F89962E6270",\r
+ "03F17A16B3F91848269ECDD38EBB2165",\r
+ "DA1248C3180348BAD4A93B4D9856C9DF",\r
+ "3D10D7B63F3452C06CDF6CCE18BE0C2C",\r
+ "4AB823E7477DFDDC0E6789018FCB6258",\r
+ "E6478BA56A77E70CFDAA5C843ABDE30E",\r
+ "1673064895FBEAF7F09C5429FF75772D",\r
+ "4488033AE9F2EFD0CA9383BFCA1A94E9",\r
+ "978F3B8C8F9D6F46626CAC3C0BCB9217",\r
+ "E08C8A7E582E15E5527F1D9E2EECB236",\r
+ "CEC155B76AC5FFDA4CF4F9CA91E49A7A",\r
+ "D5AC7165763225DD2A38CDC6862C29AD",\r
+ "03680FE19F7CE7275452020BE70E8204",\r
+ "461DF740C9781C388E94BB861CEB54F6",\r
+ "451BD60367F96483042742219786A074",\r
+ "E4DFA42671A02E57EF173B85C0EA9F2B",\r
+ "ED11B89E76274282227D854700A78B9E",\r
+ "433946EAA51EA47AF33895F2B90B3B75",\r
+ "6BC6D616A5D7D0284A5910AB35022528",\r
+ "D2A920ECFE919D354B5F49EAE9719C98",\r
+ "3A061B17F6A92885EFBD0676985B373D",\r
+ "FADEEC16E33EA2F4688499D157E20D8F",\r
+ "5CDEFEDE59601AA3C3CDA36FA6B1FA13",\r
+ "9574B00039844D92EBBA7EE8719265F8",\r
+ "9A9CF33758671787E5006928188643FA",\r
+ "2CDDD634C846BA66BB46CBFEA4A674F9",\r
+ "D28BAE029393C3E7E26E9FAFBBB4B98F",\r
+ "EC27529B1BEE0A9AB6A0D73EBC82E9B7",\r
+ "3CB25C09472AFF6EE7E2B47CCD7CCB17",\r
+ "DEE33103A7283370D725E44CA38F8FE5",\r
+ "27F9BCD1AAC64BFFC11E7815702C1A69",\r
+ "5DF534FFAD4ED0749A9988E9849D0021",\r
+ "A48BEE75DB04FB60CA2B80F752A8421B",\r
+ "024C8CF70BC86EE5CE03678CB7AF45F9",\r
+ "3C19AC0F8A3A3862CE577831301E166B",\r
+ "C5E355B796A57421D59CA6BE82E73BCA",\r
+ "D94033276417ABFB05A69D15B6E386E2",\r
+ "24B36559EA3A9B9B958FE6DA3E5B8D85",\r
+ "20FD4FEAA0E8BF0CCE7861D74EF4CB72",\r
+ "350E20D5174277B9EC314C501570A11D",\r
+ "87A29D61B7C604D238FE73045A7EFD57",\r
+ "2C3164C1CC7D0064816BDC0FAA362C52",\r
+ "195FE5E8A05A2ED594F6E4400EEE10B3",\r
+ "E4663DF19B9A21A5A284C2BD7F905025",\r
+ "21B88714CFB4E2A933BD281A2C4743FD",\r
+ "CBFC3980D704FD0FC54378AB84E17870",\r
+ "BC5144BAA48BDEB8B63E22E03DA418EF",\r
+ "5A1DBAEF1EE2984B8395DA3BDFFA3CCC",\r
+ "F0B11CD0729DFCC80CEC903D97159574",\r
+ "9F95314ACFDDC6D1914B7F19A9CC8209",\r
+ "595736F6F0F70914A94E9E007F022519",\r
+ "1F19F57892CAE586FCDFB4C694DEB183",\r
+ "540700EE1F6F3DAB0B3EDDF6CAEE1EF5",\r
+ "14A342A91019A331687A2254E6626CA2",\r
+ "7B25F3C3B2EEA18D743EF283140F29FF",\r
+ "46C2587D66E5E6FA7F7CA6411AD28047",\r
+ "09470E72229D954ED5EE73886DFEEBA9",\r
+ "D77C03DE92D4D0D79EF8D4824EF365EB",\r
+ "1D190219F290E0F1715D152D41A23593",\r
+ "A2CD332CE3A0818769616292E87F757B",\r
+ "D54AFA6CE60FBF9341A3690E21385102",\r
+ "06E5C364DED628A3F5E05E613E356F46",\r
+ "EAE63C0E62556DAC85D221099896355A",\r
+ "1FED060E2C6FC93EE764403A889985A2",\r
+ "C25235C1A30FDEC1C7CB5C5737B2A588",\r
+ "796DBEF95147D4D30873AD8B7B92EFC0",\r
+ "CBCF0FB34D98D0BD5C22CE37211A46BF",\r
+ "94B44DA6466126CAFA7C7FD09063FC24",\r
+ "D78C5B5EBF9B4DBDA6AE506C5074C8FE",\r
+ "6C27444C27204B043812CF8CF95F9769",\r
+ "BE94524EE5A2AA50BBA8B75F4C0AEBCF",\r
+ "A0AEAAE91BA9F31F51AEB3588CF3A39E",\r
+ "275297779C28266EF9FE4C6A13C08488",\r
+ "86523D92BB8672CB01CF4A77FD725882",\r
+ "4B8327640E9F33322A04DD96FCBF9A36",\r
+ "CE52AF650D088CA559425223F4D32694",\r
+ "DFF4945E0336DF4C1C56BC700EFF837F",\r
+ "B6FDDEF4752765E347D5D2DC196D1252",\r
+ "D23684E3D963B3AFCF1A114ACA90CBD6",\r
+ "3A7AC027753E2A18C2CEAB9E17C11FD0",\r
+ "8F6786BD007528BA26603C1601CDD0D8",\r
+ "D17D073B01E71502E28B47AB551168B3",\r
+ "A469DA517119FAB95876F41D06D40FFA",\r
+ "6091AA3B695C11F5C0B6AD26D3D862FF",\r
+ "70F9E67F9F8DF1294131662DC6E69364",\r
+ "D154DCAFAD8B207FA5CBC95E9996B559",\r
+ "4934D541E8B46FA339C805A7AEB9E5DA",\r
+ "62564C738F3EFE186E1A127A0C4D3C61",\r
+ "07805AA043986EB23693E23BEF8F3438",\r
+ "DF0B4931038BADE848DEE3B4B85AA44B",\r
+ "592D5FDED76582E4143C65099309477C",\r
+ "C9B8D6545580D3DFBCDD09B954ED4E92",\r
+ "5DCCD5D6EB7C1B42ACB008201DF707A0",\r
+ "A2A91682FFEB6ED1D34340946829E6F9",\r
+ "E45D185B797000348D9267960A68435D",\r
+ "45E060DAE5901CDA8089E10D4F4C246B",\r
+ "F6951AFACC0079A369C71FDCFF45DF50",\r
+ "9E95E00F351D5B3AC3D0E22E626DDAD6",\r
+ "9CB566FF26D92DAD083B51FDC18C173C",\r
+ "C9C82766176A9B228EB9A974A010B4FB",\r
+ "D8E26AA02945881D5137F1C1E1386E88",\r
+ "C0E024CCD68FF5FFA4D139C355A77C55",\r
+ "0B18B3D16F491619DA338640DF391D43",\r
+ "DBE09AC8F66027BF20CB6E434F252EFC",\r
+ "6D04E5E43C5B9CBE05FEB9606B6480FE",\r
+ "DD1D6553B96BE526D9FEE0FBD7176866",\r
+ "0260CA7E3F979FD015B0DD4690E16D2A",\r
+ "9893734DE10EDCC8A67C3B110B8B8CC6",\r
+ "93B30B750516B2D18808D710C2EE84EF",\r
+ "16F65FA47BE3CB5E6DFE7C6C37016C0E",\r
+ "F3847210D5391E2360608E5ACB560581",\r
+ "8754462CD223366D0753913E6AF2643D",\r
+ "1EA20617468D1B806A1FD58145462017",\r
+ "3B155D927355D737C6BE9DDA60136E2E",\r
+ "26144F7B66DAA91B6333DBD3850502B3",\r
+ "E4F9A4AB52CED8134C649BF319EBCC90",\r
+ "B9DDD29AC6128A6CAB121E34A4C62B36",\r
+ "6FCDDAD898F2CE4EFF51294F5EAAF5C9",\r
+ "C9A6FE2BF4028080BEA6F7FC417BD7E3",\r
+ "6A2026846D8609D60F298A9C0673127F",\r
+ "2CB25C005E26EFEA44336C4C97A4240B",\r
+ "496967AB8680DDD73D09A0E4C7DCC8AA",\r
+ "D5AF94DE93487D1F3A8C577CB84A66A4",\r
+ "84BDAC569CAE2828705F267CC8376E90",\r
+ "F7401DDA5AD5AB712B7EB5D10C6F99B6",\r
+ "1C9D54318539EBD4C3B5B7E37BF119F0",\r
+ "ACA572D65FB2764CFFD4A6ECA090EA0D",\r
+ "36D9C627B8C2A886A10CCB36EAE3DFBB",\r
+ "010EDBF5981E143A81D646E597A4A568",\r
+ "8DB44D538DC20CC2F40F3067FD298E60",\r
+ "930EB53BC71E6AC4B82972BDCD5AAFB3",\r
+ "6C42A81EDCBC9517CCD89C30C95597B4",\r
+ "DA389847AD06DF19D76EE119C71E1DD3",\r
+ "E018FDAE13D3118F9A5D1A647A3F0462",\r
+ "2AA65DB36264239D3846180FABDFAD20",\r
+ "1472163E9A4F780F1CEB44B07ECF4FDB",\r
+ "C8273FDC8F3A9F72E91097614B62397C",\r
+ "66C8427DCD733AAF7B3470CB7D976E3F",\r
+ "146131CB17F1424D4F8DA91E6F80C1D0",\r
+ "2610D0AD83659081AE085266A88770DC",\r
+ "38A2B5A974B0575C5D733917FB0D4570",\r
+ "E21D401EBC60DE20D6C486E4F39A588B",\r
+ "E51D5F88C670B079C0CA1F0C2C4405A2",\r
+ "246A94788A642FB3D1B823C8762380C8",\r
+ "B80C391C5C41A4C3B30C68E0E3D7550F",\r
+ "B77C4754FC64EB9A1154A9AF0BB1F21C",\r
+ "FB554DE520D159A06BF219FC7F34A02F",\r
+ "A89FBA152D76B4927BEED160DDB76C57",\r
+ "5676EAB4A98D2E8473B3F3D46424247C",\r
+ "4E8F068BD7EDE52A639036EC86C33568",\r
+ "F0193C4D7AFF1791EE4C07EB4A1824FC",\r
+ "AC8686EECA9BA761AFE82D67B928C33F",\r
+ "5FAF8573E33B145B6A369CD3606AB2C9",\r
+ "31587E9944AB1C16B844ECAD0DF2E7DA",\r
+ "D017FECD91148ABA37F6F3068AA67D8A",\r
+ "788EF2F021A73CBA2794B616078A8500",\r
+ "5D1EF20DCED6BCBC12131AC7C54788AA",\r
+ "B3C8CF961FAF9EA05FDDE6D1E4D8F663",\r
+ "143075C70605861C7FAC6526199E459F",\r
+ "A5AE12EADE9A87268D898BFC8FC0252A",\r
+ "0924F7CF2E877A4819F5244A360DCEA9",\r
+ "3D9E9635AFCC3E291CC7AB3F27D1C99A",\r
+ "9D80FEEBF87510E2B8FB98BB54FD788C",\r
+ "5F9D1A082A1A37985F174002ECA01309",\r
+ "A390EBB1D1403930184A44B4876646E4",\r
+ "700FE918981C3195BB6C4BCB46B74E29",\r
+ "907984406F7BF2D17FB1EB15B673D747",\r
+ "C32A956DCFC875C2AC7C7CC8B8CC26E1",\r
+ "02646E2EBFA9B820CF8424E9B9B6EB51",\r
+ "621FDA3A5BBD54C6D3C685816BD4EAD8",\r
+ "D4E216040426DFAF18B152469BC5AC2F",\r
+ "9D0635B9D33B6CDBD71F5D246EA17CC8",\r
+ "10ABAD1BD9BAE5448808765583A2CC1A",\r
+ "6891889E16544E355FF65A793C39C9A8",\r
+ "CC735582E68072C163CD9DDF46B91279",\r
+ "C5C68B9AEEB7F878DF578EFA562F9574",\r
+ "5F4764395A667A47D73452955D0D2CE8",\r
+ "701448331F66106CEFDDF1EB8267C357",\r
+ "CB3EE56D2E14B4E1941666F13379D657",\r
+ "9FE16EFD18AB6E1981191851FEDB0764",\r
+ "3DC9BA24E1B223589B147ADCEB4C8E48",\r
+ "1C333032682E7D4DE5E5AFC05C3E483C",\r
+ "D593CC99A95AFEF7E92038E05A59D00A",\r
+ "51E7F96F53B4353923452C222134E1EC",\r
+ "4075B357A1A2B473400C3B25F32F81A4",\r
+ "302E341A3EBCD74F0D55F61714570284",\r
+ "57ABDD8231280DA01C5042B78CF76522",\r
+ "17F9EA7EEA17AC1ADF0E190FEF799E92",\r
+ "2E1BDD563DD87EE5C338DD6D098D0A7A",\r
+ "EB869996E6F8BFB2BFDD9E0C4504DBB2",\r
+ "C2E01549E9DECF317468B3E018C61BA8",\r
+ "8DA875D033C01DD463B244A1770F4A22",\r
+ "8BA0DCF3A186844F026D022F8839D696",\r
+ "E9691FF9A6CC6970E51670A0FD5B88C1",\r
+ "F2BAEC06FAEED30F88EE63BA081A6E5B",\r
+ "9C39D4C459AE5753394D6094ADC21E78",\r
+ "6345B532A11904502EA43BA99C6BD2B2",\r
+ "5FFAE3061A95172E4070CEDCE1E428C8",\r
+ "0A4566BE4CDF9ADCE5DEC865B5AB34CD",\r
+ "CA17FCCE79B7404F2559B22928F126FB",\r
+ "97CA39B849ED73A6470A97C821D82F58",\r
+ "8198CB06BC684C6D3E9B7989428DCF7A",\r
+ "F53C464C705EE0F28D9A4C59374928BD",\r
+ "9ADB3D4CCA559BB98C3E2ED73DBF1154",\r
+ "1946DABF6A03A2A2C3D0B05080AED6FC",\r
+ "5ED301D747D3CC715445EBDEC62F2FB4",\r
+ "6585C8F43D13A6BEAB6419FC5935B9D0",\r
+ "2A5B56A596680FCC0E05F5E0F151ECAE",\r
+ "F5D6FF414FD2C6181494D20C37F2B8C4",\r
+ "85399C01F59FFFB5204F19F8482F00B8",\r
+ "92097B4C88A041DDF98144BC8D22E8E7",\r
+ "89BD5B73B356AB412AEF9F76CEA2D65C",\r
+ "2536969093C55FF9454692F2FAC2F530",\r
+ "07FC76A872843F3F6E0081EE9396D637",\r
+ "E38BA8EC2AA741358DCC93E8F141C491",\r
+ "D028EE23E4A89075D0B03E868D7D3A42",\r
+ "8CD9423DFC459E547155C5D1D522E540",\r
+ "080E9517EB1677719ACF728086040AE3",\r
+ "7C1700211A3991FC0ECDED0AB3E576B0",\r
+ "DABCBCC855839251DB51E224FBE87435",\r
+ "68D56FAD0406947A4DD27A7448C10F1D",\r
+ "DA9A11479844D1FFEE24BBF3719A9925",\r
+ "5E4BA572F8D23E738DA9B05BA24B8D81",\r
+ "A115A2065D667E3F0B883837A6E903F8",\r
+ "3E9E90DC33EAC2437D86AD30B137E66E",\r
+ "01CE82D8FBCDAE824CB3C48E495C3692",\r
+ "0C9CFF163CE936FAAF083CFD3DEA3117",\r
+ "5131BA9BD48F2BBA85560680DF504B52",\r
+ "9DC503BBF09823AEC8A977A5AD26CCB2",\r
+ "9A6DB0C0862E506A9E397225884041D7",\r
+ "430BF9570804185E1AB6365FC6A6860C",\r
+ "3525EBC02F4886E6A5A3762813E8CE8A",\r
+ "07FA265C763779CCE224C7BAD671027B",\r
+ "E8B72B4E8BE243438C9FFF1F0E205872",\r
+ "109D4F999A0E11ACE1F05E6B22CBCB50",\r
+ "45A5E8D4C3ED58403FF08D68A0CC4029",\r
+ "196865964DB3D417B6BD4D586BCB7634",\r
+ "60436AD45AC7D30D99195F815D98D2AE",\r
+ "BB07A23F0B61014B197620C185E2CD75",\r
+ "5BC0B2850129C854423AFF0751FE343B",\r
+ "7541A78F96738E6417D2A24BD2BECA40",\r
+ "B0A303054412882E464591F1546C5B9E",\r
+ "778C06D8A355EEEE214FCEA14B4E0EEF",\r
+ "09614206D15CBACE63227D06DB6BEEBB",\r
+ "41B97FB20E427A9FDBBB358D9262255D",\r
+ "C1940F703D845F957652C2D64ABD7ADF",\r
+ "D2D44FCDAE5332343366DB297EFCF21B",\r
+ "EA8196B79DBE167B6AA9896E287EED2B",\r
+ "D6B0B0C4BA6C7DBE5ED467A1E3F06C2D",\r
+ "EC51EB295250C22C2FB01816FB72BCAE",\r
+ "ADED6630A07CE9C7408A155D3BD0D36F",\r
+ "697C9245B9937F32F5D1C82319F0363A",\r
+ "AAD5AD50C6262AAEC30541A1B7B5B19C",\r
+ "7D34B893855341EC625BD6875AC18C0D",\r
+ "7EF05105440F83862F5D780E88F02B41",\r
+ "C377C06403382061AF2C9C93A8E70DF6",\r
+ "1DBDB3FFDC052DACC83318853ABC6DE5",\r
+ "69A6EAB00432517D0BF483C91C0963C7",\r
+ "0797F41DC217C80446E1D514BD6AB197",\r
+ "9DFD76575902A637C01343C58E011A03",\r
+ "ACF4328AE78F34B9FA9B459747CC2658",\r
+ "B0479AEA12BAC4FE2384CF98995150C6",\r
+ "9DD52789EFE3FFB99F33B3DA5030109A",\r
+ "ABBB755E4621EF8F1214C19F649FB9FD",\r
+ "DA27FB8174357BCE2BED0E7354F380F9",\r
+ "C59A0663F0993838F6E5856593BDC5EF",\r
+ "ED60B264B5213E831607A99C0CE5E57E",\r
+ "E50548746846F3EB77B8C520640884ED",\r
+ "28282CC7D21D6A2923641E52D188EF0C",\r
+ "0DFA5B02ABB18E5A815305216D6D4F8E",\r
+ "7359635C0EECEFE31D673395FB46FB99",\r
+ "73C679F7D5AEF2745C9737BB4C47FB36",\r
+ "B192BD472A4D2EAFB786E97458967626",\r
+ "0EC327F6C8A2B147598CA3FDE61DC6A4",\r
+ "FC418EB3C41B859B38D4B6F646629729",\r
+ "30249E5AC282B1C981EA64B609F3A154",\r
+ "5E6E08646D12150776BB43C2D78A9703",\r
+ "FAEB3D5DE652CD3447DCEB343F30394A",\r
+ "A8E88706823F6993EF80D05C1C7B2CF0",\r
+ "8CED86677E6E00A1A1B15968F2D3CCE6",\r
+ "9FC7C23858BE03BDEBB84E90DB6786A9",\r
+ "B4FBD65B33F70D8CF7F1111AC4649C36",\r
+ "C5C32D5ED03C4B53CC8C1BD0EF0DBBF6",\r
+ "D1A7F03B773E5C212464B63709C6A891",\r
+ "6B7161D8745947AC6950438EA138D028",\r
+ "FD47A9F7E366EE7A09BC508B00460661",\r
+ "00D40B003DC3A0D9310B659B98C7E416",\r
+ "EEA4C79DCC8E2BDA691F20AC48BE0717",\r
+ "E78F43B11C204403E5751F89D05A2509",\r
+ "D0F0E3D1F1244BB979931E38DD1786EF",\r
+ "042E639DC4E1E4DDE7B75B749EA6F765",\r
+ "BC032FDD0EFE29503A980A7D07AB46A8",\r
+ "0C93AC949C0DA6446EFFB86183B6C910",\r
+ "E0D343E14DA75C917B4A5CEC4810D7C2",\r
+ "0EAFB821748408279B937B626792E619",\r
+ "FA1AC6E02D23B106A1FEF18B274A553F",\r
+ "0DADFE019CD12368075507DF33C1A1E9",\r
+ "3A0879B414465D9FFBAF86B33A63A1B9",\r
+ "62199FADC76D0BE1805D3BA0B7D914BF",\r
+ "1B06D6C5D333E742730130CF78E719B4",\r
+ "F1F848824C32E9DCDCBF21580F069329",\r
+ "1A09050CBD684F784D8E965E0782F28A",\r
+ "79C2969E7DED2BA7D088F3F320692360",\r
+ "091A658A2F7444C16ACCB669450C7B63",\r
+ "97C1E3A72CCA65FA977D5ED0E8A7BBFC",\r
+ "70C430C6DB9A17828937305A2DF91A2A",\r
+ "629553457FBE2479098571C7C903FDE8",\r
+ "A25B25A61F612669E7D91265C7D476BA",\r
+ "EB7E4E49B8AE0F024570DDA293254FED",\r
+ "38FE15D61CCA84516E924ADCE5014F67",\r
+ "3AD208492249108C9F3EBEB167AD0583",\r
+ "299BA9F9BF5AB05C3580FC26EDD1ED12",\r
+ "19DC705B857A60FB07717B2EA5717781",\r
+ "FFC8AEB885B5EFCAD06B6DBEBF92E76B",\r
+ "F58900C5E0B385253FF2546250A0142B",\r
+ "2EE67B56280BC462429CEE6E3370CBC1",\r
+ "20DB650A9C8E9A84AB4D25F7EDC8F03F",\r
+ "3C36DA169525CF818843805F25B78AE5",\r
+ "9A781D960DB9E45E37779042FEA51922",\r
+ "6560395EC269C672A3C288226EFDBA77",\r
+ "8C772B7A189AC544453D5916EBB27B9A",\r
+ "77CA5468CC48E843D05F78EED9D6578F",\r
+ "72CDCC71DC82C60D4429C9E2D8195BAA",\r
+ "8080D68CE60E94B40B5B8B69EEB35AFA",\r
+ "44222D3CDE299C04369D58AC0EBA1E8E",\r
+ "9B8721B0A8DFC691C5BC5885DBFCB27A",\r
+ "0DC015CE9A3A3414B5E62EC643384183",\r
+ "705715448A8DA412025CE38345C2A148",\r
+ "C32B5B0B6FBAE165266C569F4B6ECF0B",\r
+ "4DCA6C75192A01DDCA9476AF2A521E87",\r
+ "058691E627ECBC36AC07B6DB423BD698",\r
+ "7444527095838FE080FC2BCDD30847EB"];\r
+ \r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var aes:AESKey = new AESKey(key);\r
+ aes.encrypt(pt);\r
+ var out:String = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+cts[i]+" to "+out, cts[i]==out);\r
+ // now go back to plaintext.\r
+ aes.decrypt(pt);\r
+ out = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+pts[i]+" to "+out, pts[i]==out);\r
+ }\r
+ }\r
+ \r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ARC4Test\r
+ * \r
+ * A test class for ARC4\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.util.Hex;\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.crypto.prng.ARC4;\r
+ \r
+ public class ARC4Test extends TestCase\r
+ {\r
+ public function ARC4Test(h:ITestHarness)\r
+ {\r
+ super(h, "ARC4 Test");\r
+ runTest(testLameVectors,"ARC4 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Sad test vectors pilfered from\r
+ * http://en.wikipedia.org/wiki/RC4\r
+ */\r
+ public function testLameVectors():void {\r
+ var keys:Array = [\r
+ Hex.fromString("Key"),\r
+ Hex.fromString("Wiki"),\r
+ Hex.fromString("Secret")];\r
+ var pts:Array = [\r
+ Hex.fromString("Plaintext"),\r
+ Hex.fromString("pedia"),\r
+ Hex.fromString("Attack at dawn")];\r
+ var cts:Array = [\r
+ "BBF316E8D940AF0AD3",\r
+ "1021BF0420",\r
+ "45A01F645FC35B383552544B9BF5"];\r
+ \r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var rc4:ARC4 = new ARC4(key);\r
+ rc4.encrypt(pt);\r
+ var out:String = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+cts[i]+" to "+out, cts[i]==out);\r
+ // now go back to plaintext\r
+ rc4.init(key);\r
+ rc4.decrypt(pt);\r
+ out = Hex.fromArray(pt);\r
+ assert("comparing "+pts[i]+" to "+out, pts[i]==out);\r
+ }\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * BigIntegerTest\r
+ * \r
+ * A test class for BigInteger\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.math.BigInteger;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ public class BigIntegerTest extends TestCase\r
+ {\r
+ public function BigIntegerTest(h:ITestHarness)\r
+ {\r
+ super(h, "BigInteger Tests");\r
+ runTest(testAdd, "BigInteger Addition");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ public function testAdd():void {\r
+ var n1:BigInteger = BigInteger.nbv(25);\r
+ var n2:BigInteger = BigInteger.nbv(1002);\r
+ var n3:BigInteger = n1.add(n2);\r
+ var v:int = n3.valueOf();\r
+ assert("25+1002 = "+v, 25+1002==v);\r
+\r
+ var p:BigInteger = new BigInteger(Hex.toArray("e564d8b801a61f47"));\r
+ var xp:BigInteger = new BigInteger(Hex.toArray("99246db2a3507fa"));\r
+ \r
+ xp = xp.add(p);\r
+ \r
+ assert("xp==eef71f932bdb2741", xp.toString(16)=="eef71f932bdb2741");\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * BlowFishKeyTest\r
+ * \r
+ * A test class for BlowFishKey\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.symmetric.BlowFishKey;\r
+ import com.hurlant.util.Hex;\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class BlowFishKeyTest extends TestCase\r
+ {\r
+ public function BlowFishKeyTest(h:ITestHarness)\r
+ {\r
+ super(h, "BlowFishKey Test");\r
+ runTest(testECB,"BlowFish ECB Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Test vectors from http://www.schneier.com/code/vectors.txt\r
+ */\r
+ public function testECB():void {\r
+ var keys:Array = [\r
+ "0000000000000000",\r
+ "FFFFFFFFFFFFFFFF",\r
+ "3000000000000000",\r
+ "1111111111111111",\r
+ "0123456789ABCDEF",\r
+ "1111111111111111",\r
+ "0000000000000000",\r
+ "FEDCBA9876543210",\r
+ "7CA110454A1A6E57",\r
+ "0131D9619DC1376E",\r
+ "07A1133E4A0B2686",\r
+ "3849674C2602319E",\r
+ "04B915BA43FEB5B6",\r
+ "0113B970FD34F2CE",\r
+ "0170F175468FB5E6",\r
+ "43297FAD38E373FE",\r
+ "07A7137045DA2A16",\r
+ "04689104C2FD3B2F",\r
+ "37D06BB516CB7546",\r
+ "1F08260D1AC2465E",\r
+ "584023641ABA6176",\r
+ "025816164629B007",\r
+ "49793EBC79B3258F",\r
+ "4FB05E1515AB73A7",\r
+ "49E95D6D4CA229BF",\r
+ "018310DC409B26D6",\r
+ "1C587F1C13924FEF",\r
+ "0101010101010101",\r
+ "1F1F1F1F0E0E0E0E",\r
+ "E0FEE0FEF1FEF1FE",\r
+ "0000000000000000",\r
+ "FFFFFFFFFFFFFFFF",\r
+ "0123456789ABCDEF",\r
+ "FEDCBA9876543210" ];\r
+ var pts:Array = [\r
+ "0000000000000000",\r
+ "FFFFFFFFFFFFFFFF",\r
+ "1000000000000001",\r
+ "1111111111111111",\r
+ "1111111111111111",\r
+ "0123456789ABCDEF",\r
+ "0000000000000000",\r
+ "0123456789ABCDEF",\r
+ "01A1D6D039776742",\r
+ "5CD54CA83DEF57DA",\r
+ "0248D43806F67172",\r
+ "51454B582DDF440A",\r
+ "42FD443059577FA2",\r
+ "059B5E0851CF143A",\r
+ "0756D8E0774761D2",\r
+ "762514B829BF486A",\r
+ "3BDD119049372802",\r
+ "26955F6835AF609A",\r
+ "164D5E404F275232",\r
+ "6B056E18759F5CCA",\r
+ "004BD6EF09176062",\r
+ "480D39006EE762F2",\r
+ "437540C8698F3CFA",\r
+ "072D43A077075292",\r
+ "02FE55778117F12A",\r
+ "1D9D5C5018F728C2",\r
+ "305532286D6F295A",\r
+ "0123456789ABCDEF",\r
+ "0123456789ABCDEF",\r
+ "0123456789ABCDEF",\r
+ "FFFFFFFFFFFFFFFF",\r
+ "0000000000000000",\r
+ "0000000000000000",\r
+ "FFFFFFFFFFFFFFFF" ];\r
+ var cts:Array = [\r
+ "4EF997456198DD78",\r
+ "51866FD5B85ECB8A",\r
+ "7D856F9A613063F2",\r
+ "2466DD878B963C9D",\r
+ "61F9C3802281B096",\r
+ "7D0CC630AFDA1EC7",\r
+ "4EF997456198DD78",\r
+ "0ACEAB0FC6A0A28D",\r
+ "59C68245EB05282B",\r
+ "B1B8CC0B250F09A0",\r
+ "1730E5778BEA1DA4",\r
+ "A25E7856CF2651EB",\r
+ "353882B109CE8F1A",\r
+ "48F4D0884C379918",\r
+ "432193B78951FC98",\r
+ "13F04154D69D1AE5",\r
+ "2EEDDA93FFD39C79",\r
+ "D887E0393C2DA6E3",\r
+ "5F99D04F5B163969",\r
+ "4A057A3B24D3977B",\r
+ "452031C1E4FADA8E",\r
+ "7555AE39F59B87BD",\r
+ "53C55F9CB49FC019",\r
+ "7A8E7BFA937E89A3",\r
+ "CF9C5D7A4986ADB5",\r
+ "D1ABB290658BC778",\r
+ "55CB3774D13EF201",\r
+ "FA34EC4847B268B2",\r
+ "A790795108EA3CAE",\r
+ "C39E072D9FAC631D",\r
+ "014933E0CDAFF6E4",\r
+ "F21E9A77B71C49BC",\r
+ "245946885754369A",\r
+ "6B5C5A9C5D9E0A5A" ];\r
+\r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var bf:BlowFishKey = new BlowFishKey(key);\r
+ bf.encrypt(pt);\r
+ var out:String = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+cts[i]+" to "+out, cts[i]==out);\r
+ // now go back to plaintext\r
+ bf.decrypt(pt);\r
+ out = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+pts[i]+" to "+out, pts[i]==out);\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * CBCModeTest\r
+ * \r
+ * A test class for CBCMode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.CBCMode;\r
+ import com.hurlant.crypto.symmetric.NullPad;\r
+ import com.hurlant.crypto.symmetric.XTeaKey;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class CBCModeTest extends TestCase\r
+ {\r
+ public function CBCModeTest(h:ITestHarness) {\r
+ super(h, "CBCMode Test");\r
+ runTest(testAES,"CBC AES Test Vectors");\r
+ runTest(testXTea,"CBC XTea Test Vectors");\r
+ //\r
+ runTest(testCBC_AES128, "CBC AES-128 Test Vectors");\r
+ runTest(testCBC_AES192, "CBC AES-192 Test Vectors");\r
+ runTest(testCBC_AES256, "CBC AES-256 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Hawt NIST Vectors: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf\r
+ * Section F.2.1 and below.\r
+ */\r
+ public function testCBC_AES128():void {\r
+ var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "7649abac8119b246cee98e9b12e9197d" + \r
+ "5086cb9b507219ee95db113a917678b2" + \r
+ "73bed6b8e3c1743b7116e69e22229516" + \r
+ "3ff1caa1681fac09120eca307586e1a7");\r
+ var cbc:CBCMode = new CBCMode(new AESKey(key), new NullPad);\r
+ cbc.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cbc.encrypt(src);\r
+ assert("CBC_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cbc.decrypt(src);\r
+ assert("CBC_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testCBC_AES192():void {\r
+ var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "4f021db243bc633d7178183a9fa071e8" + \r
+ "b4d9ada9ad7dedf4e5e738763f69145a" + \r
+ "571b242012fb7ae07fa9baac3df102e0" + \r
+ "08b0e27988598881d920a9e64f5615cd");\r
+ var cbc:CBCMode = new CBCMode(new AESKey(key), new NullPad);\r
+ cbc.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cbc.encrypt(src);\r
+ assert("CBC_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cbc.decrypt(src);\r
+ assert("CBC_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testCBC_AES256():void {\r
+ var key:ByteArray = Hex.toArray(\r
+ "603deb1015ca71be2b73aef0857d7781" + \r
+ "1f352c073b6108d72d9810a30914dff4");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "f58c4c04d6e5f1ba779eabfb5f7bfbd6" + \r
+ "9cfc4e967edb808d679f777bc6702c7d" + \r
+ "39f23369a9d9bacfa530e26304231461" + \r
+ "b2eb05e2c39be9fcda6c19078c6a9d1b");\r
+ var cbc:CBCMode = new CBCMode(new AESKey(key), new NullPad);\r
+ cbc.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cbc.encrypt(src);\r
+ assert("CBC_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cbc.decrypt(src);\r
+ assert("CBC_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ \r
+ \r
+ /**\r
+ * For now the main goal is to show we can decrypt what we encrypt in this mode.\r
+ * Eventually, this should get correlated with some well known vectors.\r
+ */\r
+ public function testAES():void {\r
+ var keys:Array = [\r
+ "00010203050607080A0B0C0D0F101112",\r
+ "14151617191A1B1C1E1F202123242526"];\r
+ var cts:Array = [\r
+ "D8F532538289EF7D06B506A4FD5BE9C94894C5508A8D8E29AB600DB0261F0555A8FA287B89E65C0973F1F8283E70C72863FE1C8F1F782084CE05626E961A67B3",\r
+ "59AB30F4D4EE6E4FF9907EF65B1FB68C96890CE217689B1BE0C93ED51CF21BB5A0101A8C30714EC4F52DBC9C6F4126067D363F67ABE58463005E679B68F0B496"];\r
+ var pts:Array = [\r
+ "506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359",\r
+ "5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B"];\r
+\r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var aes:AESKey = new AESKey(key);\r
+ var cbc:CBCMode = new CBCMode(aes);\r
+ cbc.IV = Hex.toArray("00000000000000000000000000000000");\r
+ cbc.encrypt(pt);\r
+ var str:String = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+cts[i]+" to "+str, cts[i]==str);\r
+ // back to pt\r
+ cbc.decrypt(pt);\r
+ str = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+pts[i]+" to "+str, pts[i]==str);\r
+ }\r
+ }\r
+ public function testXTea():void {\r
+ var keys:Array=[\r
+ "00000000000000000000000000000000",\r
+ "2b02056806144976775d0e266c287843"];\r
+ var cts:Array = [\r
+ "2dc7e8d3695b0538d8f1640d46dca717790af2ab545e11f3b08e798eb3f17b1744299d4d20b534aa",\r
+ "790958213819878370eb8251ffdac371081c5a457fc42502c63910306fea150be8674c3b8e675516"];\r
+ var pts:Array=[\r
+ "0000000000000000000000000000000000000000000000000000000000000000",\r
+ "74657374206d652e74657374206d652e74657374206d652e74657374206d652e"];\r
+ \r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var tea:XTeaKey = new XTeaKey(key);\r
+ var cbc:CBCMode = new CBCMode(tea);\r
+ cbc.IV = Hex.toArray("0000000000000000");\r
+ cbc.encrypt(pt);\r
+ var str:String = Hex.fromArray(pt);\r
+ assert("comparing "+cts[i]+" to "+str, cts[i]==str);\r
+ // now go back to plaintext.\r
+ cbc.decrypt(pt);\r
+ str = Hex.fromArray(pt);\r
+ assert("comparing "+pts[i]+" to "+str, pts[i]==str);\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * CFB8ModeTest\r
+ * \r
+ * A test class for CFB8Mode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.crypto.symmetric.CFB8Mode;\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.NullPad;\r
+ \r
+ public class CFB8ModeTest extends TestCase\r
+ {\r
+ public function CFB8ModeTest(h:ITestHarness) {\r
+ super(h,"CBF8Mode Test");\r
+ runTest(testCFB8_AES128, "CFB-8 AES-128 Test Vectors");\r
+ runTest(testCFB8_AES192, "CFB-8 AES-192 Test Vectors");\r
+ runTest(testCFB8_AES256, "CFB-8 AES-192 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf\r
+ */\r
+ public function testCFB8_AES128():void {\r
+ var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");\r
+ var pt:ByteArray = Hex.toArray("6bc1bee22e409f96e93d7e117393172aae2d");\r
+ var ct:ByteArray = Hex.toArray("3b79424c9c0dd436bace9e0ed4586a4f32b9");\r
+ var cfb8:CFB8Mode = new CFB8Mode(new AESKey(key), new NullPad);\r
+ cfb8.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cfb8.encrypt(src);\r
+ assert("CFB8_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cfb8.decrypt(src);\r
+ assert("CFB8_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testCFB8_AES192():void {\r
+ var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");\r
+ var pt:ByteArray = Hex.toArray("6bc1bee22e409f96e93d7e117393172aae2d");\r
+ var ct:ByteArray = Hex.toArray("cda2521ef0a905ca44cd057cbf0d47a0678a");\r
+ var cfb8:CFB8Mode = new CFB8Mode(new AESKey(key), new NullPad);\r
+ cfb8.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cfb8.encrypt(src);\r
+ assert("CFB8_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cfb8.decrypt(src);\r
+ assert("CFB8_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testCFB8_AES256():void {\r
+ var key:ByteArray = Hex.toArray("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");\r
+ var pt:ByteArray = Hex.toArray("6bc1bee22e409f96e93d7e117393172aae2d");\r
+ var ct:ByteArray = Hex.toArray("dc1f1a8520a64db55fcc8ac554844e889700");\r
+ var cfb8:CFB8Mode = new CFB8Mode(new AESKey(key), new NullPad);\r
+ cfb8.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cfb8.encrypt(src);\r
+ assert("CFB8_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cfb8.decrypt(src);\r
+ assert("CFB8_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * CFBModeTest\r
+ * \r
+ * A test class for CFBMode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.CFBMode;\r
+ import com.hurlant.crypto.symmetric.NullPad;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+\r
+ public class CFBModeTest extends TestCase\r
+ {\r
+ public function CFBModeTest(h:ITestHarness)\r
+ {\r
+ super(h, "CFBMode Test");\r
+ runTest(testCFB_AES128, "CFB AES-128 Test Vectors");\r
+ runTest(testCFB_AES192, "CFB AES-192 Test Vectors");\r
+ runTest(testCFB_AES256, "CFB AES-256 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf\r
+ */\r
+ public function testCFB_AES128():void {\r
+ var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "3b3fd92eb72dad20333449f8e83cfb4a" + \r
+ "c8a64537a0b3a93fcde3cdad9f1ce58b" + \r
+ "26751f67a3cbb140b1808cf187a4f4df" + \r
+ "c04b05357c5d1c0eeac4c66f9ff7f2e6");\r
+ var cfb:CFBMode = new CFBMode(new AESKey(key), new NullPad);\r
+ cfb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cfb.encrypt(src);\r
+ assert("CFB_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cfb.decrypt(src);\r
+ assert("CFB_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testCFB_AES192():void {\r
+ var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "cdc80d6fddf18cab34c25909c99a4174" + \r
+ "67ce7f7f81173621961a2b70171d3d7a" + \r
+ "2e1e8a1dd59b88b1c8e60fed1efac4c9" + \r
+ "c05f9f9ca9834fa042ae8fba584b09ff");\r
+ var cfb:CFBMode = new CFBMode(new AESKey(key), new NullPad);\r
+ cfb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cfb.encrypt(src);\r
+ assert("CFB_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cfb.decrypt(src);\r
+ assert("CFB_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testCFB_AES256():void {\r
+ var key:ByteArray = Hex.toArray(\r
+ "603deb1015ca71be2b73aef0857d7781" + \r
+ "1f352c073b6108d72d9810a30914dff4");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "dc7e84bfda79164b7ecd8486985d3860" + \r
+ "39ffed143b28b1c832113c6331e5407b" + \r
+ "df10132415e54b92a13ed0a8267ae2f9" + \r
+ "75a385741ab9cef82031623d55b1e471");\r
+ var cfb:CFBMode = new CFBMode(new AESKey(key), new NullPad);\r
+ cfb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ cfb.encrypt(src);\r
+ assert("CFB_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ cfb.decrypt(src);\r
+ assert("CFB_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * CTRModeTest\r
+ * \r
+ * A test class for CTRMode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.crypto.symmetric.CTRMode;\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.NullPad;\r
+ \r
+ public class CTRModeTest extends TestCase\r
+ {\r
+ public function CTRModeTest(h:ITestHarness)\r
+ {\r
+ super(h, "CTRMode Test");\r
+ runTest(testCTR_AES128, "CTR AES-128 Test Vectors");\r
+ runTest(testCTR_AES192, "CTR AES-192 Test Vectors");\r
+ runTest(testCTR_AES256, "CTR AES-256 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Vectors from http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38A.pdf\r
+ * Section F.5.1 and below.\r
+ */\r
+ public function testCTR_AES128():void {\r
+ var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" +\r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "874d6191b620e3261bef6864990db6ce" + \r
+ "9806f66b7970fdff8617187bb9fffdff" + \r
+ "5ae4df3edbd5d35e5b4f09020db03eab" + \r
+ "1e031dda2fbe03d1792170a0f3009cee");\r
+ var ctr:CTRMode = new CTRMode(new AESKey(key), new NullPad);\r
+ ctr.IV = Hex.toArray("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ctr.encrypt(src);\r
+ var hsrc:String = Hex.fromArray(src);\r
+ var hct:String = Hex.fromArray(ct);\r
+ assert("CTR_AES128 test 1: "+hsrc+" != "+hct, hsrc==hct);\r
+ ctr.decrypt(src);\r
+ hsrc = Hex.fromArray(src);\r
+ var hpt:String = Hex.fromArray(pt);\r
+ assert("CTR_AES128 test 2: "+hsrc+" != "+hpt, hsrc==hpt);\r
+ }\r
+ public function testCTR_AES192():void {\r
+ var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" +\r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "1abc932417521ca24f2b0459fe7e6e0b" + \r
+ "090339ec0aa6faefd5ccc2c6f4ce8e94" + \r
+ "1e36b26bd1ebc670d1bd1d665620abf7" + \r
+ "4f78a7f6d29809585a97daec58c6b050");\r
+ var ctr:CTRMode = new CTRMode(new AESKey(key), new NullPad);\r
+ ctr.IV = Hex.toArray("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ctr.encrypt(src);\r
+ var hsrc:String = Hex.fromArray(src);\r
+ var hct:String = Hex.fromArray(ct);\r
+ assert("CTR_AES192 test 1: "+hsrc+" != "+hct, hsrc==hct);\r
+ ctr.decrypt(src);\r
+ hsrc = Hex.fromArray(src);\r
+ var hpt:String = Hex.fromArray(pt);\r
+ assert("CTR_AES192 test 2: "+hsrc+" != "+hpt, hsrc==hpt);\r
+ }\r
+ public function testCTR_AES256():void {\r
+ var key:ByteArray = Hex.toArray("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" +\r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "601ec313775789a5b7a7f504bbf3d228" + \r
+ "f443e3ca4d62b59aca84e990cacaf5c5" + \r
+ "2b0930daa23de94ce87017ba2d84988d" + \r
+ "dfc9c58db67aada613c2dd08457941a6");\r
+ var ctr:CTRMode = new CTRMode(new AESKey(key), new NullPad);\r
+ ctr.IV = Hex.toArray("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ctr.encrypt(src);\r
+ var hsrc:String = Hex.fromArray(src);\r
+ var hct:String = Hex.fromArray(ct);\r
+ assert("CTR_AES256 test 1: "+hsrc+" != "+hct, hsrc==hct);\r
+ ctr.decrypt(src);\r
+ hsrc = Hex.fromArray(src);\r
+ var hpt:String = Hex.fromArray(pt);\r
+ assert("CTR_AES256 test 2: "+hsrc+" != "+hpt, hsrc==hpt);\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * DesKeyTest\r
+ * \r
+ * A test class for DesKey\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.symmetric.DESKey;\r
+ import com.hurlant.util.Hex;\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class DESKeyTest extends TestCase\r
+ {\r
+ public function DESKeyTest(h:ITestHarness)\r
+ {\r
+ super(h, "DESKey Test");\r
+ runTest(testECB,"DES ECB Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Test vectors mostly grabbed from\r
+ * http://csrc.nist.gov/publications/nistpubs/800-17/800-17.pdf\r
+ * (Appendix A and B)\r
+ * incomplete.\r
+ */\r
+ public function testECB():void {\r
+ var keys:Array = [\r
+ "3b3898371520f75e", // grabbed from the output of some js implementation out there\r
+ "10316E028C8F3B4A", // appendix A vector\r
+ "0101010101010101", // appendix B Table 1, round 0\r
+ "0101010101010101", // round 1\r
+ "0101010101010101", // 2\r
+ "0101010101010101", \r
+ "0101010101010101",\r
+ "0101010101010101",\r
+ "0101010101010101",\r
+ "0101010101010101",\r
+ "0101010101010101", // round 8\r
+ "8001010101010101", // app B, tbl 2, round 0\r
+ "4001010101010101",\r
+ "2001010101010101",\r
+ "1001010101010101",\r
+ "0801010101010101",\r
+ "0401010101010101",\r
+ "0201010101010101",\r
+ "0180010101010101",\r
+ "0140010101010101", // round 8\r
+ ];\r
+ var pts:Array = [\r
+ "0000000000000000", // js\r
+ "0000000000000000", // App A\r
+ "8000000000000000", // App B, tbl 1, rnd0\r
+ "4000000000000000",\r
+ "2000000000000000",\r
+ "1000000000000000",\r
+ "0800000000000000", // rnd 4\r
+ "0400000000000000",\r
+ "0200000000000000",\r
+ "0100000000000000",\r
+ "0080000000000000", // round 8\r
+ "0000000000000000", // App B, tbl2, rnd0\r
+ "0000000000000000",\r
+ "0000000000000000",\r
+ "0000000000000000",\r
+ "0000000000000000",\r
+ "0000000000000000",\r
+ "0000000000000000",\r
+ "0000000000000000",\r
+ "0000000000000000", // rnd 8\r
+ ];\r
+ var cts:Array = [\r
+ "83A1E814889253E0", // js\r
+ "82DCBAFBDEAB6602", // App A\r
+ "95F8A5E5DD31D900", // App b, tbl 1, rnd 0\r
+ "DD7F121CA5015619",\r
+ "2E8653104F3834EA",\r
+ "4BD388FF6CD81D4F",\r
+ "20B9E767B2FB1456",\r
+ "55579380D77138EF",\r
+ "6CC5DEFAAF04512F",\r
+ "0D9F279BA5D87260",\r
+ "D9031B0271BD5A0A", // rnd 8\r
+ "95A8D72813DAA94D", // App B, tbl 2, rnd 0\r
+ "0EEC1487DD8C26D5",\r
+ "7AD16FFB79C45926",\r
+ "D3746294CA6A6CF3",\r
+ "809F5F873C1FD761",\r
+ "C02FAFFEC989D1FC",\r
+ "4615AA1D33E72F10",\r
+ "2055123350C00858",\r
+ "DF3B99D6577397C8", // rnd 8\r
+ ];\r
+ \r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var des:DESKey = new DESKey(key);\r
+ des.encrypt(pt);\r
+ var out:String = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+cts[i]+" to "+out, cts[i]==out);\r
+ // now go back to plaintext\r
+ des.decrypt(pt);\r
+ out = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+pts[i]+" to "+out, pts[i]==out);\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ECBModeTest\r
+ * \r
+ * A test class for ECBMode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.ECBMode;\r
+ import com.hurlant.crypto.symmetric.NullPad;\r
+ import com.hurlant.crypto.symmetric.XTeaKey;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class ECBModeTest extends TestCase\r
+ {\r
+ public function ECBModeTest(h:ITestHarness) {\r
+ super(h, "ECBMode Test");\r
+ runTest(testAES,"ECB AES Test Vectors");\r
+ runTest(testXTea,"ECB XTea Test Vectors");\r
+ runTest(testECB_AES128,"ECB AES-128 Test Vectors");\r
+ runTest(testECB_AES192,"ECB AES-192 Test Vectors");\r
+ runTest(testECB_AES256,"ECB AES-256 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ /**\r
+ * For now the main goal is to show we can decrypt what we encrypt in this mode.\r
+ * Eventually, this should get correlated with some well known vectors.\r
+ * yay. found hawt test vectors: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf\r
+ */\r
+ public function testECB_AES128():void {\r
+ var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "3ad77bb40d7a3660a89ecaf32466ef97" + \r
+ "f5d3d58503b9699de785895a96fdbaaf" + \r
+ "43b1cd7f598ece23881b00e3ed030688" + \r
+ "7b0c785e27e8ad3f8223207104725dd4");\r
+ var ecb:ECBMode = new ECBMode(new AESKey(key), new NullPad);\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ecb.encrypt(src);\r
+ assert("ECB_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ ecb.decrypt(src);\r
+ assert("ECB_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testECB_AES192():void {\r
+ var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "bd334f1d6e45f25ff712a214571fa5cc" + \r
+ "974104846d0ad3ad7734ecb3ecee4eef" + \r
+ "ef7afd2270e2e60adce0ba2face6444e" + \r
+ "9a4b41ba738d6c72fb16691603c18e0e");\r
+ var ecb:ECBMode = new ECBMode(new AESKey(key), new NullPad);\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ecb.encrypt(src);\r
+ assert("ECB_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ ecb.decrypt(src);\r
+ assert("ECB_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ public function testECB_AES256():void {\r
+ var key:ByteArray = Hex.toArray(\r
+ "603deb1015ca71be2b73aef0857d7781" + \r
+ "1f352c073b6108d72d9810a30914dff4");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "f3eed1bdb5d2a03c064b5a7e3db181f8" + \r
+ "591ccb10d410ed26dc5ba74a31362870" + \r
+ "b6ed21b99ca6f4f9f153e7b1beafed1d" + \r
+ "23304b7a39f9f3ff067d8d8f9e24ecc7");\r
+ var ecb:ECBMode = new ECBMode(new AESKey(key), new NullPad);\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ecb.encrypt(src);\r
+ assert("ECB_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ ecb.decrypt(src);\r
+ assert("ECB_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ // crappier, older testing. keeping around for no good reason.\r
+ public function testAES():void {\r
+ var keys:Array = [\r
+ "00010203050607080A0B0C0D0F101112",\r
+ "14151617191A1B1C1E1F202123242526"];\r
+ var pts:Array = [\r
+ "506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359",\r
+ "5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B"];\r
+ var cts:Array = [\r
+ "D8F532538289EF7D06B506A4FD5BE9C9D8F532538289EF7D06B506A4FD5BE9C9D8F532538289EF7D06B506A4FD5BE9C96DE5F607AB7EB8202F3957703B04E8B5",\r
+ "59AB30F4D4EE6E4FF9907EF65B1FB68C59AB30F4D4EE6E4FF9907EF65B1FB68C59AB30F4D4EE6E4FF9907EF65B1FB68C2993487785CB1CFDA6BB4F0F345F76C7"];\r
+\r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var aes:AESKey = new AESKey(key);\r
+ var ecb:ECBMode = new ECBMode(aes);\r
+ ecb.encrypt(pt);\r
+ var str:String = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+cts[i]+" to "+str, cts[i]==str);\r
+ // back to pt\r
+ ecb.decrypt(pt);\r
+ str = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+pts[i]+" to "+str, pts[i]==str);\r
+ }\r
+ }\r
+ public function testXTea():void {\r
+ var keys:Array=[\r
+ "00000000000000000000000000000000",\r
+ "2b02056806144976775d0e266c287843"];\r
+ var pts:Array=[\r
+ "0000000000000000000000000000000000000000000000000000000000000000",\r
+ "74657374206d652e74657374206d652e74657374206d652e74657374206d652e"];\r
+ var cts:Array=[\r
+ "2dc7e8d3695b05382dc7e8d3695b05382dc7e8d3695b05382dc7e8d3695b053820578a874233632d",\r
+ "79095821381987837909582138198783790958213819878379095821381987830e4dc3c48b2edf32"];\r
+ // self-fullfilling vectors.\r
+ // oh well, at least I can decrypt what I produce. :(\r
+ \r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var tea:XTeaKey = new XTeaKey(key);\r
+ var ecb:ECBMode = new ECBMode(tea);\r
+ ecb.encrypt(pt);\r
+ var str:String = Hex.fromArray(pt);\r
+ assert("comparing "+cts[i]+" to "+str, cts[i]==str);\r
+ // now go back to plaintext.\r
+ ecb.decrypt(pt);\r
+ str = Hex.fromArray(pt);\r
+ assert("comparing "+pts[i]+" to "+str, pts[i]==str);\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * HMACTest\r
+ * \r
+ * A test class for HMAC\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.hash.HMAC;\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ import com.hurlant.crypto.hash.SHA224;\r
+ import com.hurlant.crypto.hash.SHA256;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class HMACTest extends TestCase\r
+ {\r
+ public function HMACTest(h:ITestHarness)\r
+ {\r
+ super(h, "HMAC Test");\r
+ runTest(testHMAC_MD5,"HMAC MD5 Test Vectors");\r
+ runTest(testHMAC_SHA_1,"HMAC SHA-1 Test Vectors");\r
+ runTest(testHMAC_SHA_2,"HMAC SHA-224/SHA-256 Test Vectors");\r
+ runTest(testHMAC96_MD5,"HMAC-96 MD5 Test Vectors");\r
+ runTest(testHMAC96_SHA_1,"HMAC-96 SHA-1 Test Vectors");\r
+ runTest(testHMAC128_SHA_2,"HMAC-128 SHA-224/SHA-256 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ /**\r
+ * Test vectors taking from RFC2202\r
+ * http://tools.ietf.org/html/rfc2202\r
+ * Yes, it's from an RFC, jefe! Now waddayawant?\r
+ */\r
+ public function testHMAC_SHA_1():void {\r
+ var keys:Array = [\r
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",\r
+ Hex.fromString("Jefe"),\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",\r
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",\r
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];\r
+ var pts:Array = [\r
+ Hex.fromString("Hi There"),\r
+ Hex.fromString("what do ya want for nothing?"),\r
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",\r
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",\r
+ Hex.fromString("Test With Truncation"),\r
+ Hex.fromString("Test Using Larger Than Block-Size Key - Hash Key First"),\r
+ Hex.fromString("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data")];\r
+ var cts:Array = [\r
+ "b617318655057264e28bc0b6fb378c8ef146be00",\r
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",\r
+ "125d7342b9ac11cd91a39af48aa17b4f63f175d3", \r
+ "4c9007f4026250c6bc8414f9bf50c86c2d7235da", \r
+ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",\r
+ "aa4ae5e15272d00e95705637ce8a3b55ed402112",\r
+ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"];\r
+ \r
+ var hmac:HMAC = new HMAC(new SHA1());\r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var digest:ByteArray = hmac.compute(key, pt);\r
+ assert("HMAC-SHA-1 test "+i, Hex.fromArray(digest) == cts[i]);\r
+ }\r
+ }\r
+ public function testHMAC96_SHA_1():void {\r
+ var hmac:HMAC = new HMAC(new SHA1, 96);\r
+ var key:ByteArray = Hex.toArray("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");\r
+ var pt:ByteArray = Hex.toArray(Hex.fromString("Test With Truncation"));\r
+ var ct:String = "4c1a03424b55e07fe7f27be1";\r
+ var digest:ByteArray = hmac.compute(key, pt);\r
+ assert("HMAC96-SHA-1 test", Hex.fromArray(digest) == ct);\r
+ }\r
+ \r
+ public function testHMAC_MD5():void {\r
+ var keys:Array = [\r
+ Hex.fromString("Jefe"),\r
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",\r
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",\r
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];\r
+ var pts:Array = [\r
+ Hex.fromString("what do ya want for nothing?"),\r
+ Hex.fromString("Hi There"),\r
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",\r
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",\r
+ Hex.fromString("Test With Truncation"),\r
+ Hex.fromString("Test Using Larger Than Block-Size Key - Hash Key First"),\r
+ Hex.fromString("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data")];\r
+ var cts:Array = [\r
+ "750c783e6ab0b503eaa86e310a5db738",\r
+ "9294727a3638bb1c13f48ef8158bfc9d",\r
+ "56be34521d144c88dbb8c733f0e8b3f6", \r
+ "697eaf0aca3a3aea3a75164746ffaa79",\r
+ "56461ef2342edc00f9bab995690efd4c",\r
+ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",\r
+ "6f630fad67cda0ee1fb1f562db3aa53e"];\r
+\r
+ var hmac:HMAC = new HMAC(new MD5());\r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var digest:ByteArray = hmac.compute(key, pt);\r
+ assert("HMAC-MD5 test "+i, Hex.fromArray(digest) == cts[i]);\r
+ }\r
+ }\r
+ public function testHMAC96_MD5():void {\r
+ var hmac:HMAC = new HMAC(new MD5, 96);\r
+ var key:ByteArray = Hex.toArray("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");\r
+ var pt:ByteArray = Hex.toArray(Hex.fromString("Test With Truncation"));\r
+ var ct:String = "56461ef2342edc00f9bab995";\r
+ var digest:ByteArray = hmac.compute(key, pt);\r
+ assert("HMAC96-MD5 test", Hex.fromArray(digest) == ct);\r
+ }\r
+ \r
+ /**\r
+ * Test vectors for HMAC-SHA-2 taken from RFC4231\r
+ * http://www.ietf.org/rfc/rfc4231.txt\r
+ * Still the same lame strings, but hidden in hex. why not.\r
+ */\r
+ public function testHMAC_SHA_2():void {\r
+ var keys:Array = [\r
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",\r
+ "4a656665",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",\r
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",\r
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];\r
+ var pts:Array = [\r
+ "4869205468657265",\r
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",\r
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",\r
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",\r
+ "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374",\r
+ "5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e"];\r
+ var cts224:Array = [\r
+ "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22",\r
+ "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44",\r
+ "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea",\r
+ "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a",\r
+ "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e",\r
+ "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1"];\r
+ var cts256:Array = [\r
+ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",\r
+ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",\r
+ "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",\r
+ "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",\r
+ "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",\r
+ "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"];\r
+ // 384 and 512 will be added. someday. if I ever figure how to do 64bit computations half efficiently in as3\r
+\r
+ var hmac224:HMAC = new HMAC(new SHA224);\r
+ var hmac256:HMAC = new HMAC(new SHA256);\r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var digest224:ByteArray = hmac224.compute(key, pt);\r
+ assert("HMAC-SHA-224 test "+i, Hex.fromArray(digest224) == cts224[i]);\r
+ var digest256:ByteArray = hmac256.compute(key, pt);\r
+ assert("HMAC-SHA-256 test "+i, Hex.fromArray(digest256) == cts256[i]);\r
+ }\r
+ }\r
+ public function testHMAC128_SHA_2():void {\r
+ var hmac224:HMAC = new HMAC(new SHA224,128);\r
+ var hmac256:HMAC = new HMAC(new SHA256,128);\r
+ var key:ByteArray = Hex.toArray("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");\r
+ var pt:ByteArray = Hex.toArray("546573742057697468205472756e636174696f6e");\r
+ var ct224:String = "0e2aea68a90c8d37c988bcdb9fca6fa8";\r
+ var ct256:String = "a3b6167473100ee06e0c796c2955552b";\r
+ var digest224:ByteArray = hmac224.compute(key, pt);\r
+ assert("HMAC128-SHA-224 test", Hex.fromArray(digest224) == ct224);\r
+ var digest256:ByteArray = hmac256.compute(key, pt);\r
+ assert("HMAC128-SHA-256 test", Hex.fromArray(digest256) == ct256);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ITestHarness\r
+ * \r
+ * An interface to specify what's available for test cases to use.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ public interface ITestHarness\r
+ {\r
+ function beginTestCase(name:String):void;\r
+ function endTestCase():void;\r
+ \r
+ function beginTest(name:String):void;\r
+ function passTest():void;\r
+ function failTest(msg:String):void;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * MD2Test\r
+ * \r
+ * A test class for MD2\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.hash.MD2;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class MD2Test extends TestCase\r
+ {\r
+ public function MD2Test(h:ITestHarness)\r
+ {\r
+ super(h, "MD2 Test");\r
+ runTest(testMd2, "MD2 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Test Vectors grabbed from\r
+ * http://www.faqs.org/rfcs/rfc1319.html\r
+ */\r
+ public function testMd2():void {\r
+ var srcs:Array = [\r
+ "",\r
+ Hex.fromString("a"),\r
+ Hex.fromString("abc"),\r
+ Hex.fromString("message digest"),\r
+ Hex.fromString("abcdefghijklmnopqrstuvwxyz"),\r
+ Hex.fromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),\r
+ Hex.fromString("12345678901234567890123456789012345678901234567890123456789012345678901234567890")\r
+ ];\r
+ var hashes:Array = [\r
+ "8350e5a3e24c153df2275c9f80692773",\r
+ "32ec01ec4a6dac72c0ab96fb34c0b5d1",\r
+ "da853b0d3f88d99b30283a69e6ded6bb",\r
+ "ab4f496bfb2a530b219ff33031fe06b0",\r
+ "4e8ddff3650292ab5a4108c3aa47940b",\r
+ "da33def2a42df13975352846c30338cd",\r
+ "d5976f79d83d3a0dc9806c3c66f3efd8"\r
+ ];\r
+ var md2:MD2 = new MD2;\r
+ for (var i:uint=0;i<srcs.length;i++) {\r
+ var src:ByteArray = Hex.toArray(srcs[i]);\r
+ var digest:ByteArray = md2.hash(src);\r
+ assert("MD2 Test "+i, Hex.fromArray(digest) == hashes[i]);\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * MD5Test\r
+ * \r
+ * A test class for MD5\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class MD5Test extends TestCase\r
+ {\r
+ public function MD5Test(h:ITestHarness)\r
+ {\r
+ super(h, "MD5 Test");\r
+ runTest(testMd5,"MD5 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Test Vectors grabbed from\r
+ * http://www.faqs.org/rfcs/rfc1321.html\r
+ */\r
+ public function testMd5():void {\r
+ var srcs:Array = [\r
+ "",\r
+ Hex.fromString("a"),\r
+ Hex.fromString("abc"),\r
+ Hex.fromString("message digest"),\r
+ Hex.fromString("abcdefghijklmnopqrstuvwxyz"),\r
+ Hex.fromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),\r
+ Hex.fromString("12345678901234567890123456789012345678901234567890123456789012345678901234567890")\r
+ ];\r
+ var hashes:Array = [\r
+ "d41d8cd98f00b204e9800998ecf8427e",\r
+ "0cc175b9c0f1b6a831c399e269772661",\r
+ "900150983cd24fb0d6963f7d28e17f72",\r
+ "f96b697d7cb7938d525a2f31aaf161d0",\r
+ "c3fcd3d76192e4007dfb496cca67e13b",\r
+ "d174ab98d277d9f5a5611c2c9f419d9f",\r
+ "57edf4a22be3c955ac49da2e2107b67a"\r
+ ];\r
+ var md5:MD5 = new MD5;\r
+ for (var i:uint=0;i<srcs.length;i++) {\r
+ var src:ByteArray = Hex.toArray(srcs[i]);\r
+ var digest:ByteArray = md5.hash(src);\r
+ assert("MD5 Test "+i, Hex.fromArray(digest) == hashes[i]);\r
+ }\r
+ \r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * OFBModeTest\r
+ * \r
+ * A test class for OFBMode\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.crypto.symmetric.OFBMode;\r
+ import com.hurlant.crypto.symmetric.AESKey;\r
+ import com.hurlant.crypto.symmetric.NullPad;\r
+ \r
+ public class OFBModeTest extends TestCase\r
+ {\r
+ public function OFBModeTest(h:ITestHarness)\r
+ {\r
+ super(h, "OFBMode Test");\r
+ runTest(testOFB_AES128,"OFB AES-128 Test Vectors");\r
+ runTest(testOFB_AES192,"OFB AES-192 Test Vectors");\r
+ runTest(testOFB_AES256,"OFB AES-256 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Nist Vectors: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf\r
+ * Section F.4.1 and below.\r
+ */\r
+ public function testOFB_AES128():void {\r
+ var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" +\r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "3b3fd92eb72dad20333449f8e83cfb4a" +\r
+ "7789508d16918f03f53c52dac54ed825" + \r
+ "9740051e9c5fecf64344f7a82260edcc" + \r
+ "304c6528f659c77866a510d9c1d6ae5e");\r
+ var ofb:OFBMode = new OFBMode(new AESKey(key), new NullPad);\r
+ ofb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ofb.encrypt(src);\r
+ assert("OFB_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ ofb.decrypt(src);\r
+ assert("OFB_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ \r
+ public function testOFB_AES192():void {\r
+ var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "cdc80d6fddf18cab34c25909c99a4174" + \r
+ "fcc28b8d4c63837c09e81700c1100401" + \r
+ "8d9a9aeac0f6596f559c6d4daf59a5f2" + \r
+ "6d9f200857ca6c3e9cac524bd9acc92a");\r
+ var ofb:OFBMode = new OFBMode(new AESKey(key), new NullPad);\r
+ ofb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ofb.encrypt(src);\r
+ assert("OFB_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ ofb.decrypt(src);\r
+ assert("OFB_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ \r
+ public function testOFB_AES256():void {\r
+ var key:ByteArray = Hex.toArray(\r
+ "603deb1015ca71be2b73aef0857d7781" + \r
+ "1f352c073b6108d72d9810a30914dff4");\r
+ var pt:ByteArray = Hex.toArray(\r
+ "6bc1bee22e409f96e93d7e117393172a" + \r
+ "ae2d8a571e03ac9c9eb76fac45af8e51" + \r
+ "30c81c46a35ce411e5fbc1191a0a52ef" + \r
+ "f69f2445df4f9b17ad2b417be66c3710");\r
+ var ct:ByteArray = Hex.toArray(\r
+ "dc7e84bfda79164b7ecd8486985d3860" + \r
+ "4febdc6740d20b3ac88f6ad82a4fb08d" + \r
+ "71ab47a086e86eedf39d1c5bba97c408" + \r
+ "0126141d67f37be8538f5a8be740e484");\r
+ var ofb:OFBMode = new OFBMode(new AESKey(key), new NullPad);\r
+ ofb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");\r
+ var src:ByteArray = new ByteArray;\r
+ src.writeBytes(pt);\r
+ ofb.encrypt(src);\r
+ assert("OFB_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));\r
+ ofb.decrypt(src);\r
+ assert("OFB_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * RSAKeyTest\r
+ * \r
+ * A test class for RSAKey\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.rsa.RSAKey;\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.util.der.PEM;\r
+ \r
+ public class RSAKeyTest extends TestCase\r
+ {\r
+ public function RSAKeyTest(h:ITestHarness)\r
+ {\r
+ super(h, "RSA Testing");\r
+ \r
+ runTest(testSmoke,"RSA smoke test");\r
+ runTest(testGenerate, "RSA Key Generation test");\r
+ runTest(testPEM, "RSA Private Key PEM parsing");\r
+ runTest(testPEM2, "RSA Public Key PEM parsing");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ public function testSmoke():void {\r
+ var N:String ="C4E3F7212602E1E396C0B6623CF11D26204ACE3E7D26685E037AD2507DCE82FC" + \r
+ "28F2D5F8A67FC3AFAB89A6D818D1F4C28CFA548418BD9F8E7426789A67E73E41";\r
+ var E:String = "10001";\r
+ var D:String = "7cd1745aec69096129b1f42da52ac9eae0afebbe0bc2ec89253598dcf454960e" + \r
+ "3e5e4ec9f8c87202b986601dd167253ee3fb3fa047e14f1dfd5ccd37e931b29d";\r
+ var P:String = "f0e4dd1eac5622bd3932860fc749bbc48662edabdf3d2826059acc0251ac0d3b";\r
+ var Q:String = "d13cb38fbcd06ee9bca330b4000b3dae5dae12b27e5173e4d888c325cda61ab3";\r
+ var DMP1:String = "b3d5571197fc31b0eb6b4153b425e24c033b054d22b9c8282254fe69d8c8c593";\r
+ var DMQ1:String = "968ffe89e50d7b72585a79b65cfdb9c1da0963cceb56c3759e57334de5a0ac3f";\r
+ var IQMP:String = "d9bc4f420e93adad9f007d0e5744c2fe051c9ed9d3c9b65f439a18e13d6e3908";\r
+ // create a key.\r
+ var rsa:RSAKey = RSAKey.parsePrivateKey(N,E,D, P,Q,DMP1,DMQ1,IQMP);\r
+ var txt:String = "hello";\r
+ var src:ByteArray = Hex.toArray(Hex.fromString(txt));\r
+ var dst:ByteArray = new ByteArray;\r
+ var dst2:ByteArray = new ByteArray;\r
+ rsa.encrypt(src, dst, src.length);\r
+ rsa.decrypt(dst, dst2, dst.length);\r
+ var txt2:String = Hex.toString(Hex.fromArray(dst2));\r
+ assert("rsa encrypt+decrypt", txt==txt2);\r
+ }\r
+ \r
+ public function testGenerate():void {\r
+ var rsa:RSAKey = RSAKey.generate(256, "10001");\r
+ // same lame smoke test here.\r
+ var txt:String = "hello";\r
+ var src:ByteArray = Hex.toArray(Hex.fromString(txt));\r
+ var dst:ByteArray = new ByteArray;\r
+ var dst2:ByteArray = new ByteArray;\r
+ rsa.encrypt(src, dst, src.length);\r
+ rsa.decrypt(dst, dst2, dst.length);\r
+ var txt2:String = Hex.toString(Hex.fromArray(dst2));\r
+ assert("rsa encrypt+decrypt", txt==txt2);\r
+ }\r
+ \r
+ public function testPEM():void {\r
+ var pem:String = "-----BEGIN RSA PRIVATE KEY-----\n" + \r
+ "MGQCAQACEQDJG3bkuB9Ie7jOldQTVdzPAgMBAAECEQCOGqcPhP8t8mX8cb4cQEaR\n" + \r
+ "AgkA5WTYuAGmH0cCCQDgbrto0i7qOQIINYr5btGrtccCCQCYy4qX4JDEMQIJAJll\n" + \r
+ "OnLVtCWk\n" + \r
+ "-----END RSA PRIVATE KEY-----";\r
+ var rsa:RSAKey = PEM.readRSAPrivateKey(pem);\r
+ //trace(rsa.dump());\r
+\r
+ // obligatory use\r
+ var txt:String = "hello";\r
+ var src:ByteArray = Hex.toArray(Hex.fromString(txt));\r
+ var dst:ByteArray = new ByteArray;\r
+ var dst2:ByteArray = new ByteArray;\r
+ rsa.encrypt(src, dst, src.length);\r
+ rsa.decrypt(dst, dst2, dst.length);\r
+ var txt2:String = Hex.toString(Hex.fromArray(dst2));\r
+ assert("rsa encrypt+decrypt", txt==txt2);\r
+ }\r
+ public function testPEM2():void {\r
+ var pem:String = "-----BEGIN PUBLIC KEY-----\n" + \r
+ "MCwwDQYJKoZIhvcNAQEBBQADGwAwGAIRAMkbduS4H0h7uM6V1BNV3M8CAwEAAQ==\n" + \r
+ "-----END PUBLIC KEY-----";\r
+ var rsa:RSAKey = PEM.readRSAPublicKey(pem);\r
+ //trace(rsa.dump());\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * SHA1Test\r
+ * \r
+ * A test class for SHA1\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class SHA1Test extends TestCase\r
+ {\r
+ public function SHA1Test(h:ITestHarness)\r
+ {\r
+ super(h, "SHA-1 Test");\r
+ runTest(testSha1,"SHA-1 Test Vectors");\r
+ runTest(testLongSha1,"SHA-1 Long Test Vectors");\r
+ h.endTestCase();\r
+ } \r
+ \r
+ /**\r
+ * Test Vectors grabbed from\r
+ * http://csrc.nist.gov/cryptval/shs.htm\r
+ */\r
+ public function testSha1():void {\r
+ var srcs:Array = [\r
+ "",\r
+ "a8",\r
+ "3000",\r
+ "42749e",\r
+ "9fc3fe08",\r
+ "b5c1c6f1af",\r
+ "e47571e5022e",\r
+ "3e1b28839fb758",\r
+ "a81350cbb224cb90",\r
+ "c243d167923dec3ce1",\r
+ "50ac18c59d6a37a29bf4",\r
+ "98e2b611ad3b1cccf634f6",\r
+ "73fe9afb68e1e8712e5d4eec",\r
+ "9e701ed7d412a9226a2a130e66",\r
+ "6d3ee90413b0a7cbf69e5e6144ca",\r
+ "fae24d56514efcb530fd4802f5e71f",\r
+ "c5a22dd6eda3fe2bdc4ddb3ce6b35fd1",\r
+ "d98cded2adabf08fda356445c781802d95",\r
+ "bcc6d7087a84f00103ccb32e5f5487a751a2",\r
+ "36ecacb1055434190dbbc556c48bafcb0feb0d",\r
+ "5ff9edb69e8f6bbd498eb4537580b7fba7ad31d0",\r
+ "c95b441d8270822a46a798fae5defcf7b26abace36",\r
+ "83104c1d8a55b28f906f1b72cb53f68cbb097b44f860",\r
+ "755175528d55c39c56493d697b790f099a5ce741f7754b",\r
+ "088fc38128bbdb9fd7d65228b3184b3faac6c8715f07272f",\r
+ "a4a586eb9245a6c87e3adf1009ac8a49f46c07e14185016895",\r
+ "8e7c555270c006092c2a3189e2a526b873e2e269f0fb28245256",\r
+ "a5f3bfa6bb0ba3b59f6b9cbdef8a558ec565e8aa3121f405e7f2f0",\r
+ "589054f0d2bd3c2c85b466bfd8ce18e6ec3e0b87d944cd093ba36469",\r
+ "a0abb12083b5bbc78128601bf1cbdbc0fdf4b862b24d899953d8da0ff3",\r
+ "82143f4cea6fadbf998e128a8811dc75301cf1db4f079501ea568da68eeb",\r
+ "9f1231dd6df1ff7bc0b0d4f989d048672683ce35d956d2f57913046267e6f3",\r
+ "041c512b5eed791f80d3282f3a28df263bb1df95e1239a7650e5670fc2187919",\r
+ "17e81f6ae8c2e5579d69dafa6e070e7111461552d314b691e7a3e7a4feb3fae418",\r
+ "d15976b23a1d712ad28fad04d805f572026b54dd64961fda94d5355a0cc98620cf77",\r
+ "09fce4d434f6bd32a44e04b848ff50ec9f642a8a85b37a264dc73f130f22838443328f",\r
+ "f17af27d776ec82a257d8d46d2b46b639462c56984cc1be9c1222eadb8b26594a25c709d",\r
+ "b13ce635d6f8758143ffb114f2f601cb20b6276951416a2f94fbf4ad081779d79f4f195b22",\r
+ "5498793f60916ff1c918dde572cdea76da8629ba4ead6d065de3dfb48de94d234cc1c5002910",\r
+ "498a1e0b39fa49582ae688cd715c86fbaf8a81b8b11b4d1594c49c902d197c8ba8a621fd6e3be5",\r
+ "3a36ae71521f9af628b3e34dcb0d4513f84c78ee49f10416a98857150b8b15cb5c83afb4b570376e",\r
+ "dcc76b40ae0ea3ba253e92ac50fcde791662c5b6c948538cffc2d95e9de99cac34dfca38910db2678f",\r
+ "5b5ec6ec4fd3ad9c4906f65c747fd4233c11a1736b6b228b92e90cddabb0c7c2fcf9716d3fad261dff33",\r
+ "df48a37b29b1d6de4e94717d60cdb4293fcf170bba388bddf7a9035a15d433f20fd697c3e4c8b8c5f590ab",\r
+ "1f179b3b82250a65e1b0aee949e218e2f45c7a8dbfd6ba08de05c55acfc226b48c68d7f7057e5675cd96fcfc",\r
+ "ee3d72da3a44d971578972a8e6780ce64941267e0f7d0179b214fa97855e1790e888e09fbe3a70412176cb3b54",\r
+ "d4d4c7843d312b30f610b3682254c8be96d5f6684503f8fbfbcd15774fc1b084d3741afb8d24aaa8ab9c104f7258",\r
+ "32c094944f5936a190a0877fb9178a7bf60ceae36fd530671c5b38c5dbd5e6a6c0d615c2ac8ad04b213cc589541cf6",\r
+ "e5d3180c14bf27a5409fa12b104a8fd7e9639609bfde6ee82bbf9648be2546d29688a65e2e3f3da47a45ac14343c9c02",\r
+ "e7b6e4b69f724327e41e1188a37f4fe38b1dba19cbf5a7311d6e32f1038e97ab506ee05aebebc1eed09fc0e357109818b9",\r
+ "bc880cb83b8ac68ef2fedc2da95e7677ce2aa18b0e2d8b322701f67af7d5e7a0d96e9e33326ccb7747cfff0852b961bfd475",\r
+ "235ea9c2ba7af25400f2e98a47a291b0bccdaad63faa2475721fda5510cc7dad814bce8dabb611790a6abe56030b798b75c944",\r
+ "07e3e29fed63104b8410f323b975fd9fba53f636af8c4e68a53fb202ca35dd9ee07cb169ec5186292e44c27e5696a967f5e67709",\r
+ "65d2a1dd60a517eb27bfbf530cf6a5458f9d5f4730058bd9814379547f34241822bf67e6335a6d8b5ed06abf8841884c636a25733f",\r
+ "dcc86b3bd461615bab739d8daafac231c0f462e819ad29f9f14058f3ab5b75941d4241ea2f17ebb8a458831b37a9b16dead4a76a9b0e",\r
+ "4627d54f0568dc126b62a8c35fb46a9ac5024400f2995e51635636e1afc4373dbb848eb32df23914230560b82477e9c3572647a7f2bb92",\r
+ "ba531affd4381168ef24d8b275a84d9254c7f5cc55fded53aa8024b2c5c5c8aa7146fe1d1b83d62b70467e9a2e2cb67b3361830adbab28d7",\r
+ "8764dcbcf89dcf4282eb644e3d568bdccb4b13508bfa7bfe0ffc05efd1390be22109969262992d377691eb4f77f3d59ea8466a74abf57b2ef4",\r
+ "497d9df9ddb554f3d17870b1a31986c1be277bc44feff713544217a9f579623d18b5ffae306c25a45521d2759a72c0459b58957255ab592f3be4",\r
+ "72c3c2e065aefa8d9f7a65229e818176eef05da83f835107ba90ec2e95472e73e538f783b416c04654ba8909f26a12db6e5c4e376b7615e4a25819",\r
+ "7cc9894454d0055ab5069a33984e2f712bef7e3124960d33559f5f3b81906bb66fe64da13c153ca7f5cabc89667314c32c01036d12ecaf5f9a78de98",\r
+ "74e8404d5a453c5f4d306f2cfa338ca65501c840ddab3fb82117933483afd6913c56aaf8a0a0a6b2a342fc3d9dc7599f4a850dfa15d06c61966d74ea59",\r
+ "46fe5ed326c8fe376fcc92dc9e2714e2240d3253b105adfbb256ff7a19bc40975c604ad7c0071c4fd78a7cb64786e1bece548fa4833c04065fe593f6fb10",\r
+ "836dfa2524d621cf07c3d2908835de859e549d35030433c796b81272fd8bc0348e8ddbc7705a5ad1fdf2155b6bc48884ac0cd376925f069a37849c089c8645",\r
+ "7e3a4c325cb9c52b88387f93d01ae86d42098f5efa7f9457388b5e74b6d28b2438d42d8b64703324d4aa25ab6aad153ae30cd2b2af4d5e5c00a8a2d0220c6116"];\r
+ var hashes:Array = [\r
+ "da39a3ee5e6b4b0d3255bfef95601890afd80709",\r
+ "99f2aa95e36f95c2acb0eaf23998f030638f3f15",\r
+ "f944dcd635f9801f7ac90a407fbc479964dec024",\r
+ "a444319e9b6cc1e8464c511ec0969c37d6bb2619",\r
+ "16a0ff84fcc156fd5d3ca3a744f20a232d172253",\r
+ "fec9deebfcdedaf66dda525e1be43597a73a1f93",\r
+ "8ce051181f0ed5e9d0c498f6bc4caf448d20deb5",\r
+ "67da53837d89e03bf652ef09c369a3415937cfd3",\r
+ "305e4ff9888ad855a78573cddf4c5640cce7e946",\r
+ "5902b77b3265f023f9bbc396ba1a93fa3509bde7",\r
+ "fcade5f5d156bf6f9af97bdfa9c19bccfb4ff6ab",\r
+ "1d20fbe00533c10e3cbd6b27088a5de0c632c4b5",\r
+ "7e1b7e0f7a8f3455a9c03e9580fd63ae205a2d93",\r
+ "706f0677146307b20bb0e8d6311e329966884d13",\r
+ "a7241a703aaf0d53fe142f86bf2e849251fa8dff",\r
+ "400f53546916d33ad01a5e6df66822dfbdc4e9e6",\r
+ "fac8ab93c1ae6c16f0311872b984f729dc928ccd",\r
+ "fba6d750c18da58f6e2aab10112b9a5ef3301b3b",\r
+ "29d27c2d44c205c8107f0351b05753ac708226b6",\r
+ "b971bfc1ebd6f359e8d74cb7ecfe7f898d0ba845",\r
+ "96d08c430094b9fcc164ad2fb6f72d0a24268f68",\r
+ "a287ea752a593d5209e287881a09c49fa3f0beb1",\r
+ "a06c713779cbd88519ed4a585ac0cb8a5e9d612b",\r
+ "bff7d52c13a3688132a1d407b1ab40f5b5ace298",\r
+ "c7566b91d7b6f56bdfcaa9781a7b6841aacb17e9",\r
+ "ffa30c0b5c550ea4b1e34f8a60ec9295a1e06ac1",\r
+ "29e66ed23e914351e872aa761df6e4f1a07f4b81",\r
+ "b28cf5e5b806a01491d41f69bd9248765c5dc292",\r
+ "60224fb72c46069652cd78bcd08029ef64da62f3",\r
+ "b72c4a86f72608f24c05f3b9088ef92fba431df7",\r
+ "73779ad5d6b71b9b8328ef7220ff12eb167076ac",\r
+ "a09671d4452d7cf50015c914a1e31973d20cc1a0",\r
+ "e88cdcd233d99184a6fd260b8fca1b7f7687aee0",\r
+ "010def22850deb1168d525e8c84c28116cb8a269",\r
+ "aeaa40ba1717ed5439b1e6ea901b294ba500f9ad",\r
+ "c6433791238795e34f080a5f1f1723f065463ca0",\r
+ "e21e22b89c1bb944a32932e6b2a2f20d491982c3",\r
+ "575323a9661f5d28387964d2ba6ab92c17d05a8a",\r
+ "feb44494af72f245bfe68e86c4d7986d57c11db7",\r
+ "cff2290b3648ba2831b98dde436a72f9ebf51eee",\r
+ "9b4efe9d27b965905b0c3dab67b8d7c9ebacd56c",\r
+ "afedb0ff156205bcd831cbdbda43db8b0588c113",\r
+ "8deb1e858f88293a5e5e4d521a34b2a4efa70fc4",\r
+ "95cbdac0f74afa69cebd0e5c7defbc6faf0cbeaf",\r
+ "f0307bcb92842e5ae0cd4f4f14f3df7f877fbef2",\r
+ "7b13bb0dbf14964bd63b133ac85e22100542ef55",\r
+ "c314d2b6cf439be678d2a74e890d96cfac1c02ed",\r
+ "4d0be361e410b47a9d67d8ce0bb6a8e01c53c078",\r
+ "e5353431ffae097f675cbf498869f6fbb6e1c9f2",\r
+ "b8720a7068a085c018ab18961de2765aa6cd9ac4",\r
+ "b0732181568543ba85f2b6da602b4b065d9931aa",\r
+ "9c22674cf3222c3ba921672694aafee4ce67b96b",\r
+ "d128335f4cecca9066cdae08958ce656ff0b4cfc",\r
+ "0b67c57ac578de88a2ae055caeaec8bb9b0085a0",\r
+ "c766f912a89d4ccda88e0cce6a713ef5f178b596",\r
+ "9aa3925a9dcb177b15ccff9b78e70cf344858779",\r
+ "4811fa30042fc076acf37c8e2274d025307e5943",\r
+ "6743018450c9730761ee2b130df9b91c1e118150",\r
+ "71ad4a19d37d92a5e6ef3694ddbeb5aa61ada645",\r
+ "a7d9dc68dacefb7d6116186048cb355cc548e11d",\r
+ "142e429f0522ba5abf5131fa81df82d355b96909",\r
+ "ef72db70dcbcab991e9637976c6faf00d22caae9",\r
+ "f220a7457f4588d639dc21407c942e9843f8e26b",\r
+ "ddd2117b6e309c233ede85f962a0c2fc215e5c69",\r
+ "a3054427cdb13f164a610b348702724c808a0dcc"];\r
+ // ok. let's loop.\r
+ var sha1:SHA1 = new SHA1;\r
+ for (var i:uint=0;i<srcs.length;i++) {\r
+ var src:ByteArray = Hex.toArray(srcs[i]);\r
+ var digest:ByteArray = sha1.hash(src);\r
+ assert("SHA1 Test "+i, Hex.fromArray(digest) == hashes[i]);\r
+ }\r
+ \r
+ }\r
+ /**\r
+ * A few long SHA-1, from the same page\r
+ */\r
+ public function testLongSha1():void {\r
+ var srcs:Array = [\r
+ "ec29561244ede706b6eb30a1c371d74450a105c3f9735f7fa9fe38cf67f304a5736a106e92e17139a6813b1c81a4f3d3fb9546ab4296fa9f722826c066869edacd73b2548035185813e22634a9da44000d95a281ff9f264ecce0a931222162d021cca28db5f3c2aa24945ab1e31cb413ae29810fd794cad5dfaf29ec43cb38d198fe4ae1da2359780221405bd6712a5305da4b1b737fce7cd21c0eb7728d08235a9011",\r
+ "5fc2c3f6a7e79dc94be526e5166a238899d54927ce470018fbfd668fd9dd97cbf64e2c91584d01da63be3cc9fdff8adfefc3ac728e1e335b9cdc87f069172e323d094b47fa1e652afe4d6aa147a9f46fda33cacb65f3aa12234746b9007a8c85fe982afed7815221e43dba553d8fe8a022cdac1b99eeeea359e5a9d2e72e382dffa6d19f359f4f27dc3434cd27daeeda8e38594873398678065fbb23665aba9309d946135da0e4a4afdadff14db18e85e71dd93c3bf9faf7f25c8194c4269b1ee3d9934097ab990025d9c3aaf63d5109f52335dd3959d38ae485050e4bbb6235574fc0102be8f7a306d6e8de6ba6becf80f37415b57f9898a5824e77414197422be3d36a6080",\r
+ "0f865f46a8f3aed2da18482aa09a8f390dc9da07d51d1bd10fe0bf5f3928d5927d08733d32075535a6d1c8ac1b2dc6ba0f2f633dc1af68e3f0fa3d85e6c60cb7b56c239dc1519a007ea536a07b518ecca02a6c31b46b76f021620ef3fc6976804018380e5ab9c558ebfc5cb1c9ed2d974722bf8ab6398f1f2b82fa5083f85c16a5767a3a07271d67743f00850ce8ec428c7f22f1cf01f99895c0c844845b06a06cecb0c6cf83eb55a1d4ebc44c2c13f6f7aa5e0e08abfd84e7864279057abc471ee4a45dbbb5774afa24e51791a0eada11093b88681fe30baa3b2e94113dc63342c51ca5d1a6096d0897b626e42cb91761058008f746f35465465540ad8c6b8b60f7e1461b3ce9e6529625984cb8c7d46f07f735be067588a0117f23e34ff57800e2bbe9a1605fde6087fb15d22c5d3ac47566b8c448b0cee40373e5ba6eaa21abee71366afbb27dbbd300477d70c371e7b8963812f5ed4fb784fb2f3bd1d3afe883cdd47ef32beaea",\r
+ "4893f1c763625f2c6ce53aacf28026f14b3cd8687e1a1d3b60a81e80fcd1e2b038f9145ab64a0718f948f7c3c9ac92e3d86fb669a5257da1a18c776291653688338210a3242120f101788e8acc9110db9258b1554bf3d26602516ea93606a25a7f566c0c758fb39ecd9d876bc5d8abc1c3205095382c2474cb1f8bbdb45c2c0e659cb0fc703ec607a5de6bcc7a28687db1ee1c8f34797bb2441d5706d210df8c2d7d65dbded36414d063c117b52a51f7a4eb9cac0782e008b47459ed5acac0bc1f20121087f992ad985511b33c866d18e63f585478ee5a5e654b19d81231d98683ae3f0533565aba43dce408d7e3c4c6be11d8f05165f29c9dcb2030c4ee31d3a04e7421aa92c3231a1fc07e50e95fea7389a5e65891afaba51cf55e36a9d089bf293accb356d5d06547307d6e41456d4ed146a056179971c56521c83109bf922866186e184a99a96c7bb96df8937e35970e438412a2b8d744cf2ad87cb605d4232e976f9f15169776e4e5b6b786132c966b25fc56d815c56c819af5e159aa39f8a93d38115f5580cda93bc073c30b39920e726fe861b72483a3f886269ab7a8eefe952f35d25c4eb7f443f4f3f26e43d51fb54591e6a6dad25fcdf5142033084e5624bdd51435e77dea86b8",\r
+ "cf494c18a4e17bf03910631471bca5ba7edea8b9a63381e3463517961749848eb03abefd4ce676dece3740860255f57c261a558aa9c7f11432f549a9e4ce31d8e17c79450ce2ccfc148ad904aedfb138219d7052088520495355dadd90f72e6f69f9c6176d3d45f113f275b7fbc2a295784d41384cd7d629b23d1459a22e45fd5097ec9bf65fa965d3555ec77367903c32141065fc24da5c56963d46a2da3c279e4035fb2fb1c0025d9dda5b9e3443d457d92401a0d3f58b48469ecb1862dc975cdbe75ca099526db8b0329b03928206f084c633c04eef5e8e377f118d30edf592504be9d2802651ec78aeb02aea167a03fc3e23e5fc907c324f283f89ab37e84687a9c74ccf055402db95c29ba2c8d79b2bd4fa96459f8e3b78e07e923b81198267492196ecb71e01c331f8df245ec5bdf8d0e05c91e63bb299f0f6324895304dda721d39410458f117c87b7dd6a0ee734b79fcbe482b2c9e9aa0cef03a39d4b0c86de3bc34b4aadabfa373fd2258f7c40c187744d237080762382f547a36adb117839ca72f8ebbc5a20a07e86f4c8bb923f5787698d278f6db0040e76e54645bb0f97083995b34b9aa445fc424455058795828dd00c32471ec402a307f5aa1b37b1a86d6dae3bcbfbe9ba41cab0beeabf489af0073d4b3837d3f14b815120bc3602d072b5aeefcdec655fe756b660eba7dcf34675acbce317746270599424b9248791a0780449c1eabbb9459cc1e588bfd74df9b1b711c85c09d8aa171b309281947e8f4b6ac438753158f4f36fa"];\r
+ var hashes:Array = [\r
+ "970111c4e77bcc88cc20459c02b69b4aa8f58217",\r
+ "0423dc76a8791107d14e13f5265b343f24cc0f19",\r
+ "6692a71d73e00f27df976bc56df4970650d90e45",\r
+ "dc5859dd5163c4354d5d577b855fa98e37f04384",\r
+ "4c17926feb6e87f5bca7890d8a5cde744f231dab"];\r
+ // ok. let's loop.\r
+ var sha1:SHA1 = new SHA1;\r
+ for (var i:uint=0;i<srcs.length;i++) {\r
+ var src:ByteArray = Hex.toArray(srcs[i]);\r
+ var digest:ByteArray = sha1.hash(src);\r
+ assert("SHA1 Long Test "+i, Hex.fromArray(digest) == hashes[i]);\r
+ }\r
+ \r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * SHA224Test\r
+ * \r
+ * A test class for SHA224\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.hash.SHA224;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class SHA224Test extends TestCase\r
+ {\r
+ public function SHA224Test(h:ITestHarness)\r
+ {\r
+ super(h,"SHA-224 Test");\r
+ runTest(testSha224,"SHA-224 Test Vectors");\r
+ // takes a few seconds, but uncomment if you must.\r
+ //runTest(testLongSha224,"SHA-224 Long Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Test vectors courtesy of\r
+ * http://www.ietf.org/rfc/rfc3874.txt\r
+ */\r
+ public function testSha224():void {\r
+ var srcs:Array = [\r
+ Hex.fromString("abc"),\r
+ Hex.fromString("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")];\r
+ var hashes:Array = [\r
+ "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",\r
+ "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"];\r
+ \r
+ var sha224:SHA224 = new SHA224;\r
+ for (var i:uint=0;i<srcs.length;i++) {\r
+ var src:ByteArray = Hex.toArray(srcs[i]);\r
+ var digest:ByteArray = sha224.hash(src);\r
+ assert("SHA224 Test "+i, Hex.fromArray(digest) == hashes[i]);\r
+ }\r
+ }\r
+ public function testLongSha224():void {\r
+ var src:ByteArray = new ByteArray;\r
+ var a:uint = "a".charCodeAt(0);\r
+ for (var i:uint=0;i<1e6;i++) {\r
+ src[i] = a;\r
+ }\r
+ var sha224:SHA224 = new SHA224;\r
+ var digest:ByteArray = sha224.hash(src);\r
+ var hash:String = "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67";\r
+ assert("SHA224 Long Test", Hex.fromArray(digest) == hash);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * SHA256Test\r
+ * \r
+ * A test class for SHA256\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.hash.SHA256;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class SHA256Test extends TestCase\r
+ {\r
+ public function SHA256Test(h:ITestHarness)\r
+ {\r
+ super(h,"SHA-256 Test");\r
+ runTest(testSha256,"SHA-256 Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Test vectors courtesy of\r
+ * https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/sha/Sha-2-256.unverified.test-vectors\r
+ */\r
+ public function testSha256():void {\r
+ var srcs:Array = [\r
+ Hex.fromString(""),\r
+ Hex.fromString("a"),\r
+ Hex.fromString("abc"),\r
+ Hex.fromString("message digest"),\r
+ Hex.fromString("abcdefghijklmnopqrstuvwxyz"),\r
+ Hex.fromString("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),\r
+ Hex.fromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),\r
+ Hex.fromString("12345678901234567890123456789012345678901234567890123456789012345678901234567890"),\r
+ ];\r
+ var hashes:Array = [\r
+ "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",\r
+ "CA978112CA1BBDCAFAC231B39A23DC4DA786EFF8147C4E72B9807785AFEE48BB",\r
+ "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD",\r
+ "F7846F55CF23E14EEBEAB5B4E1550CAD5B509E3348FBC4EFA3A1413D393CB650",\r
+ "71C480DF93D6AE2F1EFAD1447C66C9525E316218CF51FC8D9ED832F2DAF18B73",\r
+ "248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1",\r
+ "DB4BFCBD4DA0CD85A60C3C37D3FBD8805C77F15FC6B1FDFE614EE0A7C8FDB4C0",\r
+ "F371BC4A311F2B009EEF952DD83CA80E2B60026C8E935592D0F9C308453C813E"];\r
+ \r
+ // loop.\r
+ var sha256:SHA256 = new SHA256;\r
+ for (var i:uint=0;i<srcs.length;i++) {\r
+ var src:ByteArray = Hex.toArray(srcs[i]);\r
+ var digest:ByteArray = sha256.hash(src);\r
+ assert("SHA256 Test "+i, Hex.fromArray(digest) == hashes[i].toLowerCase());\r
+ }\r
+ \r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TLSPRFTest\r
+ * \r
+ * A test class for TLFPRF\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.crypto.prng.TLSPRF;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ public class TLSPRFTest extends TestCase\r
+ {\r
+ public function TLSPRFTest(h:ITestHarness) {\r
+ super(h, "TLS-PRF Testing");\r
+ runTest(testVector, "TLF-PRF Test Vector");\r
+ h.endTestCase()\r
+ }\r
+ \r
+ /**\r
+ * Test Vector as defined in\r
+ * http://www.imc.org/ietf-tls/mail-archive/msg01589.html\r
+ */\r
+ private function testVector():void {\r
+ var secret:ByteArray = new ByteArray;\r
+ for (var i:uint=0;i<48;i++) {\r
+ secret[i]= 0xab;\r
+ }\r
+ var label:String = "PRF Testvector";\r
+ var seed:ByteArray = new ByteArray;\r
+ for (i=0;i<64;i++) {\r
+ seed[i] = 0xcd;\r
+ }\r
+ var prf:TLSPRF = new TLSPRF(secret, label, seed);\r
+ var out:ByteArray = new ByteArray;\r
+ prf.nextBytes(out, 104);\r
+ var expected:String = "D3 D4 D1 E3 49 B5 D5 15 04 46 66 D5 1D E3 2B AB" + \r
+ "25 8C B5 21 B6 B0 53 46 3E 35 48 32 FD 97 67 54" + \r
+ "44 3B CF 9A 29 65 19 BC 28 9A BC BC 11 87 E4 EB" + \r
+ "D3 1E 60 23 53 77 6C 40 8A AF B7 4C BC 85 EF F6" + \r
+ "92 55 F9 78 8F AA 18 4C BB 95 7A 98 19 D8 4A 5D" + \r
+ "7E B0 06 EB 45 9D 3A E8 DE 98 10 45 4B 8B 2D 8F" + \r
+ "1A FB C6 55 A8 C9 A0 13";\r
+ var expect:String = Hex.fromArray(Hex.toArray(expected));\r
+ assert("out == expected", Hex.fromArray(out)==expect);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TestCase\r
+ * \r
+ * Embryonic unit test support class.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ public class TestCase \r
+ {\r
+ public var harness:ITestHarness;\r
+ \r
+ public function TestCase(h:ITestHarness, title:String) {\r
+ harness = h;\r
+ harness.beginTestCase(title);\r
+ }\r
+ \r
+ \r
+ public function assert(msg:String, value:Boolean):void {\r
+ if (value) {\r
+// TestHarness.print("+ ",msg);\r
+ return;\r
+ }\r
+ throw new Error("Test Failure:"+msg);\r
+ }\r
+ \r
+ public function runTest(f:Function, title:String):void {\r
+ harness.beginTest(title);\r
+ try {\r
+ f();\r
+ } catch (e:Error) {\r
+ trace("EXCEPTION THROWN: "+e);\r
+ trace(e.getStackTrace());\r
+ harness.failTest(e.toString());\r
+ return;\r
+ }\r
+ harness.passTest();\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TripleDESKeyTest\r
+ * \r
+ * A test class for TripleDESKey\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.symmetric.TripleDESKey;\r
+ import com.hurlant.util.Hex;\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.crypto.symmetric.ICipher;\r
+ import com.hurlant.crypto.symmetric.ECBMode;\r
+ \r
+ public class TripleDESKeyTest extends TestCase\r
+ {\r
+ public function TripleDESKeyTest(h:ITestHarness)\r
+ {\r
+ super(h, "Triped Des Test");\r
+ runTest(testECB,"Triple DES ECB Test Vectors");\r
+ h.endTestCase();\r
+ }\r
+ \r
+ /**\r
+ * Lots of vectors at http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf\r
+ * XXX move them in here.\r
+ */\r
+ public function testECB():void {\r
+ var keys:Array = [\r
+ "010101010101010101010101010101010101010101010101",\r
+ "dd24b3aafcc69278d650dad234956b01e371384619492ac4",\r
+ ];\r
+ var pts:Array = [\r
+ "8000000000000000",\r
+ "F36B21045A030303",\r
+ ];\r
+ var cts:Array = [\r
+ "95F8A5E5DD31D900",\r
+ "E823A43DEEA4D0A4",\r
+ ];\r
+ \r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var ede:TripleDESKey = new TripleDESKey(key);\r
+ ede.encrypt(pt);\r
+ var out:String = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+cts[i]+" to "+out, cts[i]==out);\r
+ // now go back to plaintext\r
+ ede.decrypt(pt);\r
+ out = Hex.fromArray(pt).toUpperCase();\r
+ assert("comparing "+pts[i]+" to "+out, pts[i]==out);\r
+ }\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * XTeaKeyTest\r
+ * \r
+ * A test class for XTeaKey\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tests\r
+{\r
+ import com.hurlant.crypto.prng.Random;\r
+ import com.hurlant.crypto.symmetric.ECBMode;\r
+ import com.hurlant.crypto.symmetric.XTeaKey;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ import flash.utils.getTimer;\r
+ \r
+ public class XTeaKeyTest extends TestCase\r
+ {\r
+ public function XTeaKeyTest(h:ITestHarness) {\r
+ super(h, "XTeaKey Test");\r
+ runTest(testGetBlockSize, "XTea Block Size");\r
+ runTest(testVectors, "XTea Test Vectors");\r
+ \r
+ h.endTestCase();\r
+ }\r
+ \r
+ public function testGetBlockSize():void {\r
+ var tea:XTeaKey = new XTeaKey(Hex.toArray("deadbabecafebeefdeadbabecafebeef"));\r
+ assert("tea blocksize", tea.getBlockSize()==8);\r
+ }\r
+ \r
+ public function testVectors():void {\r
+ // blah.\r
+ // can't find working test vectors.\r
+ // algorithms should not get published without vectors :(\r
+ var keys:Array=[\r
+ "00000000000000000000000000000000",\r
+ "2b02056806144976775d0e266c287843"];\r
+ var pts:Array=[\r
+ "0000000000000000",\r
+ "74657374206d652e"];\r
+ var cts:Array=[\r
+ "2dc7e8d3695b0538",\r
+ "7909582138198783"];\r
+ // self-fullfilling vectors.\r
+ // oh well, at least I can decrypt what I produce. :(\r
+ \r
+ for (var i:uint=0;i<keys.length;i++) {\r
+ var key:ByteArray = Hex.toArray(keys[i]);\r
+ var pt:ByteArray = Hex.toArray(pts[i]);\r
+ var tea:XTeaKey = new XTeaKey(key);\r
+ tea.encrypt(pt);\r
+ var out:String = Hex.fromArray(pt);\r
+ assert("comparing "+cts[i]+" to "+out, cts[i]==out);\r
+ // now go back to plaintext.\r
+ pt.position=0;\r
+ tea.decrypt(pt);\r
+ out = Hex.fromArray(pt);\r
+ assert("comparing "+pts[i]+" to "+out, pts[i]==out);\r
+ }\r
+ }\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**
+ * BulkCiphers
+ *
+ * An enumeration of bulk ciphers available for TLS, along with their properties,
+ * with a few convenience methods to go with it.
+ * Copyright (c) 2007 Henri Torgemane
+ *
+ * See LICENSE.txt for full license information.
+ */
+package com.hurlant.crypto.tls {
+ import com.hurlant.crypto.Crypto;
+ import flash.utils.ByteArray;
+ import com.hurlant.crypto.symmetric.ICipher;
+ import com.hurlant.crypto.symmetric.TLSPad;
+ import com.hurlant.crypto.symmetric.SSLPad;
+
+ public class BulkCiphers {
+ public static const STREAM_CIPHER:uint = 0;
+ public static const BLOCK_CIPHER:uint = 1;
+
+ public static const NULL:uint = 0;
+ public static const RC4_40:uint = 1;
+ public static const RC4_128:uint = 2
+ public static const RC2_CBC_40:uint = 3; // XXX I don't have that one.
+ public static const DES_CBC:uint = 4;
+ public static const DES3_EDE_CBC:uint = 5;
+ public static const DES40_CBC:uint = 6;
+ public static const IDEA_CBC:uint = 7; // XXX I don't have that one.
+ public static const AES_128:uint = 8;
+ public static const AES_256:uint = 9;
+
+ private static const algos:Array =
+ ['', 'rc4', 'rc4', '', 'des-cbc', '3des-cbc', 'des-cbc', '', 'aes', 'aes'];
+
+ private static var _props:Array;
+
+ init();
+ private static function init():void {
+ _props = [];
+ _props[NULL] = new BulkCiphers(STREAM_CIPHER, 0, 0, 0, 0, 0);
+ _props[RC4_40] = new BulkCiphers(STREAM_CIPHER, 5, 16, 40, 0, 0);
+ _props[RC4_128] = new BulkCiphers(STREAM_CIPHER, 16, 16, 128, 0, 0);
+ _props[RC2_CBC_40] = new BulkCiphers( BLOCK_CIPHER, 5, 16, 40, 8, 8);
+ _props[DES_CBC] = new BulkCiphers( BLOCK_CIPHER, 8, 8, 56, 8, 8);
+ _props[DES3_EDE_CBC] = new BulkCiphers( BLOCK_CIPHER, 24, 24, 168, 8, 8);
+ _props[DES40_CBC] = new BulkCiphers( BLOCK_CIPHER, 5, 8, 40, 8, 8);
+ _props[IDEA_CBC] = new BulkCiphers( BLOCK_CIPHER, 16, 16, 128, 8, 8);
+ _props[AES_128] = new BulkCiphers( BLOCK_CIPHER, 16, 16, 128, 16, 16);
+ _props[AES_256] = new BulkCiphers( BLOCK_CIPHER, 32, 32, 256, 16, 16);
+ }
+
+ private static function getProp(cipher:uint):BulkCiphers {
+ var p:BulkCiphers = _props[cipher];
+ if (p==null) {
+ throw new Error("Unknown bulk cipher "+cipher.toString(16));
+ }
+ return p;
+ }
+ public static function getType(cipher:uint):uint {
+ return getProp(cipher).type;
+ }
+ public static function getKeyBytes(cipher:uint):uint {
+ return getProp(cipher).keyBytes;
+ }
+ public static function getExpandedKeyBytes(cipher:uint):uint {
+ return getProp(cipher).expandedKeyBytes;
+ }
+ public static function getEffectiveKeyBits(cipher:uint):uint {
+ return getProp(cipher).effectiveKeyBits;
+ }
+ public static function getIVSize(cipher:uint):uint {
+ return getProp(cipher).IVSize;
+ }
+ public static function getBlockSize(cipher:uint):uint {
+ return getProp(cipher).blockSize;
+ }
+ public static function getCipher(cipher:uint, key:ByteArray, proto:uint):ICipher {
+ if (proto == TLSSecurityParameters.PROTOCOL_VERSION) {
+ return Crypto.getCipher(algos[cipher], key, new TLSPad);
+ } else {
+ return Crypto.getCipher(algos[cipher], key, new SSLPad);
+ }
+ }
+
+
+ private var type:uint;
+ private var keyBytes:uint;
+ private var expandedKeyBytes:uint;
+ private var effectiveKeyBits:uint;
+ private var IVSize:uint;
+ private var blockSize:uint;
+
+ public function BulkCiphers(t:uint, kb:uint, ekb:uint, fkb:uint, ivs:uint, bs:uint) {
+ type = t;
+ keyBytes = kb;
+ expandedKeyBytes = ekb;
+ effectiveKeyBits = fkb;
+ IVSize = ivs;
+ blockSize = bs;
+ }
+ }
+}
--- /dev/null
+/**\r
+ * CipherSuites\r
+ * \r
+ * An enumeration of cipher-suites available for TLS to use, along with\r
+ * their properties, and some convenience methods\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ \r
+ public class CipherSuites {\r
+ \r
+ \r
+ // only the lines marked "ok" are currently implemented.\r
+ \r
+ // rfc 2246\r
+ \r
+ public static const TLS_NULL_WITH_NULL_NULL:uint = 0x0000; // ok\r
+ public static const TLS_RSA_WITH_NULL_MD5:uint = 0x0001; // ok\r
+ public static const TLS_RSA_WITH_NULL_SHA:uint = 0x0002; // ok\r
+ public static const TLS_RSA_WITH_RC4_128_MD5:uint = 0x0004; // ok\r
+ public static const TLS_RSA_WITH_RC4_128_SHA:uint = 0x0005; // ok\r
+ public static const TLS_RSA_WITH_IDEA_CBC_SHA:uint = 0x0007;\r
+ public static const TLS_RSA_WITH_DES_CBC_SHA:uint = 0x0009; // ok\r
+ public static const TLS_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x000A; // ok\r
+ \r
+ public static const TLS_DH_DSS_WITH_DES_CBC_SHA:uint = 0x000C;\r
+ public static const TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:uint = 0x000D;\r
+ public static const TLS_DH_RSA_WITH_DES_CBC_SHA:uint = 0x000F;\r
+ public static const TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x0010;\r
+ public static const TLS_DHE_DSS_WITH_DES_CBC_SHA:uint = 0x0012;\r
+ public static const TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:uint = 0x0013;\r
+ public static const TLS_DHE_RSA_WITH_DES_CBC_SHA:uint = 0x0015;\r
+ public static const TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x0016;\r
+ \r
+ public static const TLS_DH_anon_WITH_RC4_128_MD5:uint = 0x0018;\r
+ public static const TLS_DH_anon_WITH_DES_CBC_SHA:uint = 0x001A;\r
+ public static const TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:uint = 0x001B;\r
+ \r
+ // rfc3268\r
+ \r
+ public static const TLS_RSA_WITH_AES_128_CBC_SHA:uint = 0x002F; // ok\r
+ public static const TLS_DH_DSS_WITH_AES_128_CBC_SHA:uint = 0x0030;\r
+ public static const TLS_DH_RSA_WITH_AES_128_CBC_SHA:uint = 0x0031;\r
+ public static const TLS_DHE_DSS_WITH_AES_128_CBC_SHA:uint = 0x0032;\r
+ public static const TLS_DHE_RSA_WITH_AES_128_CBC_SHA:uint = 0x0033;\r
+ public static const TLS_DH_anon_WITH_AES_128_CBC_SHA:uint = 0x0034;\r
+ \r
+ public static const TLS_RSA_WITH_AES_256_CBC_SHA:uint = 0x0035; // ok\r
+ public static const TLS_DH_DSS_WITH_AES_256_CBC_SHA:uint = 0x0036;\r
+ public static const TLS_DH_RSA_WITH_AES_256_CBC_SHA:uint = 0x0037;\r
+ public static const TLS_DHE_DSS_WITH_AES_256_CBC_SHA:uint = 0x0038;\r
+ public static const TLS_DHE_RSA_WITH_AES_256_CBC_SHA:uint = 0x0039;\r
+ public static const TLS_DH_anon_WITH_AES_256_CBC_SHA:uint = 0x003A;\r
+ \r
+ private static var _props:Array;\r
+ \r
+ init();\r
+ private static function init():void {\r
+ _props = [];\r
+ _props[TLS_NULL_WITH_NULL_NULL] = new CipherSuites(BulkCiphers.NULL, MACs.NULL, KeyExchanges.NULL);\r
+ _props[TLS_RSA_WITH_NULL_MD5] = new CipherSuites(BulkCiphers.NULL, MACs.MD5, KeyExchanges.RSA);\r
+ _props[TLS_RSA_WITH_NULL_SHA] = new CipherSuites(BulkCiphers.NULL, MACs.SHA1, KeyExchanges.RSA);\r
+ _props[TLS_RSA_WITH_RC4_128_MD5] = new CipherSuites(BulkCiphers.RC4_128, MACs.MD5, KeyExchanges.RSA);\r
+ _props[TLS_RSA_WITH_RC4_128_SHA] = new CipherSuites(BulkCiphers.RC4_128, MACs.SHA1, KeyExchanges.RSA);\r
+ _props[TLS_RSA_WITH_DES_CBC_SHA] = new CipherSuites(BulkCiphers.DES_CBC, MACs.SHA1, KeyExchanges.RSA);\r
+ _props[TLS_RSA_WITH_3DES_EDE_CBC_SHA] = new CipherSuites(BulkCiphers.DES3_EDE_CBC, MACs.SHA1, KeyExchanges.RSA);\r
+ _props[TLS_RSA_WITH_AES_128_CBC_SHA] = new CipherSuites(BulkCiphers.AES_128, MACs.SHA1, KeyExchanges.RSA);\r
+ _props[TLS_RSA_WITH_AES_256_CBC_SHA] = new CipherSuites(BulkCiphers.AES_256, MACs.SHA1, KeyExchanges.RSA);\r
+ \r
+ // ...\r
+ // more later\r
+ }\r
+ \r
+ private static function getProp(cipher:uint):CipherSuites {\r
+ var p:CipherSuites = _props[cipher];\r
+ if (p==null) {\r
+ throw new Error("Unknown cipher "+cipher.toString(16));\r
+ }\r
+ return p;\r
+ }\r
+ public static function getBulkCipher(cipher:uint):uint {\r
+ return getProp(cipher).cipher;\r
+ }\r
+ public static function getMac(cipher:uint):uint {\r
+ return getProp(cipher).hash;\r
+ }\r
+ public static function getKeyExchange(cipher:uint):uint {\r
+ return getProp(cipher).key;\r
+ }\r
+ \r
+ public static function getDefaultSuites():Array {\r
+ // a list of acceptable ciphers, sorted by preference.\r
+ return [\r
+ TLS_RSA_WITH_AES_256_CBC_SHA,\r
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,\r
+ TLS_RSA_WITH_AES_128_CBC_SHA,\r
+ TLS_RSA_WITH_RC4_128_SHA,\r
+ TLS_RSA_WITH_RC4_128_MD5,\r
+ TLS_RSA_WITH_DES_CBC_SHA\r
+ ];\r
+ }\r
+ \r
+ public var cipher:uint;\r
+ public var hash:uint;\r
+ public var key:uint;\r
+ \r
+ public function CipherSuites(cipher:uint, hash:uint, key:uint) {\r
+ this.cipher = cipher;\r
+ this.hash = hash;\r
+ this.key = key;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * IConnectionState\r
+ * \r
+ * Interface for TLS/SSL Connection states.\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.utils.ByteArray;\r
+ public interface IConnectionState {\r
+ function decrypt(type:uint, length:uint, p:ByteArray) : ByteArray; \r
+ function encrypt(type:uint, p:ByteArray) : ByteArray; \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ISecurityParameters\r
+ * \r
+ * This class encapsulates all the security parameters that get negotiated\r
+ * during the TLS handshake. It also holds all the key derivation methods.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.utils.ByteArray;\r
+ \r
+ public interface ISecurityParameters {\r
+ function get version() : uint;\r
+ function reset():void;\r
+ function getBulkCipher():uint;\r
+ function getCipherType():uint;\r
+ function getMacAlgorithm():uint;\r
+ function setCipher(cipher:uint):void;\r
+ function setCompression(algo:uint):void;\r
+ function setPreMasterSecret(secret:ByteArray):void;\r
+ function setClientRandom(secret:ByteArray):void;\r
+ function setServerRandom(secret:ByteArray):void;\r
+ function get useRSA():Boolean;\r
+ function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray;\r
+ function computeCertificateVerify( side:uint, handshakeRecords:ByteArray):ByteArray;\r
+ function getConnectionStates():Object;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * KeyExchanges\r
+ * \r
+ * An enumeration of key exchange methods defined by TLS\r
+ * ( right now, only RSA is actually implemented )\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ public class KeyExchanges {\r
+ public static const NULL:uint = 0;\r
+ public static const RSA:uint = 1;\r
+ public static const DH_DSS:uint = 2;\r
+ public static const DH_RSA:uint = 3;\r
+ public static const DHE_DSS:uint = 4;\r
+ public static const DHE_RSA:uint = 5;\r
+ public static const DH_anon:uint = 6;\r
+ \r
+ public static function useRSA(p:uint):Boolean {\r
+ return (p==RSA);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * MACs\r
+ * \r
+ * An enumeration of MACs implemented for TLS 1.0/SSL 3.0\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import com.hurlant.crypto.Crypto;\r
+ import com.hurlant.crypto.hash.HMAC;\r
+ import com.hurlant.crypto.hash.MAC;\r
+ \r
+ public class MACs {\r
+ public static const NULL:uint = 0;\r
+ public static const MD5:uint = 1;\r
+ public static const SHA1:uint = 2;\r
+ \r
+ public static function getHashSize(hash:uint):uint {\r
+ return [0,16,20][hash];\r
+ } \r
+ \r
+ public static function getPadSize(hash:uint):int {\r
+ return [0, 48, 40][hash];\r
+ } \r
+ \r
+ public static function getHMAC(hash:uint):HMAC {\r
+ if (hash==NULL) return null;\r
+ return Crypto.getHMAC(['',"md5","sha1"][hash]);\r
+ }\r
+ \r
+ public static function getMAC(hash:uint):MAC {\r
+ return Crypto.getMAC(['', "md5", "sha1"][hash]);\r
+ } \r
+ \r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**
+ * TLSConnectionState
+ *
+ * This class encapsulates the read or write state of a TLS connection,
+ * and implementes the encrypting and hashing of packets.
+ * Copyright (c) 2007 Henri Torgemane
+ *
+ * See LICENSE.txt for full license information.
+ */
+package com.hurlant.crypto.tls {
+ import flash.utils.IDataInput;
+ import flash.utils.ByteArray;
+ import com.hurlant.crypto.hash.MD5;
+ import com.hurlant.crypto.hash.MAC;
+ import com.hurlant.crypto.hash.IHash;
+ import com.hurlant.crypto.symmetric.ICipher;
+ import com.hurlant.crypto.symmetric.IVMode;
+ import com.hurlant.util.Hex;
+ import com.hurlant.util.ArrayUtil;
+
+ public class SSLConnectionState implements IConnectionState {
+
+ // compression state
+
+ // cipher state
+ private var bulkCipher:uint;
+ private var cipherType:uint;
+ private var CIPHER_key:ByteArray;
+ private var CIPHER_IV:ByteArray;
+ private var cipher:ICipher;
+ private var ivmode:IVMode;
+
+ // mac secret
+ private var macAlgorithm:uint;
+ private var MAC_write_secret:ByteArray;
+ private var mac:MAC;
+
+ // sequence number. uint64
+
+ private var seq_lo:uint = 0x0;
+ private var seq_hi:uint = 0x0;
+
+ public function SSLConnectionState(
+ bulkCipher:uint=0, cipherType:uint=0, macAlgorithm:uint=0,
+ mac_enc:ByteArray=null, key:ByteArray=null, IV:ByteArray=null) {
+ this.bulkCipher = bulkCipher;
+ this.cipherType = cipherType;
+ this.macAlgorithm = macAlgorithm;
+ MAC_write_secret = mac_enc;
+ mac = MACs.getMAC(macAlgorithm);
+
+ CIPHER_key = key;
+ CIPHER_IV = IV;
+ cipher = BulkCiphers.getCipher(bulkCipher, key, 0x0300);
+ if (cipher is IVMode) {
+ ivmode = cipher as IVMode;
+ ivmode.IV = IV;
+ }
+
+ }
+
+ public function decrypt(type:uint, length:uint, p:ByteArray):ByteArray {
+ // decompression is a nop.
+
+ if (cipherType == BulkCiphers.STREAM_CIPHER) {
+ if (bulkCipher == BulkCiphers.NULL) {
+ // no-op
+ } else {
+ cipher.decrypt(p);
+ }
+ } else {
+ p.position = 0;
+ // block cipher
+ if (bulkCipher == BulkCiphers.NULL) {
+
+ } else {
+ var nextIV:ByteArray = new ByteArray;
+ nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
+ p.position = 0;
+ cipher.decrypt(p);
+
+ CIPHER_IV = nextIV;
+ ivmode.IV = nextIV;
+ }
+ }
+
+ if (macAlgorithm!=MACs.NULL) {
+ // there will be CTX delay here as well,
+ // I should probably optmize the hell out of it
+ var data:ByteArray = new ByteArray;
+ var len:uint = p.length - mac.getHashSize();
+ data.writeUnsignedInt(seq_hi);
+ data.writeUnsignedInt(seq_lo);
+
+ data.writeByte(type);
+ data.writeShort(len);
+ if (len!=0) {
+ data.writeBytes(p, 0, len);
+ }
+ var mac_enc:ByteArray = mac.compute(MAC_write_secret, data);
+ // compare "mac" with the last X bytes of p.
+ var mac_received:ByteArray = new ByteArray;
+ mac_received.writeBytes(p, len, mac.getHashSize());
+ if (ArrayUtil.equals(mac_enc, mac_received)) {
+ // happy happy joy joy
+ } else {
+ throw new TLSError("Bad Mac Data", TLSError.bad_record_mac);
+ }
+ p.length = len;
+ p.position = 0;
+ }
+ // increment seq
+ seq_lo++;
+ if (seq_lo==0) seq_hi++;
+ return p;
+ }
+ public function encrypt(type:uint, p:ByteArray):ByteArray {
+ var mac_enc:ByteArray = null;
+ if (macAlgorithm!=MACs.NULL) {
+ var data:ByteArray = new ByteArray;
+ // data.writeUnsignedInt(seq);
+
+ // Sequence
+ data.writeUnsignedInt(seq_hi);
+ data.writeUnsignedInt(seq_lo);
+
+ // Type
+ data.writeByte(type);
+
+ // Length
+ data.writeShort(p.length);
+
+ // The data
+ if (p.length!=0) {
+ data.writeBytes(p);
+ }
+
+ // trace("data for the MAC: " + Hex.fromArray(data));
+ mac_enc = mac.compute(MAC_write_secret, data);
+ // trace("MAC: " + Hex.fromArray( mac_enc ));
+ p.position = p.length;
+ p.writeBytes(mac_enc);
+ }
+
+ // trace("Record to encrypt: " + Hex.fromArray(p));
+
+ p.position = 0;
+ if (cipherType == BulkCiphers.STREAM_CIPHER) {
+ // stream cipher
+ if (bulkCipher == BulkCiphers.NULL) {
+ // no-op
+ } else {
+ cipher.encrypt(p);
+ }
+ } else {
+ // block cipher
+ cipher.encrypt(p);
+ // adjust IV
+ var nextIV:ByteArray = new ByteArray;
+ nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
+ CIPHER_IV = nextIV;
+ ivmode.IV = nextIV;
+ }
+ // increment seq
+ seq_lo++;
+ if (seq_lo==0) seq_hi++;
+ return p;
+ }
+
+ }
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * SSLEvent\r
+ * \r
+ * This is used by TLSEngine to let the application layer know\r
+ * when we're ready for sending, or have received application data\r
+ * This Event was created by Bobby Parker to support SSL 3.0.\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.events.Event;\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class SSLEvent extends Event {\r
+ \r
+ static public const DATA:String = "data";\r
+ static public const READY:String = "ready";\r
+ \r
+ public var data:ByteArray;\r
+ \r
+ public function SSLEvent(type:String, data:ByteArray = null) {\r
+ this.data = data;\r
+ super(type, false, false);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TLSSecurityParameters\r
+ * \r
+ * This class encapsulates all the security parameters that get negotiated\r
+ * during the TLS handshake. It also holds all the key derivation methods.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;\r
+ \r
+ public class SSLSecurityParameters implements ISecurityParameters {\r
+ \r
+ // COMPRESSION\r
+ public static const COMPRESSION_NULL:uint = 0;\r
+ \r
+ private var entity:uint; // SERVER | CLIENT\r
+ private var bulkCipher:uint; // BULK_CIPHER_*\r
+ private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER\r
+ private var keySize:uint;\r
+ private var keyMaterialLength:uint;\r
+ private var keyBlock:ByteArray;\r
+ private var IVSize:uint;\r
+ private var MAC_length:uint;\r
+ private var macAlgorithm:uint; // MAC_*\r
+ private var hashSize:uint;\r
+ private var compression:uint; // COMPRESSION_NULL\r
+ private var masterSecret:ByteArray; // 48 bytes\r
+ private var clientRandom:ByteArray; // 32 bytes\r
+ private var serverRandom:ByteArray; // 32 bytes\r
+ private var pad_1:ByteArray; // varies\r
+ private var pad_2:ByteArray; // varies\r
+ private var ignoreCNMismatch:Boolean = true;\r
+ private var trustAllCerts:Boolean = false;\r
+ private var trustSelfSigned:Boolean = false;\r
+ public static const PROTOCOL_VERSION:uint = 0x0300;\r
+ \r
+ // not strictly speaking part of this, but yeah.\r
+ public var keyExchange:uint;\r
+ \r
+ public function get version() : uint { \r
+ return PROTOCOL_VERSION;\r
+ }\r
+ public function SSLSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:ByteArray = null) {\r
+ this.entity = entity;\r
+ reset();\r
+ }\r
+ \r
+ public function reset():void {\r
+ bulkCipher = BulkCiphers.NULL;\r
+ cipherType = BulkCiphers.BLOCK_CIPHER;\r
+ macAlgorithm = MACs.NULL;\r
+ compression = COMPRESSION_NULL;\r
+ masterSecret = null;\r
+ }\r
+ \r
+ public function getBulkCipher():uint {\r
+ return bulkCipher;\r
+ }\r
+ public function getCipherType():uint {\r
+ return cipherType;\r
+ }\r
+ public function getMacAlgorithm():uint {\r
+ return macAlgorithm;\r
+ }\r
+ \r
+ public function setCipher(cipher:uint):void {\r
+ bulkCipher = CipherSuites.getBulkCipher(cipher);\r
+ cipherType = BulkCiphers.getType(bulkCipher);\r
+ keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); // 8\r
+ keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5\r
+ IVSize = BulkCiphers.getIVSize(bulkCipher);\r
+\r
+\r
+ keyExchange = CipherSuites.getKeyExchange(cipher);\r
+ \r
+ macAlgorithm = CipherSuites.getMac(cipher);\r
+ hashSize = MACs.getHashSize(macAlgorithm);\r
+ pad_1 = new ByteArray();\r
+ pad_2 = new ByteArray();\r
+ for (var x:int = 0; x < 48; x++) {\r
+ pad_1.writeByte(0x36);\r
+ pad_2.writeByte(0x5c);\r
+ } \r
+ }\r
+ public function setCompression(algo:uint):void {\r
+ compression = algo;\r
+ }\r
+ \r
+ public function setPreMasterSecret(secret:ByteArray):void {\r
+ /* Warning! Following code may cause madness\r
+ Tread not here, unless ye be men of valor.\r
+ \r
+ ***** Official Prophylactic Comment ******\r
+ (to protect the unwary...this code actually works, that's all you need to know)\r
+ \r
+ This does two things, computes the master secret, and generates the keyBlock\r
+ \r
+ \r
+ To compute the master_secret, the following algorithm is used.\r
+ for SSL 3, this means\r
+ master = MD5( premaster + SHA1('A' + premaster + client_random + server_random ) ) +\r
+ MD5( premaster + SHA1('BB' + premaster + client_random + server_random ) ) +\r
+ MD5( premaster + SHA1('CCC' + premaster + client_random + server_random ) )\r
+ */ \r
+ var tempHashA:ByteArray = new ByteArray(); // temporary hash, gets reused a lot\r
+ var tempHashB:ByteArray = new ByteArray(); // temporary hash, gets reused a lot\r
+ \r
+ var shaHash:ByteArray;\r
+ var mdHash:ByteArray;\r
+ \r
+ var i:int;\r
+ var j:int;\r
+ \r
+ var sha:SHA1 = new SHA1();\r
+ var md:MD5 = new MD5();\r
+ \r
+ var k:ByteArray = new ByteArray();\r
+ \r
+ k.writeBytes(secret);\r
+ k.writeBytes(clientRandom);\r
+ k.writeBytes(serverRandom);\r
+ \r
+ masterSecret = new ByteArray();\r
+ var pad_char:uint = 0x41;\r
+ \r
+ for ( i = 0; i < 3; i++) {\r
+ // SHA portion\r
+ tempHashA.position = 0;\r
+ \r
+ for ( j = 0; j < i + 1; j++) {\r
+ tempHashA.writeByte(pad_char);\r
+ }\r
+ pad_char++;\r
+ \r
+ tempHashA.writeBytes(k);\r
+ shaHash = sha.hash(tempHashA);\r
+ \r
+ // MD5 portion\r
+ tempHashB.position = 0;\r
+ tempHashB.writeBytes(secret); \r
+ tempHashB.writeBytes(shaHash); \r
+ mdHash = md.hash(tempHashB);\r
+ \r
+ // copy into my key\r
+ masterSecret.writeBytes(mdHash);\r
+ }\r
+ \r
+ // *************** END MASTER SECRET **************\r
+ \r
+ // More prophylactic comments\r
+ // *************** START KEY BLOCK ****************\r
+ \r
+ // So here, I'm setting up the keyBlock array that I will derive MACs, keys, and IVs from.\r
+ // Rebuild k (hash seed)\r
+ \r
+ k.position = 0; \r
+ k.writeBytes(masterSecret);\r
+ k.writeBytes(serverRandom);\r
+ k.writeBytes(clientRandom);\r
+ \r
+ keyBlock = new ByteArray(); \r
+ \r
+ tempHashA = new ByteArray();\r
+ tempHashB = new ByteArray();\r
+ // now for 16 iterations to get 256 bytes (16 * 16), better to have more than not enough\r
+ pad_char = 0x41;\r
+ for ( i = 0; i < 16; i++) {\r
+ tempHashA.position = 0; \r
+ \r
+ for ( j = 0; j < i + 1; j++) {\r
+ tempHashA.writeByte(pad_char);\r
+ }\r
+ pad_char++;\r
+ tempHashA.writeBytes(k);\r
+ shaHash = sha.hash(tempHashA); \r
+ \r
+ tempHashB.position = 0; \r
+ tempHashB.writeBytes(masterSecret);\r
+ tempHashB.writeBytes(shaHash, 0);\r
+ mdHash = md.hash(tempHashB);\r
+ \r
+ keyBlock.writeBytes(mdHash); \r
+ }\r
+ }\r
+ \r
+ public function setClientRandom(secret:ByteArray):void {\r
+ clientRandom = secret;\r
+ }\r
+ public function setServerRandom(secret:ByteArray):void {\r
+ serverRandom = secret;\r
+ }\r
+ \r
+ public function get useRSA():Boolean {\r
+ return KeyExchanges.useRSA(keyExchange);\r
+ }\r
+ \r
+ // This is the Finished message\r
+ // if you value your sanity, stay away...far away\r
+ public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {\r
+ // for SSL 3.0, this consists of\r
+ // finished = md5( masterSecret + pad2 + md5( handshake + sender + masterSecret + pad1 ) ) +\r
+ // sha1( masterSecret + pad2 + sha1( handshake + sender + masterSecret + pad1 ) )\r
+ \r
+ // trace("Handshake messages: " + Hex.fromArray(handshakeMessages));\r
+ var sha:SHA1 = new SHA1();\r
+ var md:MD5 = new MD5();\r
+ var k:ByteArray = new ByteArray(); // handshake + sender + masterSecret + pad1\r
+ var j:ByteArray = new ByteArray(); // masterSecret + pad2 + k\r
+ \r
+ var innerKey:ByteArray;\r
+ var outerKey:ByteArray = new ByteArray();\r
+ \r
+ var hashSha:ByteArray;\r
+ var hashMD:ByteArray;\r
+ \r
+ var sideBytes:ByteArray = new ByteArray();\r
+ if (side == TLSEngine.CLIENT) {\r
+ sideBytes.writeUnsignedInt(0x434C4E54);\r
+ } else {\r
+ sideBytes.writeUnsignedInt(0x53525652);\r
+ }\r
+ \r
+ // Do the SHA1 part of the routine first\r
+ masterSecret.position = 0;\r
+ k.writeBytes(handshakeMessages);\r
+ k.writeBytes(sideBytes);\r
+ k.writeBytes(masterSecret);\r
+ k.writeBytes(pad_1, 0, 40); // limited to 40 chars for SHA1\r
+ \r
+ innerKey = sha.hash(k);\r
+ // trace("Inner SHA Key: " + Hex.fromArray(innerKey));\r
+ \r
+ j.writeBytes(masterSecret);\r
+ j.writeBytes(pad_2, 0, 40); // limited to 40 chars for SHA1\r
+ j.writeBytes(innerKey);\r
+ \r
+ hashSha = sha.hash(j);\r
+ // trace("Outer SHA Key: " + Hex.fromArray(hashSha));\r
+ \r
+ // Rebuild k for MD5\r
+ k = new ByteArray();\r
+ \r
+ k.writeBytes(handshakeMessages);\r
+ k.writeBytes(sideBytes);\r
+ k.writeBytes(masterSecret);\r
+ k.writeBytes(pad_1); // Take the whole length of pad_1 & pad_2 for MD5\r
+ \r
+ innerKey = md.hash(k);\r
+ // trace("Inner MD5 Key: " + Hex.fromArray(innerKey));\r
+ \r
+ j = new ByteArray();\r
+ j.writeBytes(masterSecret);\r
+ j.writeBytes(pad_2); // see above re: 48 byte pad\r
+ j.writeBytes(innerKey); \r
+ \r
+ hashMD = md.hash(j);\r
+ // trace("Outer MD5 Key: " + Hex.fromArray(hashMD));\r
+ \r
+ outerKey.writeBytes(hashMD, 0, hashMD.length);\r
+ outerKey.writeBytes(hashSha, 0, hashSha.length);\r
+ var out:String = Hex.fromArray(outerKey);\r
+ // trace("Finished Message: " + out);\r
+ outerKey.position = 0;\r
+ \r
+ return outerKey;\r
+ \r
+ }\r
+ \r
+ public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {\r
+ // TODO: Implement this, but I don't forsee it being necessary at this point in time, since for purposes\r
+ // of the override, I'm only going to use TLS\r
+ return null; \r
+ }\r
+ \r
+ public function getConnectionStates():Object {\r
+ \r
+ if (masterSecret != null) {\r
+ // so now, I have to derive the actual keys from the keyblock that I generated in setPremasterSecret.\r
+ // for MY purposes, I need RSA-AES 128/256 + SHA\r
+ // so I'm gonna have keylen = 32, minlen = 32, mac_length = 20, iv_length = 16\r
+ // but...I can get this data from the settings returned in the constructor when this object is \r
+ // It strikes me that TLS does this more elegantly...\r
+ \r
+ var mac_length:int = hashSize as Number;\r
+ var key_length:int = keySize as Number;\r
+ var iv_length:int = IVSize as Number;\r
+ \r
+ var client_write_MAC:ByteArray = new ByteArray();\r
+ var server_write_MAC:ByteArray = new ByteArray();\r
+ var client_write_key:ByteArray = new ByteArray();\r
+ var server_write_key:ByteArray = new ByteArray();\r
+ var client_write_IV:ByteArray = new ByteArray();\r
+ var server_write_IV:ByteArray = new ByteArray();\r
+ \r
+ // Derive the keys from the keyblock\r
+ // Get the MACs first\r
+ keyBlock.position = 0;\r
+ keyBlock.readBytes(client_write_MAC, 0, mac_length);\r
+ keyBlock.readBytes(server_write_MAC, 0, mac_length);\r
+ \r
+ // keyBlock.position is now at MAC_length * 2\r
+ // then get the keys\r
+ keyBlock.readBytes(client_write_key, 0, key_length);\r
+ keyBlock.readBytes(server_write_key, 0, key_length);\r
+ \r
+ // keyBlock.position is now at (MAC_length * 2) + (keySize * 2) \r
+ // and then the IVs\r
+ keyBlock.readBytes(client_write_IV, 0, iv_length);\r
+ keyBlock.readBytes(server_write_IV, 0, iv_length);\r
+ \r
+ // reset this in case it's needed, for some reason or another, but I doubt it\r
+ keyBlock.position = 0;\r
+ \r
+ var client_write:SSLConnectionState = new SSLConnectionState(\r
+ bulkCipher, cipherType, macAlgorithm,\r
+ client_write_MAC, client_write_key, client_write_IV);\r
+ var server_write:SSLConnectionState = new SSLConnectionState(\r
+ bulkCipher, cipherType, macAlgorithm,\r
+ server_write_MAC, server_write_key, server_write_IV);\r
+ \r
+ if (entity == TLSEngine.CLIENT) {\r
+ return {read:server_write, write:client_write};\r
+ } else {\r
+ return {read:client_write, write:server_write};\r
+ }\r
+\r
+\r
+ } else {\r
+ return {read:new SSLConnectionState, write:new SSLConnectionState};\r
+ }\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TLSConfig\r
+ * \r
+ * A set of configuration parameters for use by a TLSSocket or a TLSEngine.\r
+ * Most parameters are optional and will be set to appropriate default values for most use.\r
+ * \r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.der.PEM;\r
+ import com.hurlant.crypto.rsa.RSAKey;\r
+ import com.hurlant.crypto.cert.X509CertificateCollection;\r
+ import com.hurlant.crypto.cert.MozillaRootCertificates;\r
+ \r
+ public class TLSConfig {\r
+ public var entity:uint; // SERVER | CLIENT\r
+ \r
+ public var certificate:ByteArray;\r
+ public var privateKey:RSAKey;\r
+ \r
+ public var cipherSuites:Array;\r
+ \r
+ public var compressions:Array;\r
+ public var ignoreCommonNameMismatch:Boolean = false;\r
+ public var trustAllCertificates:Boolean = false;\r
+ public var trustSelfSignedCertificates:Boolean = false;\r
+ public var promptUserForAcceptCert:Boolean = false;\r
+ public var CAStore:X509CertificateCollection;\r
+ public var localKeyStore:X509CertificateCollection;\r
+ public var version:uint;\r
+ \r
+ public function TLSConfig( entity:uint, cipherSuites:Array = null, compressions:Array = null, \r
+ certificate:ByteArray = null, privateKey:RSAKey = null, CAStore:X509CertificateCollection = null, ver:uint = 0x00) {\r
+ this.entity = entity;\r
+ this.cipherSuites = cipherSuites;\r
+ this.compressions = compressions;\r
+ this.certificate = certificate;\r
+ this.privateKey = privateKey;\r
+ this.CAStore = CAStore;\r
+ this.version = ver;\r
+ // default settings.\r
+ if (cipherSuites==null) {\r
+ this.cipherSuites = CipherSuites.getDefaultSuites();\r
+ }\r
+ if (compressions==null) {\r
+ this.compressions = [TLSSecurityParameters.COMPRESSION_NULL];\r
+ }\r
+ \r
+ if (CAStore==null) {\r
+ this.CAStore = new MozillaRootCertificates;\r
+ }\r
+ \r
+ if (ver==0x00) {\r
+ // Default to TLS\r
+ this.version = TLSSecurityParameters.PROTOCOL_VERSION;\r
+ } \r
+ }\r
+ \r
+ public function setPEMCertificate(cert:String, key:String = null):void {\r
+ if (key == null) {\r
+ key = cert; // for folks who like to concat those two in one file.\r
+ }\r
+ certificate = PEM.readCertIntoArray(cert);\r
+ privateKey = PEM.readRSAPrivateKey(key);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * TLSConnectionState\r
+ * \r
+ * This class encapsulates the read or write state of a TLS connection,\r
+ * and implementes the encrypting and hashing of packets. \r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.utils.IDataInput;\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.HMAC;\r
+ import com.hurlant.crypto.hash.IHash;\r
+ import com.hurlant.crypto.symmetric.ICipher;\r
+ import com.hurlant.crypto.symmetric.IVMode;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.util.ArrayUtil;\r
+ \r
+ public class TLSConnectionState implements IConnectionState {\r
+\r
+\r
+ // compression state\r
+ \r
+ // cipher state\r
+ private var bulkCipher:uint;\r
+ private var cipherType:uint;\r
+ private var CIPHER_key:ByteArray;\r
+ private var CIPHER_IV:ByteArray;\r
+ private var cipher:ICipher;\r
+ private var ivmode:IVMode;\r
+ \r
+ // mac secret\r
+ private var macAlgorithm:uint;\r
+ private var MAC_write_secret:ByteArray;\r
+ private var hmac:HMAC;\r
+ \r
+ // sequence number. uint64\r
+ private var seq_lo:uint;\r
+ private var seq_hi:uint;\r
+ \r
+\r
+\r
+ public function TLSConnectionState(\r
+ bulkCipher:uint=0, cipherType:uint=0, macAlgorithm:uint=0,\r
+ mac:ByteArray=null, key:ByteArray=null, IV:ByteArray=null) {\r
+ this.bulkCipher = bulkCipher;\r
+ this.cipherType = cipherType;\r
+ this.macAlgorithm = macAlgorithm;\r
+ MAC_write_secret = mac;\r
+ hmac = MACs.getHMAC(macAlgorithm);\r
+ CIPHER_key = key;\r
+ CIPHER_IV = IV;\r
+ cipher = BulkCiphers.getCipher(bulkCipher, key, 0x0301);\r
+ if (cipher is IVMode) {\r
+ ivmode = cipher as IVMode;\r
+ ivmode.IV = IV;\r
+ }\r
+ }\r
+ \r
+ public function decrypt(type:uint, length:uint, p:ByteArray):ByteArray {\r
+ // decompression is a nop.\r
+ \r
+ if (cipherType == BulkCiphers.STREAM_CIPHER) {\r
+ if (bulkCipher == BulkCiphers.NULL) {\r
+ // no-op\r
+ } else {\r
+ cipher.decrypt(p);\r
+ }\r
+ } else {\r
+ // block cipher\r
+ var nextIV:ByteArray = new ByteArray;\r
+ nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);\r
+ \r
+ cipher.decrypt(p);\r
+\r
+\r
+ CIPHER_IV = nextIV;\r
+ ivmode.IV = nextIV;\r
+ }\r
+ if (macAlgorithm!=MACs.NULL) {\r
+ var data:ByteArray = new ByteArray;\r
+ var len:uint = p.length - hmac.getHashSize();\r
+ data.writeUnsignedInt(seq_hi);\r
+ data.writeUnsignedInt(seq_lo);\r
+ data.writeByte(type);\r
+ data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);\r
+ data.writeShort(len);\r
+ if (len!=0) {\r
+ data.writeBytes(p, 0, len);\r
+ }\r
+ var mac:ByteArray = hmac.compute(MAC_write_secret, data);\r
+ // compare "mac" with the last X bytes of p.\r
+ var mac_received:ByteArray = new ByteArray;\r
+ mac_received.writeBytes(p, len, hmac.getHashSize());\r
+ if (ArrayUtil.equals(mac, mac_received)) {\r
+ // happy happy joy joy\r
+ } else {\r
+ throw new TLSError("Bad Mac Data", TLSError.bad_record_mac);\r
+ }\r
+ p.length = len;\r
+ p.position = 0;\r
+ }\r
+ // increment seq\r
+ seq_lo++;\r
+ if (seq_lo==0) seq_hi++;\r
+ return p;\r
+ }\r
+ public function encrypt(type:uint, p:ByteArray):ByteArray {\r
+ var mac:ByteArray = null;\r
+ if (macAlgorithm!=MACs.NULL) {\r
+ var data:ByteArray = new ByteArray;\r
+ data.writeUnsignedInt(seq_hi);\r
+ data.writeUnsignedInt(seq_lo);\r
+ data.writeByte(type);\r
+ data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);\r
+ data.writeShort(p.length);\r
+ if (p.length!=0) {\r
+ data.writeBytes(p, 0, p.length);\r
+ }\r
+ mac = hmac.compute(MAC_write_secret, data);\r
+ p.position = p.length;\r
+ p.writeBytes(mac);\r
+ }\r
+ p.position = 0;\r
+ if (cipherType == BulkCiphers.STREAM_CIPHER) {\r
+ // stream cipher\r
+ if (bulkCipher == BulkCiphers.NULL) {\r
+ // no-op\r
+ } else {\r
+ cipher.encrypt(p);\r
+ }\r
+ } else {\r
+ // block cipher\r
+ cipher.encrypt(p);\r
+ // adjust IV\r
+ var nextIV:ByteArray = new ByteArray;\r
+ nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);\r
+ CIPHER_IV = nextIV;\r
+ ivmode.IV = nextIV;\r
+ }\r
+ // increment seq\r
+ seq_lo++;\r
+ if (seq_lo==0) seq_hi++;\r
+ // compression is a nop.\r
+ return p;\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**
+ * TLSEngine
+ *
+ * A TLS protocol implementation.
+ * See comment below for some details.
+ * Copyright (c) 2007 Henri Torgemane
+ *
+ * Patched(heavily) by Bobby Parker (shortwave@gmail.com)
+ *
+ * See LICENSE.txt for full license information.
+ */
+package com.hurlant.crypto.tls {
+ import com.hurlant.crypto.cert.X509Certificate;
+ import com.hurlant.crypto.cert.X509CertificateCollection;
+ import com.hurlant.crypto.prng.Random;
+ import com.hurlant.util.ArrayUtil;
+ import com.hurlant.util.Hex;
+
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.ProgressEvent;
+ import flash.utils.ByteArray;
+ import flash.utils.IDataInput;
+ import flash.utils.IDataOutput;
+ import flash.utils.clearTimeout;
+ import flash.utils.setTimeout;
+ import com.hurlant.crypto.prng.ARC4;
+
+
+ [Event(name="close", type="flash.events.Event")]
+ [Event(name="socketData", type="flash.events.ProgressEvent")]
+ [Event(name="ready", type="com.hurlant.crypto.tls.TLSEvent")]
+ [Event(name="data", type="com.hurlant.crypto.tls.TLSEvent")]
+
+ /**
+ * The heart of the TLS protocol.
+ * This class can work in server or client mode.
+ *
+ * This doesn't fully implement the TLS protocol.
+ *
+ * Things missing that I'd like to add:
+ * - support for client-side certificates
+ * - general code clean-up to make sure we don't have gaping securite holes
+ *
+ * Things that aren't there that I won't add:
+ * - support for "export" cypher suites (deprecated in later TLS versions)
+ * - support for "anon" cypher suites (deprecated in later TLS versions)
+ *
+ * Things that I'm unsure about adding later:
+ * - compression. Compressing encrypted streams is barely worth the CPU cycles.
+ * - diffie-hellman based key exchange mechanisms. Nifty, but would we miss it?
+ *
+ * @author henri
+ *
+ */
+ public class TLSEngine extends EventDispatcher {
+
+ public static const SERVER:uint = 0;
+ public static const CLIENT:uint = 1;
+ public var protocol_version:uint;
+
+
+
+ private static const PROTOCOL_HANDSHAKE:uint = 22;
+ private static const PROTOCOL_ALERT:uint = 21;
+ private static const PROTOCOL_CHANGE_CIPHER_SPEC:uint = 20;
+ private static const PROTOCOL_APPLICATION_DATA:uint = 23;
+
+
+ private static const STATE_NEW:uint = 0; // brand new. nothing happened yet
+ private static const STATE_NEGOTIATING:uint = 1; // we're figuring out what to use
+ private static const STATE_READY:uint = 2; // we're ready for AppData stuff to go over us.
+ private static const STATE_CLOSED:uint = 3; // we're done done.
+
+ private var _entity:uint; // SERVER | CLIENT
+ private var _config:TLSConfig;
+
+ private var _state:uint;
+
+ private var _securityParameters:ISecurityParameters;
+
+ private var _currentReadState:IConnectionState;
+ private var _currentWriteState:IConnectionState;
+ private var _pendingReadState:IConnectionState;
+ private var _pendingWriteState:IConnectionState;
+
+ private var _handshakePayloads:ByteArray;
+ private var _handshakeRecords:ByteArray; // For client-side certificate verify
+
+ private var _iStream:IDataInput;
+ private var _oStream:IDataOutput;
+
+ // temporary store for X509 certs received by this engine.
+ private var _store:X509CertificateCollection;
+ // the main certificate received from the other side.
+ private var _otherCertificate:X509Certificate;
+
+ public function get peerCertificate() : X509Certificate {
+ return _otherCertificate;
+ }
+ // If this isn't null, we expect this identity to be found in the Cert's Subject CN.
+ private var _otherIdentity:String;
+
+ // The client-side cert
+ private var _myCertficate:X509Certificate;
+ // My Identity
+ private var _myIdentity:String;
+
+ /**
+ *
+ * @param config A TLSConfig instance describing how we're supposed to work
+ * @param iStream An input stream to read TLS data from
+ * @param oStream An output stream to write TLS data to
+ * @param otherIdentity An optional identifier. If set, this will be checked against the Subject CN of the other side's certificate.
+ *
+ */
+ function TLSEngine(config:TLSConfig, iStream:IDataInput, oStream:IDataOutput, otherIdentity:String = null) {
+ _entity = config.entity;
+ _config = config;
+ _iStream = iStream;
+ _oStream = oStream;
+ _otherIdentity = otherIdentity;
+
+ _state = STATE_NEW;
+
+ // Pick the right set of callbacks
+ _entityHandshakeHandlers = _entity == CLIENT ? handshakeHandlersClient : handshakeHandlersServer;
+
+ // setting up new security parameters needs to be controlled by...something.
+ if (_config.version == SSLSecurityParameters.PROTOCOL_VERSION) {
+ _securityParameters = new SSLSecurityParameters(_entity);
+ } else {
+ _securityParameters = new TLSSecurityParameters(_entity, _config.certificate, _config.privateKey);
+ }
+ protocol_version = _config.version;
+
+ // So this...why is it here, other than to preclude a possible null pointer situation?
+ var states:Object = _securityParameters.getConnectionStates();
+
+ _currentReadState = states.read;
+ _currentWriteState = states.write;
+
+ _handshakePayloads = new ByteArray;
+
+ _store = new X509CertificateCollection;
+ }
+
+ /**
+ * This starts the TLS negotiation for a TLS Client.
+ *
+ * This is a no-op for a TLS Server.
+ *
+ */
+ public function start():void {
+ if (_entity == CLIENT) {
+ try {
+ startHandshake();
+ } catch (e:TLSError) {
+ handleTLSError(e);
+ }
+ }
+ }
+
+
+ public function dataAvailable(e:* = null):void {
+ if (_state == STATE_CLOSED) return; // ignore
+ try {
+ parseRecord(_iStream);
+ } catch (e:TLSError) {
+ handleTLSError(e);
+ }
+ }
+
+ public function close(e:TLSError = null):void {
+ if (_state == STATE_CLOSED) return; // ignore
+ // ok. send an Alert to let the peer know
+ var rec:ByteArray = new ByteArray;
+ if (e==null && _state != STATE_READY) {
+ // use canceled while handshaking. be nice about it
+ rec[0] = 1;
+ rec[1] = TLSError.user_canceled;
+ sendRecord(PROTOCOL_ALERT, rec);
+ }
+ rec[0] = 2;
+ if (e == null) {
+ rec[1] = TLSError.close_notify;
+ } else {
+ rec[1] = e.errorID;
+ trace("TLSEngine shutdown triggered by "+e);
+ }
+ sendRecord(PROTOCOL_ALERT, rec);
+
+ _state = STATE_CLOSED;
+ dispatchEvent(new Event(Event.CLOSE));
+ }
+
+ private var _packetQueue:Array = [];
+ private function parseRecord(stream:IDataInput):void {
+ var p:ByteArray;
+ while(_state!=STATE_CLOSED && stream.bytesAvailable>4) {
+
+ if (_packetQueue.length>0) {
+ var packet:Object = _packetQueue.shift();
+ p = packet.data;
+ if (stream.bytesAvailable+p.length>=packet.length) {
+ // we have a whole packet. put together.
+ stream.readBytes(p, p.length, packet.length-p.length);
+ parseOneRecord(packet.type, packet.length, p);
+ // do another loop to parse any leftover record
+ continue;
+ } else {
+ // not enough. grab the data and park it.
+ stream.readBytes(p, p.length, stream.bytesAvailable);
+ _packetQueue.push(packet);
+ continue;
+ }
+ }
+
+
+ var type:uint = stream.readByte();
+ var ver:uint = stream.readShort();
+ var length:uint = stream.readShort();
+ if (length>16384+2048) { // support compression and encryption overhead.
+ throw new TLSError("Excessive TLS Record length: "+length, TLSError.record_overflow);
+ }
+ // Can pretty much assume that if I'm here, I've got a default config, so let's use it.
+ if (ver != _securityParameters.version ) {
+ throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
+ }
+
+ p = new ByteArray;
+ var actualLength:uint = Math.min(stream.bytesAvailable, length);
+ stream.readBytes(p, 0, actualLength);
+ if (actualLength == length) {
+ parseOneRecord(type, length, p);
+ } else {
+ _packetQueue.push({type:type, length:length, data:p});
+ }
+ }
+ }
+
+
+ // Protocol handler map, provides a mapping of protocol types to individual packet handlers
+ private var protocolHandlers:Object = { 23 : parseApplicationData, // PROTOCOL_APPLICATION_DATA
+ 22 : parseHandshake, // PROTOCOL_HANDSHAKE
+ 21 : parseAlert, // PROTOCOL_ALERT
+ 20 : parseChangeCipherSpec }; // PROTOCOL_CHANGE_CIPHER_SPEC
+
+ /**
+ * Modified to support the notion of a handler map(see above ), since it makes for better clarity (IMHO of course).
+ */
+ private function parseOneRecord(type:uint, length:uint, p:ByteArray):void {
+ p = _currentReadState.decrypt(type, length, p);
+ if (p.length>16384) {
+ throw new TLSError("Excessive Decrypted TLS Record length: "+p.length, TLSError.record_overflow);
+ }
+ if (protocolHandlers.hasOwnProperty( type )) {
+ while( p != null)
+ p = protocolHandlers[ type ]( p );
+ } else {
+ throw new TLSError("Unsupported TLS Record Content Type: "+type.toString( 16 ), TLSError.unexpected_message);
+ }
+ }
+
+ ///////// handshake handling
+ // session identifier
+ // peer certificate
+ // compression method
+ // cipher spec
+ // master secret
+ // is resumable
+ private static const HANDSHAKE_HELLO_REQUEST:uint = 0;
+ private static const HANDSHAKE_CLIENT_HELLO:uint = 1;
+ private static const HANDSHAKE_SERVER_HELLO:uint = 2;
+ private static const HANDSHAKE_CERTIFICATE:uint = 11;
+ private static const HANDSHAKE_SERVER_KEY_EXCHANGE:uint = 12;
+ private static const HANDSHAKE_CERTIFICATE_REQUEST:uint = 13;
+ private static const HANDSHAKE_HELLO_DONE:uint = 14;
+ private static const HANDSHAKE_CERTIFICATE_VERIFY:uint = 15;
+ private static const HANDSHAKE_CLIENT_KEY_EXCHANGE:uint = 16;
+ private static const HANDSHAKE_FINISHED:uint = 20;
+
+ // Server handshake handler map
+ private var handshakeHandlersServer:Object = { 0 : notifyStateError, // HANDSHAKE_HELLO_REQUEST
+ 1 : parseHandshakeClientHello, // HANDSHAKE_CLIENT_HELLO
+ 2 : notifyStateError, // HANDSHAKE_SERVER_HELLO
+ 11 : loadCertificates, // HANDSHAKE_CERTIFICATE
+ 12 : notifyStateError, // HANDSHAKE_SERVER_KEY_EXCHANGE
+ 13 : notifyStateError, // HANDSHAKE_CERTIFICATE_REQUEST
+ 14 : notifyStateError, // HANDSHAKE_HELLO_DONE
+ 15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
+ 16 : parseHandshakeClientKeyExchange, // HANDSHAKE_CLIENT_KEY_EXCHANGE
+ 20 : verifyHandshake // HANDSHAKE_FINISHED
+ };
+
+ // Client handshake handler map
+ private var handshakeHandlersClient:Object = { 0 : parseHandshakeHello, // HANDSHAKE_HELLO_REQUEST
+ 1 : notifyStateError, // HANDSHAKE_CLIENT_HELLO
+ 2 : parseHandshakeServerHello, // HANDSHAKE_SERVER_HELLO
+ 11 : loadCertificates, // HANDSHAKE_CERTIFICATE
+ 12 : parseServerKeyExchange, // HANDSHAKE_SERVER_KEY_EXCHANGE
+ 13 : setStateRespondWithCertificate, // HANDSHAKE_CERTIFICATE
+ 14 : sendClientAck, // HANDSHAKE_HELLO_DONE
+ 15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
+ 16 : notifyStateError, // HANDSHAKE_CLIENT_KEY_EXCHANGE
+ 20 : verifyHandshake // HANDSHAKE_FINISHED
+ };
+ private var _entityHandshakeHandlers:Object;
+ private var _handshakeCanContinue:Boolean = true; // For handling cases where I might need to pause processing during a handshake (cert issues, etc.).
+ private var _handshakeQueue:Array = [];
+ /**
+ * The handshake is always started by the client.
+ */
+ private function startHandshake():void {
+ _state = STATE_NEGOTIATING;
+ // reset some other handshake state. XXX
+ sendClientHello();
+ }
+
+ /**
+ * Handle the incoming handshake packet.
+ *
+ */
+ private function parseHandshake(p:ByteArray):ByteArray {
+
+ if (p.length<4) {
+ trace("Handshake packet is way too short. bailing.");
+ return null;
+ }
+
+ p.position = 0;
+
+ var rec:ByteArray = p;
+ var type:uint = rec.readUnsignedByte();
+ var tmp:uint = rec.readUnsignedByte();
+ var length:uint = (tmp<<16) | rec.readUnsignedShort();
+ if (length+4>p.length) {
+ // partial read.
+ trace("Handshake packet is incomplete. bailing.");
+ return null;
+ }
+
+ // we need to copy the record, to have a valid FINISHED exchange.
+ if (type!=HANDSHAKE_FINISHED) {
+ _handshakePayloads.writeBytes(p, 0, length+4);
+ }
+
+ // Surf the handler map and find the right handler for this handshake packet type.
+ // I modified the individual handlers so they encapsulate all possible knowledge
+ // about the incoming packet type, so no previous handling or massaging of the data
+ // is required, as was the case using the switch statement. BP
+ if (_entityHandshakeHandlers.hasOwnProperty( type )) {
+ if (_entityHandshakeHandlers[ type ] is Function)
+ _entityHandshakeHandlers[ type ]( rec );
+ } else {
+ throw new TLSError( "Unimplemented or unknown handshake type!", TLSError.internal_error );
+ }
+
+ // Get set up for the next packet.
+ if (length+4<p.length) {
+ var n:ByteArray = new ByteArray;
+ n.writeBytes(p,length+4, p.length-(length+4));
+ return n;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Throw an error when the detected handshake state isn't a valid state for the given entity type (client vs. server, etc. ).
+ * This really should abort the handshake, since there's no case in which a server should EVER be confused about the type of entity it is. BP
+ */
+ private function notifyStateError( rec:ByteArray ) : void {
+ throw new TLSError( "Invalid handshake state for a TLS Entity type of " + _entity, TLSError.internal_error );
+ }
+
+ /**
+ * two unimplemented functions
+ */
+ private function parseClientKeyExchange( rec:ByteArray ) : void {
+ throw new TLSError( "ClientKeyExchange is currently unimplemented!", TLSError.internal_error );
+ }
+
+ private function parseServerKeyExchange( rec:ByteArray ) : void {
+ throw new TLSError( "ServerKeyExchange is currently unimplemented!", TLSError.internal_error );
+ }
+
+ /**
+ * Test the server's Finished message for validity against the data we know about. Only slightly rewritten. BP
+ */
+ private function verifyHandshake( rec:ByteArray):void {
+ // Get the Finished message
+ var verifyData:ByteArray = new ByteArray;
+ // This, in the vain hope that noboby is using SSL 2 anymore
+ if (_securityParameters.version == SSLSecurityParameters.PROTOCOL_VERSION) {
+ rec.readBytes(verifyData, 0, 36); // length should be (in fact, better be) 16 + 20 (md5-size + sha1-size)
+ } else { // presuming TLS
+ rec.readBytes(verifyData, 0, 12);
+ }
+
+ var data:ByteArray = _securityParameters.computeVerifyData(1-_entity, _handshakePayloads);
+
+ if (ArrayUtil.equals(verifyData, data)) {
+ _state = STATE_READY;
+ dispatchEvent(new TLSEvent(TLSEvent.READY));
+ } else {
+ throw new TLSError("Invalid Finished mac.", TLSError.bad_record_mac);
+ }
+ }
+
+ // enforceClient/enforceServer removed in favor of state-driven function maps
+
+ /**
+ * Handle a HANDSHAKE_HELLO
+ */
+ private function parseHandshakeHello( rec:ByteArray ) : void {
+ if (_state != STATE_READY) {
+ trace("Received an HELLO_REQUEST before being in state READY. ignoring.");
+ return;
+ }
+ _handshakePayloads = new ByteArray;
+ startHandshake();
+ }
+
+ /**
+ * Handle a HANDSHAKE_CLIENT_KEY_EXCHANGE
+ */
+ private function parseHandshakeClientKeyExchange(rec:ByteArray):void {
+ if (_securityParameters.useRSA) {
+ // skip 2 bytes for length.
+ var len:uint = rec.readShort();
+ var cipher:ByteArray = new ByteArray;
+ rec.readBytes(cipher, 0, len);
+ var preMasterSecret:ByteArray = new ByteArray;
+ _config.privateKey.decrypt(cipher, preMasterSecret, len);
+ _securityParameters.setPreMasterSecret(preMasterSecret);
+
+ // now is a good time to get our pending states
+ var o:Object = _securityParameters.getConnectionStates();
+ _pendingReadState = o.read;
+ _pendingWriteState = o.write;
+
+ } else {
+ throw new TLSError("parseHandshakeClientKeyExchange not implemented for DH modes.", TLSError.internal_error);
+ }
+
+ }
+
+ /**
+ * Handle HANDSHAKE_SERVER_HELLO - client-side
+ */
+ private function parseHandshakeServerHello( rec:IDataInput ) : void {
+
+ var ver:uint = rec.readShort();
+ if (ver != _securityParameters.version) {
+ throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
+ }
+ var random:ByteArray = new ByteArray;
+ rec.readBytes(random, 0, 32);
+ var session_length:uint = rec.readByte();
+ var session:ByteArray = new ByteArray;
+ if (session_length > 0) {
+ // some implementations don't assign a session ID
+ rec.readBytes(session, 0, session_length);
+ }
+
+ _securityParameters.setCipher(rec.readShort());
+ _securityParameters.setCompression(rec.readByte());
+ _securityParameters.setServerRandom(random);
+ }
+
+ /**
+ * Handle HANDSHAKE_CLIENT_HELLO - server side
+ */
+ private function parseHandshakeClientHello( rec:IDataInput ) : void {
+ var ret:Object;
+ var ver:uint = rec.readShort();
+ if (ver != _securityParameters.version) {
+ throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
+ }
+
+ var random:ByteArray = new ByteArray;
+ rec.readBytes(random, 0, 32);
+ var session_length:uint = rec.readByte();
+ var session:ByteArray = new ByteArray;
+ if (session_length > 0) {
+ // some implementations don't assign a session ID
+ rec.readBytes(session, 0, session_length);
+ }
+ var suites:Array = [];
+
+ var suites_length:uint = rec.readShort();
+ for (var i:uint=0;i<suites_length/2;i++) {
+ suites.push(rec.readShort());
+ }
+
+ var compressions:Array = [];
+
+ var comp_length:uint = rec.readByte();
+ for (i=0;i<comp_length;i++) {
+ compressions.push(rec.readByte());
+ }
+
+ ret = {random:random, session:session, suites:suites, compressions:compressions};
+
+ var sofar:uint = 2+32+1+session_length+2+suites_length+1+comp_length;
+ var extensions:Array = [];
+ if (sofar<length) {
+ // we have extensions. great.
+ var ext_total_length:uint = rec.readShort();
+ while (ext_total_length>0) {
+ var ext_type:uint = rec.readShort();
+ var ext_length:uint = rec.readShort();
+ var ext_data:ByteArray = new ByteArray;
+ rec.readBytes(ext_data, 0, ext_length);
+ ext_total_length -= 4+ext_length;
+ extensions.push({type:ext_type, length:ext_length, data:ext_data});
+ }
+ }
+ ret.ext = extensions;
+
+ sendServerHello(ret);
+ sendCertificate();
+ // TODO: Modify to handle case of requesting a certificate from the client, for "client authentication",
+ // and testing purposes, will probably never actually need it.
+ sendServerHelloDone();
+ }
+
+ private function sendClientHello():void {
+ var rec:ByteArray = new ByteArray;
+ // version - modified to support version attribute from ISecurityParameters
+ rec.writeShort(_securityParameters.version);
+ // random
+ var prng:Random = new Random;
+ var clientRandom:ByteArray = new ByteArray;
+ prng.nextBytes(clientRandom, 32);
+ _securityParameters.setClientRandom(clientRandom);
+ rec.writeBytes(clientRandom,0,32);
+ // session
+ rec.writeByte(32);
+ prng.nextBytes(rec, 32);
+ // Cipher suites
+ var cs:Array = _config.cipherSuites;
+ rec.writeShort(2* cs.length);
+ for (var i:int=0;i<cs.length;i++) {
+ rec.writeShort(cs[i]);
+ }
+ // Compression
+ cs = _config.compressions;
+ rec.writeByte(cs.length);
+ for (i=0;i<cs.length;i++) {
+ rec.writeByte(cs[i]);
+ }
+ // no extensions, yet.
+ rec.position = 0;
+ sendHandshake(HANDSHAKE_CLIENT_HELLO, rec.length, rec);
+ }
+
+ private function findMatch(a1:Array, a2:Array):int {
+ for (var i:int=0;i<a1.length;i++) {
+ var e:uint = a1[i];
+ if (a2.indexOf(e)>-1) {
+ return e;
+ }
+ }
+ return -1;
+ }
+
+ private function sendServerHello(v:Object):void {
+ var cipher:int = findMatch(_config.cipherSuites, v.suites);
+ if (cipher == -1) {
+ throw new TLSError("No compatible cipher found.", TLSError.handshake_failure);
+ }
+ _securityParameters.setCipher(cipher);
+
+ var comp:int = findMatch(_config.compressions, v.compressions);
+ if (comp == 01) {
+ throw new TLSError("No compatible compression method found.", TLSError.handshake_failure);
+ }
+ _securityParameters.setCompression(comp);
+ _securityParameters.setClientRandom(v.random);
+
+
+ var rec:ByteArray = new ByteArray;
+ rec.writeShort(_securityParameters.version);
+ var prng:Random = new Random;
+ var serverRandom:ByteArray = new ByteArray;
+ prng.nextBytes(serverRandom, 32);
+ _securityParameters.setServerRandom(serverRandom);
+ rec.writeBytes(serverRandom,0,32);
+ // session
+ rec.writeByte(32);
+ prng.nextBytes(rec, 32);
+ // Cipher suite
+ rec.writeShort(v.suites[0]);
+ // Compression
+ rec.writeByte(v.compressions[0]);
+ rec.position = 0;
+ sendHandshake(HANDSHAKE_SERVER_HELLO, rec.length, rec);
+ }
+
+ private var sendClientCert:Boolean = false;
+ private function setStateRespondWithCertificate( r:ByteArray = null) : void {
+ sendClientCert = true;
+ }
+
+ private function sendCertificate( r:ByteArray = null ):void {
+ var cert:ByteArray = _config.certificate;
+ var len:uint;
+ var len2:uint;
+ var rec:ByteArray = new ByteArray;
+ // Look for a certficate chain, if we have one, send it, if we don't, send an empty record.
+ if (cert != null) {
+ len = cert.length;
+ len2 = cert.length + 3;
+ rec.writeByte(len2>>16);
+ rec.writeShort(len2&65535);
+ rec.writeByte(len>>16);
+ rec.writeShort(len&65535);
+ rec.writeBytes(cert);
+ } else {
+ rec.writeShort( 0 );
+ rec.writeByte( 0 );
+ }
+ rec.position = 0;
+ sendHandshake(HANDSHAKE_CERTIFICATE, rec.length, rec);
+ }
+
+ private function sendCertificateVerify():void {
+ var rec:ByteArray = new ByteArray();
+ // Encrypt the handshake payloads here
+ var data:ByteArray = _securityParameters.computeCertificateVerify(_entity, _handshakePayloads);
+ data.position=0;
+ sendHandshake(HANDSHAKE_CERTIFICATE_VERIFY, data.length, data);
+ }
+
+ private function sendServerHelloDone():void {
+ var rec:ByteArray = new ByteArray;
+ sendHandshake(HANDSHAKE_HELLO_DONE, rec.length, rec);
+ }
+
+ private function sendClientKeyExchange():void {
+ if (_securityParameters.useRSA) {
+ var p:ByteArray = new ByteArray;
+ p.writeShort(_securityParameters.version);
+ var prng:Random = new Random;
+ prng.nextBytes(p, 46);
+ p.position = 0;
+
+ var preMasterSecret:ByteArray = new ByteArray;
+ preMasterSecret.writeBytes(p, 0, p.length);
+ preMasterSecret.position = 0;
+ _securityParameters.setPreMasterSecret(preMasterSecret);
+
+ var enc_key:ByteArray = new ByteArray;
+ _otherCertificate.getPublicKey().encrypt(preMasterSecret, enc_key, preMasterSecret.length);
+
+ enc_key.position = 0;
+ var rec:ByteArray = new ByteArray;
+
+ // TLS requires the size of the premaster key be sent BUT
+ // SSL 3.0 does not
+ if (_securityParameters.version > 0x0300) {
+ rec.writeShort(enc_key.length);
+ }
+ rec.writeBytes(enc_key, 0, enc_key.length);
+
+ rec.position=0;
+
+ sendHandshake(HANDSHAKE_CLIENT_KEY_EXCHANGE, rec.length, rec);
+
+ // now is a good time to get our pending states
+ var o:Object = _securityParameters.getConnectionStates();
+ _pendingReadState = o.read;
+ _pendingWriteState = o.write;
+
+ } else {
+ throw new TLSError("Non-RSA Client Key Exchange not implemented.", TLSError.internal_error);
+ }
+ }
+ private function sendFinished():void {
+ var data:ByteArray = _securityParameters.computeVerifyData(_entity, _handshakePayloads);
+ data.position=0;
+ sendHandshake(HANDSHAKE_FINISHED, data.length, data);
+ }
+
+ private function sendHandshake(type:uint, len:uint, payload:IDataInput):void {
+ var rec:ByteArray = new ByteArray;
+ rec.writeByte(type);
+ rec.writeByte(0);
+ rec.writeShort(len);
+ payload.readBytes(rec, rec.position, len);
+ _handshakePayloads.writeBytes(rec, 0, rec.length);
+ sendRecord(PROTOCOL_HANDSHAKE, rec);
+ }
+
+ private function sendChangeCipherSpec():void {
+ var rec:ByteArray = new ByteArray;
+ rec[0] = 1;
+ sendRecord(PROTOCOL_CHANGE_CIPHER_SPEC, rec);
+
+ // right after, switch the cipher for writing.
+ _currentWriteState = _pendingWriteState;
+ _pendingWriteState = null;
+ }
+
+ public function sendApplicationData(data:ByteArray, offset:uint=0, length:uint=0):void {
+ var rec:ByteArray = new ByteArray;
+ var len:uint = length;
+ // BIG FAT WARNING: Patch from Arlen Cuss ALA As3crypto group on Google code.
+ // This addresses data overflow issues when the packet size hits the max length boundary.
+ if (len == 0) len = data.length;
+ while (len>16384) {
+ rec.position = 0;
+ rec.writeBytes(data, offset, 16384);
+ rec.position = 0;
+ sendRecord(PROTOCOL_APPLICATION_DATA, rec);
+ offset += 16384;
+ len -= 16384;
+ }
+ rec.position = 0;
+ rec.writeBytes(data, offset, len);
+ // trace("Data I'm sending..." + Hex.fromArray( data ));
+ rec.position = 0;
+ sendRecord(PROTOCOL_APPLICATION_DATA, rec);
+ }
+ private function sendRecord(type:uint, payload:ByteArray):void {
+ // encrypt
+ payload = _currentWriteState.encrypt(type, payload);
+
+ _oStream.writeByte(type);
+ _oStream.writeShort(_securityParameters.version);
+ _oStream.writeShort(payload.length);
+ _oStream.writeBytes(payload, 0, payload.length);
+
+ scheduleWrite();
+ }
+
+ private var _writeScheduler:uint;
+ private function scheduleWrite():void {
+ if (_writeScheduler!=0) return;
+ _writeScheduler = setTimeout(commitWrite, 0);
+ }
+ private function commitWrite():void {
+ clearTimeout(_writeScheduler);
+ _writeScheduler = 0;
+ if (_state != STATE_CLOSED) {
+ dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA));
+ }
+ }
+
+ private function sendClientAck( rec:ByteArray ):void {
+ if ( _handshakeCanContinue ) {
+ // If I have a pending cert request, send it
+ if (sendClientCert)
+ sendCertificate();
+ // send a client key exchange
+ sendClientKeyExchange();
+ // Send the certificate verify, if we have one
+ if (_config.certificate != null)
+ sendCertificateVerify();
+ // send a change cipher spec
+ sendChangeCipherSpec();
+ // send a finished
+ sendFinished();
+ }
+ }
+
+ /**
+ * Vaguely gross function that parses a RSA key out of a certificate.
+ *
+ * As long as that certificate looks just the way we expect it to.
+ *
+ */
+ private function loadCertificates( rec:ByteArray ):void {
+ var tmp:uint = rec.readByte();
+ var certs_len:uint = (tmp<<16) | rec.readShort();
+ var certs:Array = [];
+
+ while (certs_len>0) {
+ tmp = rec.readByte();
+ var cert_len:uint = (tmp<<16) | rec.readShort();
+ var cert:ByteArray = new ByteArray;
+ rec.readBytes(cert, 0, cert_len);
+ certs.push(cert);
+ certs_len -= 3 + cert_len;
+ }
+
+ var firstCert:X509Certificate = null;
+ for (var i:int=0;i<certs.length;i++) {
+ var x509:X509Certificate = new X509Certificate(certs[i]);
+ _store.addCertificate(x509);
+ if (firstCert==null) {
+ firstCert = x509;
+ }
+ }
+
+
+ // Test first for trust override parameters
+ // This nice trust override stuff comes from Joey Parrish via As3crypto forums
+ var certTrusted:Boolean;
+ if (_config.trustAllCertificates) {
+ certTrusted = true; // Blatantly trust everything
+ } else if (_config.trustSelfSignedCertificates ) {
+ // Self-signed certs
+ certTrusted = firstCert.isSelfSigned(new Date);
+ } else {
+ // Certs with a signer in the CA store - realistically, I should setup an event chain to handle this
+ certTrusted = firstCert.isSigned(_store, _config.CAStore );
+ }
+
+ // Good so far
+ if (certTrusted) {
+ // ok, that's encouraging. now for the hostname match.
+ if (_otherIdentity==null || _config.ignoreCommonNameMismatch ) {
+ // we don't care who we're talking with. groovy.
+ _otherCertificate = firstCert;
+ } else {
+ // use regex to handle wildcard certs
+ var commonName:String = firstCert.getCommonName();
+ // replace all regex special characters with escaped version, except for asterisk
+ // replace the asterisk with a regex sequence to match one or more non-dot characters
+ var commonNameRegex:RegExp = new RegExp( commonName.replace(/[\^\\\-$.[\]|()?+{}]/g, "\\$&").replace(/\*/g, "[^.]+"), "gi");
+ if (commonNameRegex.exec(_otherIdentity)) {
+ _otherCertificate = firstCert;
+ } else {
+ if (_config.promptUserForAcceptCert ) {
+ _handshakeCanContinue = false;
+ dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
+ } else {
+ throw new TLSError("Invalid common name: "+firstCert.getCommonName()+", expected "+_otherIdentity, TLSError.bad_certificate);
+ }
+ }
+ }
+
+ } else {
+ // Let's ask the user if we can accept this cert. I'm not certain of the behaviour in case of timeouts,
+ // so I probably need to handle the case by killing and restarting the connection rather than continuing if it becomes
+ // an issue. We shall see. BP
+ if (_config.promptUserForAcceptCert) {
+ _handshakeCanContinue = false;
+ dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
+ } else {
+ // Cannot continue, die.
+ throw new TLSError("Cannot verify certificate", TLSError.bad_certificate);
+ }
+ }
+ }
+
+ // Accept the peer cert, and keep going
+ public function acceptPeerCertificate() : void {
+ _handshakeCanContinue = true;
+ sendClientAck( null );
+ }
+
+ // Step off biotch! No trust for you!
+ public function rejectPeerCertificate() : void {
+ throw new TLSError("Peer certificate not accepted!", TLSError.bad_certificate);
+ }
+
+
+ private function parseAlert(p:ByteArray):void {
+ //throw new Error("Alert not implemented.");
+ // 7.2
+ trace("GOT ALERT! type="+p[1]);
+ close();
+ }
+ private function parseChangeCipherSpec(p:ByteArray):void {
+ p.readUnsignedByte();
+ if (_pendingReadState==null) {
+ throw new TLSError("Not ready to Change Cipher Spec, damnit.", TLSError.unexpected_message);
+ }
+ _currentReadState = _pendingReadState;
+ _pendingReadState = null;
+ // 7.1
+ }
+ private function parseApplicationData(p:ByteArray):void {
+ if (_state != STATE_READY) {
+ throw new TLSError("Too soon for data!", TLSError.unexpected_message);
+ return;
+ }
+ dispatchEvent(new TLSEvent(TLSEvent.DATA, p));
+ }
+
+ private function handleTLSError(e:TLSError):void {
+ // basic rules to keep things simple:
+ // - Make a good faith attempt at notifying peers
+ // - TLSErrors are always fatal.
+ // BP: Meh...not always. Common Name mismatches appear to be common on servers. Instead of closing, let's pause, and ask for confirmation
+ // before we tear the connection down.
+
+ close(e);
+ }
+ }
+}
--- /dev/null
+/**\r
+ * TLSError\r
+ * \r
+ * A error that can be thrown when something wrong happens in the TLS protocol.\r
+ * This is handled in TLSEngine by generating a TLS ALERT as appropriate.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ public class TLSError extends Error {\r
+ public static const close_notify:uint = 0;\r
+ public static const unexpected_message:uint = 10;\r
+ public static const bad_record_mac:uint = 20;\r
+ public static const decryption_failed:uint = 21;\r
+ public static const record_overflow:uint = 22;\r
+ public static const decompression_failure:uint = 30;\r
+ public static const handshake_failure:uint = 40;\r
+ public static const bad_certificate:uint = 42;\r
+ public static const unsupported_certificate:uint = 43;\r
+ public static const certificate_revoked:uint = 44;\r
+ public static const certificate_expired:uint = 45;\r
+ public static const certificate_unknown:uint = 46;\r
+ public static const illegal_parameter:uint = 47;\r
+ public static const unknown_ca:uint = 48;\r
+ public static const access_denied:uint = 49;\r
+ public static const decode_error:uint = 50;\r
+ public static const decrypt_error:uint = 51;\r
+ public static const protocol_version:uint = 70;\r
+ public static const insufficient_security:uint = 71;\r
+ public static const internal_error:uint = 80;\r
+ public static const user_canceled:uint = 90;\r
+ public static const no_renegotiation:uint = 100;\r
+ \r
+ public function TLSError(message:String, id:int) {\r
+ super(message,id);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TLSEvent\r
+ * \r
+ * This is used by TLSEngine to let the application layer know\r
+ * when we're ready for sending, or have received application data\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.events.Event;\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class TLSEvent extends Event {\r
+ \r
+ static public const DATA:String = "data";\r
+ static public const READY:String = "ready";\r
+ static public const PROMPT_ACCEPT_CERT:String = "promptAcceptCert";\r
+ \r
+ public var data:ByteArray;\r
+ \r
+ public function TLSEvent(type:String, data:ByteArray = null) {\r
+ this.data = data;\r
+ super(type, false, false);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TLSSecurityParameters\r
+ * \r
+ * This class encapsulates all the security parameters that get negotiated\r
+ * during the TLS handshake. It also holds all the key derivation methods.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Patched by Bobby Parker (sh0rtwave@gmail.com)\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import com.hurlant.crypto.hash.MD5;\r
+ import com.hurlant.crypto.hash.SHA1;\r
+ import com.hurlant.crypto.prng.TLSPRF;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ import flash.utils.ByteArray;
+ import com.hurlant.crypto.rsa.RSAKey;\r
+ \r
+ public class TLSSecurityParameters implements ISecurityParameters {\r
+ \r
+ // COMPRESSION\r
+ public static const COMPRESSION_NULL:uint = 0;\r
+ \r
+ // This is probably not smart. Revise this to use all settings from TLSConfig, since this shouldn't really know about\r
+ // user settings, those are best handled from the engine at a session level.\r
+ public static var IGNORE_CN_MISMATCH:Boolean = true;\r
+ public static var ENABLE_USER_CLIENT_CERTIFICATE:Boolean = false;\r
+ public static var USER_CERTIFICATE:String;\r
+ \r
+ \r
+ private var cert:ByteArray; // Local Cert\r
+ private var key:RSAKey; // local key\r
+ private var entity:uint; // SERVER | CLIENT\r
+ private var bulkCipher:uint; // BULK_CIPHER_*\r
+ private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER\r
+ private var keySize:uint;\r
+ private var keyMaterialLength:uint;\r
+ private var IVSize:uint;\r
+ private var macAlgorithm:uint; // MAC_*\r
+ private var hashSize:uint;\r
+ private var compression:uint; // COMPRESSION_NULL\r
+ private var masterSecret:ByteArray; // 48 bytes\r
+ private var clientRandom:ByteArray; // 32 bytes\r
+ private var serverRandom:ByteArray; // 32 bytes\r
+ private var ignoreCNMismatch:Boolean = true;\r
+ private var trustAllCerts:Boolean = false;\r
+ private var trustSelfSigned:Boolean = false;\r
+ public static const PROTOCOL_VERSION:uint = 0x0301;
+ private var tlsDebug:Boolean = false;\r
+
+ \r
+ // not strictly speaking part of this, but yeah.\r
+ public var keyExchange:uint;\r
+ public function TLSSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:RSAKey = null) {\r
+ this.entity = entity;\r
+ reset();\r
+ key = localKey;\r
+ cert = localCert;\r
+ }\r
+ \r
+ public function get version() : uint {\r
+ return PROTOCOL_VERSION;\r
+ }\r
+ \r
+ public function reset():void {\r
+ bulkCipher = BulkCiphers.NULL;\r
+ cipherType = BulkCiphers.BLOCK_CIPHER;\r
+ macAlgorithm = MACs.NULL;\r
+ compression = COMPRESSION_NULL;\r
+ masterSecret = null;\r
+ }\r
+ \r
+ public function getBulkCipher():uint {\r
+ return bulkCipher;\r
+ }\r
+ public function getCipherType():uint {\r
+ return cipherType;\r
+ }\r
+ public function getMacAlgorithm():uint {\r
+ return macAlgorithm;\r
+ }\r
+ \r
+ public function setCipher(cipher:uint):void {\r
+ bulkCipher = CipherSuites.getBulkCipher(cipher);\r
+ cipherType = BulkCiphers.getType(bulkCipher);\r
+ keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); // 8\r
+ keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5\r
+ IVSize = BulkCiphers.getIVSize(bulkCipher);\r
+ \r
+ keyExchange = CipherSuites.getKeyExchange(cipher);\r
+ \r
+ macAlgorithm = CipherSuites.getMac(cipher);\r
+ hashSize = MACs.getHashSize(macAlgorithm);\r
+ }\r
+ public function setCompression(algo:uint):void {\r
+ compression = algo;\r
+ }\r
+ public function setPreMasterSecret(secret:ByteArray):void {\r
+ // compute master_secret\r
+ var seed:ByteArray = new ByteArray;\r
+ seed.writeBytes(clientRandom, 0, clientRandom.length);\r
+ seed.writeBytes(serverRandom, 0, serverRandom.length);\r
+ var prf:TLSPRF = new TLSPRF(secret, "master secret", seed);\r
+ masterSecret = new ByteArray;\r
+ prf.nextBytes(masterSecret, 48);\r
+ if (tlsDebug)\r
+ trace("Master Secret: " + Hex.fromArray( masterSecret, true ));\r
+ }\r
+ public function setClientRandom(secret:ByteArray):void {\r
+ clientRandom = secret;\r
+ }\r
+ public function setServerRandom(secret:ByteArray):void { \r
+ serverRandom = secret;\r
+ }\r
+ \r
+ public function get useRSA():Boolean {\r
+ return KeyExchanges.useRSA(keyExchange);\r
+ }\r
+ \r
+ public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {\r
+ var seed:ByteArray = new ByteArray;\r
+ var md5:MD5 = new MD5;\r
+ if (tlsDebug)\r
+ trace("Handshake value: " + Hex.fromArray(handshakeMessages, true ));\r
+ seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());\r
+ var sha:SHA1 = new SHA1;\r
+ seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());\r
+ if (tlsDebug)\r
+ trace("Seed in: " + Hex.fromArray(seed, true ));\r
+ var prf:TLSPRF = new TLSPRF(masterSecret, (side==TLSEngine.CLIENT) ? "client finished" : "server finished", seed);\r
+ var out:ByteArray = new ByteArray;\r
+ prf.nextBytes(out, 12);\r
+ if (tlsDebug)\r
+ trace("Finished out: " + Hex.fromArray(out, true ));\r
+ out.position = 0;\r
+ return out;\r
+ }\r
+ \r
+ // client side certficate check - This is probably incorrect somehow\r
+ public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {\r
+ var seed:ByteArray = new ByteArray;\r
+ var md5:MD5 = new MD5;\r
+ seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());\r
+ var sha:SHA1 = new SHA1;\r
+ seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());\r
+ \r
+ // Now that I have my hashes of existing handshake messages (which I'm not sure about the length of yet) then \r
+ // Sign that with my private key\r
+ seed.position = 0;\r
+ var out:ByteArray = new ByteArray();\r
+ key.sign( seed, out, seed.bytesAvailable);\r
+ out.position = 0;\r
+ return out; \r
+ }\r
+ \r
+ public function getConnectionStates():Object {\r
+ if (masterSecret != null) {\r
+ var seed:ByteArray = new ByteArray;\r
+ seed.writeBytes(serverRandom, 0, serverRandom.length);\r
+ seed.writeBytes(clientRandom, 0, clientRandom.length);\r
+ var prf:TLSPRF = new TLSPRF(masterSecret, "key expansion", seed);\r
+ \r
+ var client_write_MAC:ByteArray = new ByteArray;\r
+ prf.nextBytes(client_write_MAC, hashSize);\r
+ var server_write_MAC:ByteArray = new ByteArray;\r
+ prf.nextBytes(server_write_MAC, hashSize);\r
+ var client_write_key:ByteArray = new ByteArray;\r
+ prf.nextBytes(client_write_key, keyMaterialLength);\r
+ var server_write_key:ByteArray = new ByteArray;\r
+ prf.nextBytes(server_write_key, keyMaterialLength);\r
+ var client_write_IV:ByteArray = new ByteArray;\r
+ prf.nextBytes(client_write_IV, IVSize);\r
+ var server_write_IV:ByteArray = new ByteArray;\r
+ prf.nextBytes(server_write_IV, IVSize);\r
+\r
+ var client_write:TLSConnectionState = new TLSConnectionState(\r
+ bulkCipher, cipherType, macAlgorithm,\r
+ client_write_MAC, client_write_key, client_write_IV);\r
+ var server_write:TLSConnectionState = new TLSConnectionState(\r
+ bulkCipher, cipherType, macAlgorithm,\r
+ server_write_MAC, server_write_key, server_write_IV);\r
+ \r
+ if (entity == TLSEngine.CLIENT) {\r
+ return {read:server_write, write:client_write};\r
+ } else {\r
+ return {read:client_write, write:server_write};\r
+ }\r
+\r
+ } else {\r
+ return {read:new TLSConnectionState, write:new TLSConnectionState};\r
+ }\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * TLSSocket\r
+ * \r
+ * This is the "end-user" TLS class.\r
+ * It works just like a Socket, by encapsulating a Socket and\r
+ * wrapping the TLS protocol around the data that passes over it.\r
+ * This class can either create a socket connection, or reuse an\r
+ * existing connected socket. The later is useful for STARTTLS flows.\r
+ * \r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.events.Event;\r
+ import flash.events.EventDispatcher;\r
+ import flash.events.IOErrorEvent;\r
+ import flash.events.ProgressEvent;\r
+ import flash.events.SecurityErrorEvent;\r
+ import flash.net.ObjectEncoding;\r
+ import flash.net.Socket;\r
+ import flash.utils.ByteArray;\r
+ import flash.utils.Endian;\r
+ import flash.utils.IDataInput;\r
+ import flash.utils.IDataOutput;\r
+ import flash.utils.clearTimeout;\r
+ import flash.utils.setTimeout;
+ import com.hurlant.crypto.cert.X509Certificate;
+ \r
+ \r
+ [Event(name="close", type="flash.events.Event")]\r
+ [Event(name="connect", type="flash.events.Event")]\r
+ [Event(name="ioError", type="flash.events.IOErrorEvent")]\r
+ [Event(name="securityError", type="flash.events.SecurityErrorEvent")]\r
+ [Event(name="socketData", type="flash.events.ProgressEvent")]\r
+ [Event(name="acceptPeerCertificatePrompt", type="flash.events.Event")]\r
+ \r
+ /**\r
+ * It feels like a socket, but it wraps the stream\r
+ * over TLS 1.0\r
+ * \r
+ * That's all.\r
+ * \r
+ */\r
+ public class TLSSocket extends Socket implements IDataInput, IDataOutput {\r
+ \r
+ private var _endian:String;\r
+ private var _objectEncoding:uint;\r
+ \r
+ private var _iStream:ByteArray;\r
+ private var _oStream:ByteArray;\r
+ private var _iStream_cursor:uint;\r
+ \r
+ private var _socket:Socket;\r
+ private var _config:TLSConfig;\r
+ private var _engine:TLSEngine;\r
+ public static const ACCEPT_PEER_CERT_PROMPT:String = "acceptPeerCertificatePrompt"\r
+ \r
+ public function TLSSocket(host:String = null, port:int = 0, config:TLSConfig = null) {\r
+ _config = config;\r
+ if (host!=null && port!=0) {\r
+ connect(host, port);\r
+ }\r
+ }\r
+ \r
+ override public function get bytesAvailable():uint {\r
+ return _iStream.bytesAvailable;\r
+ }\r
+ override public function get connected():Boolean {\r
+ return _socket.connected;\r
+ }\r
+ override public function get endian():String {\r
+ return _endian;\r
+ }\r
+ override public function set endian(value:String):void {\r
+ _endian = value;\r
+ _iStream.endian = value;\r
+ _oStream.endian = value;\r
+ }\r
+ override public function get objectEncoding():uint {\r
+ return _objectEncoding;\r
+ }\r
+ override public function set objectEncoding(value:uint):void {\r
+ _objectEncoding = value;\r
+ _iStream.objectEncoding = value;\r
+ _oStream.objectEncoding = value;\r
+ }\r
+ \r
+ \r
+ private function onTLSData(event:TLSEvent):void {\r
+ if (_iStream.position == _iStream.length) {\r
+ _iStream.position = 0;\r
+ _iStream.length = 0;\r
+ _iStream_cursor = 0;\r
+ }\r
+ var cursor:uint = _iStream.position;\r
+ _iStream.position = _iStream_cursor;\r
+ _iStream.writeBytes(event.data);\r
+ _iStream_cursor = _iStream.position;\r
+ _iStream.position = cursor;\r
+ dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, event.data.length));\r
+ }\r
+ \r
+ private function onTLSReady(event:TLSEvent):void {\r
+ _ready = true;\r
+ scheduleWrite();\r
+ }\r
+ \r
+ private function onTLSClose(event:Event):void {\r
+ dispatchEvent(event);\r
+ // trace("Received TLS close");\r
+ close();\r
+ }\r
+ \r
+ private var _ready:Boolean;\r
+ private var _writeScheduler:uint;\r
+ private function scheduleWrite():void {\r
+ if (_writeScheduler!=0) return;\r
+ _writeScheduler = setTimeout(commitWrite, 0);\r
+ }\r
+ private function commitWrite():void {\r
+ clearTimeout(_writeScheduler);\r
+ _writeScheduler = 0;\r
+ if (_ready) {\r
+ _engine.sendApplicationData(_oStream);\r
+ _oStream.length = 0;\r
+ }\r
+ }\r
+ \r
+ \r
+ override public function close():void {\r
+ _ready = false;\r
+ _engine.close();\r
+ if (_socket.connected) {\r
+ _socket.flush();\r
+ _socket.close();\r
+ }\r
+ }\r
+ public function setTLSConfig( config:TLSConfig) : void {\r
+ _config = config;\r
+ } \r
+\r
+ override public function connect(host:String, port:int):void {\r
+ init(new Socket, _config, host);\r
+ _socket.connect(host, port);\r
+ _engine.start();\r
+ }\r
+ \r
+ public function releaseSocket() : void {\r
+ _socket.removeEventListener(Event.CONNECT, dispatchEvent);\r
+ _socket.removeEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);\r
+ _socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);\r
+ _socket.removeEventListener(Event.CLOSE, dispatchEvent);\r
+ _socket.removeEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);\r
+ _socket = null; \r
+ }\r
+ \r
+ public function reinitialize(host:String, config:TLSConfig) : void {\r
+ // Reinitialize the connection using new values\r
+ // but re-use the existing socket\r
+ // Doubt this is useful in any valid context other than my specific case (VMWare)\r
+ var ba:ByteArray = new ByteArray;\r
+ \r
+ if (_socket.bytesAvailable > 0) {\r
+ _socket.readBytes(ba, 0, _socket.bytesAvailable); \r
+ }\r
+ // Do nothing with it.\r
+ _iStream = new ByteArray;\r
+ _oStream = new ByteArray;\r
+ _iStream_cursor = 0;\r
+ objectEncoding = ObjectEncoding.DEFAULT;\r
+ endian = Endian.BIG_ENDIAN;\r
+ /* \r
+ _socket.addEventListener(Event.CONNECT, dispatchEvent);\r
+ _socket.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);\r
+ _socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);\r
+ _socket.addEventListener(Event.CLOSE, dispatchEvent);\r
+ */\r
+ \r
+ if (config == null) {\r
+ config = new TLSConfig(TLSEngine.CLIENT);\r
+ }\r
+ \r
+ _engine = new TLSEngine(config, _socket, _socket, host);\r
+ _engine.addEventListener(TLSEvent.DATA, onTLSData);\r
+ _engine.addEventListener(TLSEvent.READY, onTLSReady);\r
+ _engine.addEventListener(Event.CLOSE, onTLSClose);\r
+ _engine.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { _socket.flush(); });\r
+ _socket.addEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);\r
+ _engine.addEventListener( TLSEvent.PROMPT_ACCEPT_CERT, onAcceptCert );\r
+\r
+ _ready = false;\r
+ _engine.start();\r
+ }\r
+ \r
+ public function startTLS(socket:Socket, host:String, config:TLSConfig = null):void {\r
+ if (!socket.connected) {\r
+ throw new Error("Cannot STARTTLS on a socket that isn't connected.");\r
+ }\r
+ init(socket, config, host);\r
+ _engine.start();\r
+ }\r
+ \r
+ private function init(socket:Socket, config:TLSConfig, host:String):void {\r
+ _iStream = new ByteArray;\r
+ _oStream = new ByteArray;\r
+ _iStream_cursor = 0;\r
+ objectEncoding = ObjectEncoding.DEFAULT;\r
+ endian = Endian.BIG_ENDIAN;\r
+ _socket = socket;\r
+ _socket.addEventListener(Event.CONNECT, dispatchEvent);\r
+ _socket.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);\r
+ _socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);\r
+ _socket.addEventListener(Event.CLOSE, dispatchEvent);\r
+ \r
+ if (config == null) {\r
+ config = new TLSConfig(TLSEngine.CLIENT);\r
+ }\r
+ _engine = new TLSEngine(config, _socket, _socket, host);\r
+ _engine.addEventListener(TLSEvent.DATA, onTLSData);\r
+ _engine.addEventListener( TLSEvent.PROMPT_ACCEPT_CERT, onAcceptCert );\r
+ _engine.addEventListener(TLSEvent.READY, onTLSReady);\r
+ _engine.addEventListener(Event.CLOSE, onTLSClose);\r
+ _engine.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { if(connected) _socket.flush(); });\r
+ _socket.addEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);\r
+\r
+ _ready = false;\r
+ }\r
+ \r
+ override public function flush():void {\r
+ commitWrite();\r
+ _socket.flush();\r
+ }\r
+ \r
+ override public function readBoolean():Boolean {\r
+ return _iStream.readBoolean();\r
+ }\r
+ \r
+ override public function readByte():int {\r
+ return _iStream.readByte();\r
+ }\r
+ \r
+ override public function readBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void {\r
+ return _iStream.readBytes(bytes, offset, length);\r
+ }\r
+ \r
+ override public function readDouble():Number {\r
+ return _iStream.readDouble();\r
+ }\r
+ \r
+ override public function readFloat():Number {\r
+ return _iStream.readFloat();\r
+ }\r
+ \r
+ override public function readInt():int {\r
+ return _iStream.readInt();\r
+ }\r
+ \r
+ override public function readMultiByte(length:uint, charSet:String):String {\r
+ return _iStream.readMultiByte(length, charSet);\r
+ }\r
+ \r
+ override public function readObject():* {\r
+ return _iStream.readObject();\r
+ }\r
+ \r
+ override public function readShort():int {\r
+ return _iStream.readShort();\r
+ }\r
+ \r
+ override public function readUnsignedByte():uint {\r
+ return _iStream.readUnsignedByte();\r
+ }\r
+ \r
+ override public function readUnsignedInt():uint {\r
+ return _iStream.readUnsignedInt();\r
+ }\r
+ \r
+ override public function readUnsignedShort():uint {\r
+ return _iStream.readUnsignedShort();\r
+ }\r
+ \r
+ override public function readUTF():String {\r
+ return _iStream.readUTF();\r
+ }\r
+ \r
+ override public function readUTFBytes(length:uint):String {\r
+ return _iStream.readUTFBytes(length);\r
+ }\r
+ \r
+ override public function writeBoolean(value:Boolean):void {\r
+ _oStream.writeBoolean(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeByte(value:int):void {\r
+ _oStream.writeByte(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void {\r
+ _oStream.writeBytes(bytes, offset, length);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeDouble(value:Number):void {\r
+ _oStream.writeDouble(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeFloat(value:Number):void {\r
+ _oStream.writeFloat(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeInt(value:int):void {\r
+ _oStream.writeInt(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeMultiByte(value:String, charSet:String):void {\r
+ _oStream.writeMultiByte(value, charSet);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeObject(object:*):void {\r
+ _oStream.writeObject(object);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeShort(value:int):void {\r
+ _oStream.writeShort(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeUnsignedInt(value:uint):void {\r
+ _oStream.writeUnsignedInt(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeUTF(value:String):void {\r
+ _oStream.writeUTF(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ override public function writeUTFBytes(value:String):void {\r
+ _oStream.writeUTFBytes(value);\r
+ scheduleWrite();\r
+ }\r
+ \r
+ public function getPeerCertificate() : X509Certificate {\r
+ return _engine.peerCertificate;\r
+ }\r
+ \r
+ public function onAcceptCert( event:TLSEvent ) : void {\r
+ dispatchEvent( new TLSSocketEvent( _engine.peerCertificate ) );\r
+ }\r
+ \r
+ // These are just a passthroughs to the engine. Encapsulation, et al\r
+ public function acceptPeerCertificate( event:Event ) : void {\r
+ _engine.acceptPeerCertificate();\r
+ }\r
+ \r
+ public function rejectPeerCertificate( event:Event ) : void {\r
+ _engine.rejectPeerCertificate();\r
+ }\r
+ \r
+ }\r
+}\r
+ \r
--- /dev/null
+/**\r
+ * TLSEvent\r
+ * \r
+ * This is used by TLSEngine to let the application layer know\r
+ * when we're ready for sending, or have received application data\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.crypto.tls {\r
+ import flash.events.Event;\r
+ import flash.utils.ByteArray;
+ import com.hurlant.crypto.cert.X509Certificate;\r
+ \r
+ public class TLSSocketEvent extends Event {\r
+ \r
+ static public const PROMPT_ACCEPT_CERT:String = "promptAcceptCert";\r
+ \r
+ public var cert:X509Certificate;\r
+ \r
+ public function TLSSocketEvent( cert:X509Certificate = null) { \r
+ super(PROMPT_ACCEPT_CERT, false, false);\r
+ this.cert = cert;\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**
+ * TLSTest
+ *
+ * A test class for TLS. Not a finished product.
+ * Copyright (c) 2007 Henri Torgemane
+ *
+ * See LICENSE.txt for full license information.
+ */
+package com.hurlant.crypto.tls {
+ import com.hurlant.crypto.cert.X509Certificate;
+ import com.hurlant.crypto.cert.X509CertificateCollection;
+ import com.hurlant.util.Hex;
+ import com.hurlant.util.der.PEM;
+
+ import flash.events.Event;
+ import flash.events.ProgressEvent;
+ import flash.net.Socket;
+ import flash.utils.ByteArray;
+ import flash.utils.getTimer;
+
+ public class TLSTest {
+
+
+ public var myDebugData:String;
+
+ //[Embed(source="/src/host.cert",mimeType="application/octet-stream")]
+ public var myCert:Class;
+ //[Embed(source="/src/host.key",mimeType="application/octet-stream")]
+ public var myKey:Class;
+
+ public function TLSTest(host:String = null, port:int = 0, type:int = 0 ) {
+ //loopback();
+ if (host != null) {
+ if (type == 0) { // SSL 3.0
+ connectLoginYahooCom();
+ // connectLocalSSL(host, port);
+ } else {
+ connectLocalTLS(host, port);
+ }
+ } else {
+ testSocket();
+ }
+ }
+
+ public function connectLoginYahooCom():void {
+ trace("Connecting test socket");
+ var s:Socket = new Socket("esx.bluebearllc.net", 903);
+
+ var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT,
+ null,
+ null,
+ null,
+ null,
+ null,
+ SSLSecurityParameters.PROTOCOL_VERSION);
+
+ var client:TLSEngine = new TLSEngine(clientConfig, s, s);
+ // hook some events.
+ s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
+ client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
+ client.start();
+
+ }
+ public function connectLocalTLS(host:String, port:int):void {
+ var s:Socket = new Socket(host, port);
+
+ var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT);
+
+ var client:TLSEngine = new TLSEngine(clientConfig, s, s);
+ // hook some events.
+ s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
+ client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
+
+ client.start();
+
+ }
+ public function connectLocalSSL(host:String, port:int):void {
+ var s:Socket = new Socket(host, port);
+
+ var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT,
+ null,
+ null,
+ null,
+ null,
+ null,
+ SSLSecurityParameters.PROTOCOL_VERSION);
+
+ var client:TLSEngine = new TLSEngine(clientConfig, s, s);
+ // hook some events.
+ s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
+ client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
+
+ client.start();
+ }
+
+ public function loopback():void {
+
+ var server_write:ByteArray = new ByteArray;
+ var client_write:ByteArray = new ByteArray;
+ var server_write_cursor:uint = 0;
+ var client_write_cursor:uint = 0;
+
+ var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT, null, null, null, null, null, SSLSecurityParameters.PROTOCOL_VERSION);
+ var serverConfig:TLSConfig = new TLSConfig(TLSEngine.SERVER, null, null, null, null, null, SSLSecurityParameters.PROTOCOL_VERSION);
+
+
+ var cert:ByteArray = new myCert;
+ var key:ByteArray = new myKey;
+ serverConfig.setPEMCertificate(cert.readUTFBytes(cert.length), key.readUTFBytes(key.length));
+ // tmp, for debugging. currently useless
+ cert.position = 0;
+ key.position = 0;
+ clientConfig.setPEMCertificate(cert.readUTFBytes(cert.length), key.readUTFBytes(key.length));
+ // put the server cert in the client's trusted store, to keep things happy.
+ clientConfig.CAStore = new X509CertificateCollection;
+ cert.position = 0;
+ var x509:X509Certificate = new X509Certificate(PEM.readCertIntoArray(cert.readUTFBytes(cert.length)));
+ clientConfig.CAStore.addCertificate(x509);
+
+
+ var server:TLSEngine = new TLSEngine(serverConfig, client_write, server_write);
+ var client:TLSEngine = new TLSEngine(clientConfig, server_write, client_write);
+
+ server.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*=null):void {
+ trace("server wrote something!");
+ trace(Hex.fromArray(server_write));
+ var l:uint = server_write.position;
+ server_write.position = server_write_cursor;
+ client.dataAvailable(e);
+ server_write.position = l;
+ server_write_cursor = l;
+ });
+ client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*=null):void {
+ trace("client wrote something!");
+ trace(Hex.fromArray(client_write));
+ var l:uint = client_write.position;
+ client_write.position = client_write_cursor;
+ server.dataAvailable(e);
+ client_write.position = l;
+ client_write_cursor = l;
+ });
+
+ server.start();
+ client.start();
+ }
+
+ public function testSocket():void {
+ var hosts:Array = [
+ "bugs.adobe.com", // apache
+ "login.yahoo.com", // apache, bigger response
+ "login.live.com", // IIS-6, chain of 3 certs
+ "banking.wellsfargo.com", // custom, sends its CA cert along for the ride.
+ "www.bankofamerica.com" // sun-one, chain of 3 certs
+ ];
+ var i:int =0;
+ (function next():void {
+ testHost(hosts[i++], next);
+ })();
+ }
+
+ private function testHost(host:String, next:Function):void {
+ if (host==null) return;
+ var t1:int = getTimer();
+
+ var host:String = host;
+ var t:TLSSocket = new TLSSocket;
+ t.connect(host, 4433);
+ t.writeUTFBytes("GET / HTTP/1.0\nHost: "+host+"\n\n");
+ t.addEventListener(Event.CLOSE, function(e:*):void {
+ var s:String = t.readUTFBytes(t.bytesAvailable);
+ trace("Response from "+host+": "+s.length+" characters");
+ var bytes:ByteArray = new ByteArray();
+ t.readBytes(bytes, 0, t.bytesAvailable);
+ trace(Hex.fromArray(bytes));
+ trace("Time used = "+(getTimer()-t1)+"ms");
+ next();
+ });
+ }
+ }
+}
--- /dev/null
+package com.hurlant.math\r
+{\r
+ use namespace bi_internal;\r
+\r
+ internal class BarrettReduction implements IReduction\r
+ {\r
+ private var m:BigInteger;\r
+ private var r2:BigInteger;\r
+ private var q3:BigInteger;\r
+ private var mu:BigInteger;\r
+ \r
+ public function BarrettReduction(m:BigInteger) {\r
+ // setup Barrett\r
+ r2 = new BigInteger;\r
+ q3 = new BigInteger;\r
+ BigInteger.ONE.dlShiftTo(2*m.t, r2);\r
+ mu = r2.divide(m);\r
+ this.m = m;\r
+ }\r
+ \r
+ public function revert(x:BigInteger):BigInteger\r
+ {\r
+ return x;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param x\r
+ * @param y\r
+ * @param r = x*y mod m; x != r\r
+ * \r
+ */\r
+ public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void\r
+ {\r
+ x.multiplyTo(y, r);\r
+ reduce(r);\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param x\r
+ * @param r = x^2 mod m; x != r\r
+ * \r
+ */\r
+ public function sqrTo(x:BigInteger, r:BigInteger):void\r
+ {\r
+ x.squareTo(r);\r
+ reduce(r);\r
+ }\r
+ \r
+ public function convert(x:BigInteger):BigInteger\r
+ {\r
+ if (x.s<0 || x.t>2*m.t) {\r
+ return x.mod(m);\r
+ } else if (x.compareTo(m)<0) {\r
+ return x;\r
+ } else {\r
+ var r:BigInteger = new BigInteger;\r
+ x.copyTo(r);\r
+ reduce(r);\r
+ return r;\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param x = x mod m (HAC 14.42)\r
+ * \r
+ */\r
+ public function reduce(lx:BigInteger):void\r
+ {\r
+ var x:BigInteger = lx as BigInteger;\r
+ x.drShiftTo(m.t-1,r2);\r
+ if (x.t>m.t+1) {\r
+ x.t = m.t+1;\r
+ x.clamp();\r
+ }\r
+ mu.multiplyUpperTo(r2, m.t+1, q3);\r
+ m.multiplyLowerTo(q3, m.t+1, r2);\r
+ while (x.compareTo(r2)<0) {\r
+ x.dAddOffset(1, m.t+1);\r
+ }\r
+ x.subTo(r2,x);\r
+ while (x.compareTo(m)>=0) {\r
+ x.subTo(m,x);\r
+ }\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * BigInteger\r
+ * \r
+ * An ActionScript 3 implementation of BigInteger (light version)\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * Derived from:\r
+ * The jsbn library, Copyright (c) 2003-2005 Tom Wu\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.math\r
+{\r
+\r
+ import com.hurlant.crypto.prng.Random;\r
+ import com.hurlant.util.Hex;\r
+ import com.hurlant.util.Memory;\r
+ \r
+ import flash.utils.ByteArray;\r
+ use namespace bi_internal;\r
+\r
+ public class BigInteger\r
+ {\r
+ public static const DB:int = 30; // number of significant bits per chunk\r
+ public static const DV:int = (1<<DB);\r
+ public static const DM:int = (DV-1); // Max value in a chunk\r
+ \r
+ public static const BI_FP:int = 52;\r
+ public static const FV:Number = Math.pow(2, BI_FP);\r
+ public static const F1:int = BI_FP - DB;\r
+ public static const F2:int = 2*DB - BI_FP;\r
+ \r
+ public static const ZERO:BigInteger = nbv(0);\r
+ public static const ONE:BigInteger = nbv(1);\r
+ \r
+ /*bi_internal */public var t:int; // number of chunks.\r
+ bi_internal var s:int; // sign\r
+ bi_internal var a:Array; // chunks\r
+ \r
+ /**\r
+ * \r
+ * @param value\r
+ * @param radix WARNING: If value is ByteArray, this holds the number of bytes to use.\r
+ * @param unsigned\r
+ * \r
+ */\r
+ public function BigInteger(value:* = null, radix:int = 0, unsigned:Boolean = false) {\r
+ a = new Array;\r
+ if (value is String) {\r
+ if (radix&&radix!=16) throw new Error("BigInteger construction with radix!=16 is not supported.");\r
+ value = Hex.toArray(value);\r
+ radix=0;\r
+ }\r
+ if (value is ByteArray) {\r
+ var array:ByteArray = value as ByteArray;\r
+ var length:int = radix || (array.length - array.position);\r
+ fromArray(array, length, unsigned);\r
+ }\r
+ }\r
+ public function dispose():void {\r
+ var r:Random = new Random;\r
+ for (var i:uint=0;i<a.length;i++) {\r
+ a[i] = r.nextByte();\r
+ delete a[i];\r
+ }\r
+ a=null;\r
+ t=0;\r
+ s=0;\r
+ Memory.gc();\r
+ }\r
+ \r
+ public function toString(radix:Number=16):String {\r
+ if (s<0) return "-"+negate().toString(radix);\r
+ var k:int;\r
+ switch (radix) {\r
+ case 2: k=1; break;\r
+ case 4: k=2; break;\r
+ case 8: k=3; break;\r
+ case 16: k=4; break;\r
+ case 32: k=5; break;\r
+ default:\r
+// return toRadix(radix);\r
+ }\r
+ var km:int = (1<<k)-1;\r
+ var d:int = 0;\r
+ var m:Boolean = false;\r
+ var r:String = "";\r
+ var i:int = t;\r
+ var p:int = DB-(i*DB)%k;\r
+ if (i-->0) {\r
+ if (p<DB && (d=a[i]>>p)>0) {\r
+ m = true;\r
+ r = d.toString(36);\r
+ }\r
+ while (i >= 0) {\r
+ if (p<k) {\r
+ d = (a[i]&((1<<p)-1))<<(k-p);\r
+ d|= a[--i]>>(p+=DB-k);\r
+ } else {\r
+ d = (a[i]>>(p-=k))&km;\r
+ if (p<=0) {\r
+ p += DB;\r
+ --i;\r
+ }\r
+ }\r
+ if (d>0) {\r
+ m = true;\r
+ }\r
+ if (m) {\r
+ r += d.toString(36);\r
+ }\r
+ }\r
+ }\r
+ return m?r:"0";\r
+ }\r
+ public function toArray(array:ByteArray):uint {\r
+ const k:int = 8;\r
+ const km:int = (1<<8)-1;\r
+ var d:int = 0;\r
+ var i:int = t;\r
+ var p:int = DB-(i*DB)%k;\r
+ var m:Boolean = false;\r
+ var c:int = 0;\r
+ if (i-->0) {\r
+ if (p<DB && (d=a[i]>>p)>0) {\r
+ m = true;\r
+ array.writeByte(d);\r
+ c++;\r
+ }\r
+ while (i >= 0) {\r
+ if (p<k) {\r
+ d = (a[i]&((1<<p)-1))<<(k-p);\r
+ d|= a[--i]>>(p+=DB-k);\r
+ } else {\r
+ d = (a[i]>>(p-=k))&km;\r
+ if (p<=0) {\r
+ p += DB;\r
+ --i;\r
+ }\r
+ }\r
+ if (d>0) {\r
+ m = true;\r
+ }\r
+ if (m) {\r
+ array.writeByte(d);\r
+ c++;\r
+ }\r
+ }\r
+ }\r
+ return c;\r
+ }\r
+ /**\r
+ * best-effort attempt to fit into a Number.\r
+ * precision can be lost if it just can't fit.\r
+ */\r
+ public function valueOf():Number {\r
+ if (s==-1) {\r
+ return -negate().valueOf();\r
+ }\r
+ var coef:Number = 1;\r
+ var value:Number = 0;\r
+ for (var i:uint=0;i<t;i++) {\r
+ value += a[i]*coef;\r
+ coef *= DV;\r
+ }\r
+ return value;\r
+ }\r
+ /**\r
+ * -this\r
+ */\r
+ public function negate():BigInteger {\r
+ var r:BigInteger = nbi();\r
+ ZERO.subTo(this, r);\r
+ return r;\r
+ }\r
+ /**\r
+ * |this|\r
+ */\r
+ public function abs():BigInteger {\r
+ return (s<0)?negate():this;\r
+ }\r
+ /**\r
+ * return + if this > v, - if this < v, 0 if equal\r
+ */\r
+ public function compareTo(v:BigInteger):int {\r
+ var r:int = s - v.s;\r
+ if (r!=0) {\r
+ return r;\r
+ }\r
+ var i:int = t;\r
+ r = i-v.t;\r
+ if (r!=0) {\r
+ return r;\r
+ }\r
+ while (--i >=0) {\r
+ r=a[i]-v.a[i];\r
+ if (r != 0) return r;\r
+ }\r
+ return 0;\r
+ }\r
+ /**\r
+ * returns bit length of the integer x\r
+ */\r
+ bi_internal function nbits(x:int):int {\r
+ var r:int = 1;\r
+ var t:int;\r
+ if ((t=x>>>16) != 0) { x = t; r += 16; }\r
+ if ((t=x>>8) != 0) { x = t; r += 8; }\r
+ if ((t=x>>4) != 0) { x = t; r += 4; }\r
+ if ((t=x>>2) != 0) { x = t; r += 2; }\r
+ if ((t=x>>1) != 0) { x = t; r += 1; }\r
+ return r;\r
+ }\r
+ /**\r
+ * returns the number of bits in this\r
+ */\r
+ public function bitLength():int {\r
+ if (t<=0) return 0;\r
+ return DB*(t-1)+nbits(a[t-1]^(s&DM));\r
+ }\r
+ /**\r
+ * \r
+ * @param v\r
+ * @return this % v\r
+ * \r
+ */\r
+ public function mod(v:BigInteger):BigInteger {\r
+ var r:BigInteger = nbi();\r
+ abs().divRemTo(v,null,r);\r
+ if (s<0 && r.compareTo(ZERO)>0) {\r
+ v.subTo(r,r);\r
+ }\r
+ return r;\r
+ }\r
+ /**\r
+ * this^e % m, 0 <= e < 2^32\r
+ */\r
+ public function modPowInt(e:int, m:BigInteger):BigInteger {\r
+ var z:IReduction;\r
+ if (e<256 || m.isEven()) {\r
+ z = new ClassicReduction(m);\r
+ } else {\r
+ z = new MontgomeryReduction(m);\r
+ }\r
+ return exp(e, z);\r
+ }\r
+\r
+ /**\r
+ * copy this to r\r
+ */\r
+ bi_internal function copyTo(r:BigInteger):void {\r
+ for (var i:int = t-1; i>=0; --i) {\r
+ r.a[i] = a[i];\r
+ }\r
+ r.t = t;\r
+ r.s = s;\r
+ }\r
+ /**\r
+ * set from integer value "value", -DV <= value < DV\r
+ */\r
+ bi_internal function fromInt(value:int):void {\r
+ t = 1;\r
+ s = (value<0)?-1:0;\r
+ if (value>0) {\r
+ a[0] = value;\r
+ } else if (value<-1) {\r
+ a[0] = value+DV;\r
+ } else {\r
+ t = 0;\r
+ }\r
+ }\r
+ /**\r
+ * set from ByteArray and length,\r
+ * starting a current position\r
+ * If length goes beyond the array, pad with zeroes.\r
+ */\r
+ bi_internal function fromArray(value:ByteArray, length:int, unsigned:Boolean = false):void {\r
+ var p:int = value.position;\r
+ var i:int = p+length;\r
+ var sh:int = 0;\r
+ const k:int = 8;\r
+ t = 0;\r
+ s = 0;\r
+ while (--i >= p) {\r
+ var x:int = i<value.length?value[i]:0;\r
+ if (sh == 0) {\r
+ a[t++] = x;\r
+ } else if (sh+k > DB) {\r
+ a[t-1] |= (x&((1<<(DB-sh))-1))<<sh;\r
+ a[t++] = x>>(DB-sh);\r
+ } else {\r
+ a[t-1] |= x<<sh;\r
+ }\r
+ sh += k;\r
+ if (sh >= DB) sh -= DB;\r
+ }\r
+ if (!unsigned && (value[0]&0x80)==0x80) {\r
+ s = -1;\r
+ if (sh > 0) {\r
+ a[t-1] |= ((1<<(DB-sh))-1)<<sh;\r
+ }\r
+ }\r
+ clamp();\r
+ value.position = Math.min(p+length,value.length);\r
+ }\r
+ /**\r
+ * clamp off excess high words\r
+ */\r
+ bi_internal function clamp():void {\r
+ var c:int = s&DM;\r
+ while (t>0 && a[t-1]==c) {\r
+ --t;\r
+ }\r
+ }\r
+ /**\r
+ * r = this << n*DB\r
+ */\r
+ bi_internal function dlShiftTo(n:int, r:BigInteger):void {\r
+ var i:int;\r
+ for (i=t-1; i>=0; --i) {\r
+ r.a[i+n] = a[i];\r
+ }\r
+ for (i=n-1; i>=0; --i) {\r
+ r.a[i] = 0;\r
+ }\r
+ r.t = t+n;\r
+ r.s = s;\r
+ }\r
+ /**\r
+ * r = this >> n*DB\r
+ */\r
+ bi_internal function drShiftTo(n:int, r:BigInteger):void {\r
+ var i:int;\r
+ for (i=n; i<t; ++i) {\r
+ r.a[i-n] = a[i];\r
+ }\r
+ r.t = Math.max(t-n,0);\r
+ r.s = s;\r
+ }\r
+ /**\r
+ * r = this << n\r
+ */\r
+ bi_internal function lShiftTo(n:int, r:BigInteger):void {\r
+ var bs:int = n%DB;\r
+ var cbs:int = DB-bs;\r
+ var bm:int = (1<<cbs)-1;\r
+ var ds:int = n/DB;\r
+ var c:int = (s<<bs)&DM;\r
+ var i:int;\r
+ for (i=t-1; i>=0; --i) {\r
+ r.a[i+ds+1] = (a[i]>>cbs)|c;\r
+ c = (a[i]&bm)<<bs;\r
+ }\r
+ for (i=ds-1; i>=0; --i) {\r
+ r.a[i] = 0;\r
+ }\r
+ r.a[ds] = c;\r
+ r.t = t+ds+1;\r
+ r.s = s;\r
+ r.clamp();\r
+ }\r
+ /**\r
+ * r = this >> n\r
+ */\r
+ bi_internal function rShiftTo(n:int, r:BigInteger):void {\r
+ r.s = s;\r
+ var ds:int = n/DB;\r
+ if (ds >= t) {\r
+ r.t = 0;\r
+ return;\r
+ }\r
+ var bs:int = n%DB;\r
+ var cbs:int = DB-bs;\r
+ var bm:int = (1<<bs)-1;\r
+ r.a[0] = a[ds]>>bs;\r
+ var i:int;\r
+ for (i=ds+1; i<t; ++i) {\r
+ r.a[i-ds-1] |= (a[i]&bm)<<cbs;\r
+ r.a[i-ds] = a[i]>>bs;\r
+ }\r
+ if (bs>0) {\r
+ r.a[t-ds-1] |= (s&bm)<<cbs;\r
+ }\r
+ r.t = t-ds;\r
+ r.clamp();\r
+ }\r
+ /**\r
+ * r = this - v\r
+ */\r
+ bi_internal function subTo(v:BigInteger, r:BigInteger):void {\r
+ var i:int = 0;\r
+ var c:int = 0;\r
+ var m:int = Math.min(v.t, t);\r
+ while (i<m) {\r
+ c += a[i] - v.a[i];\r
+ r.a[i++] = c & DM;\r
+ c >>= DB;\r
+ }\r
+ if (v.t < t) {\r
+ c -= v.s;\r
+ while (i< t) {\r
+ c+= a[i];\r
+ r.a[i++] = c&DM;\r
+ c >>= DB;\r
+ }\r
+ c += s;\r
+ } else {\r
+ c += s;\r
+ while (i < v.t) {\r
+ c -= v.a[i];\r
+ r.a[i++] = c&DM;\r
+ c >>= DB;\r
+ }\r
+ c -= v.s;\r
+ }\r
+ r.s = (c<0)?-1:0;\r
+ if (c<-1) {\r
+ r.a[i++] = DV+c;\r
+ } else if (c>0) {\r
+ r.a[i++] = c;\r
+ }\r
+ r.t = i;\r
+ r.clamp();\r
+ }\r
+ /**\r
+ * am: Compute w_j += (x*this_i), propagates carries,\r
+ * c is initial carry, returns final carry.\r
+ * c < 3*dvalue, x < 2*dvalue, this_i < dvalue\r
+ */\r
+ bi_internal function am(i:int,x:int,w:BigInteger,j:int,c:int,n:int):int {\r
+ var xl:int = x&0x7fff;\r
+ var xh:int = x>>15;\r
+ while(--n >= 0) {\r
+ var l:int = a[i]&0x7fff;\r
+ var h:int = a[i++]>>15;\r
+ var m:int = xh*l + h*xl;\r
+ l = xl*l + ((m&0x7fff)<<15)+w.a[j]+(c&0x3fffffff);\r
+ c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);\r
+ w.a[j++] = l&0x3fffffff;\r
+ }\r
+ return c;\r
+ }\r
+ /**\r
+ * r = this * v, r != this,a (HAC 14.12)\r
+ * "this" should be the larger one if appropriate\r
+ */\r
+ bi_internal function multiplyTo(v:BigInteger, r:BigInteger):void {\r
+ var x:BigInteger = abs();\r
+ var y:BigInteger = v.abs();\r
+ var i:int = x.t;\r
+ r.t = i+y.t;\r
+ while (--i >= 0) {\r
+ r.a[i] = 0;\r
+ }\r
+ for (i=0; i<y.t; ++i) {\r
+ r.a[i+x.t] = x.am(0, y.a[i], r, i, 0, x.t);\r
+ }\r
+ r.s = 0;\r
+ r.clamp();\r
+ if (s!=v.s) {\r
+ ZERO.subTo(r, r);\r
+ }\r
+ }\r
+ /**\r
+ * r = this^2, r != this (HAC 14.16)\r
+ */\r
+ bi_internal function squareTo(r:BigInteger):void {\r
+ var x:BigInteger = abs();\r
+ var i:int = r.t = 2*x.t;\r
+ while (--i>=0) r.a[i] = 0;\r
+ for (i=0; i<x.t-1; ++i) {\r
+ var c:int = x.am(i, x.a[i], r, 2*i, 0, 1);\r
+ if ((r.a[i+x.t] += x.am(i+1, 2*x.a[i], r, 2*i+1, c, x.t-i-1)) >= DV) {\r
+ r.a[i+x.t] -= DV;\r
+ r.a[i+x.t+1] = 1;\r
+ }\r
+ }\r
+ if (r.t>0) {\r
+ r.a[r.t-1] += x.am(i, x.a[i], r, 2*i, 0, 1);\r
+ }\r
+ r.s = 0;\r
+ r.clamp();\r
+ }\r
+ /**\r
+ * divide this by m, quotient and remainder to q, r (HAC 14.20)\r
+ * r != q, this != m. q or r may be null.\r
+ */\r
+ bi_internal function divRemTo(m:BigInteger, q:BigInteger = null, r:BigInteger = null):void {\r
+ var pm:BigInteger = m.abs();\r
+ if (pm.t <= 0) return;\r
+ var pt:BigInteger = abs();\r
+ if (pt.t < pm.t) {\r
+ if (q!=null) q.fromInt(0);\r
+ if (r!=null) copyTo(r);\r
+ return;\r
+ }\r
+ if (r==null) r = nbi();\r
+ var y:BigInteger = nbi();\r
+ var ts:int = s;\r
+ var ms:int = m.s;\r
+ var nsh:int = DB-nbits(pm.a[pm.t-1]); // normalize modulus\r
+ if (nsh>0) {\r
+ pm.lShiftTo(nsh, y);\r
+ pt.lShiftTo(nsh, r);\r
+ } else {\r
+ pm.copyTo(y);\r
+ pt.copyTo(r);\r
+ }\r
+ var ys:int = y.t;\r
+ var y0:int = y.a[ys-1];\r
+ if (y0==0) return;\r
+ var yt:Number = y0*(1<<F1)+((ys>1)?y.a[ys-2]>>F2:0);\r
+ var d1:Number = FV/yt;\r
+ var d2:Number = (1<<F1)/yt;\r
+ var e:Number = 1<<F2;\r
+ var i:int = r.t;\r
+ var j:int = i-ys;\r
+ var t:BigInteger = (q==null)?nbi():q;\r
+ y.dlShiftTo(j,t);\r
+ if (r.compareTo(t)>=0) {\r
+ r.a[r.t++] = 1;\r
+ r.subTo(t,r);\r
+ }\r
+ ONE.dlShiftTo(ys,t);\r
+ t.subTo(y,y); // "negative" y so we can replace sub with am later.\r
+ while(y.t<ys) y.(y.t++, 0);\r
+ while(--j >= 0) {\r
+ // Estimate quotient digit\r
+ var qd:int = (r.a[--i]==y0)?DM:Number(r.a[i])*d1+(Number(r.a[i-1])+e)*d2;\r
+ if ((r.a[i]+= y.am(0, qd, r, j, 0, ys))<qd) { // Try it out\r
+ y.dlShiftTo(j, t);\r
+ r.subTo(t,r);\r
+ while (r.a[i]<--qd) {\r
+ r.subTo(t,r);\r
+ }\r
+ }\r
+ }\r
+ if (q!=null) {\r
+ r.drShiftTo(ys,q);\r
+ if (ts!=ms) {\r
+ ZERO.subTo(q,q);\r
+ }\r
+ }\r
+ r.t = ys;\r
+ r.clamp();\r
+ if (nsh>0) {\r
+ r.rShiftTo(nsh, r); // Denormalize remainder\r
+ }\r
+ if (ts<0) {\r
+ ZERO.subTo(r,r);\r
+ }\r
+ }\r
+ /**\r
+ * return "-1/this % 2^DB"; useful for Mont. reduction\r
+ * justification:\r
+ * xy == 1 (mod n)\r
+ * xy = 1+km\r
+ * xy(2-xy) = (1+km)(1-km)\r
+ * x[y(2-xy)] = 1-k^2.m^2\r
+ * x[y(2-xy)] == 1 (mod m^2)\r
+ * if y is 1/x mod m, then y(2-xy) is 1/x mod m^2\r
+ * should reduce x and y(2-xy) by m^2 at each step to keep size bounded\r
+ * [XXX unit test the living shit out of this.]\r
+ */\r
+ bi_internal function invDigit():int {\r
+ if (t<1) return 0;\r
+ var x:int = a[0];\r
+ if ((x&1)==0) return 0;\r
+ var y:int = x&3; // y == 1/x mod 2^2\r
+ y = (y*(2-(x&0xf )*y)) &0xf; // y == 1/x mod 2^4\r
+ y = (y*(2-(x&0xff)*y)) &0xff; // y == 1/x mod 2^8\r
+ y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16\r
+ // last step - calculate inverse mod DV directly;\r
+ // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints\r
+ // XXX 48 bit ints? Whaaaa? is there an implicit float conversion in here?\r
+ y = (y*(2-x*y%DV))%DV; // y == 1/x mod 2^dbits\r
+ // we really want the negative inverse, and -DV < y < DV\r
+ return (y>0)?DV-y:-y;\r
+ }\r
+ /**\r
+ * true iff this is even\r
+ */\r
+ bi_internal function isEven():Boolean {\r
+ return ((t>0)?(a[0]&1):s) == 0;\r
+ }\r
+ /**\r
+ * this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)\r
+ */\r
+ bi_internal function exp(e:int, z:IReduction):BigInteger {\r
+ if (e > 0xffffffff || e < 1) return ONE;\r
+ var r:BigInteger = nbi();\r
+ var r2:BigInteger = nbi();\r
+ var g:BigInteger = z.convert(this);\r
+ var i:int = nbits(e)-1;\r
+ g.copyTo(r);\r
+ while(--i>=0) {\r
+ z.sqrTo(r, r2);\r
+ if ((e&(1<<i))>0) {\r
+ z.mulTo(r2,g,r);\r
+ } else {\r
+ var t:BigInteger = r;\r
+ r = r2;\r
+ r2 = t;\r
+ }\r
+ \r
+ }\r
+ return z.revert(r);\r
+ }\r
+ bi_internal function intAt(str:String, index:int):int {\r
+ return parseInt(str.charAt(index), 36);\r
+ }\r
+\r
+\r
+ protected function nbi():* {\r
+ return new BigInteger;\r
+ }\r
+ /**\r
+ * return bigint initialized to value\r
+ */\r
+ public static function nbv(value:int):BigInteger {\r
+ var bn:BigInteger = new BigInteger;\r
+ bn.fromInt(value);\r
+ return bn;\r
+ }\r
+\r
+\r
+ // Functions above are sufficient for RSA encryption.\r
+ // The stuff below is useful for decryption and key generation\r
+\r
+ public static const lowprimes:Array = [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];\r
+ public static const lplim:int = (1<<26)/lowprimes[lowprimes.length-1];\r
+\r
+\r
+ public function clone():BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ this.copyTo(r);\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @return value as integer\r
+ * \r
+ */\r
+ public function intValue():int {\r
+ if (s<0) {\r
+ if (t==1) {\r
+ return a[0]-DV;\r
+ } else if (t==0) {\r
+ return -1;\r
+ }\r
+ } else if (t==1) {\r
+ return a[0];\r
+ } else if (t==0) {\r
+ return 0;\r
+ }\r
+ // assumes 16 < DB < 32\r
+ return ((a[1]&((1<<(32-DB))-1))<<DB)|a[0];\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @return value as byte\r
+ * \r
+ */\r
+ public function byteValue():int {\r
+ return (t==0)?s:(a[0]<<24)>>24;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @return value as short (assumes DB>=16)\r
+ * \r
+ */\r
+ public function shortValue():int {\r
+ return (t==0)?s:(a[0]<<16)>>16;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param r\r
+ * @return x s.t. r^x < DV\r
+ * \r
+ */\r
+ protected function chunkSize(r:Number):int {\r
+ return Math.floor(Math.LN2*DB/Math.log(r));\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @return 0 if this ==0, 1 if this >0\r
+ * \r
+ */\r
+ public function sigNum():int {\r
+ if (s<0) {\r
+ return -1;\r
+ } else if (t<=0 || (t==1 && a[0]<=0)) {\r
+ return 0;\r
+ } else{\r
+ return 1;\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param b: radix to use\r
+ * @return a string representing the integer converted to the radix.\r
+ * \r
+ */\r
+ protected function toRadix(b:uint=10):String {\r
+ if (sigNum()==0 || b<2 || b>32) return "0";\r
+ var cs:int = chunkSize(b);\r
+ var a:Number = Math.pow(b, cs);\r
+ var d:BigInteger = nbv(a);\r
+ var y:BigInteger = nbi();\r
+ var z:BigInteger = nbi();\r
+ var r:String = "";\r
+ divRemTo(d, y, z);\r
+ while (y.sigNum()>0) {\r
+ r = (a+z.intValue()).toString(b).substr(1) + r;\r
+ y.divRemTo(d,y,z);\r
+ }\r
+ return z.intValue().toString(b) + r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param s a string to convert from using radix.\r
+ * @param b a radix\r
+ * \r
+ */\r
+ protected function fromRadix(s:String, b:int = 10):void {\r
+ fromInt(0);\r
+ var cs:int = chunkSize(b);\r
+ var d:Number = Math.pow(b, cs);\r
+ var mi:Boolean = false;\r
+ var j:int = 0;\r
+ var w:int = 0;\r
+ for (var i:int=0;i<s.length;++i) {\r
+ var x:int = intAt(s, i);\r
+ if (x<0) {\r
+ if (s.charAt(i) == "-" && sigNum() == 0) {\r
+ mi = true;\r
+ }\r
+ continue;\r
+ }\r
+ w = b*w+x;\r
+ if (++j >= cs) {\r
+ dMultiply(d);\r
+ dAddOffset(w,0);\r
+ j=0;\r
+ w=0;\r
+ }\r
+ }\r
+ if (j>0) {\r
+ dMultiply(Math.pow(b,j));\r
+ dAddOffset(w,0);\r
+ }\r
+ if (mi) {\r
+ BigInteger.ZERO.subTo(this, this);\r
+ }\r
+ }\r
+ \r
+ // XXX function fromNumber not written yet.\r
+ \r
+ /**\r
+ * \r
+ * @return a byte array.\r
+ * \r
+ */\r
+ public function toByteArray():ByteArray {\r
+ var i:int = t;\r
+ var r:ByteArray = new ByteArray;\r
+ r[0] = s;\r
+ var p:int = DB-(i*DB)%8;\r
+ var d:int;\r
+ var k:int=0;\r
+ if (i-->0) {\r
+ if (p<DB && (d=a[i]>>p)!=(s&DM)>>p) {\r
+ r[k++] = d|(s<<(DB-p));\r
+ }\r
+ while (i>=0) {\r
+ if(p<8) {\r
+ d = (a[i]&((1<<p)-1))<<(8-p);\r
+ d|= a[--i]>>(p+=DB-8);\r
+ } else {\r
+ d = (a[i]>>(p-=8))&0xff;\r
+ if (p<=0) {\r
+ p += DB;\r
+ --i;\r
+ }\r
+ }\r
+ if ((d&0x80)!=0) d|=-256;\r
+ if (k==0 && (s&0x80)!=(d&0x80)) ++k;\r
+ if (k>0 || d!=s) r[k++] = d;\r
+ } \r
+ }\r
+ return r;\r
+ }\r
+\r
+ public function equals(a:BigInteger):Boolean {\r
+ return compareTo(a)==0;\r
+ }\r
+ public function min(a:BigInteger):BigInteger {\r
+ return (compareTo(a)<0)?this:a;\r
+ }\r
+ public function max(a:BigInteger):BigInteger {\r
+ return (compareTo(a)>0)?this:a;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a a BigInteger to perform the operation with\r
+ * @param op a Function implementing the operation\r
+ * @param r a BigInteger to store the result of the operation\r
+ * \r
+ */\r
+ protected function bitwiseTo(a:BigInteger, op:Function, r:BigInteger):void {\r
+ var i:int;\r
+ var f:int;\r
+ var m:int = Math.min(a.t, t);\r
+ for (i=0; i<m; ++i) {\r
+ r.a[i] = op(this.a[i],a.a[i]);\r
+ }\r
+ if (a.t<t) {\r
+ f = a.s&DM;\r
+ for (i=m;i<t;++i) {\r
+ r.a[i] = op(this.a[i],f);\r
+ }\r
+ r.t = t;\r
+ } else {\r
+ f = s&DM;\r
+ for (i=m;i<a.t;++i) {\r
+ r.a[i] = op(f,a.a[i]);\r
+ }\r
+ r.t = a.t;\r
+ }\r
+ r.s = op(s, a.s);\r
+ r.clamp();\r
+ }\r
+ \r
+ private function op_and(x:int, y:int):int {return x&y;}\r
+ public function and(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ bitwiseTo(a, op_and, r);\r
+ return r;\r
+ }\r
+ \r
+ private function op_or(x:int, y:int):int {return x|y;}\r
+ public function or(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ bitwiseTo(a, op_or, r);\r
+ return r;\r
+ }\r
+ \r
+ private function op_xor(x:int, y:int):int {return x^y;}\r
+ public function xor(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ bitwiseTo(a, op_xor, r);\r
+ return r;\r
+ }\r
+ \r
+ private function op_andnot(x:int, y:int):int { return x&~y;}\r
+ public function andNot(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ bitwiseTo(a, op_andnot, r);\r
+ return r;\r
+ }\r
+ \r
+ public function not():BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ for (var i:int=0;i<t;++i) {\r
+ r[i] = DM&~a[i];\r
+ }\r
+ r.t = t;\r
+ r.s = ~s;\r
+ return r;\r
+ }\r
+ \r
+ public function shiftLeft(n:int):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ if (n<0) {\r
+ rShiftTo(-n, r);\r
+ } else {\r
+ lShiftTo(n, r);\r
+ }\r
+ return r;\r
+ }\r
+ public function shiftRight(n:int):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ if (n<0) {\r
+ lShiftTo(-n, r);\r
+ } else {\r
+ rShiftTo(n, r);\r
+ }\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param x\r
+ * @return index of lowet 1-bit in x, x < 2^31\r
+ * \r
+ */\r
+ private function lbit(x:int):int {\r
+ if (x==0) return -1;\r
+ var r:int = 0;\r
+ if ((x&0xffff)==0) { x>>= 16; r += 16; }\r
+ if ((x&0xff) == 0) { x>>= 8; r += 8; }\r
+ if ((x&0xf) == 0) { x>>= 4; r += 4; }\r
+ if ((x&0x3) == 0) { x>>= 2; r += 2; }\r
+ if ((x&0x1) == 0) ++r;\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @return index of lowest 1-bit (or -1 if none)\r
+ * \r
+ */\r
+ public function getLowestSetBit():int {\r
+ for (var i:int=0;i<t;++i) {\r
+ if (a[i]!=0) return i*DB+lbit(a[i]);\r
+ }\r
+ if (s<0) return t*DB;\r
+ return -1;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param x\r
+ * @return number of 1 bits in x\r
+ * \r
+ */\r
+ private function cbit(x:int):int {\r
+ var r:uint =0;\r
+ while (x!=0) { x &= x-1; ++r }\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @return number of set bits\r
+ * \r
+ */\r
+ public function bitCount():int {\r
+ var r:int=0;\r
+ var x:int = s&DM;\r
+ for (var i:int=0;i<t;++i) {\r
+ r += cbit(a[i]^x);\r
+ }\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param n\r
+ * @return true iff nth bit is set\r
+ * \r
+ */\r
+ public function testBit(n:int):Boolean {\r
+ var j:int = Math.floor(n/DB);\r
+ if (j>=t) {\r
+ return s!=0;\r
+ }\r
+ return ((a[j]&(1<<(n%DB)))!=0);\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param n\r
+ * @param op\r
+ * @return this op (1<<n)\r
+ * \r
+ */\r
+ protected function changeBit(n:int,op:Function):BigInteger {\r
+ var r:BigInteger = BigInteger.ONE.shiftLeft(n);\r
+ bitwiseTo(r, op, r);\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param n\r
+ * @return this | (1<<n)\r
+ * \r
+ */\r
+ public function setBit(n:int):BigInteger { return changeBit(n, op_or); }\r
+\r
+ /**\r
+ * \r
+ * @param n\r
+ * @return this & ~(1<<n)\r
+ * \r
+ */\r
+ public function clearBit(n:int):BigInteger { return changeBit(n, op_andnot); }\r
+\r
+ /**\r
+ * \r
+ * @param n\r
+ * @return this ^ (1<<n)\r
+ * \r
+ */\r
+ public function flipBit(n:int):BigInteger { return changeBit(n, op_xor); }\r
+\r
+ /**\r
+ * \r
+ * @param a\r
+ * @param r = this + a\r
+ * \r
+ */\r
+ protected function addTo(a:BigInteger, r:BigInteger):void {\r
+ var i:int = 0;\r
+ var c:int = 0;\r
+ var m:int = Math.min(a.t, t);\r
+ while (i<m) {\r
+ c += this.a[i] + a.a[i];\r
+ r.a[i++] = c&DM;\r
+ c>>=DB;\r
+ }\r
+ if (a.t < t) {\r
+ c += a.s;\r
+ while (i<t) {\r
+ c += this.a[i];\r
+ r.a[i++] = c&DM;\r
+ c >>= DB;\r
+ }\r
+ c += s;\r
+ } else {\r
+ c += s;\r
+ while (i<a.t) {\r
+ c += a.a[i];\r
+ r.a[i++] = c&DM;\r
+ c >>= DB;\r
+ }\r
+ c += a.s;\r
+ }\r
+ r.s = (c<0)?-1:0;\r
+ if (c>0) {\r
+ r.a[i++] = c;\r
+ } else if (c<-1) {\r
+ r.a[i++] = DV+c;\r
+ }\r
+ r.t = i;\r
+ r.clamp();\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a\r
+ * @return this + a\r
+ * \r
+ */\r
+ public function add(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ addTo(a,r);\r
+ return r;\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param a\r
+ * @return this - a\r
+ * \r
+ */\r
+ public function subtract(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ subTo(a,r);\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a\r
+ * @return this * a\r
+ * \r
+ */\r
+ public function multiply(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ multiplyTo(a,r);\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a\r
+ * @return this / a\r
+ * \r
+ */\r
+ public function divide(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ divRemTo(a, r, null);\r
+ return r;\r
+ }\r
+ \r
+ public function remainder(a:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ divRemTo(a, null, r);\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a\r
+ * @return [this/a, this%a]\r
+ * \r
+ */\r
+ public function divideAndRemainder(a:BigInteger):Array {\r
+ var q:BigInteger = new BigInteger;\r
+ var r:BigInteger = new BigInteger;\r
+ divRemTo(a, q, r);\r
+ return [q,r];\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * this *= n, this >=0, 1 < n < DV\r
+ * \r
+ * @param n\r
+ * \r
+ */\r
+ bi_internal function dMultiply(n:int):void {\r
+ a[t] = am(0, n-1, this, 0, 0, t);\r
+ ++t;\r
+ clamp();\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * this += n << w words, this >= 0\r
+ * \r
+ * @param n\r
+ * @param w\r
+ * \r
+ */\r
+ bi_internal function dAddOffset(n:int, w:int):void {\r
+ while (t<=w) {\r
+ a[t++] = 0;\r
+ }\r
+ a[w] += n;\r
+ while (a[w] >= DV) {\r
+ a[w] -= DV;\r
+ if (++w >= t) {\r
+ a[t++] = 0;\r
+ }\r
+ ++a[w];\r
+ }\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param e\r
+ * @return this^e\r
+ * \r
+ */\r
+ public function pow(e:int):BigInteger {\r
+ return exp(e, new NullReduction);\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a\r
+ * @param n\r
+ * @param r = lower n words of "this * a", a.t <= n\r
+ * \r
+ */\r
+ bi_internal function multiplyLowerTo(a:BigInteger, n:int, r:BigInteger):void {\r
+ var i:int = Math.min(t+a.t, n);\r
+ r.s = 0; // assumes a, this >= 0\r
+ r.t = i;\r
+ while (i>0) {\r
+ r.a[--i]=0;\r
+ }\r
+ var j:int;\r
+ for (j=r.t-t;i<j;++i) {\r
+ r.a[i+t] = am(0, a.a[i], r, i, 0, t);\r
+ }\r
+ for (j=Math.min(a.t,n);i<j;++i) {\r
+ am(0, a.a[i], r, i, 0, n-i);\r
+ }\r
+ r.clamp();\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a\r
+ * @param n\r
+ * @param r = "this * a" without lower n words, n > 0\r
+ * \r
+ */\r
+ bi_internal function multiplyUpperTo(a:BigInteger, n:int, r:BigInteger):void {\r
+ --n;\r
+ var i:int = r.t = t+a.t-n;\r
+ r.s = 0; // assumes a,this >= 0\r
+ while (--i>=0) {\r
+ r.a[i] = 0;\r
+ }\r
+ for (i=Math.max(n-t,0);i<a.t;++i) {\r
+ r.a[t+i-n] = am(n-i, a.a[i], r, 0, 0, t+i-n);\r
+ }\r
+ r.clamp();\r
+ r.drShiftTo(1,r);\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param e\r
+ * @param m\r
+ * @return this^e % m (HAC 14.85)\r
+ * \r
+ */\r
+ public function modPow(e:BigInteger, m:BigInteger):BigInteger {\r
+ var i:int = e.bitLength();\r
+ var k:int;\r
+ var r:BigInteger = nbv(1);\r
+ var z:IReduction;\r
+ \r
+ if (i<=0) {\r
+ return r;\r
+ } else if (i<18) {\r
+ k=1;\r
+ } else if (i<48) {\r
+ k=3;\r
+ } else if (i<144) {\r
+ k=4;\r
+ } else if (i<768) {\r
+ k=5;\r
+ } else {\r
+ k=6;\r
+ }\r
+ if (i<8) {\r
+ z = new ClassicReduction(m);\r
+ } else if (m.isEven()) {\r
+ z = new BarrettReduction(m);\r
+ } else {\r
+ z = new MontgomeryReduction(m);\r
+ }\r
+ // precomputation\r
+ var g:Array = [];\r
+ var n:int = 3;\r
+ var k1:int = k-1;\r
+ var km:int = (1<<k)-1;\r
+ g[1] = z.convert(this);\r
+ if (k > 1) {\r
+ var g2:BigInteger = new BigInteger;\r
+ z.sqrTo(g[1], g2);\r
+ while (n<=km) {\r
+ g[n] = new BigInteger;\r
+ z.mulTo(g2, g[n-2], g[n]);\r
+ n += 2;\r
+ }\r
+ }\r
+ \r
+ var j:int = e.t-1;\r
+ var w:int;\r
+ var is1:Boolean = true;\r
+ var r2:BigInteger = new BigInteger;\r
+ var t:BigInteger;\r
+ i = nbits(e.a[j])-1;\r
+ while (j>=0) {\r
+ if (i>=k1) {\r
+ w = (e.a[j]>>(i-k1))&km;\r
+ } else {\r
+ w = (e.a[j]&((1<<(i+1))-1))<<(k1-i);\r
+ if (j>0) {\r
+ w |= e.a[j-1]>>(DB+i-k1);\r
+ }\r
+ }\r
+ n = k;\r
+ while ((w&1)==0) {\r
+ w >>= 1;\r
+ --n;\r
+ }\r
+ if ((i -= n) <0) {\r
+ i += DB;\r
+ --j;\r
+ }\r
+ if (is1) { // ret == 1, don't bother squaring or multiplying it\r
+ g[w].copyTo(r);\r
+ is1 = false;\r
+ } else {\r
+ while (n>1) {\r
+ z.sqrTo(r, r2);\r
+ z.sqrTo(r2, r);\r
+ n -= 2;\r
+ }\r
+ if (n>0) {\r
+ z.sqrTo(r, r2);\r
+ } else {\r
+ t = r;\r
+ r = r2;\r
+ r2 = t;\r
+ }\r
+ z.mulTo(r2, g[w], r);\r
+ }\r
+ while (j>=0 && (e.a[j]&(1<<i)) == 0) {\r
+ z.sqrTo(r, r2);\r
+ t = r;\r
+ r = r2;\r
+ r2 = t;\r
+ if (--i<0) {\r
+ i = DB-1;\r
+ --j;\r
+ }\r
+ \r
+ }\r
+ }\r
+ return z.revert(r);\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param a\r
+ * @return gcd(this, a) (HAC 14.54)\r
+ * \r
+ */\r
+ public function gcd(a:BigInteger):BigInteger {\r
+ var x:BigInteger = (s<0)?negate():clone();\r
+ var y:BigInteger = (a.s<0)?a.negate():a.clone();\r
+ if (x.compareTo(y)<0) {\r
+ var t:BigInteger=x;\r
+ x=y;\r
+ y=t;\r
+ }\r
+ var i:int = x.getLowestSetBit();\r
+ var g:int = y.getLowestSetBit();\r
+ if (g<0) return x;\r
+ if (i<g) g= i;\r
+ if (g>0) {\r
+ x.rShiftTo(g, x);\r
+ y.rShiftTo(g, y);\r
+ }\r
+ while (x.sigNum()>0) {\r
+ if ((i = x.getLowestSetBit()) >0) {\r
+ x.rShiftTo(i, x);\r
+ }\r
+ if ((i = y.getLowestSetBit()) >0) {\r
+ y.rShiftTo(i, y);\r
+ }\r
+ if (x.compareTo(y) >= 0) {\r
+ x.subTo(y, x);\r
+ x.rShiftTo(1, x);\r
+ } else {\r
+ y.subTo(x, y);\r
+ y.rShiftTo(1, y);\r
+ }\r
+ }\r
+ if (g>0) {\r
+ y.lShiftTo(g, y);\r
+ }\r
+ return y;\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param n\r
+ * @return this % n, n < 2^DB\r
+ * \r
+ */\r
+ protected function modInt(n:int):int {\r
+ if (n<=0) return 0;\r
+ var d:int = DV%n;\r
+ var r:int = (s<0)?n-1:0;\r
+ if (t>0) {\r
+ if (d==0) {\r
+ r = a[0]%n;\r
+ } else {\r
+ for (var i:int=t-1;i>=0;--i) {\r
+ r = (d*r+a[i])%n;\r
+ }\r
+ }\r
+ }\r
+ return r;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param m\r
+ * @return 1/this %m (HAC 14.61)\r
+ * \r
+ */\r
+ public function modInverse(m:BigInteger):BigInteger {\r
+ var ac:Boolean = m.isEven();\r
+ if ((isEven()&&ac) || m.sigNum()==0) {\r
+ return BigInteger.ZERO;\r
+ }\r
+ var u:BigInteger = m.clone();\r
+ var v:BigInteger = clone();\r
+ var a:BigInteger = nbv(1);\r
+ var b:BigInteger = nbv(0);\r
+ var c:BigInteger = nbv(0);\r
+ var d:BigInteger = nbv(1);\r
+ while (u.sigNum()!=0) {\r
+ while (u.isEven()) {\r
+ u.rShiftTo(1,u);\r
+ if (ac) {\r
+ if (!a.isEven() || !b.isEven()) {\r
+ a.addTo(this,a);\r
+ b.subTo(m,b);\r
+ }\r
+ a.rShiftTo(1,a);\r
+ } else if (!b.isEven()) {\r
+ b.subTo(m,b);\r
+ }\r
+ b.rShiftTo(1,b);\r
+ }\r
+ while (v.isEven()) {\r
+ v.rShiftTo(1,v);\r
+ if (ac) {\r
+ if (!c.isEven() || !d.isEven()) {\r
+ c.addTo(this,c);\r
+ d.subTo(m,d);\r
+ }\r
+ c.rShiftTo(1,c);\r
+ } else if (!d.isEven()) {\r
+ d.subTo(m,d);\r
+ }\r
+ d.rShiftTo(1,d);\r
+ }\r
+ if (u.compareTo(v)>=0) {\r
+ u.subTo(v,u);\r
+ if (ac) {\r
+ a.subTo(c,a);\r
+ }\r
+ b.subTo(d,b);\r
+ } else {\r
+ v.subTo(u,v);\r
+ if (ac) {\r
+ c.subTo(a,c);\r
+ }\r
+ d.subTo(b,d);\r
+ }\r
+ }\r
+ if (v.compareTo(BigInteger.ONE) != 0) {\r
+ return BigInteger.ZERO;\r
+ }\r
+ if (d.compareTo(m) >= 0) {\r
+ return d.subtract(m);\r
+ }\r
+ if (d.sigNum()<0) {\r
+ d.addTo(m,d);\r
+ } else {\r
+ return d;\r
+ }\r
+ if (d.sigNum()<0) {\r
+ return d.add(m);\r
+ } else {\r
+ return d;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param t\r
+ * @return primality with certainty >= 1-.5^t\r
+ * \r
+ */\r
+ public function isProbablePrime(t:int):Boolean {\r
+ var i:int;\r
+ var x:BigInteger = abs();\r
+ if (x.t == 1 && x.a[0]<=lowprimes[lowprimes.length-1]) {\r
+ for (i=0;i<lowprimes.length;++i) {\r
+ if (x[0]==lowprimes[i]) return true;\r
+ }\r
+ return false;\r
+ }\r
+ if (x.isEven()) return false;\r
+ i = 1;\r
+ while (i<lowprimes.length) {\r
+ var m:int = lowprimes[i];\r
+ var j:int = i+1;\r
+ while (j<lowprimes.length && m<lplim) {\r
+ m *= lowprimes[j++];\r
+ }\r
+ m = x.modInt(m);\r
+ while (i<j) {\r
+ if (m%lowprimes[i++]==0) {\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ return x.millerRabin(t);\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param t\r
+ * @return true if probably prime (HAC 4.24, Miller-Rabin)\r
+ * \r
+ */\r
+ protected function millerRabin(t:int):Boolean {\r
+ var n1:BigInteger = subtract(BigInteger.ONE);\r
+ var k:int = n1.getLowestSetBit();\r
+ if (k<=0) {\r
+ return false;\r
+ }\r
+ var r:BigInteger = n1.shiftRight(k);\r
+ t = (t+1)>>1;\r
+ if (t>lowprimes.length) {\r
+ t = lowprimes.length;\r
+ }\r
+ var a:BigInteger = new BigInteger;\r
+ for (var i:int=0;i<t;++i) {\r
+ a.fromInt(lowprimes[i]);\r
+ var y:BigInteger = a.modPow(r, this);\r
+ if (y.compareTo(BigInteger.ONE)!=0 && y.compareTo(n1)!=0) {\r
+ var j:int = 1;\r
+ while (j++<k && y.compareTo(n1)!=0) {\r
+ y = y.modPowInt(2, this);\r
+ if (y.compareTo(BigInteger.ONE)==0) {\r
+ return false;\r
+ }\r
+ }\r
+ if (y.compareTo(n1)!=0) {\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Tweak our BigInteger until it looks prime enough\r
+ * \r
+ * @param bits\r
+ * @param t\r
+ * \r
+ */\r
+ public function primify(bits:int, t:int):void {\r
+ if (!testBit(bits-1)) { // force MSB set\r
+ bitwiseTo(BigInteger.ONE.shiftLeft(bits-1), op_or, this);\r
+ }\r
+ if (isEven()) {\r
+ dAddOffset(1,0); // force odd\r
+ }\r
+ while (!isProbablePrime(t)) {\r
+ dAddOffset(2,0);\r
+ while(bitLength()>bits) subTo(BigInteger.ONE.shiftLeft(bits-1),this);\r
+ }\r
+ }\r
+\r
+ }\r
+}\r
--- /dev/null
+package com.hurlant.math\r
+{\r
+ use namespace bi_internal;\r
+ \r
+ /**\r
+ * Modular reduction using "classic" algorithm\r
+ */\r
+ internal class ClassicReduction implements IReduction\r
+ {\r
+ private var m:BigInteger;\r
+ public function ClassicReduction(m:BigInteger) {\r
+ this.m = m;\r
+ }\r
+ public function convert(x:BigInteger):BigInteger {\r
+ if (x.s<0 || x.compareTo(m)>=0) {\r
+ return x.mod(m);\r
+ }\r
+ return x;\r
+ }\r
+ public function revert(x:BigInteger):BigInteger {\r
+ return x;\r
+ }\r
+ public function reduce(x:BigInteger):void {\r
+ x.divRemTo(m, null,x);\r
+ }\r
+ public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void {\r
+ x.multiplyTo(y,r);\r
+ reduce(r);\r
+ }\r
+ public function sqrTo(x:BigInteger, r:BigInteger):void {\r
+ x.squareTo(r);\r
+ reduce(r);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package com.hurlant.math\r
+{\r
+ internal interface IReduction\r
+ {\r
+ function convert(x:BigInteger):BigInteger;\r
+ function revert(x:BigInteger):BigInteger;\r
+ function reduce(x:BigInteger):void;\r
+ function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void;\r
+ function sqrTo(x:BigInteger, r:BigInteger):void;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package com.hurlant.math\r
+{\r
+ use namespace bi_internal;\r
+ /**\r
+ * Montgomery reduction\r
+ */\r
+ internal class MontgomeryReduction implements IReduction\r
+ {\r
+ private var m:BigInteger;\r
+ private var mp:int;\r
+ private var mpl:int;\r
+ private var mph:int;\r
+ private var um:int;\r
+ private var mt2:int;\r
+ public function MontgomeryReduction(m:BigInteger) {\r
+ this.m = m;\r
+ mp = m.invDigit();\r
+ mpl = mp & 0x7fff;\r
+ mph = mp>>15;\r
+ um = (1<<(BigInteger.DB-15))-1;\r
+ mt2 = 2*m.t;\r
+ }\r
+ /**\r
+ * xR mod m\r
+ */\r
+ public function convert(x:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ x.abs().dlShiftTo(m.t, r);\r
+ r.divRemTo(m, null, r);\r
+ if (x.s<0 && r.compareTo(BigInteger.ZERO)>0) {\r
+ m.subTo(r,r);\r
+ }\r
+ return r;\r
+ }\r
+ /**\r
+ * x/R mod m\r
+ */\r
+ public function revert(x:BigInteger):BigInteger {\r
+ var r:BigInteger = new BigInteger;\r
+ x.copyTo(r);\r
+ reduce(r);\r
+ return r;\r
+ }\r
+ /**\r
+ * x = x/R mod m (HAC 14.32)\r
+ */\r
+ public function reduce(x:BigInteger):void {\r
+ while (x.t<=mt2) { // pad x so am has enough room later\r
+ x.a[x.t++] = 0;\r
+ }\r
+ for (var i:int=0; i<m.t; ++i) {\r
+ // faster way of calculating u0 = x[i]*mp mod DV\r
+ var j:int = x.a[i]&0x7fff;\r
+ var u0:int = (j*mpl+(((j*mph+(x.a[i]>>15)*mpl)&um)<<15))&BigInteger.DM;\r
+ // use am to combine the multiply-shift-add into one call\r
+ j = i+m.t;\r
+ x.a[j] += m.am(0, u0, x, i, 0, m.t);\r
+ // propagate carry\r
+ while (x.a[j]>=BigInteger.DV) {\r
+ x.a[j] -= BigInteger.DV;\r
+ x.a[++j]++;\r
+ }\r
+ }\r
+ x.clamp();\r
+ x.drShiftTo(m.t, x);\r
+ if (x.compareTo(m)>=0) {\r
+ x.subTo(m,x);\r
+ }\r
+ }\r
+ /**\r
+ * r = "x^2/R mod m"; x != r\r
+ */\r
+ public function sqrTo(x:BigInteger, r:BigInteger):void {\r
+ x.squareTo(r);\r
+ reduce(r);\r
+ }\r
+ /**\r
+ * r = "xy/R mod m"; x,y != r\r
+ */\r
+ public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void {\r
+ x.multiplyTo(y,r);\r
+ reduce(r);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package com.hurlant.math\r
+{\r
+ use namespace bi_internal;\r
+ /**\r
+ * A "null" reducer\r
+ */\r
+ public class NullReduction implements IReduction\r
+ {\r
+ public function revert(x:BigInteger):BigInteger\r
+ {\r
+ return x;\r
+ }\r
+ \r
+ public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void\r
+ {\r
+ x.multiplyTo(y,r);\r
+ }\r
+ \r
+ public function sqrTo(x:BigInteger, r:BigInteger):void\r
+ {\r
+ x.squareTo(r);\r
+ }\r
+ \r
+ public function convert(x:BigInteger):BigInteger\r
+ {\r
+ return x;\r
+ }\r
+ \r
+ public function reduce(x:BigInteger):void\r
+ {\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * bi_internal\r
+ * \r
+ * A namespace. w00t.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.math {\r
+ public namespace bi_internal = "http://crypto.hurlant.com/BigInteger";\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ArrayUtil\r
+ * \r
+ * A class that allows to compare two ByteArrays.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util {\r
+ import flash.utils.ByteArray;\r
+ \r
+ \r
+ public class ArrayUtil {\r
+ \r
+ public static function equals(a1:ByteArray, a2:ByteArray):Boolean {\r
+ if (a1.length != a2.length) return false;\r
+ var l:int = a1.length;\r
+ for (var i:int=0;i<l;i++) {\r
+ if (a1[i]!=a2[i]) return false;\r
+ }\r
+ return true;\r
+ }\r
+ }\r
+ \r
+}
\ No newline at end of file
--- /dev/null
+/* Base64 library for ActionScript 3.0.\r
+ * Based on: Ma Bingyao code.\r
+ * Optimized by: Jean-Philippe Auclair / jpauclair.wordpress.com\r
+ * Copyright (C) 2007 Ma Bingyao <andot@ujn.edu.cn>\r
+ * LastModified: Oct 26, 2009\r
+ * This library is free. You can redistribute it and/or modify it.\r
+ */\r
+package com.hurlant.util{\r
+ import flash.utils.ByteArray;\r
+\r
+ public class Base64\r
+ {\r
+ private static const _encodeChars : Vector.<int> = InitEncoreChar();\r
+ private static const _decodeChars : Vector.<int> = InitDecodeChar();\r
+\r
+ public static function encodeByteArray(data : ByteArray) : String\r
+ {\r
+ var out : ByteArray = new ByteArray();\r
+ //Presetting the length keep the memory smaller and optimize speed since there is no "grow" needed\r
+ out.length = (2 + data.length - ((data.length + 2) % 3)) * 4 / 3; //Preset length //1.6 to 1.5 ms\r
+ var i : int = 0;\r
+ var r : int = data.length % 3;\r
+ var len : int = data.length - r;\r
+ var c : int; //read (3) character AND write (4) characters\r
+\r
+ while (i < len)\r
+ {\r
+ //Read 3 Characters (8bit * 3 = 24 bits)\r
+ c = data[i++] << 16 | data[i++] << 8 | data[i++];\r
+\r
+ //Cannot optimize this to read int because of the positioning overhead. (as3 bytearray seek is slow)\r
+ //Convert to 4 Characters (6 bit * 4 = 24 bits)\r
+ c = (_encodeChars[c >>> 18] << 24) | (_encodeChars[c >>> 12 & 0x3f] << 16) | (_encodeChars[c >>> 6 & 0x3f] << 8) | _encodeChars[c & 0x3f];\r
+\r
+ //Optimization: On older and slower computer, do one write Int instead of 4 write byte: 1.5 to 0.71 ms\r
+ out.writeInt(c);\r
+ /*\r
+ out.writeByte(_encodeChars[c >> 18] );\r
+ out.writeByte(_encodeChars[c >> 12 & 0x3f]);\r
+ out.writeByte(_encodeChars[c >> 6 & 0x3f]);\r
+ out.writeByte(_encodeChars[c & 0x3f]);\r
+ */\r
+ }\r
+\r
+ if (r == 1) //Need two "=" padding\r
+ {\r
+ //Read one char, write two chars, write padding\r
+ c = data[i];\r
+ c = (_encodeChars[c >>> 2] << 24) | (_encodeChars[(c & 0x03) << 4] << 16) | 61 << 8 | 61;\r
+ out.writeInt(c);\r
+ }\r
+ else if (r == 2) //Need one "=" padding\r
+ {\r
+ c = data[i++] << 8 | data[i];\r
+ c = (_encodeChars[c >>> 10] << 24) | (_encodeChars[c >>> 4 & 0x3f] << 16) | (_encodeChars[(c & 0x0f) << 2] << 8) | 61;\r
+ out.writeInt(c);\r
+ }\r
+\r
+ out.position = 0;\r
+ return out.readUTFBytes(out.length);\r
+ }\r
+\r
+\r
+ public static function decodeToByteArray(str : String) : ByteArray\r
+ {\r
+ var c1 : int;\r
+ var c2 : int;\r
+ var c3 : int;\r
+ var c4 : int;\r
+ var i : int;\r
+ var len : int;\r
+ var out : ByteArray;\r
+ len = str.length;\r
+ i = 0;\r
+ out = new ByteArray();\r
+ var byteString : ByteArray = new ByteArray();\r
+ byteString.writeUTFBytes(str);\r
+ while (i < len)\r
+ {\r
+ //c1\r
+ do\r
+ {\r
+ c1 = _decodeChars[byteString[i++]];\r
+ } while (i < len && c1 == -1);\r
+ if (c1 == -1) break;\r
+\r
+ //c2\r
+ do\r
+ {\r
+ c2 = _decodeChars[byteString[i++]];\r
+ } while (i < len && c2 == -1);\r
+ if (c2 == -1) break;\r
+\r
+ out.writeByte((c1 << 2) | ((c2 & 0x30) >> 4));\r
+\r
+ //c3\r
+ do\r
+ {\r
+ c3 = byteString[i++];\r
+ if (c3 == 61) return out;\r
+\r
+ c3 = _decodeChars[c3];\r
+ } while (i < len && c3 == -1);\r
+ if (c3 == -1) break;\r
+\r
+ out.writeByte(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2));\r
+\r
+ //c4\r
+ do {\r
+ c4 = byteString[i++];\r
+ if (c4 == 61) return out;\r
+\r
+ c4 = _decodeChars[c4];\r
+ } while (i < len && c4 == -1);\r
+ if (c4 == -1) break;\r
+\r
+ out.writeByte(((c3 & 0x03) << 6) | c4);\r
+\r
+ }\r
+\r
+ out.position = 0;\r
+\r
+ return out;\r
+ }\r
+\r
+ public static function encode(data : String) : String {\r
+ // Convert string to ByteArray\r
+ var bytes : ByteArray = new ByteArray();\r
+ bytes.writeUTFBytes(data);\r
+\r
+ // Return encoded ByteArray\r
+ return encodeByteArray(bytes);\r
+ }\r
+\r
+ public static function decode(data : String) : String {\r
+ // Decode data to ByteArray\r
+ var bytes : ByteArray = decodeToByteArray(data);\r
+\r
+ // Convert to string and return\r
+ return bytes.readUTFBytes(bytes.length);\r
+ }\r
+\r
+ public static function InitEncoreChar() : Vector.<int>\r
+ {\r
+ var encodeChars : Vector.<int> = new Vector.<int>();\r
+ // We could push the number directly, but i think it's nice to see the characters (with no overhead on encode/decode)\r
+ var chars : String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
+ for (var i : int = 0; i < 64; i++)\r
+ {\r
+ encodeChars.push(chars.charCodeAt(i));\r
+ }\r
+ /*\r
+ encodeChars.push(\r
+ 65, 66, 67, 68, 69, 70, 71, 72,\r
+ 73, 74, 75, 76, 77, 78, 79, 80,\r
+ 81, 82, 83, 84, 85, 86, 87, 88,\r
+ 89, 90, 97, 98, 99, 100, 101, 102,\r
+ 103, 104, 105, 106, 107, 108, 109, 110,\r
+ 111, 112, 113, 114, 115, 116, 117, 118,\r
+ 119, 120, 121, 122, 48, 49, 50, 51,\r
+ 52, 53, 54, 55, 56, 57, 43, 47);\r
+ */\r
+ return encodeChars;\r
+ }\r
+\r
+ public static function InitDecodeChar() : Vector.<int>\r
+ {\r
+ var decodeChars : Vector.<int> = new Vector.<int>();\r
+\r
+ decodeChars.push(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,\r
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,\r
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,\r
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,\r
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,\r
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1\r
+ - 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);\r
+ return decodeChars;\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Hex\r
+ * \r
+ * Utility class to convert Hex strings to ByteArray or String types.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class Hex\r
+ {\r
+ /**\r
+ * Support straight hex, or colon-laced hex.\r
+ * (that means 23:03:0e:f0, but *NOT* 23:3:e:f0)\r
+ * Whitespace characters are ignored.\r
+ */\r
+ public static function toArray(hex:String):ByteArray {\r
+ hex = hex.replace(/\s|:/gm,'');\r
+ var a:ByteArray = new ByteArray;\r
+ if (hex.length&1==1) hex="0"+hex;\r
+ for (var i:uint=0;i<hex.length;i+=2) {\r
+ a[i/2] = parseInt(hex.substr(i,2),16);\r
+ }\r
+ return a;\r
+ }\r
+ \r
+ public static function fromArray(array:ByteArray, colons:Boolean=false):String {\r
+ var s:String = "";\r
+ for (var i:uint=0;i<array.length;i++) {\r
+ s+=("0"+array[i].toString(16)).substr(-2,2);\r
+ if (colons) {\r
+ if (i<array.length-1) s+=":";\r
+ }\r
+ }\r
+ return s;\r
+ }\r
+ \r
+ /**\r
+ * \r
+ * @param hex\r
+ * @return a UTF-8 string decoded from hex\r
+ * \r
+ */\r
+ public static function toString(hex:String):String {\r
+ var a:ByteArray = toArray(hex);\r
+ return a.readUTFBytes(a.length);\r
+ }\r
+ \r
+ \r
+ /**\r
+ * \r
+ * @param str\r
+ * @return a hex string encoded from the UTF-8 string str\r
+ * \r
+ */\r
+ public static function fromString(str:String, colons:Boolean=false):String {\r
+ var a:ByteArray = new ByteArray;\r
+ a.writeUTFBytes(str);\r
+ return fromArray(a, colons);\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Memory\r
+ * \r
+ * A class with a few memory-management methods, as much as \r
+ * such a thing exists in a Flash player.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util\r
+{\r
+ import flash.net.LocalConnection;\r
+ import flash.system.System;\r
+ \r
+ public class Memory\r
+ {\r
+ public static function gc():void {\r
+ // force a GC\r
+ try {\r
+ new LocalConnection().connect('foo');\r
+ new LocalConnection().connect('foo');\r
+ } catch (e:*) {}\r
+ }\r
+ public static function get used():uint {\r
+ return System.totalMemory;\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ByteString\r
+ * \r
+ * An ASN1 type for a ByteString, represented with a ByteArray\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+\r
+ public class ByteString extends ByteArray implements IAsn1Type\r
+ {\r
+ private var type:uint;\r
+ private var len:uint;\r
+ \r
+ public function ByteString(type:uint = 0x04, length:uint = 0x00) {\r
+ this.type = type;\r
+ this.len = length;\r
+ }\r
+ \r
+ public function getLength():uint\r
+ {\r
+ return len;\r
+ }\r
+ \r
+ public function getType():uint\r
+ {\r
+ return type;\r
+ }\r
+ \r
+ public function toDER():ByteArray {\r
+ return DER.wrapDER(type, this);\r
+ }\r
+ \r
+ override public function toString():String {\r
+ return DER.indent+"ByteString["+type+"]["+len+"]["+Hex.fromArray(this)+"]";\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * DER\r
+ * \r
+ * A basic class to parse DER structures.\r
+ * It is very incomplete, but sufficient to extract whatever data we need so far.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import com.hurlant.math.BigInteger;\r
+ \r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.der.Sequence;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ // goal 1: to be able to parse an RSA Private Key PEM file.\r
+ // goal 2: to parse an X509v3 cert. kinda.\r
+ \r
+ /**\r
+ * DER for dummies:\r
+ * http://luca.ntop.org/Teaching/Appunti/asn1.html\r
+ * \r
+ * This class does the bare minimum to get by. if that.\r
+ */\r
+ public class DER\r
+ {\r
+ public static var indent:String = "";\r
+ \r
+ public static function parse(der:ByteArray, structure:*=null):IAsn1Type {\r
+/* if (der.position==0) {\r
+ trace("DER.parse: "+Hex.fromArray(der));\r
+ }\r
+ */ // type\r
+ var type:int = der.readUnsignedByte();\r
+ var constructed:Boolean = (type&0x20)!=0;\r
+ type &=0x1F;\r
+ // length\r
+ var len:int = der.readUnsignedByte();\r
+ if (len>=0x80) {\r
+ // long form of length\r
+ var count:int = len & 0x7f;\r
+ len = 0;\r
+ while (count>0) {\r
+ len = (len<<8) | der.readUnsignedByte();\r
+ count--;\r
+ }\r
+ }\r
+ // data\r
+ var b:ByteArray\r
+ switch (type) {\r
+ case 0x00: // WHAT IS THIS THINGY? (seen as 0xa0)\r
+ // (note to self: read a spec someday.)\r
+ // for now, treat as a sequence.\r
+ case 0x10: // SEQUENCE/SEQUENCE OF. whatever\r
+ // treat as an array\r
+ var p:int = der.position;\r
+ var o:Sequence = new Sequence(type, len);\r
+ var arrayStruct:Array = structure as Array;\r
+ if (arrayStruct!=null) {\r
+ // copy the array, as we destroy it later.\r
+ arrayStruct = arrayStruct.concat();\r
+ }\r
+ while (der.position < p+len) {\r
+ var tmpStruct:Object = null\r
+ if (arrayStruct!=null) {\r
+ tmpStruct = arrayStruct.shift();\r
+ }\r
+ if (tmpStruct!=null) {\r
+ while (tmpStruct && tmpStruct.optional) {\r
+ // make sure we have something that looks reasonable. XXX I'm winging it here..\r
+ var wantConstructed:Boolean = (tmpStruct.value is Array);\r
+ var isConstructed:Boolean = isConstructedType(der);\r
+ if (wantConstructed!=isConstructed) {\r
+ // not found. put default stuff, or null\r
+ o.push(tmpStruct.defaultValue);\r
+ o[tmpStruct.name] = tmpStruct.defaultValue;\r
+ // try the next thing\r
+ tmpStruct = arrayStruct.shift();\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if (tmpStruct!=null) {\r
+ var name:String = tmpStruct.name;\r
+ var value:* = tmpStruct.value;\r
+ if (tmpStruct.extract) {\r
+ // we need to keep a binary copy of this element\r
+ var size:int = getLengthOfNextElement(der);\r
+ var ba:ByteArray = new ByteArray;\r
+ ba.writeBytes(der, der.position, size);\r
+ o[name+"_bin"] = ba;\r
+ }\r
+ var obj:IAsn1Type = DER.parse(der, value);\r
+ o.push(obj);\r
+ o[name] = obj;\r
+ } else {\r
+ o.push(DER.parse(der));\r
+ }\r
+ }\r
+ return o;\r
+ case 0x11: // SET/SET OF\r
+ p = der.position;\r
+ var s:Set = new Set(type, len);\r
+ while (der.position < p+len) {\r
+ s.push(DER.parse(der));\r
+ }\r
+ return s;\r
+ case 0x02: // INTEGER\r
+ // put in a BigInteger\r
+ b = new ByteArray;\r
+ der.readBytes(b,0,len);\r
+ b.position=0;\r
+ return new Integer(type, len, b);\r
+ case 0x06: // OBJECT IDENTIFIER:\r
+ b = new ByteArray;\r
+ der.readBytes(b,0,len);\r
+ b.position=0;\r
+ return new ObjectIdentifier(type, len, b);\r
+ default:\r
+ trace("I DONT KNOW HOW TO HANDLE DER stuff of TYPE "+type);\r
+ // fall through\r
+ case 0x03: // BIT STRING\r
+ if (der[der.position]==0) {\r
+ //trace("Horrible Bit String pre-padding removal hack."); // I wish I had the patience to find a spec for this.\r
+ der.position++;\r
+ len--;\r
+ }\r
+ case 0x04: // OCTET STRING\r
+ // stuff in a ByteArray for now.\r
+ var bs:ByteString = new ByteString(type, len);\r
+ der.readBytes(bs,0,len);\r
+ return bs;\r
+ case 0x05: // NULL\r
+ // if len!=0, something's horribly wrong.\r
+ // should I check?\r
+ return null;\r
+ case 0x13: // PrintableString\r
+ var ps:PrintableString = new PrintableString(type, len);\r
+ ps.setString(der.readMultiByte(len, "US-ASCII"));\r
+ return ps;\r
+ case 0x22: // XXX look up what this is. openssl uses this to store my email.\r
+ case 0x14: // T61String - an horrible format we don't even pretend to support correctly\r
+ ps = new PrintableString(type, len);\r
+ ps.setString(der.readMultiByte(len, "latin1"));\r
+ return ps;\r
+ case 0x17: // UTCTime\r
+ var ut:UTCTime = new UTCTime(type, len);\r
+ ut.setUTCTime(der.readMultiByte(len, "US-ASCII"));\r
+ return ut;\r
+ }\r
+ }\r
+ \r
+ private static function getLengthOfNextElement(b:ByteArray):int {\r
+ var p:uint = b.position;\r
+ // length\r
+ b.position++;\r
+ var len:int = b.readUnsignedByte();\r
+ if (len>=0x80) {\r
+ // long form of length\r
+ var count:int = len & 0x7f;\r
+ len = 0;\r
+ while (count>0) {\r
+ len = (len<<8) | b.readUnsignedByte();\r
+ count--;\r
+ }\r
+ }\r
+ len += b.position-p; // length of length\r
+ b.position = p;\r
+ return len;\r
+ }\r
+ private static function isConstructedType(b:ByteArray):Boolean {\r
+ var type:int = b[b.position];\r
+ return (type&0x20)!=0;\r
+ }\r
+ \r
+ public static function wrapDER(type:int, data:ByteArray):ByteArray {\r
+ var d:ByteArray = new ByteArray;\r
+ d.writeByte(type);\r
+ var len:int = data.length;\r
+ if (len<128) {\r
+ d.writeByte(len);\r
+ } else if (len<256) {\r
+ d.writeByte(1 | 0x80);\r
+ d.writeByte(len);\r
+ } else if (len<65536) {\r
+ d.writeByte(2 | 0x80);\r
+ d.writeByte(len>>8);\r
+ d.writeByte(len);\r
+ } else if (len<65536*256) {\r
+ d.writeByte(3 | 0x80);\r
+ d.writeByte(len>>16);\r
+ d.writeByte(len>>8);\r
+ d.writeByte(len);\r
+ } else {\r
+ d.writeByte(4 | 0x80);\r
+ d.writeByte(len>>24);\r
+ d.writeByte(len>>16);\r
+ d.writeByte(len>>8);\r
+ d.writeByte(len);\r
+ }\r
+ d.writeBytes(data);\r
+ d.position=0;\r
+ return d;\r
+ \r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * IAsn1Type\r
+ * \r
+ * An interface for Asn-1 types.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public interface IAsn1Type\r
+ {\r
+ function getType():uint;\r
+ function getLength():uint;\r
+ \r
+ function toDER():ByteArray;\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Integer\r
+ * \r
+ * An ASN1 type for an Integer, represented with a BigInteger\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import com.hurlant.math.BigInteger;\r
+ import flash.utils.ByteArray;\r
+\r
+ public class Integer extends BigInteger implements IAsn1Type\r
+ {\r
+ private var type:uint;\r
+ private var len:uint;\r
+ \r
+ public function Integer(type:uint, length:uint, b:ByteArray) {\r
+ this.type = type;\r
+ this.len = length;\r
+ super(b);\r
+ }\r
+ \r
+ public function getLength():uint\r
+ {\r
+ return len;\r
+ }\r
+ \r
+ public function getType():uint\r
+ {\r
+ return type;\r
+ }\r
+ \r
+ override public function toString(radix:Number=0):String {\r
+ return DER.indent+"Integer["+type+"]["+len+"]["+super.toString(16)+"]";\r
+ }\r
+ \r
+ public function toDER():ByteArray {\r
+ return null;\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * OID\r
+ * \r
+ * A list of various ObjectIdentifiers.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ public class OID\r
+ {\r
+\r
+ public static const RSA_ENCRYPTION:String = "1.2.840.113549.1.1.1";\r
+ public static const MD2_WITH_RSA_ENCRYPTION:String = "1.2.840.113549.1.1.2";\r
+ public static const MD5_WITH_RSA_ENCRYPTION:String = "1.2.840.113549.1.1.4";\r
+ public static const SHA1_WITH_RSA_ENCRYPTION:String = "1.2.840.113549.1.1.5";\r
+ public static const MD2_ALGORITHM:String = "1.2.840.113549.2.2";\r
+ public static const MD5_ALGORITHM:String = "1.2.840.113549.2.5";\r
+ public static const DSA:String = "1.2.840.10040.4.1";\r
+ public static const DSA_WITH_SHA1:String = "1.2.840.10040.4.3";\r
+ public static const DH_PUBLIC_NUMBER:String = "1.2.840.10046.2.1";\r
+ public static const SHA1_ALGORITHM:String = "1.3.14.3.2.26";\r
+ \r
+ public static const COMMON_NAME:String = "2.5.4.3";\r
+ public static const SURNAME:String = "2.5.4.4";\r
+ public static const COUNTRY_NAME:String = "2.5.4.6";\r
+ public static const LOCALITY_NAME:String = "2.5.4.7";\r
+ public static const STATE_NAME:String = "2.5.4.8";\r
+ public static const ORGANIZATION_NAME:String = "2.5.4.10";\r
+ public static const ORG_UNIT_NAME:String = "2.5.4.11";\r
+ public static const TITLE:String = "2.5.4.12";\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * ObjectIdentifier\r
+ * \r
+ * An ASN1 type for an ObjectIdentifier\r
+ * We store the oid in an Array.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class ObjectIdentifier implements IAsn1Type\r
+ {\r
+ private var type:uint;\r
+ private var len:uint;\r
+ private var oid:Array;\r
+ \r
+ public function ObjectIdentifier(type:uint, length:uint, b:*) {\r
+ this.type = type;\r
+ this.len = length;\r
+ if (b is ByteArray) {\r
+ parse(b as ByteArray);\r
+ } else if (b is String) {\r
+ generate(b as String);\r
+ } else {\r
+ throw new Error("Invalid call to new ObjectIdentifier");\r
+ }\r
+ }\r
+ \r
+ private function generate(s:String):void {\r
+ oid = s.split(".");\r
+ }\r
+ \r
+ private function parse(b:ByteArray):void {\r
+ // parse stuff\r
+ // first byte = 40*value1 + value2\r
+ var o:uint = b.readUnsignedByte();\r
+ var a:Array = []\r
+ a.push(uint(o/40));\r
+ a.push(uint(o%40));\r
+ var v:uint = 0;\r
+ while (b.bytesAvailable>0) {\r
+ o = b.readUnsignedByte();\r
+ var last:Boolean = (o&0x80)==0;\r
+ o &= 0x7f;\r
+ v = v*128 + o;\r
+ if (last) {\r
+ a.push(v);\r
+ v = 0;\r
+ }\r
+ }\r
+ oid = a;\r
+ }\r
+ \r
+ public function getLength():uint\r
+ {\r
+ return len;\r
+ }\r
+ \r
+ public function getType():uint\r
+ {\r
+ return type;\r
+ }\r
+ \r
+ public function toDER():ByteArray {\r
+ var tmp:Array = [];\r
+ tmp[0] = oid[0]*40 + oid[1];\r
+ for (var i:int=2;i<oid.length;i++) {\r
+ var v:int = parseInt(oid[i]);\r
+ if (v<128) {\r
+ tmp.push(v);\r
+ } else if (v<128*128) {\r
+ tmp.push( (v>>7)|0x80 );\r
+ tmp.push( v&0x7f );\r
+ } else if (v<128*128*128) {\r
+ tmp.push( (v>>14)|0x80 );\r
+ tmp.push( (v>>7)&0x7f | 0x80 );\r
+ tmp.push( v&0x7f);\r
+ } else if (v<128*128*128*128) {\r
+ tmp.push( (v>>21)|0x80 );\r
+ tmp.push( (v>>14) & 0x7f | 0x80 );\r
+ tmp.push( (v>>7) & 0x7f | 0x80 );\r
+ tmp.push( v & 0x7f );\r
+ } else {\r
+ throw new Error("OID element bigger than we thought. :(");\r
+ }\r
+ }\r
+ len = tmp.length;\r
+ if (type==0) {\r
+ type = 6;\r
+ }\r
+ tmp.unshift(len); // assume length is small enough to fit here.\r
+ tmp.unshift(type);\r
+ var b:ByteArray = new ByteArray;\r
+ for (i=0;i<tmp.length;i++) {\r
+ b[i] = tmp[i];\r
+ }\r
+ return b;\r
+ }\r
+\r
+ public function toString():String {\r
+ return DER.indent+oid.join(".");\r
+ }\r
+ \r
+ public function dump():String {\r
+ return "OID["+type+"]["+len+"]["+toString()+"]";\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * PEM\r
+ * \r
+ * A class to parse some PEM stuff.\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import com.hurlant.crypto.rsa.RSAKey;\r
+ import com.hurlant.math.BigInteger;\r
+ import com.hurlant.util.Base64;\r
+ \r
+ import flash.utils.ByteArray;\r
+ import com.hurlant.util.Hex;\r
+ \r
+ public class PEM\r
+ {\r
+ private static const RSA_PRIVATE_KEY_HEADER:String = "-----BEGIN RSA PRIVATE KEY-----";\r
+ private static const RSA_PRIVATE_KEY_FOOTER:String = "-----END RSA PRIVATE KEY-----";\r
+ private static const RSA_PUBLIC_KEY_HEADER:String = "-----BEGIN PUBLIC KEY-----";\r
+ private static const RSA_PUBLIC_KEY_FOOTER:String = "-----END PUBLIC KEY-----";\r
+ private static const CERTIFICATE_HEADER:String = "-----BEGIN CERTIFICATE-----";\r
+ private static const CERTIFICATE_FOOTER:String = "-----END CERTIFICATE-----";\r
+ \r
+ \r
+ \r
+ /**\r
+ * \r
+ * Read a structure encoded according to\r
+ * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc\r
+ * section 11.1.2\r
+ * \r
+ * @param str\r
+ * @return \r
+ * \r
+ */\r
+ public static function readRSAPrivateKey(str:String):RSAKey {\r
+ var der:ByteArray = extractBinary(RSA_PRIVATE_KEY_HEADER, RSA_PRIVATE_KEY_FOOTER, str);\r
+ if (der==null) return null;\r
+ var obj:* = DER.parse(der);\r
+ if (obj is Array) {\r
+ var arr:Array = obj as Array;\r
+ // arr[0] is Version. should be 0. should be checked. shoulda woulda coulda.\r
+ return new RSAKey(\r
+ arr[1], // N\r
+ arr[2].valueOf(), // E\r
+ arr[3], // D\r
+ arr[4], // P\r
+ arr[5], // Q\r
+ arr[6], // DMP1\r
+ arr[7], // DMQ1 \r
+ arr[8]); // IQMP\r
+ } else {\r
+ // dunno\r
+ return null;\r
+ }\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Read a structure encoded according to some spec somewhere\r
+ * Also, follows some chunk from\r
+ * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc\r
+ * section 11.1\r
+ * \r
+ * @param str\r
+ * @return \r
+ * \r
+ */\r
+ public static function readRSAPublicKey(str:String):RSAKey {\r
+ var der:ByteArray = extractBinary(RSA_PUBLIC_KEY_HEADER, RSA_PUBLIC_KEY_FOOTER, str);\r
+ if (der==null) return null;\r
+ var obj:* = DER.parse(der);\r
+ if (obj is Array) {\r
+ var arr:Array = obj as Array;\r
+ // arr[0] = [ <some crap that means "rsaEncryption">, null ]; ( apparently, that's an X-509 Algorithm Identifier.\r
+ if (arr[0][0].toString()!=OID.RSA_ENCRYPTION) {\r
+ return null;\r
+ }\r
+ // arr[1] is a ByteArray begging to be parsed as DER\r
+ arr[1].position = 1; // there's a 0x00 byte up front. find out why later. like, read a spec.\r
+ obj = DER.parse(arr[1]);\r
+ if (obj is Array) {\r
+ arr = obj as Array;\r
+ // arr[0] = modulus\r
+ // arr[1] = public expt.\r
+ return new RSAKey(arr[0], arr[1]);\r
+ } else {\r
+ return null;\r
+ }\r
+ } else {\r
+ // dunno\r
+ return null;\r
+ }\r
+ }\r
+\r
+ public static function readCertIntoArray(str:String):ByteArray {\r
+ var tmp:ByteArray = extractBinary(CERTIFICATE_HEADER, CERTIFICATE_FOOTER, str);\r
+ return tmp;\r
+ }\r
+ \r
+ private static function extractBinary(header:String, footer:String, str:String):ByteArray {\r
+ var i:int = str.indexOf(header);\r
+ if (i==-1) return null;\r
+ i += header.length;\r
+ var j:int = str.indexOf(footer);\r
+ if (j==-1) return null;\r
+ var b64:String = str.substring(i, j);\r
+ // remove whitesapces.\r
+ b64 = b64.replace(/\s/mg, '');\r
+ // decode\r
+ return Base64.decodeToByteArray(b64);\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * PrintableString\r
+ * \r
+ * An ASN1 type for a PrintableString, held within a String\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class PrintableString implements IAsn1Type\r
+ {\r
+ protected var type:uint;\r
+ protected var len:uint;\r
+ protected var str:String;\r
+ \r
+ public function PrintableString(type:uint, length:uint) {\r
+ this.type = type;\r
+ this.len = length;\r
+ }\r
+ \r
+ public function getLength():uint\r
+ {\r
+ return len;\r
+ }\r
+ \r
+ public function getType():uint\r
+ {\r
+ return type;\r
+ }\r
+ \r
+ public function setString(s:String):void {\r
+ str = s;\r
+ }\r
+ public function getString():String {\r
+ return str;\r
+ }\r
+ \r
+ public function toString():String {\r
+ return DER.indent+str;\r
+ }\r
+ \r
+ public function toDER():ByteArray {\r
+ return null; // XXX not implemented\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Sequence\r
+ * \r
+ * An ASN1 type for a Sequence, implemented as an Array\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public dynamic class Sequence extends Array implements IAsn1Type\r
+ {\r
+ protected var type:uint;\r
+ protected var len:uint;\r
+ \r
+ public function Sequence(type:uint = 0x30, length:uint = 0x00) {\r
+ this.type = type;\r
+ this.len = length;\r
+ }\r
+ \r
+ public function getLength():uint\r
+ {\r
+ return len;\r
+ }\r
+ \r
+ public function getType():uint\r
+ {\r
+ return type;\r
+ }\r
+\r
+ public function toDER():ByteArray {\r
+ var tmp:ByteArray = new ByteArray;\r
+ for (var i:int=0;i<length;i++) {\r
+ var e:IAsn1Type = this[i];\r
+ if (e == null) { // XXX Arguably, I could have a der.Null class instead\r
+ tmp.writeByte(0x05);\r
+ tmp.writeByte(0x00);\r
+ } else {\r
+ tmp.writeBytes(e.toDER());\r
+ }\r
+ }\r
+ return DER.wrapDER(type, tmp);\r
+ }\r
+ \r
+ public function toString():String {\r
+ var s:String = DER.indent;\r
+ DER.indent += " ";\r
+ var t:String = "";\r
+ for (var i:int=0;i<length;i++) {\r
+ if (this[i]==null) continue;\r
+ var found:Boolean = false;\r
+ for (var key:String in this) {\r
+ if ( (i.toString()!=key) && this[i]==this[key]) {\r
+ t += key+": "+this[i]+"\n";\r
+ found = true;\r
+ break;\r
+ }\r
+ }\r
+ if (!found) t+=this[i]+"\n";\r
+ }\r
+// var t:String = join("\n");\r
+ DER.indent= s;\r
+ return DER.indent+"Sequence["+type+"]["+len+"][\n"+t+"\n"+s+"]";\r
+ }\r
+ \r
+ /////////\r
+ \r
+ public function findAttributeValue(oid:String):IAsn1Type {\r
+ for each (var set:* in this) {\r
+ if (set is Set) {\r
+ var child:* = set[0];\r
+ if (child is Sequence) {\r
+ var tmp:* = child[0];\r
+ if (tmp is ObjectIdentifier) {\r
+ var id:ObjectIdentifier = tmp as ObjectIdentifier;\r
+ if (id.toString()==oid) {\r
+ return child[1] as IAsn1Type;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Set\r
+ * \r
+ * An ASN1 type for an Set, that extends a Sequence\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ public dynamic class Set extends Sequence implements IAsn1Type\r
+ {\r
+ public function Set(type:uint = 0x31, length:uint = 0x00) {\r
+ super(type, length);\r
+ }\r
+\r
+\r
+ public override function toString():String {\r
+ var s:String = DER.indent;\r
+ DER.indent += " ";\r
+ var t:String = join("\n");\r
+ DER.indent= s;\r
+ return DER.indent+"Set["+type+"]["+len+"][\n"+t+"\n"+s+"]";\r
+ }\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Type\r
+ * \r
+ * A few Asn-1 structures\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import com.hurlant.util.Hex;\r
+ \r
+ public class Type\r
+ {\r
+ public static const TLS_CERT:Array = [ \r
+ {name:"signedCertificate", extract:true, value: [\r
+ {name:"versionHolder", optional:true, value: [\r
+ {name:"version"}\r
+ ], defaultValue: function():Sequence{ \r
+ var s:Sequence = new Sequence(0, 0); \r
+ var v:Integer = new Integer(2,1, Hex.toArray("00"));\r
+ s.push(v);\r
+ s.version = v;\r
+ return s;\r
+ }()\r
+ },\r
+ {name:"serialNumber"},\r
+ {name:"signature", value: [\r
+ {name:"algorithmId"}\r
+ ]},\r
+ {name:"issuer", extract:true, value: [ \r
+ {name:"type"},\r
+ {name:"value"}\r
+ ]},\r
+ {name:"validity", value: [\r
+ {name:"notBefore"},\r
+ {name:"notAfter"}\r
+ ]},\r
+ {name:"subject", extract:true, value: [\r
+ ]},\r
+ {name:"subjectPublicKeyInfo", value: [\r
+ {name:"algorithm", value: [\r
+ {name:"algorithmId"}\r
+ ]},\r
+ {name:"subjectPublicKey"}\r
+ ]},\r
+ {name:"extensions", value: [\r
+ ]}\r
+ ]}, \r
+ {name:"algorithmIdentifier",value:[\r
+ {name:"algorithmId"}\r
+ ]}, \r
+ {name:"encrypted", value:null}\r
+ ];\r
+ public static const CERTIFICATE:Array = [\r
+ {name:"tbsCertificate", value:[\r
+ {name:"tag0", value:[\r
+ {name:"version"}\r
+ ]},\r
+ {name:"serialNumber"},\r
+ {name:"signature"},\r
+ {name:"issuer", value:[\r
+ {name:"type"},\r
+ {name:"value"}\r
+ ]},\r
+ {name:"validity", value:[\r
+ {name:"notBefore"},\r
+ {name:"notAfter"}\r
+ ]},\r
+ {name:"subject"},\r
+ {name:"subjectPublicKeyInfo", value:[\r
+ {name:"algorithm"},\r
+ {name:"subjectPublicKey"}\r
+ ]},\r
+ {name:"issuerUniqueID"},\r
+ {name:"subjectUniqueID"},\r
+ {name:"extensions"}\r
+ ]},\r
+ {name:"signatureAlgorithm"},\r
+ {name:"signatureValue"}\r
+ ];\r
+ public static const RSA_PUBLIC_KEY:Array = [\r
+ {name:"modulus"},\r
+ {name:"publicExponent"}\r
+ ];\r
+ public static const RSA_SIGNATURE:Array = [\r
+ {name:"algorithm", value:[\r
+ {name:"algorithmId"}\r
+ ]},\r
+ {name:"hash"}\r
+ ];\r
+ \r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * UTCTime\r
+ * \r
+ * An ASN1 type for UTCTime, represented as a Date\r
+ * Copyright (c) 2007 Henri Torgemane\r
+ * \r
+ * See LICENSE.txt for full license information.\r
+ */\r
+package com.hurlant.util.der\r
+{\r
+ import flash.utils.ByteArray;\r
+ \r
+ public class UTCTime implements IAsn1Type\r
+ {\r
+ protected var type:uint;\r
+ protected var len:uint;\r
+ public var date:Date;\r
+ \r
+ public function UTCTime(type:uint, len:uint)\r
+ {\r
+ this.type = type;\r
+ this.len = len;\r
+ }\r
+ \r
+ public function getLength():uint\r
+ {\r
+ return len;\r
+ }\r
+ \r
+ public function getType():uint\r
+ {\r
+ return type;\r
+ }\r
+ \r
+ public function setUTCTime(str:String):void {\r
+ \r
+ var year:uint = parseInt(str.substr(0, 2));\r
+ if (year<50) {\r
+ year+=2000;\r
+ } else {\r
+ year+=1900;\r
+ }\r
+ var month:uint = parseInt(str.substr(2,2));\r
+ var day:uint = parseInt(str.substr(4,2));\r
+ var hour:uint = parseInt(str.substr(6,2));\r
+ var minute:uint = parseInt(str.substr(8,2));\r
+ // XXX this could be off by up to a day. parse the rest. someday.\r
+ date = new Date(year, month-1, day, hour, minute);\r
+ }\r
+ \r
+ \r
+ public function toString():String {\r
+ return DER.indent+"UTCTime["+type+"]["+len+"]["+date+"]";\r
+ }\r
+ \r
+ public function toDER():ByteArray {\r
+ return null // XXX not implemented\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+<!--
+ Lincense: Public Domain
+-->
+
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Sample of web_socket.js</title>
+
+ <!-- Include these three JS files: -->
+ <script type="text/javascript" src="swfobject.js"></script>
+ <script type="text/javascript" src="web_socket.js"></script>
+
+ <script type="text/javascript">
+
+ // Set URL of your WebSocketMain.swf here:
+ WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";
+ // Set this to dump debug message from Flash to console.log:
+ WEB_SOCKET_DEBUG = true;
+
+ // Everything below is the same as using standard WebSocket.
+
+ var ws;
+
+ function init() {
+
+ // Connect to Web Socket.
+ // Change host/port here to your own Web Socket server.
+ ws = new WebSocket("ws://localhost:10081/");
+
+ // Set event handlers.
+ ws.onopen = function() {
+ output("onopen");
+ };
+ ws.onmessage = function(e) {
+ // e.data contains received string.
+ output("onmessage: " + e.data);
+ };
+ ws.onclose = function() {
+ output("onclose");
+ };
+ ws.onerror = function() {
+ output("onerror");
+ };
+
+ }
+
+ function onSubmit() {
+ var input = document.getElementById("input");
+ // You can send message to the Web Socket using ws.send.
+ ws.send(input.value);
+ output("send: " + input.value);
+ input.value = "";
+ input.focus();
+ }
+
+ function onCloseClick() {
+ ws.close();
+ }
+
+ function output(str) {
+ var log = document.getElementById("log");
+ var escaped = str.replace(/&/, "&").replace(/</, "<").
+ replace(/>/, ">").replace(/"/, """); // "
+ log.innerHTML = escaped + "<br>" + log.innerHTML;
+ }
+
+ </script>
+</head><body onload="init();">
+ <form onsubmit="onSubmit(); return false;">
+ <input type="text" id="input">
+ <input type="submit" value="Send">
+ <button onclick="onCloseClick(); return false;">close</button>
+ </form>
+ <div id="log"></div>
+</body></html>
--- /dev/null
+/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
+ is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
+*/
+var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();
\ No newline at end of file
--- /dev/null
+// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
+// License: New BSD License
+// Reference: http://dev.w3.org/html5/websockets/
+// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
+
+(function() {
+
+ if (window.WebSocket) return;
+
+ var console = window.console;
+ if (!console || !console.log || !console.error) {
+ console = {log: function(){ }, error: function(){ }};
+ }
+
+ if (!swfobject.hasFlashPlayerVersion("10.0.0")) {
+ console.error("Flash Player >= 10.0.0 is required.");
+ return;
+ }
+ if (location.protocol == "file:") {
+ console.error(
+ "WARNING: web-socket-js doesn't work in file:///... URL " +
+ "unless you set Flash Security Settings properly. " +
+ "Open the page via Web server i.e. http://...");
+ }
+
+ /**
+ * This class represents a faux web socket.
+ * @param {string} url
+ * @param {array or string} protocols
+ * @param {string} proxyHost
+ * @param {int} proxyPort
+ * @param {string} headers
+ */
+ WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
+ var self = this;
+ self.__id = WebSocket.__nextId++;
+ WebSocket.__instances[self.__id] = self;
+ self.readyState = WebSocket.CONNECTING;
+ self.bufferedAmount = 0;
+ self.__events = {};
+ if (!protocols) {
+ protocols = [];
+ } else if (typeof protocols == "string") {
+ protocols = [protocols];
+ }
+ // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
+ // Otherwise, when onopen fires immediately, onopen is called before it is set.
+ setTimeout(function() {
+ WebSocket.__addTask(function() {
+ WebSocket.__flash.create(
+ self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
+ });
+ }, 0);
+ };
+
+ /**
+ * Send data to the web socket.
+ * @param {string} data The data to send to the socket.
+ * @return {boolean} True for success, false for failure.
+ */
+ WebSocket.prototype.send = function(data) {
+ if (this.readyState == WebSocket.CONNECTING) {
+ throw "INVALID_STATE_ERR: Web Socket connection has not been established";
+ }
+ // We use encodeURIComponent() here, because FABridge doesn't work if
+ // the argument includes some characters. We don't use escape() here
+ // because of this:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
+ // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
+ // preserve all Unicode characters either e.g. "\uffff" in Firefox.
+ // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
+ // additional testing.
+ var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
+ if (result < 0) { // success
+ return true;
+ } else {
+ this.bufferedAmount += result;
+ return false;
+ }
+ };
+
+ /**
+ * Close this web socket gracefully.
+ */
+ WebSocket.prototype.close = function() {
+ if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
+ return;
+ }
+ this.readyState = WebSocket.CLOSING;
+ WebSocket.__flash.close(this.__id);
+ };
+
+ /**
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
+ *
+ * @param {string} type
+ * @param {function} listener
+ * @param {boolean} useCapture
+ * @return void
+ */
+ WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
+ if (!(type in this.__events)) {
+ this.__events[type] = [];
+ }
+ this.__events[type].push(listener);
+ };
+
+ /**
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
+ *
+ * @param {string} type
+ * @param {function} listener
+ * @param {boolean} useCapture
+ * @return void
+ */
+ WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
+ if (!(type in this.__events)) return;
+ var events = this.__events[type];
+ for (var i = events.length - 1; i >= 0; --i) {
+ if (events[i] === listener) {
+ events.splice(i, 1);
+ break;
+ }
+ }
+ };
+
+ /**
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
+ *
+ * @param {Event} event
+ * @return void
+ */
+ WebSocket.prototype.dispatchEvent = function(event) {
+ var events = this.__events[event.type] || [];
+ for (var i = 0; i < events.length; ++i) {
+ events[i](event);
+ }
+ var handler = this["on" + event.type];
+ if (handler) handler(event);
+ };
+
+ /**
+ * Handles an event from Flash.
+ * @param {Object} flashEvent
+ */
+ WebSocket.prototype.__handleEvent = function(flashEvent) {
+ if ("readyState" in flashEvent) {
+ this.readyState = flashEvent.readyState;
+ }
+ if ("protocol" in flashEvent) {
+ this.protocol = flashEvent.protocol;
+ }
+
+ var jsEvent;
+ if (flashEvent.type == "open" || flashEvent.type == "error") {
+ jsEvent = this.__createSimpleEvent(flashEvent.type);
+ } else if (flashEvent.type == "close") {
+ // TODO implement jsEvent.wasClean
+ jsEvent = this.__createSimpleEvent("close");
+ } else if (flashEvent.type == "message") {
+ var data = decodeURIComponent(flashEvent.message);
+ jsEvent = this.__createMessageEvent("message", data);
+ } else {
+ throw "unknown event type: " + flashEvent.type;
+ }
+
+ this.dispatchEvent(jsEvent);
+ };
+
+ WebSocket.prototype.__createSimpleEvent = function(type) {
+ if (document.createEvent && window.Event) {
+ var event = document.createEvent("Event");
+ event.initEvent(type, false, false);
+ return event;
+ } else {
+ return {type: type, bubbles: false, cancelable: false};
+ }
+ };
+
+ WebSocket.prototype.__createMessageEvent = function(type, data) {
+ if (document.createEvent && window.MessageEvent && !window.opera) {
+ var event = document.createEvent("MessageEvent");
+ event.initMessageEvent("message", false, false, data, null, null, window, null);
+ return event;
+ } else {
+ // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
+ return {type: type, data: data, bubbles: false, cancelable: false};
+ }
+ };
+
+ /**
+ * Define the WebSocket readyState enumeration.
+ */
+ WebSocket.CONNECTING = 0;
+ WebSocket.OPEN = 1;
+ WebSocket.CLOSING = 2;
+ WebSocket.CLOSED = 3;
+
+ WebSocket.__flash = null;
+ WebSocket.__instances = {};
+ WebSocket.__tasks = [];
+ WebSocket.__nextId = 0;
+
+ /**
+ * Load a new flash security policy file.
+ * @param {string} url
+ */
+ WebSocket.loadFlashPolicyFile = function(url){
+ WebSocket.__addTask(function() {
+ WebSocket.__flash.loadManualPolicyFile(url);
+ });
+ };
+
+ /**
+ * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
+ */
+ WebSocket.__initialize = function() {
+ if (WebSocket.__flash) return;
+
+ if (WebSocket.__swfLocation) {
+ // For backword compatibility.
+ window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
+ }
+ if (!window.WEB_SOCKET_SWF_LOCATION) {
+ console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
+ return;
+ }
+ var container = document.createElement("div");
+ container.id = "webSocketContainer";
+ // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
+ // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
+ // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
+ // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
+ // the best we can do as far as we know now.
+ container.style.position = "absolute";
+ if (WebSocket.__isFlashLite()) {
+ container.style.left = "0px";
+ container.style.top = "0px";
+ } else {
+ container.style.left = "-100px";
+ container.style.top = "-100px";
+ }
+ var holder = document.createElement("div");
+ holder.id = "webSocketFlash";
+ container.appendChild(holder);
+ document.body.appendChild(container);
+ // See this article for hasPriority:
+ // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
+ swfobject.embedSWF(
+ WEB_SOCKET_SWF_LOCATION,
+ "webSocketFlash",
+ "1" /* width */,
+ "1" /* height */,
+ "10.0.0" /* SWF version */,
+ null,
+ null,
+ {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
+ null,
+ function(e) {
+ if (!e.success) {
+ console.error("[WebSocket] swfobject.embedSWF failed");
+ }
+ });
+ };
+
+ /**
+ * Called by Flash to notify JS that it's fully loaded and ready
+ * for communication.
+ */
+ WebSocket.__onFlashInitialized = function() {
+ // We need to set a timeout here to avoid round-trip calls
+ // to flash during the initialization process.
+ setTimeout(function() {
+ WebSocket.__flash = document.getElementById("webSocketFlash");
+ WebSocket.__flash.setCallerUrl(location.href);
+ WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
+ for (var i = 0; i < WebSocket.__tasks.length; ++i) {
+ WebSocket.__tasks[i]();
+ }
+ WebSocket.__tasks = [];
+ }, 0);
+ };
+
+ /**
+ * Called by Flash to notify WebSockets events are fired.
+ */
+ WebSocket.__onFlashEvent = function() {
+ setTimeout(function() {
+ try {
+ // Gets events using receiveEvents() instead of getting it from event object
+ // of Flash event. This is to make sure to keep message order.
+ // It seems sometimes Flash events don't arrive in the same order as they are sent.
+ var events = WebSocket.__flash.receiveEvents();
+ for (var i = 0; i < events.length; ++i) {
+ WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ }, 0);
+ return true;
+ };
+
+ // Called by Flash.
+ WebSocket.__log = function(message) {
+ console.log(decodeURIComponent(message));
+ };
+
+ // Called by Flash.
+ WebSocket.__error = function(message) {
+ console.error(decodeURIComponent(message));
+ };
+
+ WebSocket.__addTask = function(task) {
+ if (WebSocket.__flash) {
+ task();
+ } else {
+ WebSocket.__tasks.push(task);
+ }
+ };
+
+ /**
+ * Test if the browser is running flash lite.
+ * @return {boolean} True if flash lite is running, false otherwise.
+ */
+ WebSocket.__isFlashLite = function() {
+ if (!window.navigator || !window.navigator.mimeTypes) {
+ return false;
+ }
+ var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
+ if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
+ return false;
+ }
+ return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
+ };
+
+ if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
+ if (window.addEventListener) {
+ window.addEventListener("load", function(){
+ WebSocket.__initialize();
+ }, false);
+ } else {
+ window.attachEvent("onload", function(){
+ WebSocket.__initialize();
+ });
+ }
+ }
+
+})();
--- /dev/null
+{
+ "name": "socket.io-client"
+ , "description": "Socket.IO client for the browser and node.js"
+ , "version": "0.7.4"
+ , "main" : "./lib/io.js"
+ , "browserify": "./dist/socket.io.js"
+ , "homepage": "http://socket.io"
+ , "keywords": ["websocket", "socket", "realtime", "socket.io", "comet", "ajax"]
+ , "author": "Guillermo Rauch <guillermo@learnboost.com>"
+ , "contributors": [
+ { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
+ , { "name": "Arnout Kazemier", "email": "info@3rd-eden.com" }
+ , { "name": "Vladimir Dronnikov", "email": "dronnikov@gmail.com" }
+ ]
+ , "repository": {
+ "type": "git"
+ , "url": "https://github.com/LearnBoost/Socket.IO.git"
+ }
+ , "dependencies": {
+ "uglify-js": "1.0.3"
+ }
+ , "devDependencies": {
+ "expresso": "0.7.7"
+ , "express": "2.3.11"
+ , "jade": "0.12.1"
+ , "stylus": "0.13.3"
+ , "socket.io": "0.7.7"
+ , "socket.io-client": "0.7.4"
+ }
+ , "engines": { "node": ">= 0.4.0" }
+}
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (module, io, should) {
+
+ module.exports = {
+
+ 'add listeners': function () {
+ var event = new io.EventEmitter
+ , calls = 0;
+
+ event.on('test', function (a, b) {
+ ++calls;
+ a.should().eql('a');
+ b.should().eql('b');
+ });
+
+ event.emit('test', 'a', 'b');
+ calls.should().eql(1);
+ event.on.should().eql(event.addListener);
+ },
+
+ 'remove listener': function () {
+ var event = new io.EventEmitter;
+ function empty () { }
+
+ event.on('test', empty);
+ event.on('test:more', empty);
+ event.removeAllListeners('test');
+
+ event.listeners('test').should().eql([]);
+ event.listeners('test:more').should().eql([empty]);
+ },
+
+ 'remove all listeners with no arguments': function () {
+ var event = new io.EventEmitter;
+ function empty () { }
+
+ event.on('test', empty);
+ event.on('test:more', empty);
+ event.removeAllListeners();
+
+ // TODO: with node 0.5 we'll change this to expect []
+ event.listeners('test').should().eql([empty]);
+ event.listeners('test:more').should().eql([empty]);
+ },
+
+ 'remove listeners functions': function () {
+ var event = new io.EventEmitter
+ , calls = 0;
+
+ function one () { ++calls }
+ function two () { ++calls }
+ function three () { ++calls }
+
+ event.on('one', one);
+ event.removeListener('one', one);
+ event.listeners('one').should().eql([]);
+
+ event.on('two', two);
+ event.removeListener('two', one);
+ event.listeners('two').should().eql([two]);
+
+ event.on('three', three);
+ event.on('three', two);
+ event.removeListener('three', three);
+ event.listeners('three').should().eql([two]);
+ },
+
+ 'number of arguments': function () {
+ var event = new io.EventEmitter
+ , number = [];
+
+ event.on('test', function () {
+ number.push(arguments.length);
+ });
+
+ event.emit('test');
+ event.emit('test', null);
+ event.emit('test', null, null);
+ event.emit('test', null, null, null);
+ event.emit('test', null, null, null, null);
+ event.emit('test', null, null, null, null, null);
+
+ [0, 1, 2, 3, 4, 5].should().eql(number);
+ },
+
+ 'once': function () {
+ var event = new io.EventEmitter
+ , calls = 0;
+
+ event.once('test', function (a, b) {
+ ++calls;
+ });
+
+ event.emit('test', 'a', 'b');
+ event.emit('test', 'a', 'b');
+ event.emit('test', 'a', 'b');
+
+ function removed () {
+ should().fail('not removed');
+ };
+
+ event.once('test:removed', removed);
+ event.removeListener('test:removed', removed);
+ event.emit('test:removed');
+
+ calls.should().eql(1);
+ }
+
+ };
+
+})(
+ 'undefined' == typeof module ? module = {} : module
+ , 'undefined' == typeof io ? require('socket.io-client') : io
+ , 'undefined' == typeof should || !should.fail ? require('should') : should
+);
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (module, io, should) {
+
+ module.exports = {
+
+ 'client version number': function () {
+ io.version.should().match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);
+ },
+
+ 'socket.io protocol version': function () {
+ io.protocol.should().be.a('number');
+ io.protocol.toString().should().match(/^\d+$/);
+ },
+
+ 'socket.io available transports': function () {
+ (io.transports.length > 0).should().be_true;
+ }
+
+ };
+
+})(
+ 'undefined' == typeof module ? module = {} : module
+ , 'undefined' == typeof io ? require('socket.io-client') : io
+ , 'undefined' == typeof should ? require('should') : should
+);
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+var vm = require('vm')
+ , should = require('should');
+
+/**
+ * Generates evn variables for the vm so we can `emulate` a browser.
+ * @returns {Object} evn variables
+ */
+
+exports.env = function env () {
+ var details = {
+ location: {
+ port: 8080
+ , host: 'www.example.org'
+ , hostname: 'www.example.org'
+ , href: 'http://www.example.org/example/'
+ , pathname: '/example/'
+ , protocol: 'http:'
+ , search: ''
+ , hash: ''
+ }
+ , console: {
+ log: function(){},
+ info: function(){},
+ warn: function(){},
+ error: function(){}
+ }
+ , navigator: {
+ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit'
+ + '/534.27 (KHTML, like Gecko) Chrome/12.0.716.0 Safari/534.27'
+ , appName: 'socket.io'
+ , platform: process.platform
+ , appVersion: process.version
+ , }
+ , name: 'socket.io'
+ , innerWidth: 1024
+ , innerHeight: 768
+ , length: 1
+ , outerWidth: 1024
+ , outerHeight: 768
+ , pageXOffset: 0
+ , pageYOffset: 0
+ , screenX: 0
+ , screenY: 0
+ , screenLeft: 0
+ , screenTop: 0
+ , scrollX: 0
+ , scrollY: 0
+ , scrollTop: 0
+ , scrollLeft: 0
+ , screen: {
+ width: 0
+ , height: 0
+ }
+ };
+
+ // circular references
+ details.window = details.self = details.contentWindow = details;
+
+ // callable methods
+ details.Image = details.scrollTo = details.scrollBy = details.scroll =
+ details.resizeTo = details.resizeBy = details.prompt = details.print =
+ details.open = details.moveTo = details.moveBy = details.focus =
+ details.createPopup = details.confirm = details.close = details.blur =
+ details.alert = details.clearTimeout = details.clearInterval =
+ details.setInterval = details.setTimeout = details.XMLHttpRequest =
+ details.getComputedStyle = details.trigger = details.dispatchEvent =
+ details.removeEventListener = details.addEventListener = function(){};
+
+ // frames
+ details.frames = [details];
+
+ // document
+ details.document = details;
+ details.document.domain = details.location.href;
+
+ return details;
+};
+
+/**
+ * Executes a script in a browser like env and returns
+ * the result
+ *
+ * @param {String} contents The script content
+ * @returns {Object} The evaluated script.
+ */
+
+exports.execute = function execute (contents) {
+ var env = exports.env()
+ , script = vm.createScript(contents);
+
+ // run the script with `browser like` globals
+ script.runInNewContext(env);
+
+ return env;
+};
--- /dev/null
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Test dependencies.
+ */
+
+var builder = require('../../bin/builder')
+ , common = require('./builder.common')
+ , should = require('should');
+
+/**
+ * Tests.
+ */
+
+module.exports = {
+
+ 'version number': function () {
+ builder.version.should().match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);
+ builder.version.should().equal(require('../../lib/io').version);
+ },
+
+ 'production build LOC': function () {
+ builder(function (err, result) {
+ should.strictEqual(err, null)
+
+ var lines = result.split('\n');
+ lines.length.should().be.below(5);
+ lines[0].should().match(/production/gi);
+ Buffer.byteLength(result).should().be.below(41000);
+ });
+ },
+
+ 'development build LOC': function () {
+ builder({ minify: false }, function (err, result) {
+ should.strictEqual(err, null)
+
+ var lines = result.split('\n');
+ lines.length.should().be.above(5);
+ lines[0].should().match(/development/gi);
+ Buffer.byteLength(result).should().be.above(35000);
+ });
+ },
+
+ 'default builds': function () {
+ builder(function (err, result) {
+ should.strictEqual(err, null);
+
+ var io = common.execute(result).io
+ , transports = Object.keys(io.Transport)
+ , defaults = Object.keys(builder.transports);
+
+ /* XHR transport is private, but still available */
+ transports.length.should().be.equal(defaults.length + 1);
+
+ defaults.forEach(function (transport) {
+ transports.indexOf(transport).should().be.above(-1);
+ })
+ });
+ },
+
+ 'custom build': function () {
+ builder(['websocket'], function (err, result) {
+ should.strictEqual(err, null);
+
+ var io = common.execute(result).io
+ , transports = Object.keys(io.Transport);
+
+ transports.should().have.length(1);
+ transports[0].should().eql('websocket');
+ });
+ },
+
+ 'custom code': function () {
+ var custom = 'var hello = "world";';
+ builder({ custom: [custom], minify: false }, function (err, result) {
+ should.strictEqual(err, null);
+
+ result.should().include.string(custom);
+ });
+ },
+
+ 'node if': function () {
+ var custom = '// if node \nvar hello = "world";\n'
+ + '// end node\nvar pew = "pew";';
+
+ builder({ custom: [custom], minify: false }, function (err, result) {
+ should.strictEqual(err, null);
+
+ result.should().not.include.string(custom);
+ result.should().not.include.string('// if node');
+ result.should().not.include.string('// end node');
+ result.should().not.include.string('"world"');
+
+ result.should().include.string('var pew = "pew"');
+ });
+ },
+
+ 'globals': function () {
+ builder(function (err, result) {
+ should.strictEqual(err, null);
+
+ var io = common.execute(result)
+ , env = common.env()
+ , allowed = ['io', 'swfobject', 'WEB_SOCKET_DISABLE_AUTO_INITIALIZATION'];
+
+ Array.prototype.push.apply(allowed, Object.keys(env));
+
+ Object.keys(io).forEach(function (global) {
+ var index = allowed.indexOf(global);
+
+ // the global is not allowed!
+ if (!~index) {
+ throw new Error('Global leak: ' + global);
+ }
+ });
+ })
+ }
+
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (module, io, should) {
+
+ var parser = io.parser;
+
+ module.exports = {
+
+ 'decoding error packet': function () {
+ parser.decodePacket('7:::').should().eql({
+ type: 'error'
+ , reason: ''
+ , advice: ''
+ , endpoint: ''
+ });
+ },
+
+ 'decoding error packet with reason': function () {
+ parser.decodePacket('7:::0').should().eql({
+ type: 'error'
+ , reason: 'transport not supported'
+ , advice: ''
+ , endpoint: ''
+ });
+ },
+
+ 'decoding error packet with reason and advice': function () {
+ parser.decodePacket('7:::2+0').should().eql({
+ type: 'error'
+ , reason: 'unauthorized'
+ , advice: 'reconnect'
+ , endpoint: ''
+ });
+ },
+
+ 'decoding error packet with endpoint': function () {
+ parser.decodePacket('7::/woot').should().eql({
+ type: 'error'
+ , reason: ''
+ , advice: ''
+ , endpoint: '/woot'
+ });
+ },
+
+ 'decoding ack packet': function () {
+ parser.decodePacket('6:::140').should().eql({
+ type: 'ack'
+ , ackId: '140'
+ , endpoint: ''
+ , args: []
+ });
+ },
+
+ 'decoding ack packet with args': function () {
+ parser.decodePacket('6:::12+["woot","wa"]').should().eql({
+ type: 'ack'
+ , ackId: '12'
+ , endpoint: ''
+ , args: ['woot', 'wa']
+ });
+ },
+
+ 'decoding ack packet with bad json': function () {
+ var thrown = false;
+
+ try {
+ parser.decodePacket('6:::1+{"++]').should().eql({
+ type: 'ack'
+ , ackId: '1'
+ , endpoint: ''
+ , args: []
+ });
+ } catch (e) {
+ thrown = true;
+ }
+
+ thrown.should().be_false;
+ },
+
+ 'decoding json packet': function () {
+ parser.decodePacket('4:::"2"').should().eql({
+ type: 'json'
+ , endpoint: ''
+ , data: '2'
+ });
+ },
+
+ 'decoding json packet with message id and ack data': function () {
+ parser.decodePacket('4:1+::{"a":"b"}').should().eql({
+ type: 'json'
+ , id: 1
+ , ack: 'data'
+ , endpoint: ''
+ , data: { a: 'b' }
+ });
+ },
+
+ 'decoding an event packet': function () {
+ parser.decodePacket('5:::{"name":"woot"}').should().eql({
+ type: 'event'
+ , name: 'woot'
+ , endpoint: ''
+ , args: []
+ });
+ },
+
+ 'decoding an event packet with message id and ack': function () {
+ parser.decodePacket('5:1+::{"name":"tobi"}').should().eql({
+ type: 'event'
+ , id: 1
+ , ack: 'data'
+ , endpoint: ''
+ , name: 'tobi'
+ , args: []
+ });
+ },
+
+ 'decoding an event packet with data': function () {
+ parser.decodePacket('5:::{"name":"edwald","args":[{"a": "b"},2,"3"]}')
+ .should().eql({
+ type: 'event'
+ , name: 'edwald'
+ , endpoint: ''
+ , args: [{a: 'b'}, 2, '3']
+ });
+ },
+
+ 'decoding a message packet': function () {
+ parser.decodePacket('3:::woot').should().eql({
+ type: 'message'
+ , endpoint: ''
+ , data: 'woot'
+ });
+ },
+
+ 'decoding a message packet with id and endpoint': function () {
+ parser.decodePacket('3:5:/tobi').should().eql({
+ type: 'message'
+ , id: 5
+ , ack: true
+ , endpoint: '/tobi'
+ , data: ''
+ });
+ },
+
+ 'decoding a heartbeat packet': function () {
+ parser.decodePacket('2:::').should().eql({
+ type: 'heartbeat'
+ , endpoint: ''
+ });
+ },
+
+ 'decoding a connection packet': function () {
+ parser.decodePacket('1::/tobi').should().eql({
+ type: 'connect'
+ , endpoint: '/tobi'
+ , qs: ''
+ });
+ },
+
+ 'decoding a connection packet with query string': function () {
+ parser.decodePacket('1::/test:?test=1').should().eql({
+ type: 'connect'
+ , endpoint: '/test'
+ , qs: '?test=1'
+ });
+ },
+
+ 'decoding a disconnection packet': function () {
+ parser.decodePacket('0::/woot').should().eql({
+ type: 'disconnect'
+ , endpoint: '/woot'
+ });
+ },
+
+ 'encoding error packet': function () {
+ parser.encodePacket({
+ type: 'error'
+ , reason: ''
+ , advice: ''
+ , endpoint: ''
+ }).should().eql('7::');
+ },
+
+ 'encoding error packet with reason': function () {
+ parser.encodePacket({
+ type: 'error'
+ , reason: 'transport not supported'
+ , advice: ''
+ , endpoint: ''
+ }).should().eql('7:::0');
+ },
+
+ 'encoding error packet with reason and advice': function () {
+ parser.encodePacket({
+ type: 'error'
+ , reason: 'unauthorized'
+ , advice: 'reconnect'
+ , endpoint: ''
+ }).should().eql('7:::2+0');
+ },
+
+ 'encoding error packet with endpoint': function () {
+ parser.encodePacket({
+ type: 'error'
+ , reason: ''
+ , advice: ''
+ , endpoint: '/woot'
+ }).should().eql('7::/woot');
+ },
+
+ 'encoding ack packet': function () {
+ parser.encodePacket({
+ type: 'ack'
+ , ackId: '140'
+ , endpoint: ''
+ , args: []
+ }).should().eql('6:::140');
+ },
+
+ 'encoding ack packet with args': function () {
+ parser.encodePacket({
+ type: 'ack'
+ , ackId: '12'
+ , endpoint: ''
+ , args: ['woot', 'wa']
+ }).should().eql('6:::12+["woot","wa"]');
+ },
+
+ 'encoding json packet': function () {
+ parser.encodePacket({
+ type: 'json'
+ , endpoint: ''
+ , data: '2'
+ }).should().eql('4:::"2"');
+ },
+
+ 'encoding json packet with message id and ack data': function () {
+ parser.encodePacket({
+ type: 'json'
+ , id: 1
+ , ack: 'data'
+ , endpoint: ''
+ , data: { a: 'b' }
+ }).should().eql('4:1+::{"a":"b"}');
+ },
+
+ 'encoding an event packet': function () {
+ parser.encodePacket({
+ type: 'event'
+ , name: 'woot'
+ , endpoint: ''
+ , args: []
+ }).should().eql('5:::{"name":"woot"}');
+ },
+
+ 'encoding an event packet with message id and ack': function () {
+ parser.encodePacket({
+ type: 'event'
+ , id: 1
+ , ack: 'data'
+ , endpoint: ''
+ , name: 'tobi'
+ , args: []
+ }).should().eql('5:1+::{"name":"tobi"}');
+ },
+
+ 'encoding an event packet with data': function () {
+ parser.encodePacket({
+ type: 'event'
+ , name: 'edwald'
+ , endpoint: ''
+ , args: [{a: 'b'}, 2, '3']
+ }).should().eql('5:::{"name":"edwald","args":[{"a":"b"},2,"3"]}');
+ },
+
+ 'encoding a message packet': function () {
+ parser.encodePacket({
+ type: 'message'
+ , endpoint: ''
+ , data: 'woot'
+ }).should().eql('3:::woot');
+ },
+
+ 'encoding a message packet with id and endpoint': function () {
+ parser.encodePacket({
+ type: 'message'
+ , id: 5
+ , ack: true
+ , endpoint: '/tobi'
+ , data: ''
+ }).should().eql('3:5:/tobi');
+ },
+
+ 'encoding a heartbeat packet': function () {
+ parser.encodePacket({
+ type: 'heartbeat'
+ , endpoint: ''
+ }).should().eql('2::');
+ },
+
+ 'encoding a connection packet': function () {
+ parser.encodePacket({
+ type: 'connect'
+ , endpoint: '/tobi'
+ , qs: ''
+ }).should().eql('1::/tobi');
+ },
+
+ 'encoding a connection packet with query string': function () {
+ parser.encodePacket({
+ type: 'connect'
+ , endpoint: '/test'
+ , qs: '?test=1'
+ }).should().eql('1::/test:?test=1');
+ },
+
+ 'encoding a disconnection packet': function () {
+ parser.encodePacket({
+ type: 'disconnect'
+ , endpoint: '/woot'
+ }).should().eql('0::/woot');
+ },
+
+ 'test decoding a payload': function () {
+ parser.decodePayload('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d'
+ + '\ufffd3\ufffd0::').should().eql([
+ { type: 'message', data: '5', endpoint: '' }
+ , { type: 'message', data: '53d', endpoint: '' }
+ , { type: 'disconnect', endpoint: '' }
+ ]);
+ },
+
+ 'test encoding a payload': function () {
+ parser.encodePayload([
+ parser.encodePacket({ type: 'message', data: '5', endpoint: '' })
+ , parser.encodePacket({ type: 'message', data: '53d', endpoint: '' })
+ ]).should().eql('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d')
+ }
+
+ };
+
+})(
+ 'undefined' == typeof module ? module = {} : module
+ , 'undefined' == typeof io ? require('socket.io-client') : io
+ , 'undefined' == typeof should ? require('should') : should
+);
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (module, io, should) {
+
+ if ('object' == typeof global) {
+ return module.exports = { '': function () {} };
+ }
+
+ module.exports = {
+
+ 'test connecting the socket and disconnecting': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('connect', function () {
+ socket.disconnect();
+ next();
+ });
+ },
+
+ 'test receiving messages': function (next) {
+ var socket = create()
+ , connected = false
+ , messages = 0;
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('connect', function () {
+ connected = true;
+ });
+
+ socket.on('message', function (i) {
+ String(++messages).should().equal(i);
+ });
+
+ socket.on('disconnect', function (reason) {
+ connected.should().be_true;
+ messages.should().equal(3);
+ reason.should().eql('booted');
+ next();
+ });
+ },
+
+ 'test sending messages': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('connect', function () {
+ socket.send('echo');
+
+ socket.on('message', function (msg) {
+ msg.should().equal('echo');
+ socket.disconnect();
+ next();
+ });
+ });
+ },
+
+ 'test acks sent from client': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('connect', function () {
+ socket.on('message', function (msg) {
+ if ('tobi 2' == msg) {
+ socket.disconnect();
+ next();
+ }
+ });
+ });
+ },
+
+ 'test acks sent from server': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('connect', function () {
+ socket.send('ooo', function () {
+ socket.disconnect();
+ next();
+ });
+ });
+ },
+
+ 'test connecting to namespaces': function (next) {
+ var io = create()
+ , socket = io.socket
+ , namespaces = 2
+ , connect = 0;
+
+ function finish () {
+ socket.of('').disconnect();
+ connect.should().equal(3);
+ next();
+ }
+
+ io.on('connect', function(){
+ connect++;
+ });
+
+ socket.of('/woot').on('connect', function () {
+ connect++;
+ }).on('message', function (msg) {
+ msg.should().equal('connected to woot');
+ --namespaces || finish();
+ }).on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.of('/chat').on('connect', function () {
+ connect++;
+ }).on('message', function (msg) {
+ msg.should().equal('connected to chat');
+ --namespaces || finish();
+ }).on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ },
+
+ 'test different namespace connection methods': function (next) {
+ var io = create('/a')
+ , connect = 0
+ , message = 0
+ , socket = io.socket;
+
+ function finish () {
+ socket.of('').disconnect();
+ connect.should().equal(3);
+ message.should().equal(3);
+ next();
+ }
+
+ io.on('connect', function () {
+ ++connect;
+ }).on('message', function (data) {
+ data.should().eql('a');
+
+ if (++message === 3) finish();
+ }).on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.of('/b').on('connect', function () {
+ ++connect;
+ }).on('message', function (data) {
+ data.should().eql('b');
+
+ if (++message === 3) finish();
+ }).on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ io.of('/c').on('connect', function () {
+ ++connect;
+ }).on('message', function (data) {
+ data.should().eql('c');
+
+ if (++message === 3) finish();
+ }).on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ },
+
+ 'test disconnecting from namespaces': function (next) {
+ var socket = create().socket
+ , namespaces = 2
+ , disconnections = 0;
+
+ function finish () {
+ socket.of('').disconnect();
+ next();
+ };
+
+ socket.of('/a').on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.of('/a').on('connect', function () {
+ socket.of('/a').disconnect();
+ });
+
+ socket.of('/a').on('disconnect', function () {
+ --namespaces || finish();
+ });
+
+ socket.of('/b').on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.of('/b').on('connect', function () {
+ socket.of('/b').disconnect();
+ });
+
+ socket.of('/b').on('disconnect', function () {
+ --namespaces || finish();
+ });
+ },
+
+ 'test authorizing for namespaces': function (next) {
+ var socket = create().socket
+
+ function finish () {
+ socket.of('').disconnect();
+ next();
+ };
+
+ socket.of('/a')
+ .on('connect_failed', function (msg) {
+ next();
+ })
+ .on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+ },
+
+ 'test sending json from server': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('message', function (msg) {
+ msg.should().eql(3141592);
+ socket.disconnect();
+ next();
+ });
+ },
+
+ 'test sending json from client': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.json.send([1, 2, 3]);
+ socket.on('message', function (msg) {
+ msg.should().equal('echo');
+ socket.disconnect();
+ next();
+ });
+ },
+
+ 'test emitting an event from server': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('woot', function () {
+ socket.disconnect();
+ next();
+ });
+ },
+
+ 'test emitting an event to server': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.emit('woot');
+ socket.on('echo', function () {
+ socket.disconnect();
+ next();
+ })
+ },
+
+ 'test emitting an event from server and sending back data': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.on('woot', function (a, fn) {
+ a.should().eql(1);
+ fn('test');
+
+ socket.on('done', function () {
+ socket.disconnect();
+ next();
+ });
+ });
+ },
+
+ 'test emitting an event to server and sending back data': function (next) {
+ var socket = create();
+
+ socket.on('error', function (msg) {
+ throw new Error(msg || 'Received an error');
+ });
+
+ socket.emit('tobi', 1, 2, function (a) {
+ a.should().eql({ hello: 'world' });
+ socket.disconnect();
+ next();
+ });
+ }
+
+ };
+
+})(
+ 'undefined' == typeof module ? module = {} : module
+ , 'undefined' == typeof io ? require('socket.io-client') : io
+ , 'undefined' == typeof should ? require('should-browser') : should
+);
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+(function (module, io, should) {
+
+ module.exports = {
+
+ 'parse uri': function () {
+ var http = io.util.parseUri('http://google.com')
+ , https = io.util.parseUri('https://www.google.com:80')
+ , query = io.util.parseUri('google.com:8080/foo/bar?foo=bar');
+
+ http.protocol.should().eql('http');
+ http.port.should().eql('');
+ http.host.should().eql('google.com');
+ https.protocol.should().eql('https');
+ https.port.should().eql('80');
+ https.host.should().eql('www.google.com');
+ query.port.should().eql('8080');
+ query.query.should().eql('foo=bar');
+ query.path.should().eql('/foo/bar');
+ query.relative.should().eql('/foo/bar?foo=bar');
+ },
+
+ 'unique uri': function () {
+ var protocol = io.util.parseUri('http://google.com')
+ , noprotocol = io.util.parseUri('google.com')
+ , https = io.util.parseUri('https://google.com')
+ , path = io.util.parseUri('https://google.com/google.com/com/?foo=bar');
+
+ if ('object' == typeof window) {
+ io.util.uniqueUri(protocol).should().eql('http://google.com:3000');
+ io.util.uniqueUri(noprotocol).should().eql('http://google.com:3000');
+ } else {
+ io.util.uniqueUri(protocol).should().eql('http://google.com:80');
+ io.util.uniqueUri(noprotocol).should().eql('http://google.com:80');
+ }
+
+ io.util.uniqueUri(https).should().eql('https://google.com:443');
+ io.util.uniqueUri(path).should().eql('https://google.com:443');
+ },
+
+ 'request': function () {
+ if ('undefined' == typeof window) {
+ should.equal(io.util.request(), null);
+ } else {
+ io.util.request().should().be.a('object');
+ }
+ },
+
+ 'is array': function () {
+ io.util.isArray([]).should().be_true;
+ io.util.isArray({}).should().be_false;
+ io.util.isArray('str').should().be_false;
+ io.util.isArray(new Date).should().be_false;
+ io.util.isArray(true).should().be_false;
+ io.util.isArray(arguments).should().be_false;
+ },
+
+ 'merge, deep merge': function () {
+ var start = {
+ foo: 'bar'
+ , bar: 'baz'
+ }
+ , duplicate = {
+ foo: 'foo'
+ , bar: 'bar'
+ }
+ , extra = {
+ ping: 'pong'
+ }
+ , deep = {
+ level1:{
+ foo: 'bar'
+ , level2: {
+ foo: 'bar'
+ , level3:{
+ foo: 'bar'
+ , rescursive: deep
+ }
+ }
+ }
+ }
+ // same structure, but changed names
+ , deeper = {
+ foo: 'bar'
+ , level1:{
+ foo: 'baz'
+ , level2: {
+ foo: 'foo'
+ , level3:{
+ foo: 'pewpew'
+ , rescursive: deep
+ }
+ }
+ }
+ };
+
+ io.util.merge(start, duplicate);
+
+ start.foo.should().eql('foo');
+ start.bar.should().eql('bar');
+
+ io.util.merge(start, extra);
+ start.ping.should().eql('pong');
+ start.foo.should().eql('foo');
+
+ io.util.merge(deep, deeper);
+
+ deep.foo.should().eql('bar');
+ deep.level1.foo.should().eql('baz');
+ deep.level1.level2.foo.should().eql('foo');
+ deep.level1.level2.level3.foo.should().eql('pewpew');
+ },
+
+ 'defer': function (next) {
+ var now = +new Date;
+
+ io.util.defer(function () {
+ ((new Date - now) >= ( io.util.webkit ? 100 : 0 )).should().be_true();
+ next();
+ })
+ },
+
+ 'indexOf': function () {
+ var data = ['socket', 2, 3, 4, 'socket', 5, 6, 7, 'io'];
+ io.util.indexOf(data, 'socket', 1).should().eql(4);
+ io.util.indexOf(data, 'socket').should().eql(0);
+ io.util.indexOf(data, 'waffles').should().eql(-1);
+ }
+
+ };
+
+})(
+ 'undefined' == typeof module ? module = {} : module
+ , 'undefined' == typeof io ? require('socket.io-client') : io
+ , 'undefined' == typeof should ? require('should') : should
+);
--- /dev/null
+.DS_Store
+lib-cov
+*.seed
+*.log
+*.csv
+*.dat
+*.out
+*.pid
+node_modules
--- /dev/null
+support
+test
+examples
--- /dev/null
+
+0.7.7 / 2011-07-12
+==================
+
+ * Fixed double dispatch handling with emit to closed clients.
+ * Added test for emitting to closed clients to prevent regression.
+ * Fixed race condition in redis test.
+ * Changed Transport#end instrumentation.
+ * Leveraged $emit instead of emit internally.
+ * Made tests faster.
+ * Fixed double disconnect events.
+ * Fixed disconnect logic
+ * Simplified remote events handling in Socket.
+ * Increased testcase timeout.
+ * Fixed unknown room emitting (GH-291). [3rd-Eden]
+ * Fixed `address` in handshakeData. [3rd-Eden]
+ * Removed transports definition in chat example.
+ * Fixed room cleanup
+ * Fixed; make sure the client is cleaned up after booting.
+ * Make sure to mark the client as non-open if the connection is closed.
+ * Removed unneeded `buffer` declarations.
+ * Fixed; make sure to clear socket handlers and subscriptions upon transport close.
+
+0.7.6 / 2011-06-30
+==================
+
+ * Fixed general dispatching when a client has closed.
+
+0.7.5 / 2011-06-30
+==================
+
+ * Fixed dispatching to clients that are disconnected.
+
+0.7.4 / 2011-06-30
+==================
+
+ * Fixed; only clear handlers if they were set. [level09]
+
+0.7.3 / 2011-06-30
+==================
+
+ * Exposed handshake data to clients.
+ * Refactored dispatcher interface.
+ * Changed; Moved id generation method into the manager.
+ * Added sub-namespace authorization. [3rd-Eden]
+ * Changed; normalized SocketNamespace local eventing [dvv]
+ * Changed; Use packet.reason or default to 'packet' [3rd-Eden]
+ * Changed console.error to console.log.
+ * Fixed; bind both servers at the same time do that the test never times out.
+ * Added 304 support.
+ * Removed `Transport#name` for abstract interface.
+ * Changed; lazily require http and https module only when needed. [3rd-Eden]
+
+0.7.2 / 2011-06-22
+==================
+
+ * Make sure to write a packet (of type `noop`) when closing a poll.
+ This solves a problem with cross-domain requests being flagged as aborted and
+ reconnection being triggered.
+ * Added `noop` message type.
+
+0.7.1 / 2011-06-21
+==================
+
+ * Fixed cross-domain XHR.
+ * Added CORS test to xhr-polling suite.
+
+0.7.0 / 2010-06-21
+==================
+
+ * http://socket.io/announcement.html
--- /dev/null
+
+ALL_TESTS = $(shell find test/ -name '*.test.js')
+
+run-tests:
+ @npm link > /dev/null --local
+ @./node_modules/.bin/expresso \
+ -t 3000 \
+ -I support \
+ -I lib \
+ --serial \
+ $(TESTFLAGS) \
+ $(TESTS)
+
+test:
+ @$(MAKE) TESTS="$(ALL_TESTS)" run-tests
+
+test-cov:
+ @TESTFLAGS=--cov $(MAKE) test
+
+.PHONY: test
--- /dev/null
+# Socket.IO
+
+Socket.IO is a Node.JS project that makes WebSockets and realtime possible in
+all browsers. It also enhances WebSockets by providing built-in multiplexing,
+horizontal scalability, automatic JSON encoding/decoding, and more.
+
+## How to Install
+
+ npm install socket.io
+
+## How to use
+
+First, require `socket.io`:
+
+```js
+var io = require('socket.io');
+```
+
+Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express`
+web framework:
+
+```js
+var app = express.createServer();
+ , io = io.listen(app);
+
+app.listen(80);
+
+io.sockets.on('connection', function (socket) {
+ socket.emit('news', { hello: 'world' });
+ socket.on('my other event', function (data) {
+ console.log(data);
+ });
+});
+```
+
+Finally, load it from the client side code:
+
+```html
+<script src="/socket.io/socket.io.js"></script>
+<script>
+ var socket = io.connect('http://localhost');
+ socket.on('news', function (data) {
+ console.log(data);
+ socket.emit('my other event', { my: 'data' });
+ });
+</script>
+```
+
+For more thorough examples, look at the `examples/` directory.
+
+## Short recipes
+
+### Sending and receiving events.
+
+Socket.IO allows you to emit and receive custom events.
+Besides `connect`, `message` and `disconnect`, you can emit custom events:
+
+```js
+// note, io.listen(<port>) will create a http server for you
+var io = require('socket.io').listen(80);
+
+io.sockets.on('connection', function (socket) {
+ io.sockets.emit('this', { will: 'be received by everyone');
+
+ socket.on('private message', function (from, msg) {
+ console.log('I received a private message by ', from, ' saying ', msg);
+ });
+
+ socket.on('disconnect', function () {
+ sockets.emit('user disconnected');
+ });
+});
+```
+
+### Storing data associated to a client
+
+Sometimes it's necessary to store data associated with a client that's
+necessary for the duration of the session.
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+io.sockets.on('connection', function (socket) {
+ socket.on('set nickname', function (name) {
+ socket.set('nickname', name, function () { socket.emit('ready'); });
+ });
+
+ socket.on('msg', function () {
+ socket.get('nickname', function (err, name) {
+ console.log('Chat message by ', name);
+ });
+ });
+});
+```
+
+#### Client side
+
+```html
+<script>
+ var socket = io.connect('http://localhost');
+
+ socket.on('connect', function () {
+ socket.emit('set nickname', confirm('What is your nickname?'));
+ socket.on('ready', function () {
+ console.log('Connected !');
+ socket.emit('msg', confirm('What is your message?'));
+ });
+ });
+</script>
+```
+
+### Restricting yourself to a namespace
+
+If you have control over all the messages and events emitted for a particular
+application, using the default `/` namespace works.
+
+If you want to leverage 3rd-party code, or produce code to share with others,
+socket.io provides a way of namespacing a `socket`.
+
+This has the benefit of `multiplexing` a single connection. Instead of
+socket.io using two `WebSocket` connections, it'll use one.
+
+The following example defines a socket that listens on '/chat' and one for
+'/news':
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+var chat = io
+ .of('/chat');
+ .on('connection', function (socket) {
+ socket.emit('a message', { that: 'only', '/chat': 'will get' });
+ chat.emit('a message', { everyone: 'in', '/chat': 'will get' });
+ });
+
+var news = io
+ .of('/news');
+ .on('connection', function (socket) {
+ socket.emit('item', { news: 'item' });
+ });
+```
+
+#### Client side:
+
+```html
+<script>
+ var chat = io.connect('http://localhost/chat')
+ , news = io.connect('http://localhost/news');
+
+ chat.on('connect', function () {
+ chat.emit('hi!');
+ });
+
+ news.on('news', function () {
+ news.emit('woot');
+ });
+</script>
+```
+
+### Sending volatile messages.
+
+Sometimes certain messages can be dropped. Let's say you have an app that
+shows realtime tweets for the keyword `bieber`.
+
+If a certain client is not ready to receive messages (because of network slowness
+or other issues, or because he's connected through long polling and is in the
+middle of a request-response cycle), if he doesn't receive ALL the tweets related
+to bieber your application won't suffer.
+
+In that case, you might want to send those messages as volatile messages.
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+io.sockets.on('connection', function (socket) {
+ var tweets = setInterval(function () {
+ getBieberTweet(function (tweet) {
+ socket.volatile.emit('bieber tweet', tweet);
+ });
+ }, 100);
+
+ socket.on('disconnect', function () {
+ clearInterval(tweets);
+ });
+});
+```
+
+#### Client side
+
+In the client side, messages are received the same way whether they're volatile
+or not.
+
+### Getting acknowledgements
+
+Sometimes, you might want to get a callback when the client confirmed the message
+reception.
+
+To do this, simply pass a function as the last parameter of `.send` or `.emit`.
+What's more, when you use `.emit`, the acknowledgement is done by you, which
+means you can also pass data along:
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+io.sockets.on('connection', function (socket) {
+ socket.on('ferret', function (name, fn) {
+ fn('woot');
+ });
+});
+```
+
+#### Client side
+
+```html
+<script>
+ var socket = io.connect(); // TIP: .connect with no args does auto-discovery
+ socket.on('connection', function () {
+ socket.emit('ferret', 'tobi', function (data) {
+ console.log(data); // data will be 'woot'
+ });
+ });
+</script>
+```
+
+### Broadcasting messages
+
+To broadcast, simply add a `broadcast` flag to `emit` and `send` method calls.
+Broadcasting means sending a message to everyone else except for the socket
+that starts it.
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+io.sockets.on('connection', function (socket) {
+ socket.broadcast.emit('user connected');
+ socket.broadcast.json.send({ a: 'message' });
+});
+```
+
+### Rooms
+
+Sometimes you want to put certain sockets in the same room, so that it's easy
+to broadcast to all of them together.
+
+Think of this as built-in channels for sockets. Sockets `join` and `leave`
+rooms in each socket.
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+io.sockets.on('connection', function (socket) {
+ socket.join('justin bieber fans');
+ socket.broadcast.to('justin bieber fans').emit('new fan');
+ io.sockets.in('rammstein fans').emit('new non-fan');
+});
+```
+
+### Using it just as a cross-browser WebSocket
+
+If you just want the WebSocket semantics, you can do that too.
+Simply leverage `send` and listen on the `message` event:
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+io.sockets.on('connection', function (socket) {
+ socket.on('message', function () { });
+ socket.on('disconnect', function () { });
+});
+```
+
+#### Client side
+
+```html
+<script>
+ var socket = io.connect('http://localhost/');
+ socket.on('connect', function () {
+ socket.send('hi');
+
+ socket.on('message', function (msg) {
+ // my msg
+ });
+ });
+</script>
+```
+
+### Changing configuration
+
+Configuration in socket.io is TJ-style:
+
+#### Server side
+
+```js
+var io = require('socket.io').listen(80);
+
+io.configure(function () {
+ io.set('transports', ['websocket', 'flashsocket', 'xhr-polling']);
+});
+
+io.configure('development', function () {
+ io.set('transports', ['websocket', 'xhr-polling']);
+ io.enable('log');
+});
+```
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>
+
+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', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+Initialize the Socket object upon handshake.
+Pass it to authorization function(s).
+When a transport opens, publish the transport name with the 'open' channel
+Set the transport name to the Socket object.
+Upon handshake, set a timeout of x seconds to GC that Socket object.
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+module.exports = require('./lib/socket.io');
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var util = require('./util')
+ , toArray = util.toArray;
+
+/**
+ * Log levels.
+ */
+
+var levels = [
+ 'error'
+ , 'warn'
+ , 'info'
+ , 'debug'
+];
+
+/**
+ * Colors for log levels.
+ */
+
+var colors = [
+ 31
+ , 33
+ , 36
+ , 90
+];
+
+/**
+ * Pads the nice output to the longest log level.
+ */
+
+function pad (str) {
+ var max = 0;
+
+ for (var i = 0, l = levels.length; i < l; i++)
+ max = Math.max(max, levels[i].length);
+
+ if (str.length < max)
+ return str + new Array(max - str.length + 1).join(' ');
+
+ return str;
+};
+
+/**
+ * Logger (console).
+ *
+ * @api public
+ */
+
+var Logger = module.exports = function (opts) {
+ opts = opts || {}
+ this.colors = false !== opts.colors;
+ this.level = 3;
+};
+
+/**
+ * Log method.
+ *
+ * @api public
+ */
+
+Logger.prototype.log = function (type) {
+ var index = levels.indexOf(type);
+
+ if (index > this.level)
+ return this;
+
+ console.log.apply(
+ console
+ , [this.colors
+ ? ' \033[' + colors[index] + 'm' + pad(type) + ' -\033[39m'
+ : type + ':'
+ ].concat(toArray(arguments).slice(1))
+ );
+
+ return this;
+};
+
+/**
+ * Generate methods.
+ */
+
+levels.forEach(function (name) {
+ Logger.prototype[name] = function () {
+ this.log.apply(this, [name].concat(toArray(arguments)));
+ };
+});
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var http = require('http')
+ , https = require('https')
+ , fs = require('fs')
+ , url = require('url')
+ , util = require('./util')
+ , store = require('./store')
+ , client = require('socket.io-client')
+ , transports = require('./transports')
+ , Logger = require('./logger')
+ , Socket = require('./socket')
+ , MemoryStore = require('./stores/memory')
+ , SocketNamespace = require('./namespace')
+ , EventEmitter = process.EventEmitter;
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = Manager;
+
+/**
+ * Default transports.
+ */
+
+var defaultTransports = exports.defaultTransports = [
+ 'websocket'
+ , 'htmlfile'
+ , 'xhr-polling'
+ , 'jsonp-polling'
+];
+
+/**
+ * Inherited defaults.
+ */
+
+var parent = module.parent.exports
+ , protocol = parent.protocol;
+
+/**
+ * Manager constructor.
+ *
+ * @param {HTTPServer} server
+ * @param {Object} options, optional
+ * @api public
+ */
+
+function Manager (server) {
+ this.server = server;
+ this.namespaces = {};
+ this.sockets = this.of('');
+ this.settings = {
+ origins: '*:*'
+ , log: true
+ , store: new MemoryStore
+ , logger: new Logger
+ , heartbeats: true
+ , resource: '/socket.io'
+ , transports: defaultTransports
+ , authorization: false
+ , 'log level': 3
+ , 'close timeout': 25
+ , 'heartbeat timeout': 15
+ , 'heartbeat interval': 20
+ , 'polling duration': 20
+ , 'flash policy server': true
+ , 'flash policy port': 843
+ , 'destroy upgrade': true
+ , 'browser client': true
+ , 'browser client minification': false
+ , 'browser client etag': false
+ , 'browser client handler': false
+ , 'client store expiration': 15
+ };
+
+ this.initStore();
+
+ // reset listeners
+ this.oldListeners = server.listeners('request');
+ server.removeAllListeners('request');
+
+ var self = this;
+
+ server.on('request', function (req, res) {
+ self.handleRequest(req, res);
+ });
+
+ server.on('upgrade', function (req, socket, head) {
+ self.handleUpgrade(req, socket, head);
+ });
+
+ for (var i in transports) {
+ if (transports[i].init) {
+ transports[i].init(this);
+ }
+ }
+
+ this.log.info('socket.io started');
+};
+
+Manager.prototype.__proto__ = EventEmitter.prototype
+
+/**
+ * Store accessor shortcut.
+ *
+ * @api public
+ */
+
+Manager.prototype.__defineGetter__('store', function () {
+ var store = this.get('store');
+ store.manager = this;
+ return store;
+});
+
+/**
+ * Logger accessor.
+ *
+ * @api public
+ */
+
+Manager.prototype.__defineGetter__('log', function () {
+ if (this.disabled('log')) return;
+
+ var logger = this.get('logger');
+ logger.level = this.get('log level');
+
+ return logger;
+});
+
+/**
+ * Get settings.
+ *
+ * @api public
+ */
+
+Manager.prototype.get = function (key) {
+ return this.settings[key];
+};
+
+/**
+ * Set settings
+ *
+ * @api public
+ */
+
+Manager.prototype.set = function (key, value) {
+ if (arguments.length == 1) return this.get(key);
+ this.settings[key] = value;
+ this.emit('set:' + key, this.settings[key], key);
+ return this;
+};
+
+/**
+ * Enable a setting
+ *
+ * @api public
+ */
+
+Manager.prototype.enable = function (key) {
+ this.settings[key] = true;
+ this.emit('set:' + key, this.settings[key], key);
+ return this;
+};
+
+/**
+ * Disable a setting
+ *
+ * @api public
+ */
+
+Manager.prototype.disable = function (key) {
+ this.settings[key] = false;
+ this.emit('set:' + key, this.settings[key], key);
+ return this;
+};
+
+/**
+ * Checks if a setting is enabled
+ *
+ * @api public
+ */
+
+Manager.prototype.enabled = function (key) {
+ return !!this.settings[key];
+};
+
+/**
+ * Checks if a setting is disabled
+ *
+ * @api public
+ */
+
+Manager.prototype.disabled = function (key) {
+ return !this.settings[key];
+};
+
+/**
+ * Configure callbacks.
+ *
+ * @api public
+ */
+
+Manager.prototype.configure = function (env, fn) {
+ if ('function' == typeof env) {
+ env.call(this);
+ } else if (env == process.env.NODE_ENV) {
+ fn.call(this);
+ }
+
+ return this;
+};
+
+/**
+ * Initializes everything related to the message dispatcher.
+ *
+ * @api private
+ */
+
+Manager.prototype.initStore = function () {
+ this.handshaken = {};
+ this.connected = {};
+ this.open = {};
+ this.closed = {};
+ this.closedA = [];
+ this.rooms = {};
+ this.roomClients = {};
+
+ var self = this;
+
+ this.store.subscribe('handshake', function (id, data) {
+ self.onHandshake(id, data);
+ });
+
+ this.store.subscribe('connect', function (id) {
+ self.onConnect(id);
+ });
+
+ this.store.subscribe('open', function (id) {
+ self.onOpen(id);
+ });
+
+ this.store.subscribe('join', function (id, room) {
+ self.onJoin(id, room);
+ });
+
+ this.store.subscribe('leave', function (id, room) {
+ self.onLeave(id, room);
+ });
+
+ this.store.subscribe('close', function (id) {
+ self.onClose(id);
+ });
+
+ this.store.subscribe('dispatch', function (room, packet, volatile, exceptions) {
+ self.onDispatch(room, packet, volatile, exceptions);
+ });
+
+ this.store.subscribe('disconnect', function (id) {
+ self.onDisconnect(id);
+ });
+};
+
+/**
+ * Called when a client handshakes.
+ *
+ * @param text
+ */
+
+Manager.prototype.onHandshake = function (id, data) {
+ this.handshaken[id] = data;
+};
+
+/**
+ * Called when a client connects (ie: transport first opens)
+ *
+ * @api private
+ */
+
+Manager.prototype.onConnect = function (id) {
+ this.connected[id] = true;
+};
+
+/**
+ * Called when a client opens a request in a different node.
+ *
+ * @api private
+ */
+
+Manager.prototype.onOpen = function (id) {
+ this.open[id] = true;
+
+ // if we were buffering messages for the client, clear them
+ if (this.closed[id]) {
+ var self = this;
+
+ this.closedA.splice(this.closedA.indexOf(id), 1);
+
+ this.store.unsubscribe('dispatch:' + id, function () {
+ delete self.closed[id];
+ });
+ }
+
+ // clear the current transport
+ if (this.transports[id]) {
+ this.transports[id].discard();
+ this.transports[id] = null;
+ }
+};
+
+/**
+ * Called when a message is sent to a namespace and/or room.
+ *
+ * @api private
+ */
+
+Manager.prototype.onDispatch = function (room, packet, volatile, exceptions) {
+ if (this.rooms[room]) {
+ for (var i = 0, l = this.rooms[room].length; i < l; i++) {
+ var id = this.rooms[room][i];
+
+ if (!~exceptions.indexOf(id)) {
+ if (this.transports[id] && this.transports[id].open) {
+ this.transports[id].onDispatch(packet, volatile);
+ } else if (!volatile) {
+ this.onClientDispatch(id, packet);
+ }
+ }
+ }
+ }
+};
+
+/**
+ * Called when a client joins a nsp / room.
+ *
+ * @api private
+ */
+
+Manager.prototype.onJoin = function (id, name) {
+ if (!this.roomClients[id]) {
+ this.roomClients[id] = [];
+ }
+
+ if (!this.rooms[name]) {
+ this.rooms[name] = [];
+ }
+
+ this.rooms[name].push(id);
+ this.roomClients[id][name] = true;
+};
+
+/**
+ * Called when a client leaves a nsp / room.
+ *
+ * @param private
+ */
+
+Manager.prototype.onLeave = function (id, room) {
+ if (this.rooms[room]) {
+ this.rooms[room].splice(this.rooms[room].indexOf(id), 1);
+ delete this.roomClients[id][room];
+ }
+};
+
+/**
+ * Called when a client closes a request in different node.
+ *
+ * @api private
+ */
+
+Manager.prototype.onClose = function (id) {
+ if (this.open[id]) {
+ delete this.open[id];
+ }
+
+ this.closed[id] = [];
+ this.closedA.push(id);
+
+ var self = this;
+
+ this.store.subscribe('dispatch:' + id, function (packet, volatile) {
+ if (!volatile) {
+ self.onClientDispatch(id, packet);
+ }
+ });
+};
+
+/**
+ * Dispatches a message for a closed client.
+ *
+ * @api private
+ */
+
+Manager.prototype.onClientDispatch = function (id, packet) {
+ if (this.closed[id]) {
+ this.closed[id].push(packet);
+ }
+};
+
+/**
+ * Receives a message for a client.
+ *
+ * @api private
+ */
+
+Manager.prototype.onClientMessage = function (id, packet) {
+ if (this.namespaces[packet.endpoint]) {
+ this.namespaces[packet.endpoint].handlePacket(id, packet);
+ }
+};
+
+/**
+ * Fired when a client disconnects (not triggered).
+ *
+ * @api private
+ */
+
+Manager.prototype.onClientDisconnect = function (id, reason) {
+ this.onDisconnect(id);
+
+ for (var name in this.namespaces) {
+ if (this.roomClients[id][name]) {
+ this.namespaces[name].handleDisconnect(id, reason);
+ }
+ }
+};
+
+/**
+ * Called when a client disconnects.
+ *
+ * @param text
+ */
+
+Manager.prototype.onDisconnect = function (id, local) {
+ delete this.handshaken[id];
+
+ if (this.open[id]) {
+ delete this.open[id];
+ }
+
+ if (this.connected[id]) {
+ delete this.connected[id];
+ }
+
+ if (this.transports[id]) {
+ this.transports[id].discard();
+ delete this.transports[id];
+ }
+
+ if (this.closed[id]) {
+ delete this.closed[id];
+ this.closedA.splice(this.closedA.indexOf(id), 1);
+ }
+
+ if (this.roomClients[id]) {
+ for (var room in this.roomClients[id]) {
+ this.rooms[room].splice(this.rooms[room].indexOf(id), 1);
+ }
+ }
+
+ this.store.destroyClient(id, this.get('client store expiration'));
+
+ this.store.unsubscribe('dispatch:' + id);
+
+ if (local) {
+ this.store.unsubscribe('message:' + id);
+ this.store.unsubscribe('disconnect:' + id);
+ }
+};
+
+/**
+ * Handles an HTTP request.
+ *
+ * @api private
+ */
+
+Manager.prototype.handleRequest = function (req, res) {
+ var data = this.checkRequest(req);
+
+ if (!data) {
+ for (var i = 0, l = this.oldListeners.length; i < l; i++) {
+ this.oldListeners[i].call(this.server, req, res);
+ }
+
+ return;
+ }
+
+ if (data.static || !data.transport && !data.protocol) {
+ if (data.static && this.enabled('browser client')) {
+ this.handleClientRequest(req, res, data);
+ } else {
+ res.writeHead(200);
+ res.end('Welcome to socket.io.');
+
+ this.log.info('unhandled socket.io url');
+ }
+
+ return;
+ }
+
+ if (data.protocol != protocol) {
+ res.writeHead(500);
+ res.end('Protocol version not supported.');
+
+ this.log.info('client protocol version unsupported');
+ } else {
+ if (data.id) {
+ this.handleHTTPRequest(data, req, res);
+ } else {
+ this.handleHandshake(data, req, res);
+ }
+ }
+};
+
+/**
+ * Handles an HTTP Upgrade.
+ *
+ * @api private
+ */
+
+Manager.prototype.handleUpgrade = function (req, socket, head) {
+ var data = this.checkRequest(req)
+ , self = this;
+
+ if (!data) {
+ if (this.enabled('destroy upgrade')) {
+ socket.end();
+ this.log.debug('destroying non-socket.io upgrade');
+ }
+
+ return;
+ }
+
+ req.head = head;
+ this.handleClient(data, req);
+};
+
+/**
+ * Handles a normal handshaken HTTP request (eg: long-polling)
+ *
+ * @api private
+ */
+
+Manager.prototype.handleHTTPRequest = function (data, req, res) {
+ req.res = res;
+ this.handleClient(data, req);
+};
+
+/**
+ * Intantiantes a new client.
+ *
+ * @api private
+ */
+
+Manager.prototype.handleClient = function (data, req) {
+ var socket = req.socket
+ , store = this.store
+ , self = this;
+
+ if (undefined != data.query.disconnect) {
+ if (this.transports[data.id] && this.transports[data.id].open) {
+ this.transports[data.id].onForcedDisconnect();
+ } else {
+ this.store.publish('disconnect-force:' + data.id);
+ }
+ return;
+ }
+
+ if (!~this.get('transports').indexOf(data.transport)) {
+ this.log.warn('unknown transport: "' + data.transport + '"');
+ req.connection.end();
+ return;
+ }
+
+ var transport = new transports[data.transport](this, data, req);
+
+ if (this.handshaken[data.id]) {
+ if (transport.open) {
+ if (this.closed[data.id] && this.closed[data.id].length) {
+ transport.payload(this.closed[data.id]);
+ this.closed[data.id] = [];
+ }
+
+ this.onOpen(data.id);
+ this.store.publish('open', data.id);
+ this.transports[data.id] = transport;
+ }
+
+ if (!this.connected[data.id]) {
+ this.onConnect(data.id);
+ this.store.publish('connect', data.id);
+
+ // initialize the socket for all namespaces
+ for (var i in this.namespaces) {
+ var socket = this.namespaces[i].socket(data.id, true);
+
+ // echo back connect packet and fire connection event
+ if (i === '') {
+ this.namespaces[i].handlePacket(data.id, { type: 'connect' });
+ }
+ }
+
+ this.store.subscribe('message:' + data.id, function (packet) {
+ self.onClientMessage(data.id, packet);
+ });
+
+ this.store.subscribe('disconnect:' + data.id, function (reason) {
+ self.onClientDisconnect(data.id, reason);
+ });
+ }
+ } else {
+ if (transport.open) {
+ transport.error('client not handshaken', 'reconnect');
+ }
+
+ transport.discard();
+ }
+};
+
+/**
+ * Dictionary for static file serving
+ *
+ * @api public
+ */
+
+Manager.static = {
+ cache: {}
+ , paths: {
+ '/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf'
+ , '/static/flashsocket/WebSocketMainInsecure.swf':
+ client.dist + '/WebSocketMainInsecure.swf'
+ , '/socket.io.js': client.dist + '/socket.io.js'
+ , '/socket.io.js.min': client.dist + '/socket.io.min.js'
+ }
+ , mime: {
+ 'js': {
+ contentType: 'application/javascript'
+ , encoding: 'utf8'
+ }
+ , 'swf': {
+ contentType: 'application/x-shockwave-flash'
+ , encoding: 'binary'
+ }
+ }
+};
+
+/**
+ * Serves the client.
+ *
+ * @api private
+ */
+
+Manager.prototype.handleClientRequest = function (req, res, data) {
+ var static = Manager.static
+ , extension = data.path.split('.').pop()
+ , file = data.path + (this.enabled('browser client minification')
+ && extension == 'js' ? '.min' : '')
+ , location = static.paths[file]
+ , cache = static.cache[file];
+
+ var self = this;
+
+ /**
+ * Writes a response, safely
+ *
+ * @api private
+ */
+
+ function write (status, headers, content, encoding) {
+ try {
+ res.writeHead(status, headers || null);
+ res.end(content || '', encoding || null);
+ } catch (e) {}
+ }
+
+ function serve () {
+ if (req.headers['if-none-match'] === cache.Etag) {
+ return write(304);
+ }
+
+ var mime = static.mime[extension]
+ , headers = {
+ 'Content-Type': mime.contentType
+ , 'Content-Length': cache.length
+ };
+
+ if (self.enabled('browser client etag') && cache.Etag) {
+ headers.Etag = cache.Etag;
+ }
+
+ write(200, headers, cache.content, mime.encoding);
+ self.log.debug('served static ' + data.path);
+ }
+
+ if (this.get('browser client handler')) {
+ this.get('browser client handler').call(this, req, res);
+ } else if (!cache) {
+ fs.readFile(location, function (err, data) {
+ if (err) {
+ write(500, null, 'Error serving static ' + data.path);
+ self.log.warn('Can\'t cache '+ data.path +', ' + err.message);
+ return;
+ }
+
+ cache = Manager.static.cache[file] = {
+ content: data
+ , length: data.length
+ , Etag: client.version
+ };
+
+ serve();
+ });
+ } else {
+ serve();
+ }
+};
+
+/**
+ * Generates a session id.
+ *
+ * @api private
+ */
+
+Manager.prototype.generateId = function () {
+ return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
+ + Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
+};
+
+/**
+ * Handles a handshake request.
+ *
+ * @api private
+ */
+
+Manager.prototype.handleHandshake = function (data, req, res) {
+ var self = this;
+
+ function writeErr (status, message) {
+ if (data.query.jsonp) {
+ res.writeHead(200, { 'Content-Type': 'application/javascript' });
+ res.end('io.j[' + data.query.jsonp + '](new Error("' + message + '"));');
+ } else {
+ res.writeHead(status);
+ res.end(message);
+ }
+ };
+
+ function error (err) {
+ writeErr(500, 'handshake error');
+ self.log.warn('handshake error ' + err);
+ };
+
+ if (!this.verifyOrigin(req)) {
+ writeErr(403, 'handshake bad origin');
+ return;
+ }
+
+ var handshakeData = this.handshakeData(data);
+
+ this.authorize(handshakeData, function (err, authorized, newData) {
+ if (err) return error(err);
+
+ if (authorized) {
+ var id = self.generateId()
+ , hs = [
+ id
+ , self.get('heartbeat timeout') || ''
+ , self.get('close timeout') || ''
+ , self.transports(data).join(',')
+ ].join(':');
+
+ if (data.query.jsonp) {
+ hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';
+ res.writeHead(200, { 'Content-Type': 'application/javascript' });
+ } else {
+ res.writeHead(200);
+ }
+
+ res.end(hs);
+
+ self.onHandshake(id, newData || handshakeData);
+ self.store.publish('handshake', id, newData || handshakeData);
+
+ self.log.info('handshake authorized', id);
+ } else {
+ writeErr(403, 'handshake unauthorized');
+ self.log.info('handshake unauthorized');
+ }
+ })
+};
+
+/**
+ * Gets normalized handshake data
+ *
+ * @api private
+ */
+
+Manager.prototype.handshakeData = function (data) {
+ var connection = data.request.connection
+ , connectionAddress;
+
+ if (connection.remoteAddress) {
+ connectionAddress = {
+ address: connection.remoteAddress
+ , port: connection.remotePort
+ };
+ } else if (connection.socket && connection.socket.remoteAddress) {
+ connectionAddress = {
+ address: connection.socket.remoteAddress
+ , port: connection.socket.remotePort
+ };
+ }
+
+ return {
+ headers: data.headers
+ , address: connectionAddress
+ , time: (new Date).toString()
+ , xdomain: !!data.request.headers.origin
+ , secure: data.request.connection.secure
+ };
+};
+
+/**
+ * Verifies the origin of a request.
+ *
+ * @api private
+ */
+
+Manager.prototype.verifyOrigin = function (request) {
+ var origin = request.headers.origin
+ , origins = this.get('origins');
+
+ if (origin === 'null') origin = '*';
+
+ if (origins.indexOf('*:*') !== -1) {
+ return true;
+ }
+
+ if (origin) {
+ try {
+ var parts = url.parse(origin);
+
+ return
+ ~origins.indexOf(parts.host + ':' + parts.port) ||
+ ~origins.indexOf(parts.host + ':*') ||
+ ~origins.indexOf('*:' + parts.port);
+ } catch (ex) {}
+ }
+
+ return false;
+};
+
+/**
+ * Handles an incoming packet.
+ *
+ * @api private
+ */
+
+Manager.prototype.handlePacket = function (sessid, packet) {
+ this.of(packet.endpoint || '').handlePacket(sessid, packet);
+};
+
+/**
+ * Performs authentication.
+ *
+ * @param Object client request data
+ * @api private
+ */
+
+Manager.prototype.authorize = function (data, fn) {
+ if (this.get('authorization')) {
+ var self = this;
+
+ this.get('authorization').call(this, data, function (err, authorized) {
+ self.log.debug('client ' + authorized ? 'authorized' : 'unauthorized');
+ fn(err, authorized);
+ });
+ } else {
+ this.log.debug('client authorized');
+ fn(null, true);
+ }
+
+ return this;
+};
+
+/**
+ * Retrieves the transports adviced to the user.
+ *
+ * @api private
+ */
+
+Manager.prototype.transports = function (data) {
+ var transp = this.get('transports')
+ , ret = [];
+
+ for (var i = 0, l = transp.length; i < l; i++) {
+ var transport = transp[i];
+
+ if (transport) {
+ if (!transport.checkClient || transport.checkClient(data)) {
+ ret.push(transport);
+ }
+ }
+ }
+
+ return ret;
+};
+
+/**
+ * Checks whether a request is a socket.io one.
+ *
+ * @return {Object} a client request data object or `false`
+ * @api private
+ */
+
+var regexp = /^\/([^\/]+)\/?([^\/]+)?\/?([^\/]+)?\/?$/
+
+Manager.prototype.checkRequest = function (req) {
+ var resource = this.get('resource');
+
+ if (req.url.substr(0, resource.length) == resource) {
+ var uri = url.parse(req.url.substr(resource.length), true)
+ , path = uri.pathname || ''
+ , pieces = path.match(regexp);
+
+ // client request data
+ var data = {
+ query: uri.query || {}
+ , headers: req.headers
+ , request: req
+ , path: path
+ };
+
+ if (pieces) {
+ data.protocol = Number(pieces[1]);
+ data.transport = pieces[2];
+ data.id = pieces[3];
+ data.static = !!Manager.static.paths[path];
+ };
+
+ return data;
+ }
+
+ return false;
+};
+
+/**
+ * Declares a socket namespace
+ */
+
+Manager.prototype.of = function (nsp) {
+ if (this.namespaces[nsp]) {
+ return this.namespaces[nsp];
+ }
+
+ return this.namespaces[nsp] = new SocketNamespace(this, nsp);
+};
--- /dev/null
+/**
+ * Module dependencies.
+ */
+
+var Socket = require('./socket')
+ , EventEmitter = process.EventEmitter
+ , parser = require('./parser')
+ , util = require('./util');
+
+/**
+ * Exports the constructor.
+ */
+
+exports = module.exports = SocketNamespace;
+
+/**
+ * Constructor.
+ *
+ * @api public.
+ */
+
+function SocketNamespace (mgr, name) {
+ this.manager = mgr;
+ this.name = name || '';
+ this.sockets = {};
+ this.auth = false;
+ this.setFlags();
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+SocketNamespace.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Copies emit since we override it
+ *
+ * @api private
+ */
+
+SocketNamespace.prototype.$emit = EventEmitter.prototype.emit;
+
+/**
+ * Retrieves all clients as Socket instances as an array.
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.clients = function (room) {
+ var room = this.name + (room !== undefined ?
+ '/' + room : '');
+
+ if (!this.manager.rooms[room]) {
+ return [];
+ }
+
+ return this.manager.rooms[room].map(function (id) {
+ return this.socket(id);
+ }, this);
+};
+
+/**
+ * Access logger interface.
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.__defineGetter__('log', function () {
+ return this.manager.log;
+});
+
+/**
+ * Access store.
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.__defineGetter__('store', function () {
+ return this.manager.store;
+});
+
+/**
+ * JSON message flag.
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.__defineGetter__('json', function () {
+ this.flags.json = true;
+ return this;
+});
+
+/**
+ * Volatile message flag.
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.__defineGetter__('volatile', function () {
+ this.flags.volatile = true;
+ return this;
+});
+
+/**
+ * Overrides the room to relay messages to (flag)
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.in = function (room) {
+ this.flags.endpoint = this.name + (room ? '/' + room : '');
+ return this;
+};
+
+/**
+ * Adds a session id we should prevent relaying messages to (flag)
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.except = function (id) {
+ this.flags.exceptions.push(id);
+ return this;
+};
+
+/**
+ * Sets the default flags.
+ *
+ * @api private
+ */
+
+SocketNamespace.prototype.setFlags = function () {
+ this.flags = {
+ endpoint: this.name
+ , exceptions: []
+ };
+ return this;
+};
+
+/**
+ * Sends out a packet
+ *
+ * @api private
+ */
+
+SocketNamespace.prototype.packet = function (packet) {
+ packet.endpoint = this.name;
+
+ var store = this.store
+ , log = this.log
+ , volatile = this.flags.volatile
+ , exceptions = this.flags.exceptions
+ , packet = parser.encodePacket(packet);
+
+ this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions);
+ this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions);
+
+ this.setFlags();
+
+ return this;
+};
+
+/**
+ * Sends to everyone.
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.send = function (data) {
+ return this.packet({
+ type: this.flags.json ? 'json' : 'message'
+ , data: data
+ });
+};
+
+/**
+ * Emits to everyone (override)
+ *
+ * @api private
+ */
+
+SocketNamespace.prototype.emit = function (name) {
+ if (name == 'newListener') {
+ return this.$emit.apply(this, arguments);
+ }
+
+ return this.packet({
+ type: 'event'
+ , name: name
+ , args: util.toArray(arguments).slice(1)
+ });
+};
+
+/**
+ * Retrieves or creates a write-only socket for a client, unless specified.
+ *
+ * @param {Boolean} whether the socket will be readable when initialized
+ * @api private
+ */
+
+SocketNamespace.prototype.socket = function (sid, readable) {
+ if (!this.sockets[sid]) {
+ this.sockets[sid] = new Socket(this.manager, sid, this, readable);
+ }
+
+ return this.sockets[sid];
+};
+
+/**
+ * Sets authorization for this namespace
+ *
+ * @api public
+ */
+
+SocketNamespace.prototype.authorization = function (fn) {
+ this.auth = fn;
+ return this;
+};
+
+/**
+ * Called when a socket disconnects entirely.
+ *
+ * @api private
+ */
+
+SocketNamespace.prototype.handleDisconnect = function (sid, reason) {
+ if (this.sockets[sid] && this.sockets[sid].readable) {
+ this.sockets[sid].onDisconnect(reason);
+ }
+};
+
+/**
+ * Performs authentication.
+ *
+ * @param Object client request data
+ * @api private
+ */
+
+SocketNamespace.prototype.authorize = function (data, fn) {
+ if (this.auth) {
+ var self = this;
+
+ this.auth.call(this, data, function (err, authorized) {
+ self.log.debug('client ' +
+ (authorized ? '' : 'un') + 'authorized for ' + self.name);
+ fn(err, authorized);
+ });
+ } else {
+ this.log.debug('client authorized for ' + this.name);
+ fn(null, true);
+ }
+
+ return this;
+};
+
+/**
+ * Handles a packet.
+ *
+ * @api private
+ */
+
+SocketNamespace.prototype.handlePacket = function (sessid, packet) {
+ var socket = this.socket(sessid)
+ , dataAck = packet.ack == 'data'
+ , self = this;
+
+ function ack () {
+ self.log.debug('sending data ack packet');
+ socket.packet({
+ type: 'ack'
+ , args: util.toArray(arguments)
+ , ackId: packet.id
+ });
+ };
+
+ function error (err) {
+ self.log.warn('handshake error ' + err + ' for ' + self.name);
+ socket.packet({ type: 'error', reason: err });
+ };
+
+ function connect () {
+ self.manager.onJoin(sessid, self.name);
+ self.store.publish('join', sessid, self.name);
+
+ // packet echo
+ socket.packet({ type: 'connect' });
+
+ // emit connection event
+ self.$emit('connection', socket);
+ };
+
+ switch (packet.type) {
+ case 'connect':
+ if (packet.endpoint == '') {
+ connect();
+ } else {
+ var manager = this.manager
+ , handshakeData = manager.handshaken[sessid];
+
+ this.authorize(handshakeData, function (err, authorized, newData) {
+ if (err) return error(err);
+
+ if (authorized) {
+ manager.onHandshake(sessid, newData || handshakeData);
+ self.store.publish('handshake', sessid, newData || handshakeData);
+ connect();
+ } else {
+ error('unauthorized');
+ }
+ });
+ }
+ break;
+
+ case 'ack':
+ if (socket.acks[packet.ackId]) {
+ socket.acks[packet.ackId].apply(socket, packet.args);
+ } else {
+ this.log.info('unknown ack packet');
+ }
+ break;
+
+ case 'event':
+ var params = [packet.name].concat(packet.args);
+
+ if (dataAck)
+ params.push(ack);
+
+ socket.$emit.apply(socket, params);
+ break;
+
+ case 'disconnect':
+ this.manager.onLeave(sessid, this.name);
+ this.store.publish('leave', sessid, this.name);
+
+ socket.$emit('disconnect', packet.reason || 'packet');
+ break;
+
+ case 'json':
+ case 'message':
+ var params = ['message', packet.data];
+
+ if (dataAck)
+ params.push(ack);
+
+ socket.$emit.apply(socket, params);
+ };
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+/**
+ * Packet types.
+ */
+
+var packets = exports.packets = [
+ 'disconnect'
+ , 'connect'
+ , 'heartbeat'
+ , 'message'
+ , 'json'
+ , 'event'
+ , 'ack'
+ , 'error'
+ , 'noop'
+];
+
+/**
+ * Errors reasons.
+ */
+
+var reasons = exports.reasons = [
+ 'transport not supported'
+ , 'client not handshaken'
+ , 'unauthorized'
+];
+
+/**
+ * Errors advice.
+ */
+
+var advice = exports.advice = [
+ 'reconnect'
+];
+
+/**
+ * Encodes a packet.
+ *
+ * @api private
+ */
+
+exports.encodePacket = function (packet) {
+ var type = packets.indexOf(packet.type)
+ , id = packet.id || ''
+ , endpoint = packet.endpoint || ''
+ , ack = packet.ack
+ , data = null;
+
+ switch (packet.type) {
+ case 'error':
+ var reason = packet.reason ? reasons.indexOf(packet.reason) : ''
+ , adv = packet.advice ? advice.indexOf(packet.advice) : ''
+
+ if (reason !== '' || adv !== '')
+ data = reason + (adv !== '' ? ('+' + adv) : '')
+
+ break;
+
+ case 'message':
+ if (packet.data !== '')
+ data = packet.data;
+ break;
+
+ case 'event':
+ var ev = { name: packet.name };
+
+ if (packet.args && packet.args.length) {
+ ev.args = packet.args;
+ }
+
+ data = JSON.stringify(ev);
+ break;
+
+ case 'json':
+ data = JSON.stringify(packet.data);
+ break;
+
+ case 'connect':
+ if (packet.qs)
+ data = packet.qs;
+ break;
+
+ case 'ack':
+ data = packet.ackId
+ + (packet.args && packet.args.length
+ ? '+' + JSON.stringify(packet.args) : '');
+ break;
+ }
+
+ // construct packet with required fragments
+ var encoded = [
+ type
+ , id + (ack == 'data' ? '+' : '')
+ , endpoint
+ ];
+
+ // data fragment is optional
+ if (data !== null && data !== undefined)
+ encoded.push(data);
+
+ return encoded.join(':');
+};
+
+/**
+ * Encodes multiple messages (payload).
+ *
+ * @param {Array} messages
+ * @api private
+ */
+
+exports.encodePayload = function (packets) {
+ var decoded = '';
+
+ if (packets.length == 1)
+ return packets[0];
+
+ for (var i = 0, l = packets.length; i < l; i++) {
+ var packet = packets[i];
+ decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
+ }
+
+ return decoded;
+};
+
+/**
+ * Decodes a packet
+ *
+ * @api private
+ */
+
+var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
+
+exports.decodePacket = function (data) {
+ var pieces = data.match(regexp);
+
+ if (!pieces) return {};
+
+ var id = pieces[2] || ''
+ , data = pieces[5] || ''
+ , packet = {
+ type: packets[pieces[1]]
+ , endpoint: pieces[4] || ''
+ };
+
+ // whether we need to acknowledge the packet
+ if (id) {
+ packet.id = id;
+ if (pieces[3])
+ packet.ack = 'data';
+ else
+ packet.ack = true;
+ }
+
+ // handle different packet types
+ switch (packet.type) {
+ case 'error':
+ var pieces = data.split('+');
+ packet.reason = reasons[pieces[0]] || '';
+ packet.advice = advice[pieces[1]] || '';
+ break;
+
+ case 'message':
+ packet.data = data || '';
+ break;
+
+ case 'event':
+ try {
+ var opts = JSON.parse(data);
+ packet.name = opts.name;
+ packet.args = opts.args;
+ } catch (e) { }
+
+ packet.args = packet.args || [];
+ break;
+
+ case 'json':
+ try {
+ packet.data = JSON.parse(data);
+ } catch (e) { }
+ break;
+
+ case 'connect':
+ packet.qs = data || '';
+ break;
+
+ case 'ack':
+ var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
+ if (pieces) {
+ packet.ackId = pieces[1];
+ packet.args = [];
+
+ if (pieces[3]) {
+ try {
+ packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
+ } catch (e) { }
+ }
+ }
+ break;
+
+ case 'disconnect':
+ case 'heartbeat':
+ break;
+ };
+
+ return packet;
+};
+
+/**
+ * Decodes data payload. Detects multiple messages
+ *
+ * @return {Array} messages
+ * @api public
+ */
+
+exports.decodePayload = function (data) {
+ if (data[0] == '\ufffd') {
+ var ret = [];
+
+ for (var i = 1, length = ''; i < data.length; i++) {
+ if (data[i] == '\ufffd') {
+ ret.push(exports.decodePacket(data.substr(i + 1).substr(0, length)));
+ i += Number(length) + 1;
+ length = '';
+ } else {
+ length += data[i];
+ }
+ }
+
+ return ret;
+ } else {
+ return [exports.decodePacket(data)];
+ }
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var client = require('socket.io-client');
+
+/**
+ * Version.
+ */
+
+exports.version = '0.7.7';
+
+/**
+ * Supported protocol version.
+ */
+
+exports.protocol = 1;
+
+/**
+ * Client that we serve.
+ */
+
+exports.clientVersion = client.version;
+
+/**
+ * Attaches a manager
+ *
+ * @api public
+ */
+
+exports.listen = function (server, options, fn) {
+ if ('function' == typeof options) {
+ fn = options;
+ options = {};
+ }
+
+ if ('undefined' == typeof server) {
+ // create a server that listens on port 80
+ server = 80;
+ }
+
+ if ('number' == typeof server) {
+ // if a port number is passed
+ var port = server;
+
+ if (options && options.key)
+ server = require('https').createServer(options);
+ else
+ server = require('http').createServer();
+
+ // default response
+ server.on('request', function (req, res) {
+ res.writeHead(200);
+ res.end('Welcome to socket.io.');
+ });
+
+ server.listen(port, fn);
+ }
+
+ // otherwise assume a http/s server
+ return new exports.Manager(server);
+};
+
+/**
+ * Manager constructor.
+ *
+ * @api public
+ */
+
+exports.Manager = require('./manager');
+
+/**
+ * Transport constructor.
+ *
+ * @api public
+ */
+
+exports.Transport = require('./transport');
+
+/**
+ * Socket constructor.
+ *
+ * @api public
+ */
+
+exports.Socket = require('./socket');
+
+/**
+ * Store constructor.
+ *
+ * @api public
+ */
+
+exports.Store = require('./store');
+
+/**
+ * Memory Store constructor.
+ *
+ * @api public
+ */
+
+exports.MemoryStore = require('./stores/memory');
+
+/**
+ * Redis Store constructor.
+ *
+ * @api public
+ */
+
+exports.RedisStore = require('./stores/redis');
+
+/**
+ * Parser.
+ *
+ * @api public
+ */
+
+exports.parser = require('./parser');
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var parser = require('./parser')
+ , util = require('./util')
+ , EventEmitter = process.EventEmitter;
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = Socket;
+
+/**
+ * Socket constructor.
+ *
+ * @param {Manager} manager instance
+ * @param {String} session id
+ * @param {Namespace} namespace the socket belongs to
+ * @param {Boolean} whether the
+ * @api public
+ */
+
+function Socket (manager, id, nsp, readable) {
+ this.id = id;
+ this.namespace = nsp;
+ this.manager = manager;
+ this.disconnected = false;
+ this.ackPackets = 0;
+ this.acks = {};
+ this.setFlags();
+ this.readable = readable;
+ this.store = this.manager.store.client(this.id);
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+Socket.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Accessor shortcut for the handshake data
+ *
+ * @api private
+ */
+
+Socket.prototype.__defineGetter__('handshake', function () {
+ return this.manager.handshaken[this.id];
+});
+
+/**
+ * Accessor shortcut for the logger.
+ *
+ * @api private
+ */
+
+Socket.prototype.__defineGetter__('log', function () {
+ return this.manager.log;
+});
+
+/**
+ * JSON message flag.
+ *
+ * @api public
+ */
+
+Socket.prototype.__defineGetter__('json', function () {
+ this.flags.json = true;
+ return this;
+});
+
+/**
+ * Volatile message flag.
+ *
+ * @api public
+ */
+
+Socket.prototype.__defineGetter__('volatile', function () {
+ this.flags.volatile = true;
+ return this;
+});
+
+/**
+ * Broadcast message flag.
+ *
+ * @api public
+ */
+
+Socket.prototype.__defineGetter__('broadcast', function () {
+ this.flags.broadcast = true;
+ return this;
+});
+
+/**
+ * Overrides the room to broadcast messages to (flag)
+ *
+ * @api public
+ */
+
+Socket.prototype.to = function (room) {
+ this.flags.room = room;
+ return this;
+};
+
+/**
+ * Resets flags
+ *
+ * @api private
+ */
+
+Socket.prototype.setFlags = function () {
+ this.flags = {
+ endpoint: this.namespace.name
+ , room: ''
+ };
+ return this;
+};
+
+/**
+ * Triggered on disconnect
+ *
+ * @api private
+ */
+
+Socket.prototype.onDisconnect = function (reason) {
+ if (!this.disconnected) {
+ this.$emit('disconnect', reason);
+ this.disconnected = true;
+ }
+};
+
+/**
+ * Joins a user to a room.
+ *
+ * @api public
+ */
+
+Socket.prototype.join = function (name, fn) {
+ var nsp = this.namespace.name
+ , name = (nsp + '/') + name;
+
+ this.manager.onJoin(this.id, name);
+ this.manager.store.publish('join', this.id, name);
+
+ if (fn) {
+ this.log.warn('Client#join callback is deprecated');
+ fn();
+ }
+
+ return this;
+};
+
+/**
+ * Joins a user to a room.
+ *
+ * @api public
+ */
+
+Socket.prototype.leave = function (name, fn) {
+ var nsp = this.namespace.name
+ , name = (nsp + '/') + name;
+
+ this.manager.onLeave(this.id, name);
+ this.manager.store.publish('leave', this.id, name);
+
+ if (fn) {
+ this.log.warn('Client#leave callback is deprecated');
+ fn();
+ }
+
+ return this;
+};
+
+/**
+ * Transmits a packet.
+ *
+ * @api private
+ */
+
+Socket.prototype.packet = function (packet) {
+ if (this.flags.broadcast) {
+ this.log.debug('broadcasting packet');
+ this.namespace.in(this.flags.room).except(this.id).packet(packet);
+ } else {
+ packet.endpoint = this.flags.endpoint;
+ packet = parser.encodePacket(packet);
+
+ this.dispatch(packet, this.flags.volatile);
+ }
+
+ this.setFlags();
+
+ return this;
+};
+
+/**
+ * Dispatches a packet
+ *
+ * @api private
+ */
+
+Socket.prototype.dispatch = function (packet, volatile) {
+ if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
+ this.manager.transports[this.id].onDispatch(packet, volatile);
+ } else {
+ if (!volatile) {
+ this.manager.onClientDispatch(this.id, packet, volatile);
+ }
+
+ this.manager.store.publish('dispatch:' + this.id, packet, volatile);
+ }
+};
+
+/**
+ * Stores data for the client.
+ *
+ * @api public
+ */
+
+Socket.prototype.set = function (key, value, fn) {
+ this.store.set(key, value, fn);
+ return this;
+};
+
+/**
+ * Retrieves data for the client
+ *
+ * @api public
+ */
+
+Socket.prototype.get = function (key, fn) {
+ this.store.get(key, fn);
+ return this;
+};
+
+/**
+ * Checks data for the client
+ *
+ * @api public
+ */
+
+Socket.prototype.has = function (key, fn) {
+ this.store.has(key, fn);
+ return this;
+};
+
+/**
+ * Deletes data for the client
+ *
+ * @api public
+ */
+
+Socket.prototype.del = function (key, fn) {
+ this.store.del(key, fn);
+ return this;
+};
+
+/**
+ * Kicks client
+ *
+ * @api public
+ */
+
+Socket.prototype.disconnect = function () {
+ if (!this.disconnected) {
+ this.log.info('booting client');
+
+ if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
+ this.manager.transports[this.id].onForcedDisconnect();
+ } else {
+ this.manager.onClientDisconnect(this.id);
+ this.manager.store.publish('disconnect:' + this.id);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Send a message.
+ *
+ * @api public
+ */
+
+Socket.prototype.send = function (data, fn) {
+ var packet = {
+ type: this.flags.json ? 'json' : 'message'
+ , data: data
+ };
+
+ if (fn) {
+ packet.id = ++this.ackPackets;
+ packet.ack = true;
+ this.acks[packet.id] = fn;
+ }
+
+ return this.packet(packet);
+};
+
+/**
+ * Original emit function.
+ *
+ * @api private
+ */
+
+Socket.prototype.$emit = EventEmitter.prototype.emit;
+
+/**
+ * Emit override for custom events.
+ *
+ * @api public
+ */
+
+Socket.prototype.emit = function (ev) {
+ if (ev == 'newListener') {
+ return this.$emit.apply(this, arguments);
+ }
+
+ var args = util.toArray(arguments).slice(1)
+ , lastArg = args[args.length - 1]
+ , packet = {
+ type: 'event'
+ , name: ev
+ };
+
+ if ('function' == typeof lastArg) {
+ packet.id = ++this.ackPackets;
+ packet.ack = lastArg.length ? 'data' : true;
+ this.acks[packet.id] = lastArg;
+ args = args.slice(0, args.length - 1);
+ }
+
+ packet.args = args;
+
+ return this.packet(packet);
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Expose the constructor.
+ */
+
+exports = module.exports = Store;
+
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = process.EventEmitter;
+
+/**
+ * Store interface
+ *
+ * @api public
+ */
+
+function Store (options) {
+ this.options = options;
+ this.clients = {};
+};
+
+/**
+ * Inherit from EventEmitter.
+ */
+
+Store.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Initializes a client store
+ *
+ * @param {String} id
+ * @api public
+ */
+
+Store.prototype.client = function (id) {
+ if (!this.clients[id]) {
+ this.clients[id] = new (this.constructor.Client)(this, id);
+ }
+
+ return this.clients[id];
+};
+
+/**
+ * Destroys a client
+ *
+ * @api {String} sid
+ * @param {Number} number of seconds to expire client data
+ * @api private
+ */
+
+Store.prototype.destroyClient = function (id, expiration) {
+ if (this.clients[id]) {
+ this.clients[id].destroy(expiration);
+ delete this.clients[id];
+ }
+
+ return this;
+};
+
+/**
+ * Destroys the store
+ *
+ * @param {Number} number of seconds to expire client data
+ * @api private
+ */
+
+Store.prototype.destroy = function (clientExpiration) {
+ var keys = Object.keys(this.clients)
+ , count = keys.length;
+
+ for (var i = 0, l = count; i < l; i++) {
+ this.destroyClient(keys[i], clientExpiration);
+ }
+
+ this.clients = {};
+
+ return this;
+};
+
+/**
+ * Client.
+ *
+ * @api public
+ */
+
+Store.Client = function (store, id) {
+ this.store = store;
+ this.id = id;
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var crypto = require('crypto')
+ , Store = require('../store');
+
+/**
+ * Exports the constructor.
+ */
+
+exports = module.exports = Memory;
+Memory.Client = Client;
+
+/**
+ * Memory store
+ *
+ * @api public
+ */
+
+function Memory (opts) {
+ Store.call(this, opts);
+};
+
+/**
+ * Inherits from Store.
+ */
+
+Memory.prototype.__proto__ = Store.prototype;
+
+/**
+ * Publishes a message.
+ *
+ * @api private
+ */
+
+Memory.prototype.publish = function () { };
+
+/**
+ * Subscribes to a channel
+ *
+ * @api private
+ */
+
+Memory.prototype.subscribe = function () { };
+
+/**
+ * Unsubscribes
+ *
+ * @api private
+ */
+
+Memory.prototype.unsubscribe = function () { };
+
+/**
+ * Client constructor
+ *
+ * @api private
+ */
+
+function Client () {
+ Store.Client.apply(this, arguments);
+ this.data = {};
+};
+
+/**
+ * Inherits from Store.Client
+ */
+
+Client.prototype.__proto__ = Store.Client;
+
+/**
+ * Gets a key
+ *
+ * @api public
+ */
+
+Client.prototype.get = function (key, fn) {
+ fn(null, this.data[key] === undefined ? null : this.data[key]);
+ return this;
+};
+
+/**
+ * Sets a key
+ *
+ * @api public
+ */
+
+Client.prototype.set = function (key, value, fn) {
+ this.data[key] = value;
+ fn && fn(null);
+ return this;
+};
+
+/**
+ * Has a key
+ *
+ * @api public
+ */
+
+Client.prototype.has = function (key, fn) {
+ fn(null, key in this.data);
+};
+
+/**
+ * Deletes a key
+ *
+ * @api public
+ */
+
+Client.prototype.del = function (key, fn) {
+ delete this.data[key];
+ fn && fn(null);
+ return this;
+};
+
+/**
+ * Destroys the client.
+ *
+ * @param {Number} number of seconds to expire data
+ * @api private
+ */
+
+Client.prototype.destroy = function (expiration) {
+ if ('number' != typeof expiration) {
+ this.data = {};
+ } else {
+ var self = this;
+
+ setTimeout(function () {
+ self.data = {};
+ }, expiration * 1000);
+ }
+
+ return this;
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var crypto = require('crypto')
+ , Store = require('../store')
+ , assert = require('assert')
+ , redis = require('redis');
+
+/**
+ * Exports the constructor.
+ */
+
+exports = module.exports = Redis;
+Redis.Client = Client;
+
+/**
+ * Redis store.
+ * Options:
+ * - nodeId (fn) gets an id that uniquely identifies this node
+ * - redisPub (object) options to pass to the pub redis client
+ * - redisSub (object) options to pass to the sub redis client
+ * - redisClient (object) options to pass to the general redis client
+ * - pack (fn) custom packing, defaults to JSON or msgpack if installed
+ * - unpack (fn) custom packing, defaults to JSON or msgpack if installed
+ *
+ * @api public
+ */
+
+function Redis (opts) {
+ opts = opts || {};
+
+ // node id to uniquely identify this node
+ var nodeId = opts.nodeId || function () {
+ // by default, we generate a random id
+ return Math.abs(Math.random() * Math.random() * Date.now() | 0);
+ };
+
+ this.nodeId = nodeId();
+
+ // packing / unpacking mechanism
+ if (opts.pack) {
+ this.pack = opts.pack;
+ this.unpack = opts.unpack;
+ } else {
+ try {
+ var msgpack = require('msgpack');
+ this.pack = msgpack.pack;
+ this.unpack = msgpack.unpack;
+ } catch (e) {
+ this.pack = JSON.stringify;
+ this.unpack = JSON.parse;
+ }
+ }
+
+ // initialize a pubsub client and a regular client
+ this.pub = redis.createClient(opts.redisPub);
+ this.sub = redis.createClient(opts.redisSub);
+ this.cmd = redis.createClient(opts.redisClient);
+
+ Store.call(this, opts);
+};
+
+/**
+ * Inherits from Store.
+ */
+
+Redis.prototype.__proto__ = Store.prototype;
+
+/**
+ * Publishes a message.
+ *
+ * @api private
+ */
+
+Redis.prototype.publish = function (name) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ this.pub.publish(name, this.pack({ nodeId: this.nodeId, args: args }));
+ this.emit.apply(this, ['publish', name].concat(args));
+};
+
+/**
+ * Subscribes to a channel
+ *
+ * @api private
+ */
+
+Redis.prototype.subscribe = function (name, consumer, fn) {
+ this.sub.subscribe(name);
+
+ if (consumer || fn) {
+ var self = this;
+
+ self.sub.on('subscribe', function subscribe (ch) {
+ if (name == ch) {
+ function message (ch, msg) {
+ if (name == ch) {
+ msg = self.unpack(msg);
+
+ // we check that the message consumed wasnt emitted by this node
+ if (self.nodeId != msg.nodeId) {
+ consumer.apply(null, msg.args);
+ }
+ }
+ };
+
+ self.sub.on('message', message);
+
+ self.on('unsubscribe', function unsubscribe (ch) {
+ if (name == ch) {
+ self.sub.removeListener('message', message);
+ self.removeEvent('unsubscribe', unsubscribe);
+ }
+ });
+
+ self.sub.removeListener('subscribe', subscribe);
+
+ fn && fn();
+ }
+ });
+ }
+
+ this.emit('subscribe', name, consumer, fn);
+};
+
+/**
+ * Unsubscribes
+ *
+ * @api private
+ */
+
+Redis.prototype.unsubscribe = function (name, fn) {
+ this.sub.unsubscribe(name);
+
+ if (fn) {
+ var client = this.sub;
+
+ client.on('unsubscribe', function unsubscribe (ch) {
+ if (name == ch) {
+ fn();
+ client.removeListener('unsubscribe', unsubscribe);
+ }
+ });
+ }
+
+ this.emit('unsubscribe', name, fn);
+};
+
+/**
+ * Destroys the store
+ *
+ * @api public
+ */
+
+Redis.prototype.destroy = function () {
+ Store.prototype.destroy.call(this);
+
+ this.pub.end();
+ this.sub.end();
+ this.cmd.end();
+};
+
+/**
+ * Client constructor
+ *
+ * @api private
+ */
+
+function Client (store, id) {
+ Store.Client.call(this, store, id);
+};
+
+/**
+ * Inherits from Store.Client
+ */
+
+Client.prototype.__proto__ = Store.Client;
+
+/**
+ * Redis hash get
+ *
+ * @api private
+ */
+
+Client.prototype.get = function (key, fn) {
+ this.store.cmd.hget(this.id, key, fn);
+ return this;
+};
+
+/**
+ * Redis hash set
+ *
+ * @api private
+ */
+
+Client.prototype.set = function (key, value, fn) {
+ this.store.cmd.hset(this.id, key, value, fn);
+ return this;
+};
+
+/**
+ * Redis hash del
+ *
+ * @api private
+ */
+
+Client.prototype.del = function (key, fn) {
+ this.store.cmd.hdel(this.id, key, fn);
+ return this;
+};
+
+/**
+ * Redis hash has
+ *
+ * @api private
+ */
+
+Client.prototype.has = function (key, fn) {
+ this.store.cmd.hexists(this.id, key, function (err, has) {
+ if (err) return fn(err);
+ fn(null, !!has);
+ });
+ return this;
+};
+
+/**
+ * Destroys client
+ *
+ * @param {Number} number of seconds to expire data
+ * @api private
+ */
+
+Client.prototype.destroy = function (expiration) {
+ if ('number' != typeof expiration) {
+ this.store.cmd.del(this.id);
+ } else {
+ this.store.cmd.expire(this.id, expiration);
+ }
+
+ return this;
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var parser = require('./parser');
+
+/**
+ * Expose the constructor.
+ */
+
+exports = module.exports = Transport;
+
+/**
+ * Transport constructor.
+ *
+ * @api public
+ */
+
+function Transport (mng, data, req) {
+ this.manager = mng;
+ this.id = data.id;
+ this.disconnected = false;
+ this.drained = true;
+ this.handleRequest(req);
+};
+
+/**
+ * Access the logger.
+ *
+ * @api public
+ */
+
+Transport.prototype.__defineGetter__('log', function () {
+ return this.manager.log;
+});
+
+/**
+ * Access the store.
+ *
+ * @api public
+ */
+
+Transport.prototype.__defineGetter__('store', function () {
+ return this.manager.store;
+});
+
+/**
+ * Handles a request when it's set.
+ *
+ * @api private
+ */
+
+Transport.prototype.handleRequest = function (req) {
+ this.log.debug('setting request', req.method, req.url);
+ this.req = req;
+
+ if (req.method == 'GET') {
+ this.socket = req.socket;
+ this.open = true;
+ this.drained = true;
+ this.setHeartbeatInterval();
+
+ this.setHandlers();
+ this.onSocketConnect();
+ }
+};
+
+/**
+ * Called when a connection is first set.
+ *
+ * @api private
+ */
+
+Transport.prototype.onSocketConnect = function () { };
+
+/**
+ * Sets transport handlers
+ *
+ * @api private
+ */
+
+Transport.prototype.setHandlers = function () {
+ var self = this;
+
+ // we need to do this in a pub/sub way since the client can POST the message
+ // over a different socket (ie: different Transport instance)
+ this.store.subscribe('heartbeat-clear:' + this.id, function () {
+ self.onHeartbeatClear();
+ });
+
+ this.store.subscribe('disconnect-force:' + this.id, function () {
+ self.onForcedDisconnect();
+ });
+
+ this.store.subscribe('dispatch:' + this.id, function (packet, volatile) {
+ self.onDispatch(packet, volatile);
+ });
+
+ this.bound = {
+ end: this.onSocketEnd.bind(this)
+ , close: this.onSocketClose.bind(this)
+ , error: this.onSocketError.bind(this)
+ , drain: this.onSocketDrain.bind(this)
+ };
+
+ this.socket.on('end', this.bound.end);
+ this.socket.on('close', this.bound.close);
+ this.socket.on('error', this.bound.error);
+ this.socket.on('drain', this.bound.drain);
+
+ this.handlersSet = true;
+};
+
+/**
+ * Removes transport handlers
+ *
+ * @api private
+ */
+
+Transport.prototype.clearHandlers = function () {
+ if (this.handlersSet) {
+ this.store.unsubscribe('disconnect-force:' + this.id);
+ this.store.unsubscribe('heartbeat-clear:' + this.id);
+ this.store.unsubscribe('dispatch:' + this.id);
+
+ this.socket.removeListener('end', this.bound.end);
+ this.socket.removeListener('close', this.bound.close);
+ this.socket.removeListener('error', this.bound.error);
+ this.socket.removeListener('drain', this.bound.drain);
+ }
+};
+
+/**
+ * Called when the connection dies
+ *
+ * @api private
+ */
+
+Transport.prototype.onSocketEnd = function () {
+ this.end('socket end');
+};
+
+/**
+ * Called when the connection dies
+ *
+ * @api private
+ */
+
+Transport.prototype.onSocketClose = function (error) {
+ this.end(error ? 'socket error' : 'socket close');
+};
+
+/**
+ * Called when the connection has an error.
+ *
+ * @api private
+ */
+
+Transport.prototype.onSocketError = function (err) {
+ if (this.open) {
+ this.socket.destroy();
+ this.onClose();
+ }
+
+ this.log.info('socket error ' + err.stack);
+};
+
+/**
+ * Called when the connection is drained.
+ *
+ * @api private
+ */
+
+Transport.prototype.onSocketDrain = function () {
+ this.drained = true;
+};
+
+/**
+ * Called upon receiving a heartbeat packet.
+ *
+ * @api private
+ */
+
+Transport.prototype.onHeartbeatClear = function () {
+ this.clearHeartbeatTimeout();
+ this.setHeartbeatInterval();
+};
+
+/**
+ * Called upon a forced disconnection.
+ *
+ * @api private
+ */
+
+Transport.prototype.onForcedDisconnect = function () {
+ if (!this.disconnected) {
+ this.log.info('transport end by forced client disconnection');
+ if (this.open) {
+ this.packet({ type: 'disconnect' });
+ }
+ this.end('booted');
+ }
+};
+
+/**
+ * Dispatches a packet.
+ *
+ * @api private
+ */
+
+Transport.prototype.onDispatch = function (packet, volatile) {
+ if (volatile) {
+ this.writeVolatile(packet);
+ } else {
+ this.write(packet);
+ }
+};
+
+/**
+ * Sets the close timeout.
+ */
+
+Transport.prototype.setCloseTimeout = function () {
+ if (!this.closeTimeout) {
+ var self = this;
+
+ this.closeTimeout = setTimeout(function () {
+ self.log.debug('fired close timeout for client', self.id);
+ self.closeTimeout = null;
+ self.end('close timeout');
+ }, this.manager.get('close timeout') * 1000);
+
+ this.log.debug('set close timeout for client', this.id);
+ }
+};
+
+/**
+ * Clears the close timeout.
+ */
+
+Transport.prototype.clearCloseTimeout = function () {
+ if (this.closeTimeout) {
+ clearTimeout(this.closeTimeout);
+ this.closeTimeout = null;
+
+ this.log.debug('cleared close timeout for client', this.id);
+ }
+};
+
+/**
+ * Sets the heartbeat timeout
+ */
+
+Transport.prototype.setHeartbeatTimeout = function () {
+ if (!this.heartbeatTimeout) {
+ var self = this;
+
+ this.heartbeatTimeout = setTimeout(function () {
+ self.log.debug('fired heartbeat timeout for client', self.id);
+ self.heartbeatTimeout = null;
+ self.end('heartbeat timeout');
+ }, this.manager.get('heartbeat timeout') * 1000);
+
+ this.log.debug('set heartbeat timeout for client', this.id);
+ }
+};
+
+/**
+ * Clears the heartbeat timeout
+ *
+ * @param text
+ */
+
+Transport.prototype.clearHeartbeatTimeout = function () {
+ if (this.heartbeatTimeout) {
+ clearTimeout(this.heartbeatTimeout);
+ this.heartbeatTimeout = null;
+ this.log.debug('cleared heartbeat timeout for client', this.id);
+ }
+};
+
+/**
+ * Sets the heartbeat interval. To be called when a connection opens and when
+ * a heartbeat is received.
+ *
+ * @api private
+ */
+
+Transport.prototype.setHeartbeatInterval = function () {
+ if (!this.heartbeatInterval) {
+ var self = this;
+
+ this.heartbeatInterval = setTimeout(function () {
+ self.heartbeat();
+ self.heartbeatInterval = null;
+ }, this.manager.get('heartbeat interval') * 1000);
+
+ this.log.debug('set heartbeat interval for client', this.id);
+ }
+};
+
+/**
+ * Clears all timeouts.
+ *
+ * @api private
+ */
+
+Transport.prototype.clearTimeouts = function () {
+ this.clearCloseTimeout();
+ this.clearHeartbeatTimeout();
+ this.clearHeartbeatInterval();
+};
+
+/**
+ * Sends a heartbeat
+ *
+ * @api private
+ */
+
+Transport.prototype.heartbeat = function () {
+ if (this.open) {
+ this.log.debug('emitting heartbeat for client', this.id);
+ this.packet({ type: 'heartbeat' });
+ this.setHeartbeatTimeout();
+ }
+
+ return this;
+};
+
+/**
+ * Handles a message.
+ *
+ * @param {Object} packet object
+ * @api private
+ */
+
+Transport.prototype.onMessage = function (packet) {
+ var current = this.manager.transports[this.id];
+
+ if ('heartbeat' == packet.type) {
+ this.log.debug('got heartbeat packet');
+
+ if (current && current.open) {
+ current.onHeartbeatClear();
+ } else {
+ this.store.publish('heartbeat-clear:' + this.id);
+ }
+ } else {
+ if ('disconnect' == packet.type && packet.endpoint == '') {
+ this.log.debug('got disconnection packet');
+
+ if (current) {
+ current.onForcedDisconnect();
+ } else {
+ this.store.publish('disconnect-force:' + this.id);
+ }
+
+ return;
+ }
+
+ if (packet.id && packet.ack != 'data') {
+ this.log.debug('acknowledging packet automatically');
+
+ var ack = parser.encodePacket({
+ type: 'ack'
+ , ackId: packet.id
+ , endpoint: packet.endpoint || ''
+ });
+
+ if (current && current.open) {
+ current.onDispatch(ack);
+ } else {
+ this.manager.onClientDispatch(this.id, ack);
+ this.store.publish('dispatch:' + this.id, ack);
+ }
+ }
+
+ // handle packet locally or publish it
+ if (current) {
+ this.manager.onClientMessage(this.id, packet);
+ } else {
+ this.store.publish('message:' + this.id, packet);
+ }
+ }
+};
+
+/**
+ * Clears the heartbeat interval
+ *
+ * @api private
+ */
+
+Transport.prototype.clearHeartbeatInterval = function () {
+ if (this.heartbeatInterval) {
+ clearTimeout(this.heartbeatInterval);
+ this.heartbeatInterval = null;
+ this.log.debug('cleared heartbeat interval for client', this.id);
+ }
+};
+
+/**
+ * Finishes the connection and makes sure client doesn't reopen
+ *
+ * @api private
+ */
+
+Transport.prototype.disconnect = function (reason) {
+ this.packet({ type: 'disconnect' });
+ this.end(reason);
+
+ return this;
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+Transport.prototype.close = function () {
+ if (this.open) {
+ this.doClose();
+ this.onClose();
+ }
+};
+
+/**
+ * Called upon a connection close.
+ *
+ * @api private
+ */
+
+Transport.prototype.onClose = function () {
+ if (this.open) {
+ this.setCloseTimeout();
+ this.clearHandlers();
+ this.open = false;
+ this.manager.onClose(this.id);
+ this.store.publish('close', this.id);
+ }
+};
+
+/**
+ * Cleans up the connection, considers the client disconnected.
+ *
+ * @api private
+ */
+
+Transport.prototype.end = function (reason) {
+ if (!this.disconnected) {
+ this.log.info('transport end');
+
+ var local = this.manager.transports[this.id];
+
+ this.close();
+ this.clearTimeouts();
+ this.disconnected = true;
+
+ if (local) {
+ this.manager.onClientDisconnect(this.id, reason, true);
+ } else {
+ this.store.publish('disconnect:' + this.id, reason);
+ }
+ }
+};
+
+/**
+ * Signals that the transport should pause and buffer data.
+ *
+ * @api public
+ */
+
+Transport.prototype.discard = function () {
+ this.log.debug('discarding transport');
+ this.discarded = true;
+ this.clearTimeouts();
+ this.clearHandlers();
+
+ return this;
+};
+
+/**
+ * Writes an error packet with the specified reason and advice.
+ *
+ * @param {Number} advice
+ * @param {Number} reason
+ * @api public
+ */
+
+Transport.prototype.error = function (reason, advice) {
+ this.packet({
+ type: 'error'
+ , reason: reason
+ , advice: advice
+ });
+
+ this.log.warn(reason, advice ? ('client should ' + advice) : '');
+ this.end('error');
+};
+
+/**
+ * Write a packet.
+ *
+ * @api public
+ */
+
+Transport.prototype.packet = function (obj) {
+ return this.write(parser.encodePacket(obj));
+};
+
+/**
+ * Writes a volatile message.
+ *
+ * @api private
+ */
+
+Transport.prototype.writeVolatile = function (msg) {
+ if (this.open) {
+ if (this.drained) {
+ this.write(msg);
+ } else {
+ this.log.debug('ignoring volatile packet, buffer not drained');
+ }
+ } else {
+ this.log.debug('ignoring volatile packet, transport not open');
+ }
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+var WebSocket = require('./websocket');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = FlashSocket;
+
+/**
+ * The FlashSocket transport is just a proxy
+ * for WebSocket connections.
+ *
+ * @api public
+ */
+
+function FlashSocket (mng, data, req) {
+ WebSocket.call(this, mng, data, req);
+}
+
+/**
+ * Inherits from WebSocket.
+ */
+
+FlashSocket.prototype.__proto__ = WebSocket.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+FlashSocket.prototype.name = 'flashsocket';
+
+/**
+ * Listens for new configuration changes of the Manager
+ * this way we can enable and disable the flash server.
+ *
+ * @param {Manager} Manager instance.
+ * @api private
+ */
+
+var server;
+
+FlashSocket.init = function (manager) {
+ function create () {
+ server = require('policyfile').createServer({
+ log: function(msg){
+ manager.log.info(msg.toLowerCase());
+ }
+ }, manager.get('origins'));
+
+ server.on('close', function (e) {
+ server = null;
+ });
+
+ server.listen(manager.get('flash policy port'), manager.server);
+
+ manager.flashPolicyServer = server;
+ }
+
+ // listen for origin changes, so we can update the server
+ manager.on('set:origins', function (value, key) {
+ if (!server) return;
+
+ // update the origins and compile a new response buffer
+ server.origins = Array.isArray(value) ? value : [value];
+ server.compile();
+ });
+
+ // destory the server and create a new server
+ manager.on('set:flash policy port', function (value, key) {
+ var transports = manager.get('transports');
+
+ if (server && server.port !== value && ~transports.indexOf('flashsocket')) {
+ // destroy the server and rebuild it on a new port
+ server.close();
+ create();
+ }
+ });
+
+ // only start the server
+ manager.on('set:transports', function (value, key){
+ if (!server && ~manager.get('transports').indexOf('flashsocket')) {
+ create();
+ }
+ });
+
+ // check if we need to initialize at start
+ if (~manager.get('transports').indexOf('flashsocket')){
+ create();
+ }
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPTransport = require('./http');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = HTMLFile;
+
+/**
+ * HTMLFile transport constructor.
+ *
+ * @api public
+ */
+
+function HTMLFile (mng, data, req) {
+ HTTPTransport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+HTMLFile.prototype.__proto__ = HTTPTransport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+HTMLFile.prototype.name = 'htmlfile';
+
+/**
+ * Handles the request.
+ *
+ * @api private
+ */
+
+HTMLFile.prototype.handleRequest = function (req) {
+ HTTPTransport.prototype.handleRequest.call(this, req);
+
+ if (req.method == 'GET') {
+ req.res.writeHead(200, {
+ 'Content-Type': 'text/html'
+ , 'Connection': 'keep-alive'
+ , 'Transfer-Encoding': 'chunked'
+ });
+
+ req.res.write(
+ '<html><body>'
+ + '<script>var _ = function (msg) { parent.s._(msg, document); };</script>'
+ + new Array(174).join(' ')
+ );
+ }
+};
+
+/**
+ * Performs the write.
+ *
+ * @api private
+ */
+
+HTMLFile.prototype.write = function (data) {
+ data = '<script>_(' + JSON.stringify(data) + ');</script>';
+
+ if (this.response.write(data)) {
+ this.drained = true;
+ }
+
+ this.log.debug(this.name + ' writing', data);
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPTransport = require('./http');
+
+/**
+ * Exports the constructor.
+ */
+
+exports = module.exports = HTTPPolling;
+
+/**
+ * HTTP polling constructor.
+ *
+ * @api public.
+ */
+
+function HTTPPolling (mng, data, req) {
+ HTTPTransport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from HTTPTransport.
+ *
+ * @api public.
+ */
+
+HTTPPolling.prototype.__proto__ = HTTPTransport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+HTTPPolling.prototype.name = 'httppolling';
+
+/**
+ * Removes heartbeat timeouts for polling.
+ */
+
+HTTPPolling.prototype.setHeartbeatInterval = function () {
+ return this;
+};
+
+/**
+ * Handles a request
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.handleRequest = function (req) {
+ HTTPTransport.prototype.handleRequest.call(this, req);
+
+ if (req.method == 'GET') {
+ var self = this;
+
+ this.pollTimeout = setTimeout(function () {
+ self.packet({ type: 'noop' });
+ self.log.debug(self.name + ' closed due to exceeded duration');
+ }, this.manager.get('polling duration') * 1000);
+
+ this.log.debug('setting poll timeout');
+ }
+};
+
+/**
+ * Clears polling timeout
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.clearPollTimeout = function () {
+ if (this.pollTimeout) {
+ clearTimeout(this.pollTimeout);
+ this.pollTimeout = null;
+ this.log.debug('clearing poll timeout');
+ }
+
+ return this;
+};
+
+/**
+ * Override clear timeouts to clear the poll timeout
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.clearTimeouts = function () {
+ HTTPTransport.prototype.clearTimeouts.call(this);
+
+ this.clearPollTimeout();
+};
+
+/**
+ * doWrite to clear poll timeout
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.doWrite = function () {
+ this.clearPollTimeout();
+};
+
+/**
+ * Performs a write.
+ *
+ * @api private.
+ */
+
+HTTPPolling.prototype.write = function (data, close) {
+ this.doWrite(data);
+ this.response.end();
+ this.onClose();
+};
+
+/**
+ * Override end.
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.end = function () {
+ this.clearPollTimeout();
+ return HTTPTransport.prototype.end.call(this);
+};
+
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../transport')
+ , parser = require('../parser')
+ , qs = require('querystring');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = HTTPTransport;
+
+/**
+ * HTTP interface constructor. For all non-websocket transports.
+ *
+ * @api public
+ */
+
+function HTTPTransport (mng, data, req) {
+ Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+HTTPTransport.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Handles a request.
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.handleRequest = function (req) {
+ if (req.method == 'POST') {
+ var buffer = ''
+ , res = req.res
+ , origin = req.headers.origin
+ , headers = { 'Content-Length': 1 }
+ , self = this;
+
+ req.on('data', function (data) {
+ buffer += data;
+ });
+
+ req.on('end', function () {
+ self.onData(self.postEncoded ? qs.parse(buffer).d : buffer);
+ });
+
+ if (origin) {
+ // https://developer.mozilla.org/En/HTTP_Access_Control
+ headers['Access-Control-Allow-Origin'] = '*';
+
+ if (req.headers.cookie) {
+ headers['Access-Control-Allow-Credentials'] = 'true';
+ }
+ }
+
+ res.writeHead(200, headers);
+ res.end('1');
+ } else {
+ this.response = req.res;
+
+ Transport.prototype.handleRequest.call(this, req);
+ }
+};
+
+/**
+ * Handles data payload.
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.onData = function (data) {
+ var messages = parser.decodePayload(data);
+
+ for (var i = 0, l = messages.length; i < l; i++) {
+ this.log.debug(this.name + ' received data packet', data);
+ this.onMessage(messages[i]);
+ }
+};
+
+/**
+ * Closes the request-response cycle
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.doClose = function () {
+ this.response.end();
+};
+
+/**
+ * Writes a payload of messages
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.payload = function (msgs) {
+ this.write(parser.encodePayload(msgs));
+};
--- /dev/null
+
+/**
+ * Export transports.
+ */
+
+module.exports = {
+ websocket: require('./websocket')
+ , flashsocket: require('./flashsocket')
+ , htmlfile: require('./htmlfile')
+ , 'xhr-polling': require('./xhr-polling')
+ , 'jsonp-polling': require('./jsonp-polling')
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPPolling = require('./http-polling');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = JSONPPolling;
+
+/**
+ * JSON-P polling transport.
+ *
+ * @api public
+ */
+
+function JSONPPolling (mng, data, req) {
+ HTTPPolling.call(this, mng, data, req);
+
+ this.head = 'io.j[0](';
+ this.foot = ');';
+
+ if (data.query.i) {
+ this.head = 'io.j[' + data.query.i + '](';
+ }
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+JSONPPolling.prototype.__proto__ = HTTPPolling.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+JSONPPolling.prototype.name = 'jsonppolling';
+
+/**
+ * Make sure POST are decoded.
+ */
+
+JSONPPolling.prototype.postEncoded = true;
+
+/**
+ * Performs the write.
+ *
+ * @api private
+ */
+
+JSONPPolling.prototype.doWrite = function (data) {
+ HTTPPolling.prototype.doWrite.call(this);
+
+ var data = data === undefined
+ ? '' : this.head + JSON.stringify(data) + this.foot;
+
+ this.response.writeHead(200, {
+ 'Content-Type': 'text/javascript; charset=UTF-8'
+ , 'Content-Length': Buffer.byteLength(data)
+ , 'Connection': 'Keep-Alive'
+ });
+
+ this.response.write(data);
+ this.log.debug(this.name + ' writing', data);
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../transport')
+ , EventEmitter = process.EventEmitter
+ , crypto = require('crypto')
+ , parser = require('../parser');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = WebSocket;
+
+/**
+ * HTTP interface constructor. Interface compatible with all transports that
+ * depend on request-response cycles.
+ *
+ * @api public
+ */
+
+function WebSocket (mng, data, req) {
+ // parser
+ var self = this;
+
+ this.parser = new Parser();
+ this.parser.on('data', function (packet) {
+ self.log.debug(self.name + ' received data packet', packet);
+ self.onMessage(parser.decodePacket(packet));
+ });
+ this.parser.on('close', function () {
+ self.end();
+ });
+ this.parser.on('error', function () {
+ self.end();
+ });
+
+ Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+WebSocket.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+WebSocket.prototype.name = 'websocket';
+
+/**
+ * Called when the socket connects.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.onSocketConnect = function () {
+ var self = this;
+
+ this.socket.setNoDelay(true);
+
+ this.buffer = true;
+ this.buffered = [];
+
+ if (this.req.headers.upgrade !== 'WebSocket') {
+ this.log.warn(this.name + ' connection invalid');
+ this.end();
+ return;
+ }
+
+ var origin = this.req.headers.origin
+ , location = (this.socket.encrypted ? 'wss' : 'ws')
+ + '://' + this.req.headers.host + this.req.url
+ , waitingForNonce = false;
+
+ if (this.req.headers['sec-websocket-key1']) {
+ // If we don't have the nonce yet, wait for it (HAProxy compatibility).
+ if (! (this.req.head && this.req.head.length >= 8)) {
+ waitingForNonce = true;
+ }
+
+ var headers = [
+ 'HTTP/1.1 101 WebSocket Protocol Handshake'
+ , 'Upgrade: WebSocket'
+ , 'Connection: Upgrade'
+ , 'Sec-WebSocket-Origin: ' + origin
+ , 'Sec-WebSocket-Location: ' + location
+ ];
+
+ if (this.req.headers['sec-websocket-protocol']){
+ headers.push('Sec-WebSocket-Protocol: '
+ + this.req.headers['sec-websocket-protocol']);
+ }
+ } else {
+ var headers = [
+ 'HTTP/1.1 101 Web Socket Protocol Handshake'
+ , 'Upgrade: WebSocket'
+ , 'Connection: Upgrade'
+ , 'WebSocket-Origin: ' + origin
+ , 'WebSocket-Location: ' + location
+ ];
+ }
+
+ try {
+ this.socket.write(headers.concat('', '').join('\r\n'));
+ this.socket.setTimeout(0);
+ this.socket.setNoDelay(true);
+ this.socket.setEncoding('utf8');
+ } catch (e) {
+ this.end();
+ return;
+ }
+
+ if (waitingForNonce) {
+ this.socket.setEncoding('binary');
+ } else if (this.proveReception(headers)) {
+ self.flush();
+ }
+
+ var headBuffer = '';
+
+ this.socket.on('data', function (data) {
+ if (waitingForNonce) {
+ headBuffer += data;
+
+ if (headBuffer.length < 8) {
+ return;
+ }
+
+ // Restore the connection to utf8 encoding after receiving the nonce
+ self.socket.setEncoding('utf8');
+ waitingForNonce = false;
+
+ // Stuff the nonce into the location where it's expected to be
+ self.req.head = headBuffer.substr(0, 8);
+ headBuffer = '';
+
+ if (self.proveReception(headers)) {
+ self.flush();
+ }
+
+ return;
+ }
+
+ self.parser.add(data);
+ });
+};
+
+/**
+ * Writes to the socket.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.write = function (data) {
+ if (this.open) {
+ this.drained = false;
+
+ if (this.buffer) {
+ this.buffered.push(data);
+ return this;
+ }
+
+ var length = Buffer.byteLength(data)
+ , buffer = new Buffer(2 + length);
+
+ buffer.write('\u0000', 'binary');
+ buffer.write(data, 1, 'utf8');
+ buffer.write('\uffff', 1 + length, 'binary');
+
+ try {
+ if (this.socket.write(buffer)) {
+ this.drained = true;
+ }
+ } catch (e) {
+ this.end();
+ }
+
+ this.log.debug(this.name + ' writing', data);
+ }
+};
+
+/**
+ * Flushes the internal buffer
+ *
+ * @api private
+ */
+
+WebSocket.prototype.flush = function () {
+ this.buffer = false;
+
+ for (var i = 0, l = this.buffered.length; i < l; i++) {
+ this.write(this.buffered.splice(0, 1)[0]);
+ }
+};
+
+/**
+ * Finishes the handshake.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.proveReception = function (headers) {
+ var self = this
+ , k1 = this.req.headers['sec-websocket-key1']
+ , k2 = this.req.headers['sec-websocket-key2'];
+
+ if (k1 && k2){
+ var md5 = crypto.createHash('md5');
+
+ [k1, k2].forEach(function (k) {
+ var n = parseInt(k.replace(/[^\d]/g, ''))
+ , spaces = k.replace(/[^ ]/g, '').length;
+
+ if (spaces === 0 || n % spaces !== 0){
+ self.log.warn('Invalid ' + self.name + ' key: "' + k + '".');
+ self.end();
+ return false;
+ }
+
+ n /= spaces;
+
+ md5.update(String.fromCharCode(
+ n >> 24 & 0xFF,
+ n >> 16 & 0xFF,
+ n >> 8 & 0xFF,
+ n & 0xFF));
+ });
+
+ md5.update(this.req.head.toString('binary'));
+
+ try {
+ this.socket.write(md5.digest('binary'), 'binary');
+ } catch (e) {
+ this.end();
+ }
+ }
+
+ return true;
+};
+
+/**
+ * Writes a payload.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.payload = function (msgs) {
+ for (var i = 0, l = msgs.length; i < l; i++) {
+ this.write(msgs[i]);
+ }
+
+ return this;
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.doClose = function () {
+ this.socket.end();
+};
+
+/**
+ * WebSocket parser
+ *
+ * @api public
+ */
+
+function Parser () {
+ this.buffer = '';
+ this.i = 0;
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Adds data to the buffer.
+ *
+ * @api public
+ */
+
+Parser.prototype.add = function (data) {
+ this.buffer += data;
+ this.parse();
+};
+
+/**
+ * Parses the buffer.
+ *
+ * @api private
+ */
+
+Parser.prototype.parse = function () {
+ for (var i = this.i, chr, l = this.buffer.length; i < l; i++){
+ chr = this.buffer[i];
+
+ if (this.buffer.length == 2 && this.buffer[1] == '\u0000') {
+ this.emit('close');
+ this.buffer = '';
+ this.i = 0;
+ return;
+ }
+
+ if (i === 0){
+ if (chr != '\u0000')
+ this.error('Bad framing. Expected null byte as first frame');
+ else
+ continue;
+ }
+
+ if (chr == '\ufffd'){
+ this.emit('data', this.buffer.substr(1, i - 1));
+ this.buffer = this.buffer.substr(i + 1);
+ this.i = 0;
+ return this.parse();
+ }
+ }
+};
+
+/**
+ * Handles an error
+ *
+ * @api private
+ */
+
+Parser.prototype.error = function (reason) {
+ this.buffer = '';
+ this.i = 0;
+ this.emit('error', reason);
+ return this;
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPPolling = require('./http-polling');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = XHRPolling;
+
+/**
+ * Ajax polling transport.
+ *
+ * @api public
+ */
+
+function XHRPolling (mng, data, req) {
+ HTTPPolling.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+XHRPolling.prototype.__proto__ = HTTPPolling.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+XHRPolling.prototype.name = 'xhr-polling';
+
+/**
+ * Frames data prior to write.
+ *
+ * @api private
+ */
+
+XHRPolling.prototype.doWrite = function (data) {
+ HTTPPolling.prototype.doWrite.call(this);
+
+ var origin = this.req.headers.origin
+ , headers = {
+ 'Content-Type': 'text/plain; charset=UTF-8'
+ , 'Content-Length': data === undefined ? 0 : Buffer.byteLength(data)
+ , 'Connection': 'Keep-Alive'
+ };
+
+ if (origin) {
+ // https://developer.mozilla.org/En/HTTP_Access_Control
+ headers['Access-Control-Allow-Origin'] = '*';
+
+ if (this.req.headers.cookie) {
+ headers['Access-Control-Allow-Credentials'] = 'true';
+ }
+ }
+
+ this.response.writeHead(200, headers);
+ this.response.write(data);
+ this.log.debug(this.name + ' writing', data);
+};
--- /dev/null
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+/**
+ * Converts an enumerable to an array.
+ *
+ * @api public
+ */
+
+exports.toArray = function (enu) {
+ var arr = [];
+
+ for (var i = 0, l = enu.length; i < l; i++)
+ arr.push(enu[i]);
+
+ return arr;
+};
--- /dev/null
+
+var express = require('express')
+ , stylus = require('stylus');
+
+var app = express.createServer();
+
+app.configure(function () {
+ app.use(stylus.middleware({ src: __dirname + '/public/css' }));
+ app.use(express.static(__dirname + '/public'));
+ app.set('views', __dirname);
+ app.set('view engine', 'jade');
+});
+
+app.get('/', function (req, res) {
+ res.render('index');
+});
+
+app.get('/new', function (req, res) {
+ res.render('new');
+});
+
+app.listen(3000);
--- /dev/null
+e inde doctype 5
+html
+ head
+ title Socket.IO: realtime cross-browser web apps toolkit.
+ link(href='css/main.css', rel='stylesheet', media='all')
+
+ script(src='js/main.js')
+ script
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-18488944-1']);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+ body
+ #wrap
+ #header
+ .subtext Introducing
+ a(href='/', class='logo') Socket.IO
+ a(href='http://github.com/learnboost/socket.io-node', class='download')
+ span.version v
+ span.version .7
+ #content
+ .section
+ form(action='http://groups.google.com/group/socket_io/boxsubscribe')
+ a#google-subscribe-link(href='http://groups.google.com/group/socket_io')
+ img(src='images/groups.png', border='0')
+ #google-subscribe-input
+ | Email:
+ input#google-subscribe-email(type='text', name='email')
+ input(type='submit', name='go', value='Subscribe')
--- /dev/null
+doctype 5
+html
+ head
+ title Socket.IO: realtime cross-browser web apps toolkit.
+ link(href='css/main.css', rel='stylesheet', media='all')
+
+ script(src='js/main.js')
+ script
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-18488944-1']);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+ body
+ #wrap
+ #header
+ .subtext Introducing
+ a(href='/', class='logo') Socket.IO
+ a(href='http://github.com/learnboost/socket.io-node', class='download')
+ span.version v
+ span.version .6
+ #content
+ .section
+ form(action='http://groups.google.com/group/socket_io/boxsubscribe')
+ a#google-subscribe-link(href='http://groups.google.com/group/socket_io')
+ img(src='images/groups.png', border='0')
+ #google-subscribe-input
+ | Email:
+ input#google-subscribe-email(type='text', name='email')
+ input(type='submit', name='go', value='Subscribe')
+ .section#menu
+ ul
+ li.current: a(href='#') Home
+ li.current: a(href='#') Projects
+ li.current: a(href='#') Docs
+ li.current: a(href='#') FAQ
+ .section
+ a(href='/new') Socket.IO 0.7 is out! Click here to see what's new and what's changed.
--- /dev/null
+{
+ "name": "socket.io-website"
+ , "version": "0.0.1"
+ , "dependencies": {
+ "express": "2.3.11"
+ , "jade": "0.12.1"
+ , "stylus": "0.13.3"
+ }
+}
--- /dev/null
+function getMembers(data){
+ if (!(data && data.query && data.query.results && data.query.results.p)) return;
+ var members = document.createElement('span');
+ members.id = 'google-members-count';
+ members.innerHTML = '('+ data.query.results.p +' members)';
+ document.getElementsByTagName('FORM')[0].insertBefore(members, document.getElementById('google-subscribe-input'));
+};
+
+window.onload = function(){
+ document.getElementById('google-subscribe-email').onfocus = function(){
+ document.getElementById('google-subscribe-input').className = 'focus';
+ };
+ document.getElementById('google-subscribe-email').onblur = function(){
+ document.getElementById('google-subscribe-input').className = '';
+ };
+
+ // lame jsonp
+ var script = document.createElement('script');
+ // yql: select * from html where url="http://groups.google.com/group/socket_io/about" and xpath='//div[@class=\'maincontbox\']/table/tr[1]/td/p[1]
+ script.src = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2Fgroups.google.com%2Fgroup%2Fsocket_io%2Fabout%22%20and%20xpath%3D'%2F%2Fdiv%5B%40class%3D%5C'maincontbox%5C'%5D%2Ftable%2Ftr%5B1%5D%2Ftd%2Fp%5B1%5D'%0A&format=json&callback=getMembers";
+ document.head.appendChild(script);
+};
--- /dev/null
+{
+ "name": "socket.io"
+ , "version": "0.7.7"
+ , "description": "Real-time apps made cross-browser & easy with a WebSocket-like API"
+ , "homepage": "http://socket.io"
+ , "keywords": ["websocket", "socket", "realtime", "socket.io", "comet", "ajax"]
+ , "author": "Guillermo Rauch <guillermo@learnboost.com>"
+ , "contributors": [
+ { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
+ , { "name": "Arnout Kazemier", "email": "info@3rd-eden.com" }
+ , { "name": "Vladimir Dronnikov", "email": "dronnikov@gmail.com" }
+ ]
+ , "repository":{
+ "type": "git"
+ , "url": "https://github.com/LearnBoost/Socket.IO-node.git"
+ }
+ , "dependencies": {
+ "socket.io-client": "0.7.4"
+ , "policyfile": "0.0.3"
+ , "redis": "0.6.0"
+ }
+ , "devDependencies": {
+ "expresso": "0.7.7"
+ , "should": "0.0.4"
+ }
+ , "main": "index"
+ , "engines": { "node": ">= 0.4.0" }
+}