Pages

Tuesday, December 31, 2013

node.js, express.js & the redis sessions store with encryption

node.js

For those of you that are already familiar with the wonderful language that is node.js please read ahead. For those that are not, lets close the gap.

Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

express.js

Much like any other web or interpreted language (Ruby, PHP, Python etc), node.js also has existing framworks to cut down development time. express.js is one of those frameworks.

One of the very nice things about express.js is performing operations such as the following:

$ npm install -g express
$ express --sessions --css stylus --ejs myapp
     
  create : myapp
  create : myapp/package.json
  create : myapp/app.js
  create : myapp/public
  create : myapp/public/javascripts
  create : myapp/public/images
  create : myapp/public/stylesheets
  create : myapp/public/stylesheets/style.styl
  create : myapp/routes
  create : myapp/routes/index.js
  create : myapp/views
  create : myapp/views/index.ejs

install dependencies:

$ cd myapp && npm install

run the app:

$ node app

What the above output performs is create a new project (in the exampled named 'myapp') that contains a very simple web application complete with stylesheets, HTML & the code necessary to run a web server application.

In addition their repo contains numerous project examples to help you get your own project up and running quickly.

redis

If your not familiar with redis perhaps an alternate tool such as memcached is more familiar. Both are software which can be used to serve content quickly and efficiently as they do not utilize disk writes etc and instead store the key/value data within memory making them extremely fast and useful for things such as 'session storage'.

Now that we have some background on redis, lets go back to talking about express.js. The express.js framework is simply a high level API providing access to the connect.js middleware for node.js.

sessions

This particular concent is in its simplest form the earliest method of allowing for persistant variable use within the HTTP 1.0 protocol. Because HTTP is considered a 'stateless' protocol developers needed a way to keep information from one page request to the next.

Use of sessions within the express.js framework is very easy. See below for a simple example of its use within the project we created earlier.

app.use(express.cookieParser());
app.use(express.session({secret: 'kung fu'}));

connect.js custom session store

There are many reasons one might want to use a custom session store. From the connect.js session manual:

Warning: connection.session() MemoryStore is not designed for a production environment, as it will leak memory, and will not scale past a single process.

As noted to ensure the scalability and stability of any web application requiring use of sessions it is best to utilize a custom session store.

Not to worry there are plenty of quality session store middleware modules we can choose from.

connect-redis-crypto

The connect-redis-crypto module is based on the connect-redis module which provides a transparent method of getting/setting/destroying server side sessions from connect.js middlware and implemented within the express.js framework.

The reason why connect-redis-crypto exists is because according to OWASP session management recommendations...

The stored information can include the client IP address, User-Agent, e-mail, username, user ID, role, privilege level, access rights, language preferences, account ID, current state, last login, session timeouts, and other internal session details. If the session objects and properties contain sensitive information, such as credit card numbers, it is required to duly encrypt and protect the session management repository.

Now lets see how to use it within our project:

var express = require('express'),
    RedisStore = require('connect-redis')(express);
     
app.use(express.session({
  secret: 'cookie signature secret',
  store: store: new RedisStore({
    secret: 'sessions crypto secret'
  })
}));

Summary

Not everyone is going to require the use of encryption for managing their session data but for those that do my fork of an already great module should be of assistance.

Monday, December 9, 2013

node.js, DH key exchanges & HMAC

What the !@#$ are you talking about?

Security is difficult to understand, cryptology doubly so. I recently read a wonderful blog post regarding 'cryptographic right answers'.

Seeing as this particular blog came from an expert in the field of cryptology implementation (et al; the developer of 'scrypt' hashing algorithm) and security (former BSD security officer), I think it is worth a read.

If your in a rush, the summary goes somewhere along the lines of 'use xyz algorithm due to the following abc strengths' and 'always use an HMAC to prevent tampering'.

Use SSL/TLS! blah blah!

Yes, I agree, however this protocol is not without its faults and weaknesses

The majority of my interest in this stems from researching methods to prevent or isolate and protect HTTP header & content in the event of a cipher downgrade, side channel, brute force, session renegotiation attack stemming from a traditional MITM or BGP routing bug presents itself.

Use oAuth! blah, blah!

This is also a very valid point and I also agree. However, leaving these fields visibly defined makes it easy in the event of a 'replay attack'.

The majority of today's HMAC use within the HTTP/HTTPS protocols get embedded within the browser response or the clients request headers as shown in figure 1 and defined in the IETF oAuth draft. The 'oauth_signature' field is clearly shown. (To test or see more examples of the oAuth header values, please visit hueniverse.com)

Figure 1
GET /?abc=123 HTTP/1.1
Host: abc.com:443
Authorization: OAuth realm="https://abc.com/",
    oauth_consumer_key="xyz",
    oauth_token="456",
    oauth_nonce="213",
    oauth_timestamp="0",
    oauth_signature_method="HMAC-SHA1",
    oauth_version="2.0",
    oauth_signature="Q%2BuWrnEFBv8CEwtNuxn3bIdkjsY%3D"

In the event of a communications channel being compromised the 'oauth_signature' field can be easily recalculated by an attacker based on the modified contents leaving the server/client none-the-wiser that their message has indeed been modified.

While the concept of utilizing a HMAC to verify a message is not a new concept, the question arises 'How can one use an HMAC effectively in an scenario where the TLS/SSL communications channel has been compromised?'

Ok, ok you made you point, now what?!

While I realize that my proposal is not a standard or even typical solution to the above mentioned attack vectors, it should prove beneficial if and when the need presents itself.

Figure 2 is an exportable module to assist in creating a 'hidden' payload which contains a valid HMAC digest & data payload. This of course could be expanded to accommodate for the use of a 'nonce' as well as a 'timestamp' (both can be very beneficial, and recommended, when it comes to providing the utmost security from attacks).

Figure 1
/*
 * node-dhcp-manager
 *
 * Copyright 2013 Jason Gerfen
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

exports.createPayload = function(payload, digest, count) {
  var a = [],
      b = digest.split(''),
      iteration = count || 3,
      ret = []

  do {
    a.push(payload.substring(0, iteration))
  } while((payload = payload.substring(iteration, payload.length)) != "")

  for (var n = 0; n < a.length; n++) {
    if (b[n] && a[n]) {
        ret.push(a[n]+b[n]);
    } else if(b[n] && !a[n]) {
        ret.push(b[n]);
    } else if(!b[n] && a[n]) {
        ret.push(a[n])
    }
  }
  return ret.join('')
}

exports.extractPayload = function(payload, size, count) {
  var num = count + 1 || 4,
      regex1 = new RegExp('.{1,'+num+'}', 'g'),
      data1 = payload.match(regex1),
      regex2 = new RegExp('.{1,'+num+'}', 'g'),
      data2 = payload.match(regex2),
      digest = [],
      data = [],
      i = 0

  for (var n = 0; n < size; n++) {
    digest.push(data1[n].substr(count, data1[n].length))
  }

  data2.forEach(function(item) {
    if (i < size) {
      data.push(item.substr(0, item.length - 1))
    } else {
      data.push(item)
    }
    i++
  })

  return {
    digest: digest.join(''),
    payload: data.join('')
  }
}

What does this have to do with a DH exchange?!

Patience is a virtue! To utilize this particular module please refer to figure 3 which 'simulates' a Diffie-Hellman key exchange between two parties.

Figure 3
/*
 * node-dhcp-manager
 *
 * Copyright 2013 Jason Gerfen
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

var chai = require('chai'),
    expect = chai.expect,
    should = chai.should(),
    crypto = require('../libs/crypto'),
    hs = require('../libs/handshake'),
    bob = crypto.init(),
    alice = crypto.init(),
    bobSecret = crypto.createSharedSecret(alice.pubKey),
    bobPubKey = crypto.encryptData(bobSecret, bob.pubKey),
    bobDigest = crypto.createDigest(bobSecret, bobPubKey),
    bobPayload = hs.createPayload(bobPubKey, bobDigest, 3)
    bobObj = hs.extractPayload(bobPayload, 128, 3),
    aliceSecret = crypto.createSharedSecret(bob.pubKey),
    alicePubKey = crypto.encryptData(aliceSecret, alice.pubKey),
    aliceDigest = crypto.createDigest(aliceSecret, alicePubKey)
    alicePayload = hs.createPayload(alicePubKey, aliceDigest, 3),
    aliceObj = hs.extractPayload(alicePayload, 128, 3)

describe('handshake.js', function(){

  describe('DH exchange', function(){
    it('bob & alice must share secret', function(done){

      expect(bobSecret).to.equal(aliceSecret)

      done()
    })
  })

  describe('create payload', function(){
    it('must return valid payload', function(done){

      expect(bobPayload).to.have.length(4224)
      expect(alicePayload).to.have.length(4224)

      done()
    })
  })

  describe('extract data from payload', function(){
    it('must contain valid payload & digest', function(done){

      bobObj.should.be.a('object')
      expect(bobObj).to.have.property('digest').with.length(128)
      expect(bobObj).to.have.property('payload').with.length(4096)

      aliceObj.should.be.a('object')
      expect(aliceObj).to.have.property('digest').with.length(128)
      expect(aliceObj).to.have.property('payload').with.length(4096)

      done()
    })
  })

  describe('verify digest', function(){
    it('must contain valid digest of payload', function(done){

      expect(bobObj.digest).to.equal(bobDigest)
      expect(aliceObj.digest).to.equal(aliceDigest)

      done()
    })
  })

  describe('verify keys', function(){
    it('must contain matching keys from originals', function(done){

      expect(crypto.decryptData(bobSecret, bobObj.payload)).to.equal(bob.pubKey)
      expect(crypto.decryptData(aliceSecret, aliceObj.payload)).to.equal(alice.pubKey)

      done()
    })
  })
})

Shameless plug

The above code snippets come from a much larger project which can be found @ node-dhcp-manager.

Monday, November 25, 2013

Database encrypted fields & key lifetime policies

Encryption Key Lifetimes

The majority of projects I come across that utilize or implement symmetric encryption don't necessarily address the issue of the key lifetime.

In simplest terms, the longer a key is in use is directly proportionate to the strength of the key.

As Tyle Durden puts it, "On a long enough time line, the survival rate for everyone drops to zero."

Problem With Administration

Maintaining a key's lifetime can be time consuming.

First you have to decrypt each and every field within a database using the current key, generate a new key of adequate length, then re-encrypt the data using the new key. This is, and should be an operation that occurs at a scheduled time and preferably off duty hours.

Consider the following scenario;

A key has been in use for six months, the current threat model dictates each database encryption key should be rotated every three months. Think of a public facing database server within a corporate DMZ.

Depending on the size of the database this quite literally could take hours and possibly days and its key is already past its life cycle by three months which has severely weakened the strength of its usefulness.

I Need A Robot!!

Indeed, I could use one to get me beers but modern science has yet to grant me this one simple wish.

For those with fairly large budgets enterprise solutions exist, however for those of us that exist on shoe string budgets perhaps my project; sqlSec can be of assistance.

I have been developing sqlSec to help with symmetric key rotation using a series of stored procedures in MySQL.

The robot is not really a robot, although for the daring it can be used and fired using an event scheduler to automatically rotate encryption keys.

Features?

Sure, it has quite a few:

  1. Easy installation
  2. Easy configuration
  3. Auto-backup options
  4. Scheduler ready
  5. Testing tools
  6. Migration tools

Download?

You can use Git (recommended) or download the package.

%> git clone https://github.com/jas-/sqlSec.git

Install?

I have made this process as easy as possible. Once you have extracted the zip file or cloned the repo simply run the installer.

%> ./install
sqlSec
Automate encryption key rotation for database
encrypted fields to meet password lifetime
security policies

Creating necessary database creation objects...

Database installation credentials

Enter MySQL username: root
Enter root MySQL password: 

Database settings

Database server name [localhost]: 
1) dhcp
Select database to use: 1

Backup directory [/tmp]: 

Create a backup?  [Y/n] 
Backup created... /tmp/2013-10-23-dhcp.sql

Creating database, users & permissions
Creating key rotaton procedures

Specify encrypted fields for database: dhcp

1) cors                  8) interfaces          15) sqlSec_settings
2) dns_servers           9) myTest              16) subnets
3) dns_zones            10) options             17) traffic
4) dnssec_keys          11) pools               18) viewServers
5) failover             12) routes              19) viewServersDetails
6) groups               13) servers             20) viewTraffic
7) hosts                14) sqlSec_map          21) Quit
Select table to view fields: 7
1) id                4) hardware-address  7) lease
2) hostname          5) subnet            8) notes
3) address           6) group             9) Main
Select field to enable encryption: 4
1) id                4) hardware-address  7) lease
2) hostname          5) subnet            8) notes
3) address           6) group             9) Main
Select field to enable encryption: 6
1) id                4) hardware-address  7) lease
2) hostname          5) subnet            8) notes
3) address           6) group             9) Main
Select field to enable encryption: 9
1) cors                  8) interfaces          15) sqlSec_settings
2) dns_servers           9) myTest              16) subnets
3) dns_zones            10) options             17) traffic
4) dnssec_keys          11) pools               18) viewServers
5) failover             12) routes              19) viewServersDetails
6) groups               13) servers             20) viewTraffic
7) hosts                14) sqlSec_map          21) Quit
Select table to view fields: 12
1) id
2) hostname
3) route
4) address
5) Main
Select field to enable encryption: 4
1) id
2) hostname
3) route
4) address
5) Main
Select field to enable encryption: 5
1) cors                  8) interfaces          15) sqlSec_settings
2) dns_servers           9) myTest              16) subnets
3) dns_zones            10) options             17) traffic
4) dnssec_keys          11) pools               18) viewServers
5) failover             12) routes              19) viewServersDetails
6) groups               13) servers             20) viewTraffic
7) hosts                14) sqlSec_map          21) Quit
Select table to view fields: 16
1) id        3) subnet    5) mask      7) route
2) hostname  4) address   6) dns       8) Main
Select field to enable encryption: 4
1) id        3) subnet    5) mask      7) route
2) hostname  4) address   6) dns       8) Main
Select field to enable encryption: 8
1) cors                  8) interfaces          15) sqlSec_settings
2) dns_servers           9) myTest              16) subnets
3) dns_zones            10) options             17) traffic
4) dnssec_keys          11) pools               18) viewServers
5) failover             12) routes              19) viewServersDetails
6) groups               13) servers             20) viewTraffic
7) hosts                14) sqlSec_map          21) Quit
Select table to view fields: 4
1) id         3) keyname    5) secret
2) hostname   4) algorithm  6) Main
Select field to enable encryption: 5
1) id         3) keyname    5) secret
2) hostname   4) algorithm  6) Main
Select field to enable encryption: 6
1) cors                  8) interfaces          15) sqlSec_settings
2) dns_servers           9) myTest              16) subnets
3) dns_zones            10) options             17) traffic
4) dnssec_keys          11) pools               18) viewServers
5) failover             12) routes              19) viewServersDetails
6) groups               13) servers             20) viewTraffic
7) hosts                14) sqlSec_map          21) Quit
Select table to view fields: 21
Cleaning up...

The process performs the following operations:

  1. Creates a randomly generated user account (privilege separation)
  2. Optionally creates backup of existing database prior to migration
  3. Adds two tables to existing database (version info & table/field mapping table)
  4. Imports stored procedures used to perform key rotation operations
  5. Provides a wizard interface to add table/field mappings which require use of encryption

Testing?

Yes, yes there are. In order to run them make sure you have run the installer, selected a database to modify & then selected table & field combinations which you wish to use as encrypted fields within the database.

If you simply wish to test with bogus data you can use the following example. This example creates 100 bogus records per table/field combination specified during the installation process so the total number of records for 5 fields on 5 tables would be 500.

%> mysql -u [username] -p[password] [db-name] -e 'CALL sqlSec_DBG_FP(100)'

Next we can perform a rotation process. During this process there is quite a few things taking place.

  1. A backup is created if specified to do so
  2. Any table/field combinations are used within primary loop
  3. The current encyption key is loaded
  4. A temporary table is created
  5. A view is created based on temporary table (used as cursor loop due to limitations in MySQL)
  6. The table/field combination values are decrypted with current key and placed in newly created temporary table
  7. A new encryption key is randomly generated
  8. The decrypted data is then encrypted with the new encryption key
  9. The newly encrypted data updates the original record id as to minimize disruption of record sets
  10. Temporary tables & views are removed

Here is a testing procedure to perform the above process X number of times, in this case X=10.

%> mysql -u [username] -p[password] [db-name] -e 'CALL sqlSec_DBG_Test(10)'

Usage?

The easiest method of saving & retrieving data once you implement the sqlSec project would be to create stored procedures to handle access to the decrypted (plain text) of the cipher text fields. Here are a few examples:

Searching records
Here is a simple example of creating a stored procedure which will search a table which contains encrypted fields.

DELIMITER //
CREATE PROCEDURE Search(IN search_param CHAR(128))
BEGIN
 CALL KR_GK(@Secret);
 SELECT `plain_text_field`, AES_DECRYPT(BINARY(UNHEX(cipher_text_field)), SHA1(@Secret)) AS cipher_text_field WHERE `plain_text_field` LIKE search_param OR AES_DECRYPT(BINARY(UNHEX(cipher_text_field)), SHA1(@Secret)) LIKE search_param;
END//
DELIMITER ;

Adding new records
Here is an example procedure that can be used to insert new encrypted data

DELIMITER //
CREATE PROCEDURE Add(IN plain_txt_field CHAR(128), IN cipher_txt_field CHAR(128))
BEGIN
 CALL KR_GK(@Secret);
 INSERT INTO `table_name` (`plain_text_field`, `cipher_text_field`) VALUES (plain_txt_field, HEX(AES_ENCRYPT(cipher_txt_field, SHA1(@Secret))));
END//
DELIMITER ;

I hope that helps some of you with small budgets, this took me a week or so of development but should serve you well.

Wednesday, November 20, 2013

node.js & the <keygen> element

History shmistory

Historically speaking this particular item should not have been introduced within the W3C HTML5 specification as it technically is NOT a new feature (first developed in 1996, subsequent SPKI working group formed in 1997, while RFC-2692 & RFC-2693 released in 1999).

PKI? WTF!? FTW!!

While by no means a turn key solution in regards to automation of user authentication certificate creation & signing for use within a PKI certificate based authentication service, it serves as a simple solution to the poor man.

Teh interwebz!

As trends in web application development have moved from the original CGI (perl's common gateway interface), to PHP, to Ruby & rails and on to node.js for server side development I decided having native support for handling of the <keygen> DOM element natively within my new favorite language was needed.

we <3 node.js

Although not officially within a stable branch at the moment the new 'Certificate' class which introduces functions to work with SPKAC can be used today to help with creating X.509 certificates which can be used for client authentication today.

Patches

To try this out you need only clone the latest node.js master branch; from a command line:

sh> git clone https://github.com/joyent/node.git
sh> cd node/
sh> ./configure
sh> make
sh> su -c "make install"

A demo?!

And now my demo project; simple is as simple does;

sh> git clone https://github.com/jas-/node-spkac.git
sh> cd node-spkac/
sh> node app.js
SPKAC demo server listening on port 3000

Now simply point your browser to http://localhost:3000 to test out the project's functionality.

Runner up!

Or if you don't want to load an unknown project you can always use the test case provided below...

sh> node test-spkac.js
test-spkac.js source
var spkac = {
  '1024': {
    'md4': 'MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYjViMzYxMTktNjY5YS00ZDljLWEyYzctMGZjNGFhMjVlMmE2MA0GCSqGSIb3DQEBAwUAA4GBAF7hu0ifzmjonhAak2FhhBRsKFDzXdKIkrWxVNe8e0bZzMrWOxFM/rqBgeH3/gtOUDRS5Fnzyq425UsTYbjfiKzxGeCYCQJb1KJ2V5Ij/mIJHZr53WYEXHQTNMGR8RPm7IxwVXVSHIgAfXsXZ9IXNbFbcaLRiSTr9/N4U+MXUWL7',
    'md5': 'MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYzBkZjFlYjctMTU0NC00MWVkLWFmN2EtZDRkYjBkNDc5ZjZmMA0GCSqGSIb3DQEBBAUAA4GBALEiapUjaIPs5uEdvCP0gFK2qofo+4GpeK1A43mu28lirYPAvCWsmYvKIZIT9TxvzmQIxAfxobf70aSNlSm6MJJKmvurAK+Bpn6ZUKQZ6A1m927LvctVSYJuUi+WVmr0fGE/OfdQ+BqSm/eQ3jnm3fBPVx1uwLPgjC5g4EvGMh8M',
    'sha1': 'MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkZmI5YWI4MTQtNjY3Ny00MmE0LWE2MGMtZjkwNWQxYTY5MjRkMA0GCSqGSIb3DQEBBQUAA4GBADu1U9t3eY9O3WOofp1RHX2rkh0TPs1CeS+sNdWUSDmdV5ifaGdeXpDikEnh4QIUIeZehxwgy2EjiZqMjMJHF++KPTzfAnHuuEtpDmIGzBnodZa1qt322iGZwgREvacv78GxJBJvPP3KLe+EDDsERG1aWLJoSZRusadacdzNmdV4',
    'sha224': 'MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkMTM4Y2MxY2ItMzNkMy00Zjk1LWFiMGEtM2I2ZWFkNzhkYjY3MA0GCSqGSIb3DQEBDgUAA4GBAKIjFSzlrhJpq1I3hKt0GL62ASgS86Lte2F0Ksp2tm2Nn8vvnZf78z46SuTW54uJT6c4NKoOgf4Fi8kk5pBR49m1ckZ8zlGvMk1d9VB7JX2oM88qA8YMlBfil8W/hI2SQ80WdffuVJ18nZFp7aqnAMB7DEYBi5Ncadnzew5+4SdO',
    'sha256': 'MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkNjRhYmQzZGYtMzgyOS00NzVjLWJjNWEtMWY4YmMwYmM2YmUxMA0GCSqGSIb3DQEBCwUAA4GBAKlPC8NGR3GNZU/vkocxpnjdWoUCqN0zr4POqpuhfYdJyrnwEuhjMD7Ti2QyIXwAirjb6otm9DAMrQURKuges8yp7JeiN94efvHJi9ceUiyP3dT6EcRtgXLF7Ifx67NK9t69UuwlTs+TJJdzR1dRICLILqA0oX2GDyaV42/rF2tF',
    'sha384': 'MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkMjIxN2FjMzItMjgxMS00MmVhLTlmMmItNTk4ZTk4ZTBlZGQwMA0GCSqGSIb3DQEBDAUAA4GBAGlUNMeVZphzRAfuH5QaMWUJFKneG+Mq3cEjxDu4uXT14geBXz76zjgfMTFaVFq2B96Pge0L5tAgRlDuBbM7SzsTQWDrR4alz+nsCKu7U3usT38ecOUnczUiYOaV1bw/OFKS47nLokyj6YWAxdvDAcEApQWUGY3+HPW9As693UwD',
    'sha512': 'MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkNGVmZmZiYjgtNmI2ZC00MTllLThhNTUtOTYzYmQzNWRkYWI5MA0GCSqGSIb3DQEBDQUAA4GBALl1q2/ce5L8Ai7CsHC7nrPbSeIfSrPFctLmPoHd1EAMOJL8yFC9fZ7l7mhPqEBh+0SKch8yrxpdzRHVGnPUfhqMdoMRK0zE9s8BoBgerH08T8ScLaFZfjHQYGM2Can8rHl4D2NkPBg3g2B6yIoszV887l3Lrxkx4whK+xTacrAc',
    'rmd160': 'MIIBWzCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYTBiNDU1MzUtNTE1YS00OTM4LWI2N2UtNTM1MTI3MGJjM2FhMAoGBiskAwMBAgUAA4GBAEAoNEf9RPO4NV+Gmkd5oU5/qnw9AM81lVKDgGCHh5DZRDncX1Pqq5HS9IPy2rLFZUWpKGQiUzk0VYjeiXZkBndOvbocNpAWnnt4z4fpBn4LBBeW0hU32INDXtiSzJAN5yN+XOk5DlJ2R8YVGcp1cC/juVq95pnJZyH0UrsNgiyY'
  },
  '2048': {
    'md4': 'MIICZDCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJGMxYWMzMzFlLTAzMWItNDNhNS1hMWY2LTg1NjQ1ZWVlOThlZTANBgkqhkiG9w0BAQMFAAOCAQEAVFvmwKgxjcmf2ckdDZgP8pJtwi3LZnBy9dSUCVZqAuwuZ8aTX++Sz/2/EyJmM45LOlLVFv/qnmGZEFyd0s+g0kN/ZyZDaDpd4BjKhnUrRiTPhvVfhhyRSAZDKFDjc8ZZDkDNXBXexTBHof3y+A8CKzi1D+wcrSwwfW95g6NAMDhZ5xbsc+od9sfQMM+7sN1D/xxuZ4Chm2FnNNWjErENOz4kNwcs0xU0Q3Gjt+nJr9HFbo7bdFVqKl8Tq1VwlZu1caMuBSKyTaXscYaial5ueWcRasTtHRYuqswthTvUzC5Ap8mrOrHjKE4x385hOrpYY1uGHj2RiVouiy6oui9aMA==',
    'md5': 'MIICZDCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJGIyYTZlZDY5LWMwNjktNDgwNS1hMDYwLTIxMjAyZTBmMTlkNTANBgkqhkiG9w0BAQQFAAOCAQEADeHneffyM9PdSRm/RMSmNazAeSMxZzY+M8TxVrrtersZ2mg5MvBUaZcOV3fYGO/p3y7lI+ygn7qx8m8xTwOs82Ppl800NPfDmRkMqambN/ZxkT92sCG+KeCwuoACvUhEZn32GPRV1iu3AndUNbnsHwMAtXMvcFx0NJiyMLki4XtoD6U/D+xwtRFJoJrJNwPWoKbvrVng2T2c7rUoUsDSe85ZDmmEn9Hzw4dQuQGu0aWCe6rW5SjwhYvzYy+1AYXY+XQKv8uyQkPPJjHdG4ibMEYRcRqAC/TEEGEF0SbsuG3K0+sm9OcZnjs7utRwprjQqRaxmsRisD1oNsHL0TB2xg==',
    'sha1': 'MIICZDCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJGVjNTcyZTc5LWJjNGUtNGI3OS1iNGZjLWE2YjQ3OTc5MzBlZTANBgkqhkiG9w0BAQUFAAOCAQEAiuDJ7z8Qw/M4E++WZcuc0RfxKXgC7AQPadtKnI0YrPfOLHe3kFPjj8qDdWItS6XBNOS88NBeyn/MWUyzefetetmpGmRxnDtxmXKKEaPBJRJj7nc9+mxI6laf3F3J0p1EZxyKOgyWggx0BVIsyZNy6bHMJUE5cPXQtlp4wha9ismcFlMULJ1OBWe5xZToBPcHqW/Umw0oS1hSdU1B6r93QSgdgR6RnoeaKLKpz52riX2Qrdus8WBNHMPc9PU5kVo5gg0NduBoKFGDZVSlZLvoabD/eqirWH7q7CeJYJFPgoyXM+PRCkEvOsM4IuPRF1oNlgc6CjHfr9fUCCaPhQvFYA==',
    'sha224': 'MIICZDCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJDYyNzE1NDA1LTAzMTctNGQ5ZC04ZTY1LTdiYjhhYzk1NWJiYzANBgkqhkiG9w0BAQ4FAAOCAQEArPu8iRsO4yMhaEi8egenqbA8UrwbDujVvBsTlcP8ODLPb3WOyA4T4f0q6VJAGc3PZXYeIB3dg2L2ydsZLGYDIyX4ZszMSGzIU1iHAgaJiEXOZ0VPZ+HbdwLwJNCr9+D37XQ4JPzmzbEOp9BB9LtvNmuMWgsDaOUlwVzsufMP418lCTmEuO6MoiWHdttwavZaC6as3PZNdL9FzjGvGBHZmpSm/pmVhPhh+m1nzbZ7DxqTsjyRYC1PFAm4sybnLBT2gDrAR3Y+LQiQytO3hxHcq21EdLH8sjcouijmq7BWkH3MDzbAIKlbdjw4OsYODFlFJ5tcN+xY8qxd5OSXZuLwJQ==',
    'sha256': 'MIICZDCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJGIzNzUzMTA4LWMyMTgtNDBkNy1hMjY0LTE0NDc3NmM2NDVjZjANBgkqhkiG9w0BAQsFAAOCAQEAEjv//kS6PiYz9SAXvSYBHlswtSigNr1kS8tl6c9mOMPj1MOiXAwDC2u6qbrDCQ82OTZ5H9Q2Od2cRHbsFVmD3mkBvXVAmv1hzdc5NjRtFuzQ8kDhgSvoS9wI7UTfge+4n4zIjIWO/IDwAN4YlKYAJlp7Noj2k0f2vHAO0DS8arSp1q0912M9Jzar2x1wecBGMkgB2VzkXYSYvu1/DSAOWyb6D+U6NroAmTcoOzaipZ4ZuN3SjCkZvfXpO1yPhiElUOQu7VErull6ymcwRCIOc8SMTNXVHoMBiv2GTKfUyDhvRvFtEkMVVKJFvbZ8ROaa/cHWkgy2MgL/5tSgBbdhrQ==',
    'sha384': 'MIICZDCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJDhlNDliOWJiLTc1MTAtNDU5ZS1iOWUwLTBlYTU5MTU1OWExZDANBgkqhkiG9w0BAQwFAAOCAQEAefNKOYPURaemFAO8GUUi1966S2+HP7fEgAPzv/Fny/19hTQHpP5rGWYFGq0kvAAVhCHldEFD6+eduzrDaMVIYLD8OMOX6h688tzP3Hsy1rShdi2VzsK0nyRdZQJuLZMxmDcdXrJVTqrCbT6Ivfmah1LGbltpBbYw/Lb83kYyHEcmEr1Qkt41uHlmB7oHAM60HR2BqPMil+Pl25sx3Is6WWdesK0dxEmzR2ap/77rI4uKINWJLcP+fb0Eo5p4360WqVi1YC2lnlEYGhnyketl/ZH0QC3l31Y6ZgRO+Vn/OeIdBayEIvrJJdsaRLqhMeTzvtTvJEovRDn8AbipOsnoDg==',
    'sha512': 'MIICZDCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJGVhOGRkMjZmLTA0MTQtNGY2Yy05NGIzLTU5NjJhODBlYTc5ZDANBgkqhkiG9w0BAQ0FAAOCAQEAQCn+RvC/Ak78AOnO7YGEpqsmNO36p6cmiaxryyOcRRQbrkKRpjbjP/KkpWUELdlyVjkVnGTMIMMLxAfbvkVR+Pe3FWwfbKTs5oToVxo1NfH+h495ijS5u/PRBIDJtLnC5ggUo2hAQDppyNeyuh23oljT9+U3EDG9dDO1x01dSEUf003IqBxgLU59TOzs5+ouxISRqT7ww8DE57mWRKEQsnegKpgSka6dI7JcHFrDuV2cFN/Zha9Iyk9kE4Ox8saWa8rGZ7dL2GH4Q3PCZoTftruoyF9P7kF8qhZ8m2AfJL+6k8D2W7qRYL4LE/EmAQR9a4rN1Wd/xVlANevMrdqpnw==',
    'rmd160': 'MIICYTCCAUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGUKiE6xqFCsreRygPVnt1ZODwUKaXxgp1mWNrkWNlvdwNK088nxevVndZea3JuPIkxfNJah7muZ9ueoI2iZm6xn9kYH2eQcUeaOcnWb64t9TjMYI+LbW+zeGfyYV6Wgq8m0ExhzQWIbi8flAJAsV8VUbk6fb1a/gdfq8Sx6WYu5ttuN6p3YT+h7gijw5bcmZIzUKfESOpiYSVnARfOjtQ6IJFB0FqK5CKdYP01ZPz8p5Kn35wOkbwusk81CgRWmZhs1WoRJOCm3eE/kR5ou/6ACWB3P55DGopxyVdYsaVyyZ/TPGt6Hn/gzLQ08vyLWge6qBkVXNlWAt+yW42HR9PAgMBAAEWJDlmY2RiNDk3LWM4NzItNGY1Ny1iYmJhLTEzNTVlY2I0M2I0NjAKBgYrJAMDAQIFAAOCAQEAmAJdpd1Wo8D7tkU0EF6hMVAmHl5smeMTX11Gp+fL0hlKtG3VZ8t8Hm5is8GAGfkxWp/cPkLNU8TcET31zT3Bwr4eL/lUXu9EuqMbMJORyx7zCAhNQ5Nb19kn99D5jmJ6vHQs3bLj8AcMf/KEj8SzN/5BXUY9ksKlaMIwDwFW+odVKAOwpUPK88DFaxaZ+mhhej4jxrt3f7uZsV5K7nNvkyhYwjtjsn5MyPe9slFEe3am2mA1eI/hnkj4KLNoK2uDgh3I7c+jKZtI2fyKrKKva2p31sYxx5ybnOPG1iSg8/B7Cy4/0U2cks0lrOdXCF+YRxEUn50xxh+AlCY1iVYb0g=='
  },
  '4096': {
    'md4': 'MIIEZDCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiQyMzE5MWI4Mi1hYjAzLTRiYjYtODBiOC0xYmUxNmE4NWY3MmIwDQYJKoZIhvcNAQEDBQADggIBAIIC/e5CQkMYbXsqsidrCLQ3+PG3nURUquBZFTVC0G7Yr3v7j7iZIA3lqdn9uklTHg+hPr5o0CAF4F9NFBGH9GfXmRk3yVjvoRUw4Kn1opE9jWonjv6Lrsy7QzbWaOJ8NmIcP6QJAASpAqwmb3StndYPAU6nhZvK1ApkTFt3oKm/379/CfIA96tp9VYg7Z4X31u7C3+PT25flpWTvyVEdYIfIbNYss+SJ5gkiGB5laHWRYyiPenAdzHcQU4NCShsJb149uKe894uQsjBlme2VTULs42nMYxWH5d+ECtrKApuWF7v7yMdaypz7wskI019UytIjcFkcleG1zf2KyyUAgt4feT4zVrERcPcnu/rHaIVZ2FVwnVag8L8Dj049d+pW1xiA4zAAZ1n7Yh2p+nrd9pqsdn53A1etS3Bs0YkIHTdjc8NuD2RVFuqvzV8nyQbrsxm6jDsenMzG4BAK33AugnjzdEB1CY0hYK4miV4YFIgbkcKX26HKckHi6BIZYk61pyrDwrt62Cwbe89m68ape4VuOoTtuy///6d414DdyluPjtRHoQ75Pp3Ilpv54WXh4TesLRDnDmZcQ3at4DuHZvZMtFW5+2v2Tp6rmUM8TuT2Jb8AwF1t38Z7UU8HfDYXWhlT5rB9UtrMXyDVIBsDJW6/gai4yxWE+SPpLhFaPeZ',
    'md5': 'MIIEZDCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiQ5ZWI1MjFmMi0wYTFmLTRmNTgtOGE1ZS1jYTMxOGI4Zjk0ZTIwDQYJKoZIhvcNAQEEBQADggIBAJJJux48/uB2f9ef4lKtcz0Nn9gVfWfo5KZmThVu9MEpPGI/awHrpWA7Det1H4v1oducIUHqBKdufU9OHeYxQ8RZMan5+Da6uaBjn1dYcpQdCHstjtiJgSIxxGU7Gv4icdrJ0M4vBQ96x5dWZk24cCeL4CEqpK/UDd60cO2yk2EpFvlmws5jkJByM2EIqg19Zp5oOvixGybfxG06KMwwrZ+r3t1UgBgsiUX6P6ZLgTWqcv/TsAK4m8XO6AcxnuyU62a6f0xza+C/gvomiT/8/ZSVQh7vdDxl2QeGW75qVN7Gh9zjnnSLt8YcyeHz8YFNlrjMLGd6M2soafnUDE/PUszxqp3DrU43cbLxqOMRJBiotyR//4d0y8N3LpisI2VbN2HEX3IkdRzqVgGasOBeyBi9RUrUp7jP/84j/aBseGmaDpOZbcysLuS00s+N+JluuK4vBtMOMm6AdBZg5AWQoD+EvJsG/JHoEtx1+Tm5DsaBIm1E1IsMgRrgqvyBzIVr/Nwt+UoLNhMzKGR9PKb0gjBMld7fsHprkiurhPr5klM/+QVR1Mo/fhb1EeMwZz4se1xQ/o+hLp7I0/x7jWiYk06XlbvQj5kl/+MZA4ESBhgo1alQ2u+ecf6oEh7l2tCP08vRSIs2JcOMY5z0a16yWOrOaPION+UioRtgrMkfKyA8',
    'sha1': 'MIIEZDCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiRiYTBkNjhmMS04N2NlLTQ5OTUtODE3OS03MzczM2MyZjJlNjEwDQYJKoZIhvcNAQEFBQADggIBAL9pHr92a0OIzQRrsovVSX99gvOhkNTgDigIaxVCLR304HUyYLooRxiycYeu2yE+j66BbuC9B0W8SrkrWWAyh3/7t8Y8pYSJzItLXTzWzwWWClI15rmSl71iHJQ4hc1mY+418J39FQKfzCFAyrYwAZJ6eWSes8CYcxK9AlEbEJ4LJ+S7yJV2vIHgivXiE/pnkTkjbFg3yU2mD3cndXAHyCJwD3qKyF9ptaneC9urX3St9ZY67p8XpkJPTqGoE9LXXO75VxFIf6nAVPYwqTkEZUn8djPClMhiSjvDPirP0O/lcVWmhU+JmRzw7aQpDYew8pUyux36PCdmDCeSThgbKKd9+w1yQ/lmggXTUkxMaqCzs6K8st1V9cGykSHZEqq4yenMzqjAFlgHT01IzS+n6o0+buj9B7+3WjSgq+6EVy31fWDW3YQbw64vDkUnvxhcVDtI8SbiqcOn4SKIK0OZbE4Urx7r91gIca/cx9Bik3Wu2M6k6E796OPQvuMKqFwgXk9FJFsQ9ffMdoJpza3UwoDPL9znf2M26MhXzLKHtddb78eoTY6HP72f6tl+rGCe4dCj6Y46Q1HyF4GdCWx/ljuobJau1/rzzAcOF9ZaCJZR/6zkkUuYCh1I9OSJn58EGDMAb3duNlnZ+DNZtd0J3qPXexCAxE70Q5j+qWDAWMTY',
    'sha224': 'MIIEZDCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiRhZDg2ZjkzOS1iZDlhLTQzMGItOWQ2MS04MGQ2NTI0NzMwMDcwDQYJKoZIhvcNAQEOBQADggIBACEO5mq2bUiJV27Sw/b2lCbfqa9SHbU0nprk7cJed1JBFs1cS5cBGHtSU/bWF2xIiyU+jkVFf4jk+KGRiqu4+kdpLTbdy1eVThIsDSit7isscS4rtIRkoVrnBAmn1aJ9d1i1xTZVT4zjPydlKNNXVysqnPxgjDaxMRKk8WPafijK9PVJjX4lpXUIGS0gB3mL94Po7cvoLvlSVSM0rZxgHs4RCr/FRRQGBiCcPfKcyYWrcSL232ejP8SSaaGvOMkCy4acaBxKYOlwtxlp7bIXI5N2t5KnpgAewe3T35Piwy7BR+UkwgLMrAQRpupjXXB7q9gP+QSKZgcqIMBLov/Shg+NNlCqZnMPjhNO4ArWfHJbCQL7iQhpcBDXSmyJ3gkn2OfCLpaUqMGz5MfsZAoZQ1y0gZ1sFgR/WoycZeBW6kGdIYSur932dRwPYwOkt9WFu3GNiqqu5Rh9LamYMl5Ezc24ItzXfvKE+rvxSV2CfjeHGSvORhtgbJv39auL+3zVh7reKuhT74qRv797s2170XyZPZeJui6TCBxXafP7IxvygE9DprHu5TRnjtn+d/CnGJYZdviDNchZo/G0aLgbkhUQ56XajmgiIRD/yzVlb9246PsPhfpYkqAC3R1RiNgMaDsKCkOVlJ5DtEB+OLXbn1zZ1ksT0aHFIwpDDF9ADmbu',
    'sha256': 'MIIEZDCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiQ0ZGYwZGViNC03NWY5LTRiY2QtOTNiYi00Yjg3NWE0ZTI4ZGMwDQYJKoZIhvcNAQELBQADggIBAI89JU/5UPTvTIRc1DZJIOX/NJwQj3STqKfThN947vUgauj+0bB3rqBRo8AMyIRy4vdRm66qmA+3PLEDLtFFzTCxXP1mjYQ5KPM8IX+Chz68rkaE0ia58/tg55TyuMENJmYAjG+1IxeLTzesqRwI5P8ut/rZpu9TY795U5J4LHSUFuZWQn+VbN+hKyt3liIZSDEgEE4dTWSj2n8m4cqpRZaSbZw9uYKcylMfaIAr+Nl8i4l3WMyG1sIaCY/wz7yP0rPxg2Yazh5ksfRTuKo8K37cNfWG7Vsnfl5YI6w/9Dz49dGH0IeXl78mLbwdPVD/F0pJA37/iXW35hcj4QSp6wd6XdUJEN1GOk4qR8RTGm3W2Cw5o4g37efGa/CMeLWXBdYPgOeilh5BSL+9BtnQdqOxYvQFSuQiKoZf+A5udlaOb+5B6MnvE05oblvvYtsvqq+4/UCzztjsPhJKeTMzVX55wq4u/uqt0tJ8FYQp9MKpP72k5IdMrAlM8HdClZl6OC96PwLaehKLiRdBxhWZC7JZQ9jIaV55EHqAfxBqahrzw7fGEariWhAVkWXgEml/SlGqSCtQUqY6qge/SlvIIls5GR0ZxWiKNQtn2gSE4B+jspKyAHVFRu73bxpW7N/fI8PrPotlWfEjxdAg5Mo1bphyQH1/3jA8xzh2wvS8gEuE',
    'sha384': 'MIIEZDCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiQxMzEzZjI2Ny05NmE0LTQ5YzEtODQ4NS1iYjg4OGY5YTM2MmIwDQYJKoZIhvcNAQEMBQADggIBACWK6+9JShRHqJNRaMrQZxLMXXEiyXTAZAbTUvWWHupF6iGjC0St4BX253u2kuAr02v95Z4K2jerREjBsGbhR0pFjGpriExE5FnSooOJigvT+D6gv1Khaz56VWzcgYZDQQN2XwKCrHr/YdmDr/Sd9cdgRJ9fnJVNu9LRpE9W6BBEUJn8P3ThHf1tJHCxZqo5H7qoIB+gNZwWL5yoJ1sl4RXcdjyJ6Neza3pQ6tV6tqWn4yh65VqF+yVLMq7ycCX8vpoU16QalBkbqVUX0ap7Z4cx7U3bXCYr+lCji0VhrTSuyc4G1EL3jxf4TMjfsVJpsKR+hOhzrZNKPL1k+U59Whtc0jWFPPXY7dJEDng8+7veYu2pczBzaEvyYVHOuQl49SlaM9vFoplyADdET9Fgv0/nUm5uBNyrROlXNd7XOOzYp8Axepbq54Fs9t2EHJCcHENjHzzMgaAfjFI0ar0yBRtvhgyV7/Vw18xkTjvHZILSWA/FkKhtGD1qND6Nc5wJ/0f+B35cCTcfmO8E/vXMkfAgacgS/Q0ljkejJ/NnYm5rR5W+gAqXciE42ZWRbXH2mlAhFZu/+eGg7Rtozlgxx5qWRBCfSNTd0Srn/u2+yPAL89XKAGPjgyaXNsqR82eTiLGRNt9U0S6ob1NkfwqQ4ioO6RgDKIrz2XJ94rHdlFeQ',
    'sha512': 'MIIEZDCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiQ3ODdmYjc2ZC01NWViLTQzOWYtYjg0Ni1hZDY1ZDFjYmY5YjkwDQYJKoZIhvcNAQENBQADggIBAKTkLUiwz+VeX2OkD/YzleHVDrh3BzCXwUBtVUueDgP5/BPfAF7/p7uMZ2kM4Eg48cI9XrymIcp3I4mVa488p5M0iA+0Nx67YAhCvzed57G0vVRlb6ZM5hIduy8WCcGaxRUm7Wv8tYS2pcsPm2zTh//uWbofTcvx0otQQc6XSdhD4+4qM+Ad4neTzqFngDYsZavDPWFsYN6oODh17i3ByAnA8oVTfjSj6eYs32tAEHh5Gag+H1ebFh4QuxORUno0PpJ4sfY5l10bH6vu/j/RlXSYgHHNp2E2cjJl81Copy8J8zyYBr+kpwQRqbxiabrFtqZYFiVj87BEVSoFQMjZACPs8Ff8sGAHbuWDHzjKsZd3zsbpb2Tz5cGmvyfqc2b4xhnUHQ5T2w64kB4ZR9L03LmE5EPxSaFMayZZC/B7IJanbcaLEl5j5ce1Dn6ToeYCV65JP7ZJc7+/dNT5tU+znt2/m04vk9Vq14dhJ5d4nrXU5IkxG1dSWiyDd0Q+LW77pbf5+v4wdlBRWgoOkPGSAIztrtv0iLjBEA8mesefz7Wlkka0g865eetuIlDpjYwOPmlu+7xnstKlC5gB7V3e2gGPDX8UrGsNf0/2G+O/0K0+kPxx9WDUuWtUGRNYd+Ny1ljY4RPHBiKmPKiCJyfoUWw4j2TDbxcmCZhxEfkmXmKC',
    'rmd160': 'MIIEYTCCAkwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIY5P5YLslXFx62YGZRHfqhVEGTT4xvvJbcjT+SY0tfVl6vWI9bB1jWxMfRkuKewCLl5AeXIYmOXOdIFHTYyHFpKaBxRrDC87GLWvPkvJtspWySM5S55FpDRugKIFGTTLc3IUIZfEC5mG/F2mxzZ7cThgI99vVBlwKngvPEO4ihhNwaEfcVf3+eiQ+pfh5Uqx1n27Xj/Da5yBIyvKAqR8MHtfuhflTjqgzk7wGMi0nD/FvGsiVLEu9b3/3pnjWYOTkOsTQibPXWgAZyFRVSblt+KUW59R39Hf284rnbL0FPkhDn8Z+u2B9uYbiWoL4cuPpk3isfK/tuR5a5rME/lVwoStlncwhxJoMwiBWM/ItZBoWrm5e1ZbQRx80r7QBhl90v/oGUhM4RNuUCXGbBtJQ7Jy6edl+wnC6HQvj5KzdpK0pCMGRsIgko5G7T1rVkxpQxIjSBkps4Ijjf5TiGsTwJRQKimJWnbUHY0x+bpLaczLgHmjAIXO/5xerlNPm2CzTfyAoWcNAgohc7dn7nFBwwqy2WWRa6empXleGG6e48skenKPU99IIigGLF/xRtyplDdoPBn6xhvqLE7K8e1NiHQK+Bgby2vEVVM4PNQo9xGpfTdhN91DkvbOivOTY/G16W5Lb6EJwFuvbYeX7+hMDR5nD47DGAnvkNWV1n4zrDQIDAQABFiQ2NWU0YTRmYi1iMzAzLTQwMTMtOGFkYS0xN2NlOWE3MWUzMmUwCgYGKyQDAwECBQADggIBACrIQrhwBin9Pf6wMkc9m+y8o2/7f/4hBl2wQktcmCAyE4eBc1tXmKoYtkwsRhtm/J1lOSZv6KU+c3nDSpOZeL9oc1EAKC6eQ3YUmxlQ/BjOQRuPkC88WZcg2d7o6Xat8skrBWAEQ5LMpaVJirscsuYNloD31PmYasr3995iCX14v1jUEleWeOOiDnpB+KH7iig7HBPYFJ4QDXJVuFxq4N52cyRd4moDaMiq+nj/0UO+WPNHYObh97u2c3Scrf+Q/nGw4opyi7Oxr7e0Zy8q0Isw5ka9NwVxiSbKfi3m21g8X4zBn5+x6DuPj7+BnqqXsm8Q72FiGFneFx4LagbbVMSgBspvEOopCIxdicyU+nHR35QCWGlQ7eFk2Fmn+oOqBTwSPXKf9ehQIhuCNYgxbaHTGbFBWrdm/ap5jq66IroiOMZaZJ1Jo2kfSc+LEPuVeB1Am7c6KD6Dw8dWeDCbygwa8EbFR63S47tYlUWB+M1FgCOr62eh/iMgcyJCHvRjuKhz7ef+KH00jiBwCsBRQidjkmGrzB/sxeO3/s3O69NSsBMe3+e97eL1LgEUufPQzU6lCT/+AJbKKnkgQQJMTRCywUgiqxu4AG5ZcsgDhCmVUBgH8t7fHYfdLSTaJI3U7uN3H2QxHhBqOwJSr0vccyrMjNSyyp/VVXApOzGMsrOG'
  }
};

var crypto = require('crypto');
var certificate = new crypto.Certificate();

crypto.DEFAULT_ENCODING = 'buffer';

for (var key in spkac) {
  console.log('Testing SPKAC data created with '+key+' key size');
  for (var k in spkac[key]) {
    console.log('Performing tests on SPKAC which used '+k+' hashing algorithm');
    var buf = new Buffer(spkac[key][k]);
    console.log('\tValid: '+certificate.verifySpkac(buf));
    console.log('\tChallenge: '+certificate.exportChallenge(buf).toString('utf-8'));
    console.log('\tPublic key: \n'+certificate.exportPublicKey(buf).toString('utf-8'));
  }
}