From afae0b552e0524aabbc187d7c6bf4b005668bed5 Mon Sep 17 00:00:00 2001 From: jngrt Date: Thu, 15 May 2014 23:10:26 +0200 Subject: [PATCH] simply-crypt js test added --- js-crypt-test/js/simple-crypt-deps.js | 6856 +++++++++++++++++++++++++ js-crypt-test/js/simple-crypt.js | 1178 +++++ js-crypt-test/test.html | 44 + meshenger_roadmap | 7 + 4 files changed, 8085 insertions(+) create mode 100644 js-crypt-test/js/simple-crypt-deps.js create mode 100644 js-crypt-test/js/simple-crypt.js create mode 100644 js-crypt-test/test.html diff --git a/js-crypt-test/js/simple-crypt-deps.js b/js-crypt-test/js/simple-crypt-deps.js new file mode 100644 index 0000000..4d64502 --- /dev/null +++ b/js-crypt-test/js/simple-crypt-deps.js @@ -0,0 +1,6856 @@ +/* + * aes.js: implements AES - Advanced Encryption Standard + * from the SlowAES project, http://code.google.com/p/slowaes/ + * + * Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ), + * Mark Percival ( http://mpercival.com ), + * + * Ported from C code written by Laurent Haan ( http://www.progressive-coding.com ) + * + * Licensed under the Apache License, Version 2.0 + * http://www.apache.org/licenses/ + */ + +var slowAES = { + /* + * START AES SECTION + */ + aes:{ + // structure of valid key sizes + keySize:{ + SIZE_128:16, + SIZE_192:24, + SIZE_256:32 + }, + + // Rijndael S-box + sbox:[ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ], + + // Rijndael Inverted S-box + rsbox: + [ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb + , 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb + , 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e + , 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 + , 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 + , 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 + , 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 + , 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b + , 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 + , 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e + , 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b + , 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 + , 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f + , 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef + , 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 + , 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ], + + /* rotate the word eight bits to the left */ + rotate:function(word) + { + var c = word[0]; + for (var i = 0; i < 3; i++) + word[i] = word[i+1]; + word[3] = c; + + return word; + }, + + // Rijndael Rcon + Rcon:[ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, + 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, + 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, + 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, + 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, + 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, + 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, + 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, + 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, + 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb ], + + G2X: [ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, + 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, + 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, + 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, + 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, + 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, + 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d, + 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, + 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, + 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d, + 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, + 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, + 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd, + 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, + 0xe3, 0xe1, 0xe7, 0xe5 + ], + + G3X: [ + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, + 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, + 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, + 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, + 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, + 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, + 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, + 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, + 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e, + 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, + 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, + 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce, + 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, + 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, + 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e, + 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, + 0x1f, 0x1c, 0x19, 0x1a + ], + + G9X: [ + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, + 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, + 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20, + 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, + 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, + 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, + 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, + 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, + 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7, + 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, + 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, + 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c, + 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, + 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, + 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba, + 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, + 0x5d, 0x54, 0x4f, 0x46 + ], + + GBX: [ + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, + 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, + 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66, + 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, + 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, + 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, + 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, + 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, + 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea, + 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, + 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, + 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21, + 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, + 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, + 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67, + 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, + 0xbe, 0xb5, 0xa8, 0xa3 + ], + + GDX: [ + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, + 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, + 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac, + 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, + 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, + 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, + 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, + 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, + 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd, + 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, + 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, + 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6, + 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, + 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, + 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b, + 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, + 0x80, 0x8d, 0x9a, 0x97 + ], + + GEX: [ + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, + 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, + 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9, + 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, + 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, + 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, + 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, + 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, + 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53, + 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, + 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, + 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68, + 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, + 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, + 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25, + 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, + 0x9f, 0x91, 0x83, 0x8d + ], + + // Key Schedule Core + core:function(word,iteration) + { + /* rotate the 32-bit word 8 bits to the left */ + word = this.rotate(word); + /* apply S-Box substitution on all 4 parts of the 32-bit word */ + for (var i = 0; i < 4; ++i) + word[i] = this.sbox[word[i]]; + /* XOR the output of the rcon operation with i to the first part (leftmost) only */ + word[0] = word[0]^this.Rcon[iteration]; + return word; + }, + + /* Rijndael's key expansion + * expands an 128,192,256 key into an 176,208,240 bytes key + * + * expandedKey is a pointer to an char array of large enough size + * key is a pointer to a non-expanded key + */ + expandKey:function(key,size) + { + var expandedKeySize = (16*(this.numberOfRounds(size)+1)); + + /* current expanded keySize, in bytes */ + var currentSize = 0; + var rconIteration = 1; + var t = []; // temporary 4-byte variable + + var expandedKey = []; + for(var i = 0;i < expandedKeySize;i++) + expandedKey[i] = 0; + + /* set the 16,24,32 bytes of the expanded key to the input key */ + for (var j = 0; j < size; j++) + expandedKey[j] = key[j]; + currentSize += size; + + while (currentSize < expandedKeySize) + { + /* assign the previous 4 bytes to the temporary value t */ + for (var k = 0; k < 4; k++) + t[k] = expandedKey[(currentSize - 4) + k]; + + /* every 16,24,32 bytes we apply the core schedule to t + * and increment rconIteration afterwards + */ + if(currentSize % size == 0) + t = this.core(t, rconIteration++); + + /* For 256-bit keys, we add an extra sbox to the calculation */ + if(size == this.keySize.SIZE_256 && ((currentSize % size) == 16)) + for(var l = 0; l < 4; l++) + t[l] = this.sbox[t[l]]; + + /* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key. + * This becomes the next four bytes in the expanded key. + */ + for(var m = 0; m < 4; m++) { + expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m]; + currentSize++; + } + } + return expandedKey; + }, + + // Adds (XORs) the round key to the state + addRoundKey:function(state,roundKey) + { + for (var i = 0; i < 16; i++) + state[i] ^= roundKey[i]; + return state; + }, + + // Creates a round key from the given expanded key and the + // position within the expanded key. + createRoundKey:function(expandedKey,roundKeyPointer) + { + var roundKey = []; + for (var i = 0; i < 4; i++) + for (var j = 0; j < 4; j++) + roundKey[j*4+i] = expandedKey[roundKeyPointer + i*4 + j]; + return roundKey; + }, + + /* substitute all the values from the state with the value in the SBox + * using the state value as index for the SBox + */ + subBytes:function(state,isInv) + { + for (var i = 0; i < 16; i++) + state[i] = isInv?this.rsbox[state[i]]:this.sbox[state[i]]; + return state; + }, + + /* iterate over the 4 rows and call shiftRow() with that row */ + shiftRows:function(state,isInv) + { + for (var i = 0; i < 4; i++) + state = this.shiftRow(state,i*4, i,isInv); + return state; + }, + + /* each iteration shifts the row to the left by 1 */ + shiftRow:function(state,statePointer,nbr,isInv) + { + for (var i = 0; i < nbr; i++) + { + if(isInv) + { + var tmp = state[statePointer + 3]; + for (var j = 3; j > 0; j--) + state[statePointer + j] = state[statePointer + j-1]; + state[statePointer] = tmp; + } + else + { + var tmp = state[statePointer]; + for (var j = 0; j < 3; j++) + state[statePointer + j] = state[statePointer + j+1]; + state[statePointer + 3] = tmp; + } + } + return state; + }, + + // galois multiplication of 8 bit characters a and b + galois_multiplication:function(a,b) + { + var p = 0; + for(var counter = 0; counter < 8; counter++) + { + if((b & 1) == 1) + p ^= a; + if(p > 0x100) p ^= 0x100; + var hi_bit_set = (a & 0x80); //keep p 8 bit + a <<= 1; + if(a > 0x100) a ^= 0x100; //keep a 8 bit + if(hi_bit_set == 0x80) + a ^= 0x1b; + if(a > 0x100) a ^= 0x100; //keep a 8 bit + b >>= 1; + if(b > 0x100) b ^= 0x100; //keep b 8 bit + } + return p; + }, + + // galois multipication of the 4x4 matrix + mixColumns:function(state,isInv) + { + var column = []; + /* iterate over the 4 columns */ + for (var i = 0; i < 4; i++) + { + /* construct one column by iterating over the 4 rows */ + for (var j = 0; j < 4; j++) + column[j] = state[(j*4)+i]; + /* apply the mixColumn on one column */ + column = this.mixColumn(column,isInv); + /* put the values back into the state */ + for (var k = 0; k < 4; k++) + state[(k*4)+i] = column[k]; + } + return state; + }, + + // galois multipication of 1 column of the 4x4 matrix + mixColumn:function(column,isInv) + { + var mult = []; + if(isInv) + mult = [14,9,13,11]; + else + mult = [2,1,1,3]; + var cpy = []; + for(var i = 0; i < 4; i++) + cpy[i] = column[i]; + + column[0] = this.galois_multiplication(cpy[0],mult[0]) ^ + this.galois_multiplication(cpy[3],mult[1]) ^ + this.galois_multiplication(cpy[2],mult[2]) ^ + this.galois_multiplication(cpy[1],mult[3]); + column[1] = this.galois_multiplication(cpy[1],mult[0]) ^ + this.galois_multiplication(cpy[0],mult[1]) ^ + this.galois_multiplication(cpy[3],mult[2]) ^ + this.galois_multiplication(cpy[2],mult[3]); + column[2] = this.galois_multiplication(cpy[2],mult[0]) ^ + this.galois_multiplication(cpy[1],mult[1]) ^ + this.galois_multiplication(cpy[0],mult[2]) ^ + this.galois_multiplication(cpy[3],mult[3]); + column[3] = this.galois_multiplication(cpy[3],mult[0]) ^ + this.galois_multiplication(cpy[2],mult[1]) ^ + this.galois_multiplication(cpy[1],mult[2]) ^ + this.galois_multiplication(cpy[0],mult[3]); + return column; + }, + + // applies the 4 operations of the forward round in sequence + round:function(state, roundKey) + { + state = this.subBytes(state,false); + state = this.shiftRows(state,false); + state = this.mixColumns(state,false); + state = this.addRoundKey(state, roundKey); + return state; + }, + + // applies the 4 operations of the inverse round in sequence + invRound:function(state,roundKey) + { + state = this.shiftRows(state,true); + state = this.subBytes(state,true); + state = this.addRoundKey(state, roundKey); + state = this.mixColumns(state,true); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the forward aes, creating a round key for each round + */ + main:function(state,expandedKey,nbrRounds) + { + state = this.addRoundKey(state, this.createRoundKey(expandedKey,0)); + for (var i = 1; i < nbrRounds; i++) + state = this.round(state, this.createRoundKey(expandedKey,16*i)); + state = this.subBytes(state,false); + state = this.shiftRows(state,false); + state = this.addRoundKey(state, this.createRoundKey(expandedKey,16*nbrRounds)); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the inverse aes, creating a round key for each round + */ + invMain:function(state, expandedKey, nbrRounds) + { + state = this.addRoundKey(state, this.createRoundKey(expandedKey,16*nbrRounds)); + for (var i = nbrRounds-1; i > 0; i--) + state = this.invRound(state, this.createRoundKey(expandedKey,16*i)); + state = this.shiftRows(state,true); + state = this.subBytes(state,true); + state = this.addRoundKey(state, this.createRoundKey(expandedKey,0)); + return state; + }, + + numberOfRounds:function(size) + { + var nbrRounds; + switch (size) /* set the number of rounds */ + { + case this.keySize.SIZE_128: + nbrRounds = 10; + break; + case this.keySize.SIZE_192: + nbrRounds = 12; + break; + case this.keySize.SIZE_256: + nbrRounds = 14; + break; + default: + return null; + break; + } + return nbrRounds; + }, + + // encrypts a 128 bit input block against the given key of size specified + encrypt:function(input,key,size) + { + var output = []; + var block = []; /* the 128 bit block to encode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i+(j*4))] = input[(i*4)+j]; + + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); /* the expanded key */ + /* encrypt the block using the expandedKey */ + block = this.main(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k*4)+l] = block[(k+(l*4))]; + return output; + }, + + // decrypts a 128 bit input block against the given key of size specified + decrypt:function(input, key, size) + { + var output = []; + var block = []; /* the 128 bit block to decode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i+(j*4))] = input[(i*4)+j]; + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); + /* decrypt the block using the expandedKey */ + block = this.invMain(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++)/* unmap the block again into the output */ + for (var l = 0; l < 4; l++)/* iterate over the rows */ + output[(k*4)+l] = block[(k+(l*4))]; + return output; + } + }, + /* + * END AES SECTION + */ + + /* + * START MODE OF OPERATION SECTION + */ + //structure of supported modes of operation + modeOfOperation:{ + OFB:0, + CFB:1, + CBC:2 + }, + + // get a 16 byte block (aes operates on 128bits) + getBlock: function(bytesIn,start,end,mode) + { + if(end - start > 16) + end = start + 16; + + return bytesIn.slice(start, end); + }, + + /* + * Mode of Operation Encryption + * bytesIn - Input String as array of bytes + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + encrypt: function (bytesIn, mode, key, iv) + { + var size = key.length; + if(iv.length%16) + { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var byteArray = []; + var input = []; + var output = []; + var ciphertext = []; + var cipherOut = []; + // char firstRound + var firstRound = true; + if (mode == this.modeOfOperation.CBC) + this.padBytesIn(bytesIn); + if (bytesIn !== null) + { + for (var j = 0;j < Math.ceil(bytesIn.length/16); j++) + { + var start = j*16; + var end = j*16+16; + if(j*16+16 > bytesIn.length) + end = bytesIn.length; + byteArray = this.getBlock(bytesIn,start,end,mode); + if (mode == this.modeOfOperation.CFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for(var k = 0;k < end-start;k++) + cipherOut.push(ciphertext[k]); + input = ciphertext; + } + else if (mode == this.modeOfOperation.OFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for(var k = 0;k < end-start;k++) + cipherOut.push(ciphertext[k]); + input = output; + } + else if (mode == this.modeOfOperation.CBC) + { + for (var i = 0; i < 16; i++) + input[i] = byteArray[i] ^ ((firstRound) ? iv[i] : ciphertext[i]); + firstRound = false; + ciphertext = this.aes.encrypt(input, key, size); + // always 16 bytes because of the padding for CBC + for(var k = 0;k < 16;k++) + cipherOut.push(ciphertext[k]); + } + } + } + return cipherOut; + }, + + /* + * Mode of Operation Decryption + * cipherIn - Encrypted String as array of bytes + * originalsize - The unencrypted string length - required for CBC + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + decrypt:function(cipherIn,mode,key,iv) + { + var size = key.length; + if(iv.length%16) + { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var ciphertext = []; + var input = []; + var output = []; + var byteArray = []; + var bytesOut = []; + // char firstRound + var firstRound = true; + if (cipherIn !== null) + { + for (var j = 0;j < Math.ceil(cipherIn.length/16); j++) + { + var start = j*16; + var end = j*16+16; + if(j*16+16 > cipherIn.length) + end = cipherIn.length; + ciphertext = this.getBlock(cipherIn,start,end,mode); + if (mode == this.modeOfOperation.CFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for(var k = 0;k < end-start;k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + else if (mode == this.modeOfOperation.OFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for(var k = 0;k < end-start;k++) + bytesOut.push(byteArray[k]); + input = output; + } + else if(mode == this.modeOfOperation.CBC) + { + output = this.aes.decrypt(ciphertext, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = ((firstRound) ? iv[i] : input[i]) ^ output[i]; + firstRound = false; + for(var k = 0;k < end-start;k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + } + if(mode == this.modeOfOperation.CBC) + this.unpadBytesOut(bytesOut); + } + return bytesOut; + }, + padBytesIn: function(data) { + var len = data.length; + var padByte = 16 - (len % 16); + for (var i = 0; i < padByte; i++) { + data.push(padByte); + } + }, + unpadBytesOut: function(data) { + var padCount = 0; + var padByte = -1; + var blockSize = 16; + for (var i = data.length - 1; i >= data.length-1 - blockSize; i--) { + if (data[i] <= blockSize) { + if (padByte == -1) + padByte = data[i]; + if (data[i] != padByte) { + padCount = 0; + break; + } + padCount++; + } else + break; + if (padCount == padByte) + break; + } + if (padCount > 0) + data.splice(data.length - padCount, padCount); + } + /* + * END MODE OF OPERATION SECTION + */ +}; + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +/** + * CryptoJS core components. + */ +var CryptoJS = CryptoJS || (function (Math, undefined) { + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + function F() {} + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + F.prototype = this; + var subtype = new F(); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init')) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else if (thatWords.length > 0xffff) { + // Copy one word at a time + for (var i = 0; i < thatSigBytes; i += 4) { + thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; + } + } else { + // Copy all words at once + thisWords.push.apply(thisWords, thatWords); + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + for (var i = 0; i < nBytes; i += 4) { + words.push((Math.random() * 0x100000000) | 0); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + var processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512/32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; +}(Math)); + +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +(function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); +}(Math)); + +/* + * JavaScript implementation of Password-Based Key Derivation Function 2 + * (PBKDF2) as defined in RFC 2898. + * Version 1.5 + * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Parvez Anandam + * parvez@anandam.com + * http://anandam.com/pbkdf2 + * + * Distributed under the BSD license + * + * Uses Paul Johnston's excellent SHA-1 JavaScript library sha1.js: + * http://pajhome.org.uk/crypt/md5/sha1.html + * (uses the binb_sha1(), rstr2binb(), binb2str(), rstr2hex() functions from that libary) + * + * Thanks to Felix Gartsman for pointing out a bug in version 1.0 + * Thanks to Thijs Van der Schaeghe for pointing out a bug in version 1.1 + * Thanks to Richard Gautier for asking to clarify dependencies in version 1.2 + * Updated contact information from version 1.3 + * Thanks to Stuart Heinrich for pointing out updates to PAJ's SHA-1 library in version 1.4 + */ + + +/* + * The four arguments to the constructor of the PBKDF2 object are + * the password, salt, number of iterations and number of bytes in + * generated key. This follows the RFC 2898 definition: PBKDF2 (P, S, c, dkLen) + * + * The method deriveKey takes two parameters, both callback functions: + * the first is used to provide status on the computation, the second + * is called with the result of the computation (the generated key in hex). + * + * Example of use: + * + * + * + * + *
+ * + */ + +function PBKDF2(password, salt, num_iterations, num_bytes) +{ + // Remember the password and salt + var m_bpassword = rstr2binb(password); + var m_salt = salt; + + // Total number of iterations + var m_total_iterations = num_iterations; + + // Run iterations in chunks instead of all at once, so as to not block. + // Define size of chunk here; adjust for slower or faster machines if necessary. + var m_iterations_in_chunk = 10; + + // Iteration counter + var m_iterations_done = 0; + + // Key length, as number of bytes + var m_key_length = num_bytes; + + // The hash cache + var m_hash = null; + + // The length (number of bytes) of the output of the pseudo-random function. + // Since HMAC-SHA1 is the standard, and what is used here, it's 20 bytes. + var m_hash_length = 20; + + // Number of hash-sized blocks in the derived key (called 'l' in RFC2898) + var m_total_blocks = Math.ceil(m_key_length/m_hash_length); + + // Start computation with the first block + var m_current_block = 1; + + // Used in the HMAC-SHA1 computations + var m_ipad = new Array(16); + var m_opad = new Array(16); + + // This is where the result of the iterations gets sotred + var m_buffer = new Array(0x0,0x0,0x0,0x0,0x0); + + // The result + var m_key = ""; + + // This object + var m_this_object = this; + + // The function to call with the result + var m_result_func; + + // The function to call with status after computing every chunk + var m_status_func; + + // Set up the HMAC-SHA1 computations + if (m_bpassword.length > 16) m_bpassword = binb_sha1(m_bpassword, password.length * chrsz); + for(var i = 0; i < 16; ++i) + { + m_ipad[i] = m_bpassword[i] ^ 0x36363636; + m_opad[i] = m_bpassword[i] ^ 0x5C5C5C5C; + } + + + // Starts the computation + this.deriveKey = function(status_callback, result_callback) + { + m_status_func = status_callback; + m_result_func = result_callback; + setTimeout(function() { m_this_object.do_PBKDF2_iterations() }, 0); + } + + + // The workhorse + this.do_PBKDF2_iterations = function() + { + var iterations = m_iterations_in_chunk; + if (m_total_iterations - m_iterations_done < m_iterations_in_chunk) + iterations = m_total_iterations - m_iterations_done; + + for(var i=0; i> 24 & 0xF) + + String.fromCharCode(m_current_block >> 16 & 0xF) + + String.fromCharCode(m_current_block >> 8 & 0xF) + + String.fromCharCode(m_current_block & 0xF); + + m_hash = binb_sha1(m_ipad.concat(rstr2binb(salt_block)), + 512 + salt_block.length * 8); + m_hash = binb_sha1(m_opad.concat(m_hash), 512 + 160); + } + else + { + m_hash = binb_sha1(m_ipad.concat(m_hash), + 512 + m_hash.length * 32); + m_hash = binb_sha1(m_opad.concat(m_hash), 512 + 160); + } + + for(var j=0; j= 0) { + var v = x*this[i++]+w[j]+c; + c = Math.floor(v/0x4000000); + w[j++] = v&0x3ffffff; + } + return c; +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i,x,w,j,c,n) { + var xl = x&0x7fff, xh = x>>15; + while(--n >= 0) { + var l = this[i]&0x7fff; + var h = this[i++]>>15; + var m = xh*l+h*xl; + l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); + c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); + w[j++] = l&0x3fffffff; + } + return c; +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i,x,w,j,c,n) { + var xl = x&0x3fff, xh = x>>14; + while(--n >= 0) { + var l = this[i]&0x3fff; + var h = this[i++]>>14; + var m = xh*l+h*xl; + l = xl*l+((m&0x3fff)<<14)+w[j]+c; + c = (l>>28)+(m>>14)+xh*h; + w[j++] = l&0xfffffff; + } + return c; +} +if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; +} +else if(j_lm && (navigator.appName != "Netscape")) { + BigInteger.prototype.am = am1; + dbits = 26; +} +else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; +} + +BigInteger.prototype.DB = dbits; +BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i]; + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV +function bnpFromInt(x) { + this.t = 1; + this.s = (x<0)?-1:0; + if(x > 0) this[0] = x; + else if(x < -1) this[0] = x+this.DV; + else this.t = 0; +} + +// return bigint initialized to value +function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + +// (protected) set from string and radix +function bnpFromString(s,b) { + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 256) k = 8; // byte array + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else { this.fromRadix(s,b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while(--i >= 0) { + var x = (k==8)?s[i]&0xff:intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if(sh == 0) + this[this.t++] = x; + else if(sh+k > this.DB) { + this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); + } + else + this[this.t-1] |= x<= this.DB) sh -= this.DB; + } + if(k == 8 && (s[0]&0x80) != 0) { + this.s = -1; + if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t; +} + +// (public) return string representation in given radix +function bnToString(b) { + if(this.s < 0) return "-"+this.negate().toString(b); + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else return this.toRadix(b); + var km = (1< 0) { + if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } + while(i >= 0) { + if(p < k) { + d = (this[i]&((1<>(p+=this.DB-k); + } + else { + d = (this[i]>>(p-=k))&km; + if(p <= 0) { p += this.DB; --i; } + } + if(d > 0) m = true; + if(m) r += int2char(d); + } + } + return m?r:"0"; +} + +// (public) -this +function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } + +// (public) |this| +function bnAbs() { return (this.s<0)?this.negate():this; } + +// (public) return + if this > a, - if this < a, 0 if equal +function bnCompareTo(a) { + var r = this.s-a.s; + if(r != 0) return r; + var i = this.t; + r = i-a.t; + if(r != 0) return (this.s<0)?-r:r; + while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; + return 0; +} + +// returns bit length of the integer x +function nbits(x) { + var r = 1, t; + if((t=x>>>16) != 0) { x = t; r += 16; } + if((t=x>>8) != 0) { x = t; r += 8; } + if((t=x>>4) != 0) { x = t; r += 4; } + if((t=x>>2) != 0) { x = t; r += 2; } + if((t=x>>1) != 0) { x = t; r += 1; } + return r; +} + +// (public) return the number of bits in "this" +function bnBitLength() { + if(this.t <= 0) return 0; + return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); +} + +// (protected) r = this << n*DB +function bnpDLShiftTo(n,r) { + var i; + for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; + for(i = n-1; i >= 0; --i) r[i] = 0; + r.t = this.t+n; + r.s = this.s; +} + +// (protected) r = this >> n*DB +function bnpDRShiftTo(n,r) { + for(var i = n; i < this.t; ++i) r[i-n] = this[i]; + r.t = Math.max(this.t-n,0); + r.s = this.s; +} + +// (protected) r = this << n +function bnpLShiftTo(n,r) { + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<= 0; --i) { + r[i+ds+1] = (this[i]>>cbs)|c; + c = (this[i]&bm)<= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t+ds+1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n +function bnpRShiftTo(n,r) { + r.s = this.s; + var ds = Math.floor(n/this.DB); + if(ds >= this.t) { r.t = 0; return; } + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<>bs; + for(var i = ds+1; i < this.t; ++i) { + r[i-ds-1] |= (this[i]&bm)<>bs; + } + if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB; + } + if(a.t < this.t) { + c -= a.s; + while(i < this.t) { + c += this[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while(i < a.t) { + c -= a[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c<0)?-1:0; + if(c < -1) r[i++] = this.DV+c; + else if(c > 0) r[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +function bnpMultiplyTo(a,r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i+y.t; + while(--i >= 0) r[i] = 0; + for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); + r.s = 0; + r.clamp(); + if(this.s != a.s) BigInteger.ZERO.subTo(r,r); +} + +// (protected) r = this^2, r != this (HAC 14.16) +function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2*x.t; + while(--i >= 0) r[i] = 0; + for(i = 0; i < x.t-1; ++i) { + var c = x.am(i,x[i],r,2*i,0,1); + if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { + r[i+x.t] -= x.DV; + r[i+x.t+1] = 1; + } + } + if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +function bnpDivRemTo(m,q,r) { + var pm = m.abs(); + if(pm.t <= 0) return; + var pt = this.abs(); + if(pt.t < pm.t) { + if(q != null) q.fromInt(0); + if(r != null) this.copyTo(r); + return; + } + if(r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus + if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y[ys-1]; + if(y0 == 0) return; + var yt = y0*(1<1)?y[ys-2]>>this.F2:0); + var d1 = this.FV/yt, d2 = (1<= 0) { + r[r.t++] = 1; + r.subTo(t,r); + } + BigInteger.ONE.dlShiftTo(ys,t); + t.subTo(y,y); // "negative" y so we can replace sub with am later + while(y.t < ys) y[y.t++] = 0; + while(--j >= 0) { + // Estimate quotient digit + var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); + if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out + y.dlShiftTo(j,t); + r.subTo(t,r); + while(r[i] < --qd) r.subTo(t,r); + } + } + if(q != null) { + r.drShiftTo(ys,q); + if(ts != ms) BigInteger.ZERO.subTo(q,q); + } + r.t = ys; + r.clamp(); + if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder + if(ts < 0) BigInteger.ZERO.subTo(r,r); +} + +// (public) this mod a +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a,null,r); + if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); + return r; +} + +// Modular reduction using "classic" algorithm +function Classic(m) { this.m = m; } +function cConvert(x) { + if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} +function cRevert(x) { return x; } +function cReduce(x) { x.divRemTo(this.m,null,x); } +function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } +function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +function bnpInvDigit() { + if(this.t < 1) return 0; + var x = this[0]; + if((x&1) == 0) return 0; + var y = x&3; // y == 1/x mod 2^2 + y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 + y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 + y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y>0)?this.DV-y:-y; +} + +// Montgomery reduction +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp&0x7fff; + this.mph = this.mp>>15; + this.um = (1<<(m.DB-15))-1; + this.mt2 = 2*m.t; +} + +// xR mod m +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t,r); + r.divRemTo(this.m,null,r); + if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); + return r; +} + +// x/R mod m +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) +function montReduce(x) { + while(x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for(var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i]&0x7fff; + var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; + // use am to combine the multiply-shift-add into one call + j = i+this.m.t; + x[j] += this.m.am(0,u0,x,i,0,this.m.t); + // propagate carry + while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t,x); + if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = "x^2/R mod m"; x != r +function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = "xy/R mod m"; x,y != r +function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even +function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +function bnpExp(e,z) { + if(e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; + g.copyTo(r); + while(--i >= 0) { + z.sqrTo(r,r2); + if((e&(1< 0) z.mulTo(r2,g,r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 +function bnModPowInt(e,m) { + var z; + if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e,z); +} + +// protected +BigInteger.prototype.copyTo = bnpCopyTo; +BigInteger.prototype.fromInt = bnpFromInt; +BigInteger.prototype.fromString = bnpFromString; +BigInteger.prototype.clamp = bnpClamp; +BigInteger.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger.prototype.drShiftTo = bnpDRShiftTo; +BigInteger.prototype.lShiftTo = bnpLShiftTo; +BigInteger.prototype.rShiftTo = bnpRShiftTo; +BigInteger.prototype.subTo = bnpSubTo; +BigInteger.prototype.multiplyTo = bnpMultiplyTo; +BigInteger.prototype.squareTo = bnpSquareTo; +BigInteger.prototype.divRemTo = bnpDivRemTo; +BigInteger.prototype.invDigit = bnpInvDigit; +BigInteger.prototype.isEven = bnpIsEven; +BigInteger.prototype.exp = bnpExp; + +// public +BigInteger.prototype.toString = bnToString; +BigInteger.prototype.negate = bnNegate; +BigInteger.prototype.abs = bnAbs; +BigInteger.prototype.compareTo = bnCompareTo; +BigInteger.prototype.bitLength = bnBitLength; +BigInteger.prototype.mod = bnMod; +BigInteger.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); + +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Copyright (c) 2005-2009 Tom Wu +// All Rights Reserved. +// See "LICENSE" for details. + +// Extended JavaScript BN functions, required for RSA private ops. + +// Version 1.1: new BigInteger("0", 10) returns "proper" zero +// Version 1.2: square() API, isProbablePrime fix + +// (public) +function bnClone() { var r = nbi(); this.copyTo(r); return r; } + +// (public) return value as integer +function bnIntValue() { + if(this.s < 0) { + if(this.t == 1) return this[0]-this.DV; + else if(this.t == 0) return -1; + } + else if(this.t == 1) return this[0]; + else if(this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this[1]&((1<<(32-this.DB))-1))<>24; } + +// (public) return value as short (assumes DB>=16) +function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; } + +// (protected) return x s.t. r^x < DV +function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } + +// (public) 0 if this == 0, 1 if this > 0 +function bnSigNum() { + if(this.s < 0) return -1; + else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; + else return 1; +} + +// (protected) convert to radix string +function bnpToRadix(b) { + if(b == null) b = 10; + if(this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b,cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d,y,z); + while(y.signum() > 0) { + r = (a+z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d,y,z); + } + return z.intValue().toString(b) + r; +} + +// (protected) convert from radix string +function bnpFromRadix(s,b) { + this.fromInt(0); + if(b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b,cs), mi = false, j = 0, w = 0; + for(var i = 0; i < s.length; ++i) { + var x = intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b*w+x; + if(++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w,0); + j = 0; + w = 0; + } + } + if(j > 0) { + this.dMultiply(Math.pow(b,j)); + this.dAddOffset(w,0); + } + if(mi) BigInteger.ZERO.subTo(this,this); +} + +// (protected) alternate constructor +function bnpFromNumber(a,b,c) { + if("number" == typeof b) { + // new BigInteger(int,int,RNG) + if(a < 2) this.fromInt(1); + else { + this.fromNumber(a,c); + if(!this.testBit(a-1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); + if(this.isEven()) this.dAddOffset(1,0); // force odd + while(!this.isProbablePrime(b)) { + this.dAddOffset(2,0); + if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); + } + } + } + else { + // new BigInteger(int,RNG) + var x = new Array(), t = a&7; + x.length = (a>>3)+1; + b.nextBytes(x); + if(t > 0) x[0] &= ((1< 0) { + if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p) + r[k++] = d|(this.s<<(this.DB-p)); + while(i >= 0) { + if(p < 8) { + d = (this[i]&((1<>(p+=this.DB-8); + } + else { + d = (this[i]>>(p-=8))&0xff; + if(p <= 0) { p += this.DB; --i; } + } + if((d&0x80) != 0) d |= -256; + if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; + if(k > 0 || d != this.s) r[k++] = d; + } + } + return r; +} + +function bnEquals(a) { return(this.compareTo(a)==0); } +function bnMin(a) { return(this.compareTo(a)<0)?this:a; } +function bnMax(a) { return(this.compareTo(a)>0)?this:a; } + +// (protected) r = this op a (bitwise) +function bnpBitwiseTo(a,op,r) { + var i, f, m = Math.min(a.t,this.t); + for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]); + if(a.t < this.t) { + f = a.s&this.DM; + for(i = m; i < this.t; ++i) r[i] = op(this[i],f); + r.t = this.t; + } + else { + f = this.s&this.DM; + for(i = m; i < a.t; ++i) r[i] = op(f,a[i]); + r.t = a.t; + } + r.s = op(this.s,a.s); + r.clamp(); +} + +// (public) this & a +function op_and(x,y) { return x&y; } +function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } + +// (public) this | a +function op_or(x,y) { return x|y; } +function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } + +// (public) this ^ a +function op_xor(x,y) { return x^y; } +function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } + +// (public) this & ~a +function op_andnot(x,y) { return x&~y; } +function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } + +// (public) ~this +function bnNot() { + var r = nbi(); + for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i]; + r.t = this.t; + r.s = ~this.s; + return r; +} + +// (public) this << n +function bnShiftLeft(n) { + var r = nbi(); + if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); + return r; +} + +// (public) this >> n +function bnShiftRight(n) { + var r = nbi(); + if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); + return r; +} + +// return index of lowest 1-bit in x, x < 2^31 +function lbit(x) { + if(x == 0) return -1; + var r = 0; + if((x&0xffff) == 0) { x >>= 16; r += 16; } + if((x&0xff) == 0) { x >>= 8; r += 8; } + if((x&0xf) == 0) { x >>= 4; r += 4; } + if((x&3) == 0) { x >>= 2; r += 2; } + if((x&1) == 0) ++r; + return r; +} + +// (public) returns index of lowest 1-bit (or -1 if none) +function bnGetLowestSetBit() { + for(var i = 0; i < this.t; ++i) + if(this[i] != 0) return i*this.DB+lbit(this[i]); + if(this.s < 0) return this.t*this.DB; + return -1; +} + +// return number of 1 bits in x +function cbit(x) { + var r = 0; + while(x != 0) { x &= x-1; ++r; } + return r; +} + +// (public) return number of set bits +function bnBitCount() { + var r = 0, x = this.s&this.DM; + for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x); + return r; +} + +// (public) true iff nth bit is set +function bnTestBit(n) { + var j = Math.floor(n/this.DB); + if(j >= this.t) return(this.s!=0); + return((this[j]&(1<<(n%this.DB)))!=0); +} + +// (protected) this op (1<>= this.DB; + } + if(a.t < this.t) { + c += a.s; + while(i < this.t) { + c += this[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while(i < a.t) { + c += a[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = (c<0)?-1:0; + if(c > 0) r[i++] = c; + else if(c < -1) r[i++] = this.DV+c; + r.t = i; + r.clamp(); +} + +// (public) this + a +function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } + +// (public) this - a +function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } + +// (public) this * a +function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } + +// (public) this^2 +function bnSquare() { var r = nbi(); this.squareTo(r); return r; } + +// (public) this / a +function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } + +// (public) this % a +function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } + +// (public) [this/a,this%a] +function bnDivideAndRemainder(a) { + var q = nbi(), r = nbi(); + this.divRemTo(a,q,r); + return new Array(q,r); +} + +// (protected) this *= n, this >= 0, 1 < n < DV +function bnpDMultiply(n) { + this[this.t] = this.am(0,n-1,this,0,0,this.t); + ++this.t; + this.clamp(); +} + +// (protected) this += n << w words, this >= 0 +function bnpDAddOffset(n,w) { + if(n == 0) return; + while(this.t <= w) this[this.t++] = 0; + this[w] += n; + while(this[w] >= this.DV) { + this[w] -= this.DV; + if(++w >= this.t) this[this.t++] = 0; + ++this[w]; + } +} + +// A "null" reducer +function NullExp() {} +function nNop(x) { return x; } +function nMulTo(x,y,r) { x.multiplyTo(y,r); } +function nSqrTo(x,r) { x.squareTo(r); } + +NullExp.prototype.convert = nNop; +NullExp.prototype.revert = nNop; +NullExp.prototype.mulTo = nMulTo; +NullExp.prototype.sqrTo = nSqrTo; + +// (public) this^e +function bnPow(e) { return this.exp(e,new NullExp()); } + +// (protected) r = lower n words of "this * a", a.t <= n +// "this" should be the larger one if appropriate. +function bnpMultiplyLowerTo(a,n,r) { + var i = Math.min(this.t+a.t,n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while(i > 0) r[--i] = 0; + var j; + for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t); + for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i); + r.clamp(); +} + +// (protected) r = "this * a" without lower n words, n > 0 +// "this" should be the larger one if appropriate. +function bnpMultiplyUpperTo(a,n,r) { + --n; + var i = r.t = this.t+a.t-n; + r.s = 0; // assumes a,this >= 0 + while(--i >= 0) r[i] = 0; + for(i = Math.max(n-this.t,0); i < a.t; ++i) + r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n); + r.clamp(); + r.drShiftTo(1,r); +} + +// Barrett modular reduction +function Barrett(m) { + // setup Barrett + this.r2 = nbi(); + this.q3 = nbi(); + BigInteger.ONE.dlShiftTo(2*m.t,this.r2); + this.mu = this.r2.divide(m); + this.m = m; +} + +function barrettConvert(x) { + if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); + else if(x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } +} + +function barrettRevert(x) { return x; } + +// x = x mod m (HAC 14.42) +function barrettReduce(x) { + x.drShiftTo(this.m.t-1,this.r2); + if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } + this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); + this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); + while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); + x.subTo(this.r2,x); + while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = x^2 mod m; x != r +function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = x*y mod m; x,y != r +function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Barrett.prototype.convert = barrettConvert; +Barrett.prototype.revert = barrettRevert; +Barrett.prototype.reduce = barrettReduce; +Barrett.prototype.mulTo = barrettMulTo; +Barrett.prototype.sqrTo = barrettSqrTo; + +// (public) this^e % m (HAC 14.85) +function bnModPow(e,m) { + var i = e.bitLength(), k, r = nbv(1), z; + if(i <= 0) return r; + else if(i < 18) k = 1; + else if(i < 48) k = 3; + else if(i < 144) k = 4; + else if(i < 768) k = 5; + else k = 6; + if(i < 8) + z = new Classic(m); + else if(m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { + var g2 = nbi(); + z.sqrTo(g[1],g2); + while(n <= km) { + g[n] = nbi(); + z.mulTo(g2,g[n-2],g[n]); + n += 2; + } + } + + var j = e.t-1, w, is1 = true, r2 = nbi(), t; + i = nbits(e[j])-1; + while(j >= 0) { + if(i >= k1) w = (e[j]>>(i-k1))&km; + else { + w = (e[j]&((1<<(i+1))-1))<<(k1-i); + if(j > 0) w |= e[j-1]>>(this.DB+i-k1); + } + + n = k; + while((w&1) == 0) { w >>= 1; --n; } + if((i -= n) < 0) { i += this.DB; --j; } + if(is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } + else { + while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } + if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2,g[w],r); + } + + while(j >= 0 && (e[j]&(1< 0) { + x.rShiftTo(g,x); + y.rShiftTo(g,y); + } + while(x.signum() > 0) { + if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); + if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); + if(x.compareTo(y) >= 0) { + x.subTo(y,x); + x.rShiftTo(1,x); + } + else { + y.subTo(x,y); + y.rShiftTo(1,y); + } + } + if(g > 0) y.lShiftTo(g,y); + return y; +} + +// (protected) this % n, n < 2^26 +function bnpModInt(n) { + if(n <= 0) return 0; + var d = this.DV%n, r = (this.s<0)?n-1:0; + if(this.t > 0) + if(d == 0) r = this[0]%n; + else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n; + return r; +} + +// (public) 1/this % m (HAC 14.61) +function bnModInverse(m) { + var ac = m.isEven(); + if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while(u.signum() != 0) { + while(u.isEven()) { + u.rShiftTo(1,u); + if(ac) { + if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } + a.rShiftTo(1,a); + } + else if(!b.isEven()) b.subTo(m,b); + b.rShiftTo(1,b); + } + while(v.isEven()) { + v.rShiftTo(1,v); + if(ac) { + if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } + c.rShiftTo(1,c); + } + else if(!d.isEven()) d.subTo(m,d); + d.rShiftTo(1,d); + } + if(u.compareTo(v) >= 0) { + u.subTo(v,u); + if(ac) a.subTo(c,a); + b.subTo(d,b); + } + else { + v.subTo(u,v); + if(ac) c.subTo(a,c); + d.subTo(b,d); + } + } + if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if(d.compareTo(m) >= 0) return d.subtract(m); + if(d.signum() < 0) d.addTo(m,d); else return d; + if(d.signum() < 0) return d.add(m); else return d; +} + +var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]; +var lplim = (1<<26)/lowprimes[lowprimes.length-1]; + +// (public) test primality with certainty >= 1-.5^t +function bnIsProbablePrime(t) { + var i, x = this.abs(); + if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) { + for(i = 0; i < lowprimes.length; ++i) + if(x[0] == lowprimes[i]) return true; + return false; + } + if(x.isEven()) return false; + i = 1; + while(i < lowprimes.length) { + var m = lowprimes[i], j = i+1; + while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while(i < j) if(m%lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); +} + +// (protected) true if probably prime (HAC 4.24, Miller-Rabin) +function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if(k <= 0) return false; + var r = n1.shiftRight(k); + t = (t+1)>>1; + if(t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + for(var i = 0; i < t; ++i) { + //Pick bases at random, instead of starting at 2 + a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]); + var y = a.modPow(r,this); + if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while(j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2,this); + if(y.compareTo(BigInteger.ONE) == 0) return false; + } + if(y.compareTo(n1) != 0) return false; + } + } + return true; +} + +// protected +BigInteger.prototype.chunkSize = bnpChunkSize; +BigInteger.prototype.toRadix = bnpToRadix; +BigInteger.prototype.fromRadix = bnpFromRadix; +BigInteger.prototype.fromNumber = bnpFromNumber; +BigInteger.prototype.bitwiseTo = bnpBitwiseTo; +BigInteger.prototype.changeBit = bnpChangeBit; +BigInteger.prototype.addTo = bnpAddTo; +BigInteger.prototype.dMultiply = bnpDMultiply; +BigInteger.prototype.dAddOffset = bnpDAddOffset; +BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; +BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; +BigInteger.prototype.modInt = bnpModInt; +BigInteger.prototype.millerRabin = bnpMillerRabin; + +// public +BigInteger.prototype.clone = bnClone; +BigInteger.prototype.intValue = bnIntValue; +BigInteger.prototype.byteValue = bnByteValue; +BigInteger.prototype.shortValue = bnShortValue; +BigInteger.prototype.signum = bnSigNum; +BigInteger.prototype.toByteArray = bnToByteArray; +BigInteger.prototype.equals = bnEquals; +BigInteger.prototype.min = bnMin; +BigInteger.prototype.max = bnMax; +BigInteger.prototype.and = bnAnd; +BigInteger.prototype.or = bnOr; +BigInteger.prototype.xor = bnXor; +BigInteger.prototype.andNot = bnAndNot; +BigInteger.prototype.not = bnNot; +BigInteger.prototype.shiftLeft = bnShiftLeft; +BigInteger.prototype.shiftRight = bnShiftRight; +BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; +BigInteger.prototype.bitCount = bnBitCount; +BigInteger.prototype.testBit = bnTestBit; +BigInteger.prototype.setBit = bnSetBit; +BigInteger.prototype.clearBit = bnClearBit; +BigInteger.prototype.flipBit = bnFlipBit; +BigInteger.prototype.add = bnAdd; +BigInteger.prototype.subtract = bnSubtract; +BigInteger.prototype.multiply = bnMultiply; +BigInteger.prototype.divide = bnDivide; +BigInteger.prototype.remainder = bnRemainder; +BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; +BigInteger.prototype.modPow = bnModPow; +BigInteger.prototype.modInverse = bnModInverse; +BigInteger.prototype.pow = bnPow; +BigInteger.prototype.gcd = bnGCD; +BigInteger.prototype.isProbablePrime = bnIsProbablePrime; + +// JSBN-specific extension +BigInteger.prototype.square = bnSquare; + +// BigInteger interfaces not implemented in jsbn: + +// BigInteger(int signum, byte[] magnitude) +// double doubleValue() +// float floatValue() +// int hashCode() +// long longValue() +// static BigInteger valueOf(long val) + +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +var b64pad="="; + +function hex2b64(h) { + var i; + var c; + var ret = ""; + for(i = 0; i+3 <= h.length; i+=3) { + c = parseInt(h.substring(i,i+3),16); + ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63); + } + if(i+1 == h.length) { + c = parseInt(h.substring(i,i+1),16); + ret += b64map.charAt(c << 2); + } + else if(i+2 == h.length) { + c = parseInt(h.substring(i,i+2),16); + ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4); + } + if (b64pad) while((ret.length & 3) > 0) ret += b64pad; + return ret; +} + +// convert a base64 string to hex +function b64tohex(s) { + var ret = "" + var i; + var k = 0; // b64 state, 0-3 + var slop; + var v; + for(i = 0; i < s.length; ++i) { + if(s.charAt(i) == b64pad) break; + v = b64map.indexOf(s.charAt(i)); + if(v < 0) continue; + if(k == 0) { + ret += int2char(v >> 2); + slop = v & 3; + k = 1; + } + else if(k == 1) { + ret += int2char((slop << 2) | (v >> 4)); + slop = v & 0xf; + k = 2; + } + else if(k == 2) { + ret += int2char(slop); + ret += int2char(v >> 2); + slop = v & 3; + k = 3; + } + else { + ret += int2char((slop << 2) | (v >> 4)); + ret += int2char(v & 0xf); + k = 0; + } + } + if(k == 1) + ret += int2char(slop << 2); + return ret; +} + +// convert a base64 string to a byte/number array +function b64toBA(s) { + //piggyback on b64tohex for now, optimize later + var h = b64tohex(s); + var i; + var a = new Array(); + for(i = 0; 2*i < h.length; ++i) { + a[i] = parseInt(h.substring(2*i,2*i+2),16); + } + return a; +} + +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS 180-1 + * Version 2.2 Copyright Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); } +function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); } +function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); } +function hex_hmac_sha1(k, d) + { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } +function b64_hmac_sha1(k, d) + { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); } +function any_hmac_sha1(k, d, e) + { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); } + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA1 of a raw string + */ +function rstr_sha1(s) +{ + return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8)); +} + +/* + * Calculate the HMAC-SHA1 of a key and some data (raw strings) + */ +function rstr_hmac_sha1(key, data) +{ + var bkey = rstr2binb(key); + if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8); + return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160)); +} + +/* + * Convert a raw string to a hex string + */ +function rstr2hex(input) +{ + try { hexcase } catch(e) { hexcase=0; } + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var output = ""; + var x; + for(var i = 0; i < input.length; i++) + { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0F) + + hex_tab.charAt( x & 0x0F); + } + return output; +} + +/* + * Convert a raw string to a base-64 string + */ +function rstr2b64(input) +{ + try { b64pad } catch(e) { b64pad=''; } + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var output = ""; + var len = input.length; + for(var i = 0; i < len; i += 3) + { + var triplet = (input.charCodeAt(i) << 16) + | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) + | (i + 2 < len ? input.charCodeAt(i+2) : 0); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > input.length * 8) output += b64pad; + else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); + } + } + return output; +} + +/* + * Convert a raw string to an arbitrary string encoding + */ +function rstr2any(input, encoding) +{ + var divisor = encoding.length; + var remainders = Array(); + var i, q, x, quotient; + + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + var dividend = Array(Math.ceil(input.length / 2)); + for(i = 0; i < dividend.length; i++) + { + dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } + + /* + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. We stop when the dividend is zero. + * All remainders are stored for later use. + */ + while(dividend.length > 0) + { + quotient = Array(); + x = 0; + for(i = 0; i < dividend.length; i++) + { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if(quotient.length > 0 || q > 0) + quotient[quotient.length] = q; + } + remainders[remainders.length] = x; + dividend = quotient; + } + + /* Convert the remainders to the output string */ + var output = ""; + for(i = remainders.length - 1; i >= 0; i--) + output += encoding.charAt(remainders[i]); + + /* Append leading zero equivalents */ + var full_length = Math.ceil(input.length * 8 / + (Math.log(encoding.length) / Math.log(2))) + for(i = output.length; i < full_length; i++) + output = encoding[0] + output; + + return output; +} + +/* + * Encode a string as utf-8. + * For efficiency, this assumes the input is valid utf-16. + */ +function str2rstr_utf8(input) +{ + var output = ""; + var i = -1; + var x, y; + + while(++i < input.length) + { + /* Decode utf-16 surrogate pairs */ + x = input.charCodeAt(i); + y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; + if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) + { + x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); + i++; + } + + /* Encode output as utf-8 */ + if(x <= 0x7F) + output += String.fromCharCode(x); + else if(x <= 0x7FF) + output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), + 0x80 | ( x & 0x3F)); + else if(x <= 0xFFFF) + output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + else if(x <= 0x1FFFFF) + output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + } + return output; +} + +/* + * Encode a string as utf-16 + */ +function str2rstr_utf16le(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode( input.charCodeAt(i) & 0xFF, + (input.charCodeAt(i) >>> 8) & 0xFF); + return output; +} + +function str2rstr_utf16be(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, + input.charCodeAt(i) & 0xFF); + return output; +} + +/* + * Convert a raw string to an array of big-endian words + * Characters >255 have their high-byte silently ignored. + */ +function rstr2binb(input) +{ + var output = Array(input.length >> 2); + for(var i = 0; i < output.length; i++) + output[i] = 0; + for(var i = 0; i < input.length * 8; i += 8) + output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); + return output; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2rstr(input) +{ + var output = ""; + for(var i = 0; i < input.length * 32; i += 8) + output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF); + return output; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function binb_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + for(var j = 0; j < 80; j++) + { + if(j < 16) w[j] = x[i + j]; + else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = bit_rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if(t < 20) return (b & c) | ((~b) & d); + if(t < 40) return b ^ c ^ d; + if(t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined + * in FIPS 180-2 + * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + * Also http://anmar.eu.org/projects/jssha2/ + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); } +function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); } +function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); } +function hex_hmac_sha256(k, d) + { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); } +function b64_hmac_sha256(k, d) + { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); } +function any_hmac_sha256(k, d, e) + { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); } + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha256_vm_test() +{ + return hex_sha256("abc").toLowerCase() == + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; +} + +/* + * Calculate the sha256 of a raw string + */ +function rstr_sha256(s) +{ + return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8)); +} + +/* + * Calculate the HMAC-sha256 of a key and some data (raw strings) + */ +function rstr_hmac_sha256(key, data) +{ + var bkey = rstr2binb(key); + if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8); + return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256)); +} + +/* + * Convert a raw string to a hex string + */ +function rstr2hex(input) +{ + try { hexcase } catch(e) { hexcase=0; } + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var output = ""; + var x; + for(var i = 0; i < input.length; i++) + { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0F) + + hex_tab.charAt( x & 0x0F); + } + return output; +} + +/* + * Convert a raw string to a base-64 string + */ +function rstr2b64(input) +{ + try { b64pad } catch(e) { b64pad=''; } + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var output = ""; + var len = input.length; + for(var i = 0; i < len; i += 3) + { + var triplet = (input.charCodeAt(i) << 16) + | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) + | (i + 2 < len ? input.charCodeAt(i+2) : 0); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > input.length * 8) output += b64pad; + else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); + } + } + return output; +} + +/* + * Convert a raw string to an arbitrary string encoding + */ +function rstr2any(input, encoding) +{ + var divisor = encoding.length; + var remainders = Array(); + var i, q, x, quotient; + + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + var dividend = Array(Math.ceil(input.length / 2)); + for(i = 0; i < dividend.length; i++) + { + dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } + + /* + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. We stop when the dividend is zero. + * All remainders are stored for later use. + */ + while(dividend.length > 0) + { + quotient = Array(); + x = 0; + for(i = 0; i < dividend.length; i++) + { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if(quotient.length > 0 || q > 0) + quotient[quotient.length] = q; + } + remainders[remainders.length] = x; + dividend = quotient; + } + + /* Convert the remainders to the output string */ + var output = ""; + for(i = remainders.length - 1; i >= 0; i--) + output += encoding.charAt(remainders[i]); + + /* Append leading zero equivalents */ + var full_length = Math.ceil(input.length * 8 / + (Math.log(encoding.length) / Math.log(2))) + for(i = output.length; i < full_length; i++) + output = encoding[0] + output; + + return output; +} + +/* + * Encode a string as utf-8. + * For efficiency, this assumes the input is valid utf-16. + */ +function str2rstr_utf8(input) +{ + var output = ""; + var i = -1; + var x, y; + + while(++i < input.length) + { + /* Decode utf-16 surrogate pairs */ + x = input.charCodeAt(i); + y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; + if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) + { + x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); + i++; + } + + /* Encode output as utf-8 */ + if(x <= 0x7F) + output += String.fromCharCode(x); + else if(x <= 0x7FF) + output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), + 0x80 | ( x & 0x3F)); + else if(x <= 0xFFFF) + output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + else if(x <= 0x1FFFFF) + output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + } + return output; +} + +/* + * Encode a string as utf-16 + */ +function str2rstr_utf16le(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode( input.charCodeAt(i) & 0xFF, + (input.charCodeAt(i) >>> 8) & 0xFF); + return output; +} + +function str2rstr_utf16be(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, + input.charCodeAt(i) & 0xFF); + return output; +} + +/* + * Convert a raw string to an array of big-endian words + * Characters >255 have their high-byte silently ignored. + */ +function rstr2binb(input) +{ + var output = Array(input.length >> 2); + for(var i = 0; i < output.length; i++) + output[i] = 0; + for(var i = 0; i < input.length * 8; i += 8) + output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); + return output; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2rstr(input) +{ + var output = ""; + for(var i = 0; i < input.length * 32; i += 8) + output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF); + return output; +} + +/* + * Main sha256 function, with its support functions + */ +function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));} +function sha256_R (X, n) {return ( X >>> n );} +function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));} +function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));} +function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));} +function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));} +function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));} +function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));} +function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));} +function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));} +function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));} +function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));} + +var sha256_K = new Array +( + 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, + -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, + 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, + 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, + -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, + 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, + 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, + -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, + 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, + 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, + -1866530822, -1538233109, -1090935817, -965641998 +); + +function binb_sha256(m, l) +{ + var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534, + 1359893119, -1694144372, 528734635, 1541459225); + var W = new Array(64); + var a, b, c, d, e, f, g, h; + var i, j, T1, T2; + + /* append padding */ + m[l >> 5] |= 0x80 << (24 - l % 32); + m[((l + 64 >> 9) << 4) + 15] = l; + + for(i = 0; i < m.length; i += 16) + { + a = HASH[0]; + b = HASH[1]; + c = HASH[2]; + d = HASH[3]; + e = HASH[4]; + f = HASH[5]; + g = HASH[6]; + h = HASH[7]; + + for(j = 0; j < 64; j++) + { + if (j < 16) W[j] = m[j + i]; + else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), + sha256_Gamma0256(W[j - 15])), W[j - 16]); + + T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), + sha256_K[j]), W[j]); + T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c)); + h = g; + g = f; + f = e; + e = safe_add(d, T1); + d = c; + c = b; + b = a; + a = safe_add(T1, T2); + } + + HASH[0] = safe_add(a, HASH[0]); + HASH[1] = safe_add(b, HASH[1]); + HASH[2] = safe_add(c, HASH[2]); + HASH[3] = safe_add(d, HASH[3]); + HASH[4] = safe_add(e, HASH[4]); + HASH[5] = safe_add(f, HASH[5]); + HASH[6] = safe_add(g, HASH[6]); + HASH[7] = safe_add(h, HASH[7]); + } + return HASH; +} + +function safe_add (x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Depends on jsbn.js and rng.js + +// Version 1.1: support utf-8 encoding in pkcs1pad2 + +// convert a (hex) string to a bignum object +function parseBigInt(str,r) { + return new BigInteger(str,r); +} + +function linebrk(s,n) { + var ret = ""; + var i = 0; + while(i + n < s.length) { + ret += s.substring(i,i+n) + "\n"; + i += n; + } + return ret + s.substring(i,s.length); +} + +function byte2Hex(b) { + if(b < 0x10) + return "0" + b.toString(16); + else + return b.toString(16); +} + +// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint +function pkcs1pad2(s,n) { + if(n < s.length + 11) { // TODO: fix for utf-8 + alert("Message too long for RSA"); + return null; + } + var ba = new Array(); + var i = s.length - 1; + while(i >= 0 && n > 0) { + var c = s.charCodeAt(i--); + if(c < 128) { // encode using utf-8 + ba[--n] = c; + } + else if((c > 127) && (c < 2048)) { + ba[--n] = (c & 63) | 128; + ba[--n] = (c >> 6) | 192; + } + else { + ba[--n] = (c & 63) | 128; + ba[--n] = ((c >> 6) & 63) | 128; + ba[--n] = (c >> 12) | 224; + } + } + ba[--n] = 0; + var rng = new SecureRandom(); + var x = new Array(); + while(n > 2) { // random non-zero pad + x[0] = 0; + while(x[0] == 0) rng.nextBytes(x); + ba[--n] = x[0]; + } + ba[--n] = 2; + ba[--n] = 0; + return new BigInteger(ba); +} + +// PKCS#1 (OAEP) mask generation function +function oaep_mgf1_arr(seed, len, hash) +{ + var mask = '', i = 0; + + while (mask.length < len) + { + mask += hash(String.fromCharCode.apply(String, seed.concat([ + (i & 0xff000000) >> 24, + (i & 0x00ff0000) >> 16, + (i & 0x0000ff00) >> 8, + i & 0x000000ff]))); + i += 1; + } + + return mask; +} + +// PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint +function oaep_pad(s, n, hash, hashLen) +{ + if (!hash) + { + hash = rstr_sha1; + hashLen = 20; + } + + if (s.length + 2 * hashLen + 2 > n) + { + throw "Message too long for RSA"; + } + + var PS = '', i; + + for (i = 0; i < n - s.length - 2 * hashLen - 2; i += 1) + { + PS += '\x00'; + } + + var DB = hash('') + PS + '\x01' + s; + var seed = new Array(hashLen); + new SecureRandom().nextBytes(seed); + + var dbMask = oaep_mgf1_arr(seed, DB.length, hash); + var maskedDB = []; + + for (i = 0; i < DB.length; i += 1) + { + maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); + } + + var seedMask = oaep_mgf1_arr(maskedDB, seed.length, hash); + var maskedSeed = [0]; + + for (i = 0; i < seed.length; i += 1) + { + maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i); + } + + return new BigInteger(maskedSeed.concat(maskedDB)); +} + +// "empty" RSA key constructor +function RSAKey() { + this.n = null; + this.e = 0; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.coeff = null; +} + +// Set the public key fields N and e from hex strings +function RSASetPublic(N,E) { + this.isPublic = true; + if (typeof N !== "string") + { + this.n = N; + this.e = E; + } + else if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + } + else + alert("Invalid RSA public key"); +} + +// Perform raw public operation on "x": return x^e (mod n) +function RSADoPublic(x) { + return x.modPowInt(this.e, this.n); +} + +// Return the PKCS#1 RSA encryption of "text" as an even-length hex string +function RSAEncrypt(text) { + var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); + if(m == null) return null; + var c = this.doPublic(m); + if(c == null) return null; + var h = c.toString(16); + if((h.length & 1) == 0) return h; else return "0" + h; +} + +// Return the PKCS#1 OAEP RSA encryption of "text" as an even-length hex string +function RSAEncryptOAEP(text, hash, hashLen) { + var m = oaep_pad(text, (this.n.bitLength()+7)>>3, hash, hashLen); + if(m == null) return null; + var c = this.doPublic(m); + if(c == null) return null; + var h = c.toString(16); + if((h.length & 1) == 0) return h; else return "0" + h; +} + +// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string +//function RSAEncryptB64(text) { +// var h = this.encrypt(text); +// if(h) return hex2b64(h); else return null; +//} + +// protected +RSAKey.prototype.doPublic = RSADoPublic; + +// public +RSAKey.prototype.setPublic = RSASetPublic; +RSAKey.prototype.encrypt = RSAEncrypt; +RSAKey.prototype.encryptOAEP = RSAEncryptOAEP; +//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; + +RSAKey.prototype.type = "RSA"; + +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Depends on rsa.js and jsbn2.js + +// Version 1.1: support utf-8 decoding in pkcs1unpad2 + +// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext +function pkcs1unpad2(d,n) { + var b = d.toByteArray(); + var i = 0; + while(i < b.length && b[i] == 0) ++i; + if(b.length-i != n-1 || b[i] != 2) + return null; + ++i; + while(b[i] != 0) + if(++i >= b.length) return null; + var ret = ""; + while(++i < b.length) { + var c = b[i] & 255; + if(c < 128) { // utf-8 decode + ret += String.fromCharCode(c); + } + else if((c > 191) && (c < 224)) { + ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63)); + ++i; + } + else { + ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63)); + i += 2; + } + } + return ret; +} + +// PKCS#1 (OAEP) mask generation function +function oaep_mgf1_str(seed, len, hash) +{ + var mask = '', i = 0; + + while (mask.length < len) + { + mask += hash(seed + String.fromCharCode.apply(String, [ + (i & 0xff000000) >> 24, + (i & 0x00ff0000) >> 16, + (i & 0x0000ff00) >> 8, + i & 0x000000ff])); + i += 1; + } + + return mask; +} + +// Undo PKCS#1 (OAEP) padding and, if valid, return the plaintext +function oaep_unpad(d, n, hash, hashLen) +{ + if (!hash) + { + hash = rstr_sha1; + hashLen = 20; + } + + d = d.toByteArray(); + + var i; + + for (i = 0; i < d.length; i += 1) + { + d[i] &= 0xff; + } + + while (d.length < n) + { + d.unshift(0); + } + + d = String.fromCharCode.apply(String, d); + + if (d.length < 2 * hashLen + 2) + { + throw "Cipher too short"; + } + + var maskedSeed = d.substr(1, hashLen) + var maskedDB = d.substr(hashLen + 1); + + var seedMask = oaep_mgf1_str(maskedDB, hashLen, hash); + var seed = [], i; + + for (i = 0; i < maskedSeed.length; i += 1) + { + seed[i] = maskedSeed.charCodeAt(i) ^ seedMask.charCodeAt(i); + } + + var dbMask = oaep_mgf1_str(String.fromCharCode.apply(String, seed), + d.length - hashLen, hash); + + var DB = []; + + for (i = 0; i < maskedDB.length; i += 1) + { + DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i); + } + + DB = String.fromCharCode.apply(String, DB); + + if (DB.substr(0, hashLen) !== hash('')) + { + throw "Hash mismatch"; + } + + DB = DB.substr(hashLen); + + var first_one = DB.indexOf('\x01'); + var last_zero = (first_one != -1) ? DB.substr(0, first_one).lastIndexOf('\x00') : -1; + + if (last_zero + 1 != first_one) + { + throw "Malformed data"; + } + + return DB.substr(first_one + 1); +} + +// Set the private key fields N, e, and d from hex strings +function RSASetPrivate(N,E,D) { + this.isPrivate = true; + if (typeof N !== "string") + { + this.n = N; + this.e = E; + this.d = D; + } + else if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + this.d = parseBigInt(D,16); + } + else + alert("Invalid RSA private key"); +} + +// Set the private key fields N, e, d and CRT params from hex strings +function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) { + this.isPrivate = true; + if (N == null) throw "RSASetPrivateEx N == null"; + if (E == null) throw "RSASetPrivateEx E == null"; + if (N.length == 0) throw "RSASetPrivateEx N.length == 0"; + if (E.length == 0) throw "RSASetPrivateEx E.length == 0"; + + if (N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + this.d = parseBigInt(D,16); + this.p = parseBigInt(P,16); + this.q = parseBigInt(Q,16); + this.dmp1 = parseBigInt(DP,16); + this.dmq1 = parseBigInt(DQ,16); + this.coeff = parseBigInt(C,16); + } else { + alert("Invalid RSA private key in RSASetPrivateEx"); + } +} + +// Generate a new random private key B bits long, using public expt E +function RSAGenerate(B,E) { + var rng = new SecureRandom(); + var qs = B>>1; + this.e = parseInt(E,16); + var ee = new BigInteger(E,16); + for(;;) { + for(;;) { + this.p = new BigInteger(B-qs,1,rng); + if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break; + } + for(;;) { + this.q = new BigInteger(qs,1,rng); + if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break; + } + if(this.p.compareTo(this.q) <= 0) { + var t = this.p; + this.p = this.q; + this.q = t; + } + var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1 + var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1 + var phi = p1.multiply(q1); + if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { + this.n = this.p.multiply(this.q); // this.n = p * q + this.d = ee.modInverse(phi); // this.d = + this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1) + this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1) + this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p + break; + } + } +} + +// Perform raw private operation on "x": return x^d (mod n) +function RSADoPrivate(x) { + if(this.p == null || this.q == null) + return x.modPow(this.d, this.n); + + // TODO: re-calculate any missing CRT params + var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp? + var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq? + + while(xp.compareTo(xq) < 0) + xp = xp.add(this.p); + // NOTE: + // xp.subtract(xq) => cp -cq + // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h + // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M + return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); +} + +// Return the PKCS#1 RSA decryption of "ctext". +// "ctext" is an even-length hex string and the output is a plain string. +function RSADecrypt(ctext) { + var c = parseBigInt(ctext, 16); + var m = this.doPrivate(c); + if(m == null) return null; + return pkcs1unpad2(m, (this.n.bitLength()+7)>>3); +} + +// Return the PKCS#1 OAEP RSA decryption of "ctext". +// "ctext" is an even-length hex string and the output is a plain string. +function RSADecryptOAEP(ctext, hash, hashLen) { + var c = parseBigInt(ctext, 16); + var m = this.doPrivate(c); + if(m == null) return null; + return oaep_unpad(m, (this.n.bitLength()+7)>>3, hash, hashLen); +} + +// Return the PKCS#1 RSA decryption of "ctext". +// "ctext" is a Base64-encoded string and the output is a plain string. +//function RSAB64Decrypt(ctext) { +// var h = b64tohex(ctext); +// if(h) return this.decrypt(h); else return null; +//} + +// protected +RSAKey.prototype.doPrivate = RSADoPrivate; + +// public +RSAKey.prototype.setPrivate = RSASetPrivate; +RSAKey.prototype.setPrivateEx = RSASetPrivateEx; +RSAKey.prototype.generate = RSAGenerate; +RSAKey.prototype.decrypt = RSADecrypt; +RSAKey.prototype.decryptOAEP = RSADecryptOAEP; +//RSAKey.prototype.b64_decrypt = RSAB64Decrypt; + +/*! asn1hex-1.1.4.js (c) 2012-2013 Kenji Urushima | kjur.github.com/jsrsasign/license + */ +/* + * asn1hex.js - Hexadecimal represented ASN.1 string library + * + * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsrsasign/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name asn1hex-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version asn1hex 1.1.4 (2013-Oct-02) + * @license MIT License + */ + +/* + * MEMO: + * f('3082025b02...', 2) ... 82025b ... 3bytes + * f('020100', 2) ... 01 ... 1byte + * f('0203001...', 2) ... 03 ... 1byte + * f('02818003...', 2) ... 8180 ... 2bytes + * f('3080....0000', 2) ... 80 ... -1 + * + * Requirements: + * - ASN.1 type octet length MUST be 1. + * (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...) + */ + +/** + * ASN.1 DER encoded hexadecimal string utility class + * @name ASN1HEX + * @class ASN.1 DER encoded hexadecimal string utility class + * @since jsrsasign 1.1 + */ +var ASN1HEX = new function() { + /** + * get byte length for ASN.1 L(length) bytes + * @name getByteLengthOfL_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return byte length for ASN.1 L(length) bytes + */ + this.getByteLengthOfL_AtObj = function(s, pos) { + if (s.substring(pos + 2, pos + 3) != '8') return 1; + var i = parseInt(s.substring(pos + 3, pos + 4)); + if (i == 0) return -1; // length octet '80' indefinite length + if (0 < i && i < 10) return i + 1; // including '8?' octet; + return -2; // malformed format + }; + + /** + * get hexadecimal string for ASN.1 L(length) bytes + * @name getHexOfL_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return {String} hexadecimal string for ASN.1 L(length) bytes + */ + this.getHexOfL_AtObj = function(s, pos) { + var len = this.getByteLengthOfL_AtObj(s, pos); + if (len < 1) return ''; + return s.substring(pos + 2, pos + 2 + len * 2); + }; + + // getting ASN.1 length value at the position 'idx' of + // hexa decimal string 's'. + // + // f('3082025b02...', 0) ... 82025b ... ??? + // f('020100', 0) ... 01 ... 1 + // f('0203001...', 0) ... 03 ... 3 + // f('02818003...', 0) ... 8180 ... 128 + /** + * get integer value of ASN.1 length for ASN.1 data + * @name getIntOfL_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return ASN.1 L(length) integer value + */ + this.getIntOfL_AtObj = function(s, pos) { + var hLength = this.getHexOfL_AtObj(s, pos); + if (hLength == '') return -1; + var bi; + if (parseInt(hLength.substring(0, 1)) < 8) { + bi = new BigInteger(hLength, 16); + } else { + bi = new BigInteger(hLength.substring(2), 16); + } + return bi.intValue(); + }; + + /** + * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'. + * @name getStartPosOfV_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + */ + this.getStartPosOfV_AtObj = function(s, pos) { + var l_len = this.getByteLengthOfL_AtObj(s, pos); + if (l_len < 0) return l_len; + return pos + (l_len + 1) * 2; + }; + + /** + * get hexadecimal string of ASN.1 V(value) + * @name getHexOfV_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return {String} hexadecimal string of ASN.1 value. + */ + this.getHexOfV_AtObj = function(s, pos) { + var pos1 = this.getStartPosOfV_AtObj(s, pos); + var len = this.getIntOfL_AtObj(s, pos); + return s.substring(pos1, pos1 + len * 2); + }; + + /** + * get hexadecimal string of ASN.1 TLV at + * @name getHexOfTLV_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return {String} hexadecimal string of ASN.1 TLV. + * @since 1.1 + */ + this.getHexOfTLV_AtObj = function(s, pos) { + var hT = s.substr(pos, 2); + var hL = this.getHexOfL_AtObj(s, pos); + var hV = this.getHexOfV_AtObj(s, pos); + return hT + hL + hV; + }; + + /** + * get next sibling starting index for ASN.1 object string + * @name getPosOfNextSibling_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return next sibling starting index for ASN.1 object string + */ + this.getPosOfNextSibling_AtObj = function(s, pos) { + var pos1 = this.getStartPosOfV_AtObj(s, pos); + var len = this.getIntOfL_AtObj(s, pos); + return pos1 + len * 2; + }; + + /** + * get array of indexes of child ASN.1 objects + * @name getPosArrayOfChildren_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} start string index of ASN.1 object + * @return {Array of Number} array of indexes for childen of ASN.1 objects + */ + this.getPosArrayOfChildren_AtObj = function(h, pos) { + var a = new Array(); + var p0 = this.getStartPosOfV_AtObj(h, pos); + a.push(p0); + + var len = this.getIntOfL_AtObj(h, pos); + var p = p0; + var k = 0; + while (1) { + var pNext = this.getPosOfNextSibling_AtObj(h, p); + if (pNext == null || (pNext - p0 >= (len * 2))) break; + if (k >= 200) break; + + a.push(pNext); + p = pNext; + + k++; + } + + return a; + }; + + /** + * get string index of nth child object of ASN.1 object refered by h, idx + * @name getNthChildIndex_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx start string index of ASN.1 object + * @param {Number} nth for child + * @return {Number} string index of nth child. + * @since 1.1 + */ + this.getNthChildIndex_AtObj = function(h, idx, nth) { + var a = this.getPosArrayOfChildren_AtObj(h, idx); + return a[nth]; + }; + + // ========== decendant methods ============================== + /** + * get string index of nth child object of ASN.1 object refered by h, idx + * @name getDecendantIndexByNthList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} currentIndex start string index of ASN.1 object + * @param {Array of Number} nthList array list of nth + * @return {Number} string index refered by nthList + * @since 1.1 + * @example + * The "nthList" is a index list of structured ASN.1 object + * reference. Here is a sample structure and "nthList"s which + * refers each objects. + * + * SQUENCE - [0] + * SEQUENCE - [0, 0] + * IA5STRING 000 - [0, 0, 0] + * UTF8STRING 001 - [0, 0, 1] + * SET - [0, 1] + * IA5STRING 010 - [0, 1, 0] + * UTF8STRING 011 - [0, 1, 1] + */ + this.getDecendantIndexByNthList = function(h, currentIndex, nthList) { + if (nthList.length == 0) { + return currentIndex; + } + var firstNth = nthList.shift(); + var a = this.getPosArrayOfChildren_AtObj(h, currentIndex); + return this.getDecendantIndexByNthList(h, a[firstNth], nthList); + }; + + /** + * get hexadecimal string of ASN.1 TLV refered by current index and nth index list. + * @name getDecendantHexTLVByNthList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} currentIndex start string index of ASN.1 object + * @param {Array of Number} nthList array list of nth + * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList + * @since 1.1 + */ + this.getDecendantHexTLVByNthList = function(h, currentIndex, nthList) { + var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); + return this.getHexOfTLV_AtObj(h, idx); + }; + + /** + * get hexadecimal string of ASN.1 V refered by current index and nth index list. + * @name getDecendantHexVByNthList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} currentIndex start string index of ASN.1 object + * @param {Array of Number} nthList array list of nth + * @return {Number} hexadecimal string of ASN.1 V refered by nthList + * @since 1.1 + */ + this.getDecendantHexVByNthList = function(h, currentIndex, nthList) { + var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); + return this.getHexOfV_AtObj(h, idx); + }; +}; + +/* + * @since asn1hex 1.1.4 + */ +ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag) { + var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); + if (idx === undefined) { + throw "can't find nthList object"; + } + if (checkingTag !== undefined) { + if (h.substr(idx, 2) != checkingTag) { + throw "checking tag doesn't match: " + h.substr(idx,2) + "!=" + checkingTag; + } + } + return this.getHexOfV_AtObj(h, idx); +}; + + +/*! base64x-1.1.2 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license + */ +/* + * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library + * + * version: 1.1.2 (2013 Jul 21) + * + * Copyright (c) 2012-2013 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsjws/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + * + * DEPENDS ON: + * - base64.js - Tom Wu's Base64 library + */ + +/** + * Base64URL and supplementary functions for Tom Wu's base64.js library.
+ * This class is just provide information about global functions + * defined in 'base64x.js'. The 'base64x.js' script file provides + * global functions for converting following data each other. + *
    + *
  • (ASCII) String
  • + *
  • UTF8 String including CJK, Latin and other characters
  • + *
  • byte array
  • + *
  • hexadecimal encoded String
  • + *
  • Full URIComponent encoded String (such like "%69%94")
  • + *
  • Base64 encoded String
  • + *
  • Base64URL encoded String
  • + *
+ * All functions in 'base64x.js' are defined in {@link _global_} and not + * in this class. + * + * @class Base64URL and supplementary functions for Tom Wu's base64.js library + * @author Kenji Urushima + * @version 1.1 (07 May 2012) + * @requires base64.js + * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ + * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ + */ +function Base64x() { +} + +// ==== string / byte array ================================ +/** + * convert a string to an array of character codes + * @param {String} s + * @return {Array of Numbers} + */ +function stoBA(s) { + var a = new Array(); + for (var i = 0; i < s.length; i++) { + a[i] = s.charCodeAt(i); + } + return a; +} + +/** + * convert an array of character codes to a string + * @param {Array of Numbers} a array of character codes + * @return {String} s + */ +function BAtos(a) { + var s = ""; + for (var i = 0; i < a.length; i++) { + s = s + String.fromCharCode(a[i]); + } + return s; +} + +// ==== byte array / hex ================================ +/** + * convert an array of bytes(Number) to hexadecimal string.
+ * @param {Array of Numbers} a array of bytes + * @return {String} hexadecimal string + */ +function BAtohex(a) { + var s = ""; + for (var i = 0; i < a.length; i++) { + var hex1 = a[i].toString(16); + if (hex1.length == 1) hex1 = "0" + hex1; + s = s + hex1; + } + return s; +} + +// ==== string / hex ================================ +/** + * convert a ASCII string to a hexadecimal string of ASCII codes.
+ * NOTE: This can't be used for non ASCII characters. + * @param {s} s ASCII string + * @return {String} hexadecimal string + */ +function stohex(s) { + return BAtohex(stoBA(s)); +} + +// ==== string / base64 ================================ +/** + * convert a ASCII string to a Base64 encoded string.
+ * NOTE: This can't be used for non ASCII characters. + * @param {s} s ASCII string + * @return {String} Base64 encoded string + */ +function stob64(s) { + return hex2b64(stohex(s)); +} + +// ==== string / base64url ================================ +/** + * convert a ASCII string to a Base64URL encoded string.
+ * NOTE: This can't be used for non ASCII characters. + * @param {s} s ASCII string + * @return {String} Base64URL encoded string + */ +function stob64u(s) { + return b64tob64u(hex2b64(stohex(s))); +} + +/** + * convert a Base64URL encoded string to a ASCII string.
+ * NOTE: This can't be used for Base64URL encoded non ASCII characters. + * @param {s} s Base64URL encoded string + * @return {String} ASCII string + */ +function b64utos(s) { + return BAtos(b64toBA(b64utob64(s))); +} + +// ==== base64 / base64url ================================ +/** + * convert a Base64 encoded string to a Base64URL encoded string.
+ * Example: "ab+c3f/==" → "ab-c3f_" + * @param {String} s Base64 encoded string + * @return {String} Base64URL encoded string + */ +function b64tob64u(s) { + s = s.replace(/\=/g, ""); + s = s.replace(/\+/g, "-"); + s = s.replace(/\//g, "_"); + return s; +} + +/** + * convert a Base64URL encoded string to a Base64 encoded string.
+ * Example: "ab-c3f_" → "ab+c3f/==" + * @param {String} s Base64URL encoded string + * @return {String} Base64 encoded string + */ +function b64utob64(s) { + if (s.length % 4 == 2) s = s + "=="; + else if (s.length % 4 == 3) s = s + "="; + s = s.replace(/-/g, "+"); + s = s.replace(/_/g, "/"); + return s; +} + +// ==== hex / base64url ================================ +/** + * convert a hexadecimal string to a Base64URL encoded string.
+ * @param {String} s hexadecimal string + * @return {String} Base64URL encoded string + */ +function hextob64u(s) { + return b64tob64u(hex2b64(s)); +} + +/** + * convert a Base64URL encoded string to a hexadecimal string.
+ * @param {String} s Base64URL encoded string + * @return {String} hexadecimal string + */ +function b64utohex(s) { + return b64tohex(b64utob64(s)); +} + +var utf8tob64u, b64utoutf8; + +if (typeof Buffer === 'function') +{ + utf8tob64u = function (s) + { + return b64tob64u(new Buffer(s, 'utf8').toString('base64')); + }; + + b64utoutf8 = function (s) + { + return new Buffer(b64utob64(s), 'base64').toString('utf8'); + }; +} +else +{ +// ==== utf8 / base64url ================================ +/** + * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.
+ * @param {String} s UTF-8 encoded string + * @return {String} Base64URL encoded string + * @since 1.1 + */ + utf8tob64u = function (s) + { + return hextob64u(uricmptohex(encodeURIComponentAll(s))); + }; + +/** + * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.
+ * @param {String} s Base64URL encoded string + * @return {String} UTF-8 encoded string + * @since 1.1 + */ + b64utoutf8 = function (s) + { + return decodeURIComponent(hextouricmp(b64utohex(s))); + }; +} + +// ==== utf8 / base64url ================================ +/** + * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.
+ * @param {String} s UTF-8 encoded string + * @return {String} Base64 encoded string + * @since 1.1.1 + */ +function utf8tob64(s) { + return hex2b64(uricmptohex(encodeURIComponentAll(s))); +} + +/** + * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.
+ * @param {String} s Base64 encoded string + * @return {String} UTF-8 encoded string + * @since 1.1.1 + */ +function b64toutf8(s) { + return decodeURIComponent(hextouricmp(b64tohex(s))); +} + +// ==== utf8 / hex ================================ +/** + * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.
+ * @param {String} s UTF-8 encoded string + * @return {String} hexadecimal encoded string + * @since 1.1.1 + */ +function utf8tohex(s) { + return uricmptohex(encodeURIComponentAll(s)); +} + +/** + * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.
+ * Note that when input is improper hexadecimal string as UTF-8 string, this function returns + * 'null'. + * @param {String} s hexadecimal encoded string + * @return {String} UTF-8 encoded string or null + * @since 1.1.1 + */ +function hextoutf8(s) { + return decodeURIComponent(hextouricmp(s)); +} + +/** + * convert a hexadecimal encoded string to raw string including non printable characters.
+ * @param {String} s hexadecimal encoded string + * @return {String} raw string + * @since 1.1.2 + * @example + * hextorstr("610061") → "a\x00a" + */ +function hextorstr(sHex) { + var s = ""; + for (var i = 0; i < sHex.length - 1; i += 2) { + s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); + } + return s; +} + +/** + * convert a raw string including non printable characters to hexadecimal encoded string.
+ * @param {String} s raw string + * @return {String} hexadecimal encoded string + * @since 1.1.2 + * @example + * rstrtohex("a\x00a") → "610061" + */ +function rstrtohex(s) { + var result = ""; + for (var i = 0; i < s.length; i++) { + result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); + } + return result; +} + +// ==== URIComponent / hex ================================ +/** + * convert a URLComponent string such like "%67%68" to a hexadecimal string.
+ * @param {String} s URIComponent string such like "%67%68" + * @return {String} hexadecimal string + * @since 1.1 + */ +function uricmptohex(s) { + return s.replace(/%/g, ""); +} + +/** + * convert a hexadecimal string to a URLComponent string such like "%67%68".
+ * @param {String} s hexadecimal string + * @return {String} URIComponent string such like "%67%68" + * @since 1.1 + */ +function hextouricmp(s) { + return s.replace(/(..)/g, "%$1"); +} + +// ==== URIComponent ================================ +/** + * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".
+ * Note that these "0-9A-Za-z!'()*-._~" characters will not + * converted to "%xx" format by builtin 'encodeURIComponent()' function. + * However this 'encodeURIComponentAll()' function will convert + * all of characters into "%xx" format. + * @param {String} s hexadecimal string + * @return {String} URIComponent string such like "%67%68" + * @since 1.1 + */ +function encodeURIComponentAll(u8) { + var s = encodeURIComponent(u8); + var s2 = ""; + for (var i = 0; i < s.length; i++) { + if (s[i] == "%") { + s2 = s2 + s.substr(i, 3); + i = i + 2; + } else { + s2 = s2 + "%" + stohex(s[i]); + } + } + return s2; +} + +// ==== new lines ================================ +/** + * convert all DOS new line("\r\n") to UNIX new line("\n") in + * a String "s". + * @param {String} s string + * @return {String} converted string + */ +function newline_toUnix(s) { + s = s.replace(/\r\n/mg, "\n"); + return s; +} + +/** + * convert all UNIX new line("\r\n") to DOS new line("\n") in + * a String "s". + * @param {String} s string + * @return {String} converted string + */ +function newline_toDos(s) { + s = s.replace(/\r\n/mg, "\n"); + s = s.replace(/\n/mg, "\r\n"); + return s; +} + + +/*! crypto-1.1.5.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license + */ +/* + * crypto.js - Cryptographic Algorithm Provider class + * + * Copyright (c) 2013 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsrsasign/license + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name crypto-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version 1.1.5 (2013-Oct-06) + * @since jsrsasign 2.2 + * @license MIT License + */ + +/** + * kjur's class library name space + * @name KJUR + * @namespace kjur's class library name space + */ +if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; +/** + * kjur's cryptographic algorithm provider library name space + *

+ * This namespace privides following crytpgrahic classes. + *

    + *
  • {@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class
  • + *
  • {@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class
  • + *
  • {@link KJUR.crypto.Util} - cryptographic utility functions and properties
  • + *
+ * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. + *

+ * @name KJUR.crypto + * @namespace + */ +if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; + +/** + * static object for cryptographic function utilities + * @name KJUR.crypto.Util + * @class static object for cryptographic function utilities + * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms + * @property {Array} DEFAULTPROVIDER associative array of default provider name for each hash and signature algorithms + * @description + */ +KJUR.crypto.Util = new function() { + this.DIGESTINFOHEAD = { + 'sha1': "3021300906052b0e03021a05000414", + 'sha224': "302d300d06096086480165030402040500041c", + 'sha256': "3031300d060960864801650304020105000420", + 'sha384': "3041300d060960864801650304020205000430", + 'sha512': "3051300d060960864801650304020305000440", + 'md2': "3020300c06082a864886f70d020205000410", + 'md5': "3020300c06082a864886f70d020505000410", + 'ripemd160': "3021300906052b2403020105000414", + }; + + /* + * @since crypto 1.1.1 + */ + this.DEFAULTPROVIDER = { + 'md5': 'cryptojs', + 'sha1': 'cryptojs', + 'sha224': 'cryptojs', + 'sha256': 'cryptojs', + 'sha384': 'cryptojs', + 'sha512': 'cryptojs', + 'ripemd160': 'cryptojs', + 'hmacmd5': 'cryptojs', + 'hmacsha1': 'cryptojs', + 'hmacsha224': 'cryptojs', + 'hmacsha256': 'cryptojs', + 'hmacsha384': 'cryptojs', + 'hmacsha512': 'cryptojs', + 'hmacripemd160': 'cryptojs', + + 'MD5withRSA': 'cryptojs/jsrsa', + 'SHA1withRSA': 'cryptojs/jsrsa', + 'SHA224withRSA': 'cryptojs/jsrsa', + 'SHA256withRSA': 'cryptojs/jsrsa', + 'SHA384withRSA': 'cryptojs/jsrsa', + 'SHA512withRSA': 'cryptojs/jsrsa', + 'RIPEMD160withRSA': 'cryptojs/jsrsa', + + 'MD5withECDSA': 'cryptojs/jsrsa', + 'SHA1withECDSA': 'cryptojs/jsrsa', + 'SHA224withECDSA': 'cryptojs/jsrsa', + 'SHA256withECDSA': 'cryptojs/jsrsa', + 'SHA384withECDSA': 'cryptojs/jsrsa', + 'SHA512withECDSA': 'cryptojs/jsrsa', + 'RIPEMD160withECDSA': 'cryptojs/jsrsa', + + 'SHA1withDSA': 'cryptojs/jsrsa', + 'SHA224withDSA': 'cryptojs/jsrsa', + 'SHA256withDSA': 'cryptojs/jsrsa', + + 'MD5withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA1withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA224withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA256withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA384withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA512withRSAandMGF1': 'cryptojs/jsrsa', + 'RIPEMD160withRSAandMGF1': 'cryptojs/jsrsa', + }; + + /* + * @since crypto 1.1.2 + */ + this.CRYPTOJSMESSAGEDIGESTNAME = { + 'md5': 'CryptoJS.algo.MD5', + 'sha1': 'CryptoJS.algo.SHA1', + 'sha224': 'CryptoJS.algo.SHA224', + 'sha256': 'CryptoJS.algo.SHA256', + 'sha384': 'CryptoJS.algo.SHA384', + 'sha512': 'CryptoJS.algo.SHA512', + 'ripemd160': 'CryptoJS.algo.RIPEMD160' + }; + + /** + * get hexadecimal DigestInfo + * @name getDigestInfoHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} hHash hexadecimal hash value + * @param {String} alg hash algorithm name (ex. 'sha1') + * @return {String} hexadecimal string DigestInfo ASN.1 structure + */ + this.getDigestInfoHex = function(hHash, alg) { + if (typeof this.DIGESTINFOHEAD[alg] == "undefined") + throw "alg not supported in Util.DIGESTINFOHEAD: " + alg; + return this.DIGESTINFOHEAD[alg] + hHash; + }; + + /** + * get PKCS#1 padded hexadecimal DigestInfo + * @name getPaddedDigestInfoHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} hHash hexadecimal hash value of message to be signed + * @param {String} alg hash algorithm name (ex. 'sha1') + * @param {Integer} keySize key bit length (ex. 1024) + * @return {String} hexadecimal string of PKCS#1 padded DigestInfo + */ + this.getPaddedDigestInfoHex = function(hHash, alg, keySize) { + var hDigestInfo = this.getDigestInfoHex(hHash, alg); + var pmStrLen = keySize / 4; // minimum PM length + + if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22 + throw "key is too short for SigAlg: keylen=" + keySize + "," + alg; + + var hHead = "0001"; + var hTail = "00" + hDigestInfo; + var hMid = ""; + var fLen = pmStrLen - hHead.length - hTail.length; + for (var i = 0; i < fLen; i += 2) { + hMid += "ff"; + } + var hPaddedMessage = hHead + hMid + hTail; + return hPaddedMessage; + }; + + /** + * get hexadecimal hash of string with specified algorithm + * @name hashString + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @param {String} alg hash algorithm name + * @return {String} hexadecimal string of hash value + * @since 1.1.1 + */ + this.hashString = function(s, alg) { + var md = new KJUR.crypto.MessageDigest({'alg': alg}); + return md.digestString(s); + }; + + /** + * get hexadecimal hash of hexadecimal string with specified algorithm + * @name hashHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} sHex input hexadecimal string to be hashed + * @param {String} alg hash algorithm name + * @return {String} hexadecimal string of hash value + * @since 1.1.1 + */ + this.hashHex = function(sHex, alg) { + var md = new KJUR.crypto.MessageDigest({'alg': alg}); + return md.digestHex(sHex); + }; + + /** + * get hexadecimal SHA1 hash of string + * @name sha1 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha1 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha1', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + /** + * get hexadecimal SHA256 hash of string + * @name sha256 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha256 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + this.sha256Hex = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); + return md.digestHex(s); + }; + + /** + * get hexadecimal SHA512 hash of string + * @name sha512 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha512 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + this.sha512Hex = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); + return md.digestHex(s); + }; + + /** + * get hexadecimal MD5 hash of string + * @name md5 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.md5 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'md5', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + /** + * get hexadecimal RIPEMD160 hash of string + * @name ripemd160 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.ripemd160 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'ripemd160', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + /* + * @since 1.1.2 + */ + this.getCryptoJSMDByName = function(s) { + + }; +}; + +/** + * MessageDigest class which is very similar to java.security.MessageDigest class + * @name KJUR.crypto.MessageDigest + * @class MessageDigest class which is very similar to java.security.MessageDigest class + * @param {Array} params parameters for constructor + * @description + *
+ * Currently this supports following algorithm and providers combination: + *
    + *
  • md5 - cryptojs
  • + *
  • sha1 - cryptojs
  • + *
  • sha224 - cryptojs
  • + *
  • sha256 - cryptojs
  • + *
  • sha384 - cryptojs
  • + *
  • sha512 - cryptojs
  • + *
  • ripemd160 - cryptojs
  • + *
  • sha256 - sjcl (NEW from crypto.js 1.0.4)
  • + *
+ * @example + * // CryptoJS provider sample + * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/core.js"></script> + * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/sha1.js"></script> + * <script src="crypto-1.0.js"></script> + * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"}); + * md.updateString('aaa') + * var mdHex = md.digest() + * + * // SJCL(Stanford JavaScript Crypto Library) provider sample + * <script src="http://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script> + * <script src="crypto-1.0.js"></script> + * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only + * md.updateString('aaa') + * var mdHex = md.digest() + */ +KJUR.crypto.MessageDigest = function(params) { + var md = null; + var algName = null; + var provName = null; + + /** + * set hash algorithm and provider + * @name setAlgAndProvider + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} alg hash algorithm name + * @param {String} prov provider name + * @description + * @example + * // for SHA1 + * md.setAlgAndProvider('sha1', 'cryptojs'); + * // for RIPEMD160 + * md.setAlgAndProvider('ripemd160', 'cryptojs'); + */ + this.setAlgAndProvider = function(alg, prov) { + if (alg != null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; + + // for cryptojs + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 && + prov == 'cryptojs') { + try { + this.md = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg]).create(); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; + } + this.updateString = function(str) { + this.md.update(str); + }; + this.updateHex = function(hex) { + var wHex = CryptoJS.enc.Hex.parse(hex); + this.md.update(wHex); + }; + this.digest = function() { + var hash = this.md.finalize(); + return hash.toString(CryptoJS.enc.Hex); + }; + this.digestString = function(str) { + this.updateString(str); + return this.digest(); + }; + this.digestHex = function(hex) { + this.updateHex(hex); + return this.digest(); + }; + } + if (':sha256:'.indexOf(alg) != -1 && + prov == 'sjcl') { + try { + this.md = new sjcl.hash.sha256(); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; + } + this.updateString = function(str) { + this.md.update(str); + }; + this.updateHex = function(hex) { + var baHex = sjcl.codec.hex.toBits(hex); + this.md.update(baHex); + }; + this.digest = function() { + var hash = this.md.finalize(); + return sjcl.codec.hex.fromBits(hash); + }; + this.digestString = function(str) { + this.updateString(str); + return this.digest(); + }; + this.digestHex = function(hex) { + this.updateHex(hex); + return this.digest(); + }; + } + }; + + /** + * update digest by specified string + * @name updateString + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} str string to update + * @description + * @example + * md.updateString('New York'); + */ + this.updateString = function(str) { + throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * update digest by specified hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} hex hexadecimal string to update + * @description + * @example + * md.updateHex('0afe36'); + */ + this.updateHex = function(hex) { + throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * completes hash calculation and returns hash result + * @name digest + * @memberOf KJUR.crypto.MessageDigest + * @function + * @description + * @example + * md.digest() + */ + this.digest = function() { + throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * performs final update on the digest using string, then completes the digest computation + * @name digestString + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} str string to final update + * @description + * @example + * md.digestString('aaa') + */ + this.digestString = function(str) { + throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * performs final update on the digest using hexadecimal string, then completes the digest computation + * @name digestHex + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} hex hexadecimal string to final update + * @description + * @example + * md.digestHex('0f2abd') + */ + this.digestHex = function(hex) { + throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + if (params !== undefined) { + if (params['alg'] !== undefined) { + this.algName = params['alg']; + if (params['prov'] === undefined) + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + this.setAlgAndProvider(this.algName, this.provName); + } + } +}; + +/** + * Mac(Message Authentication Code) class which is very similar to java.security.Mac class + * @name KJUR.crypto.Mac + * @class Mac class which is very similar to java.security.Mac class + * @param {Array} params parameters for constructor + * @description + *
+ * Currently this supports following algorithm and providers combination: + *
    + *
  • hmacmd5 - cryptojs
  • + *
  • hmacsha1 - cryptojs
  • + *
  • hmacsha224 - cryptojs
  • + *
  • hmacsha256 - cryptojs
  • + *
  • hmacsha384 - cryptojs
  • + *
  • hmacsha512 - cryptojs
  • + *
+ * NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4. + * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS + * to avoid those issue. + * @example + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", prov: "cryptojs", "pass": "pass"}); + * mac.updateString('aaa') + * var macHex = md.doFinal() + */ +KJUR.crypto.Mac = function(params) { + var mac = null; + var pass = null; + var algName = null; + var provName = null; + var algProv = null; + + this.setAlgAndProvider = function(alg, prov) { + if (alg == null) alg = "hmacsha1"; + + alg = alg.toLowerCase(); + if (alg.substr(0, 4) != "hmac") { + throw "setAlgAndProvider unsupported HMAC alg: " + alg; + } + + if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; + this.algProv = alg + "/" + prov; + + var hashAlg = alg.substr(4); + + // for cryptojs + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 && + prov == 'cryptojs') { + try { + var mdObj = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]); + this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex; + } + this.updateString = function(str) { + this.mac.update(str); + }; + this.updateHex = function(hex) { + var wHex = CryptoJS.enc.Hex.parse(hex); + this.mac.update(wHex); + }; + this.doFinal = function() { + var hash = this.mac.finalize(); + return hash.toString(CryptoJS.enc.Hex); + }; + this.doFinalString = function(str) { + this.updateString(str); + return this.doFinal(); + }; + this.doFinalHex = function(hex) { + this.updateHex(hex); + return this.doFinal(); + }; + } + }; + + /** + * update digest by specified string + * @name updateString + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} str string to update + * @description + * @example + * md.updateString('New York'); + */ + this.updateString = function(str) { + throw "updateString(str) not supported for this alg/prov: " + this.algProv; + }; + + /** + * update digest by specified hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} hex hexadecimal string to update + * @description + * @example + * md.updateHex('0afe36'); + */ + this.updateHex = function(hex) { + throw "updateHex(hex) not supported for this alg/prov: " + this.algProv; + }; + + /** + * completes hash calculation and returns hash result + * @name doFinal + * @memberOf KJUR.crypto.Mac + * @function + * @description + * @example + * md.digest() + */ + this.doFinal = function() { + throw "digest() not supported for this alg/prov: " + this.algProv; + }; + + /** + * performs final update on the digest using string, then completes the digest computation + * @name doFinalString + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} str string to final update + * @description + * @example + * md.digestString('aaa') + */ + this.doFinalString = function(str) { + throw "digestString(str) not supported for this alg/prov: " + this.algProv; + }; + + /** + * performs final update on the digest using hexadecimal string, + * then completes the digest computation + * @name doFinalHex + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} hex hexadecimal string to final update + * @description + * @example + * md.digestHex('0f2abd') + */ + this.doFinalHex = function(hex) { + throw "digestHex(hex) not supported for this alg/prov: " + this.algProv; + }; + + if (params !== undefined) { + if (params['pass'] !== undefined) { + this.pass = params['pass']; + } + if (params['alg'] !== undefined) { + this.algName = params['alg']; + if (params['prov'] === undefined) + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + this.setAlgAndProvider(this.algName, this.provName); + } + } +}; + +/** + * Signature class which is very similar to java.security.Signature class + * @name KJUR.crypto.Signature + * @class Signature class which is very similar to java.security.Signature class + * @param {Array} params parameters for constructor + * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null + * @description + *
+ * As for params of constructor's argument, it can be specify following attributes: + *
    + *
  • alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})
  • + *
  • provider - currently 'cryptojs/jsrsa' only
  • + *
+ *

SUPPORTED ALGORITHMS AND PROVIDERS

+ * This Signature class supports following signature algorithm and provider names: + *
    + *
  • MD5withRSA - cryptojs/jsrsa
  • + *
  • SHA1withRSA - cryptojs/jsrsa
  • + *
  • SHA224withRSA - cryptojs/jsrsa
  • + *
  • SHA256withRSA - cryptojs/jsrsa
  • + *
  • SHA384withRSA - cryptojs/jsrsa
  • + *
  • SHA512withRSA - cryptojs/jsrsa
  • + *
  • RIPEMD160withRSA - cryptojs/jsrsa
  • + *
  • MD5withECDSA - cryptojs/jsrsa
  • + *
  • SHA1withECDSA - cryptojs/jsrsa
  • + *
  • SHA224withECDSA - cryptojs/jsrsa
  • + *
  • SHA256withECDSA - cryptojs/jsrsa
  • + *
  • SHA384withECDSA - cryptojs/jsrsa
  • + *
  • SHA512withECDSA - cryptojs/jsrsa
  • + *
  • RIPEMD160withECDSA - cryptojs/jsrsa
  • + *
  • MD5withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA1withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA224withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA256withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA384withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA512withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • RIPEMD160withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA1withDSA - cryptojs/jsrsa
  • + *
  • SHA224withDSA - cryptojs/jsrsa
  • + *
  • SHA256withDSA - cryptojs/jsrsa
  • + *
+ * Here are supported elliptic cryptographic curve names and their aliases for ECDSA: + *
    + *
  • secp256k1
  • + *
  • secp256r1, NIST P-256, P-256, prime256v1
  • + *
  • secp384r1, NIST P-384, P-384
  • + *
+ * NOTE1: DSA signing algorithm is also supported since crypto 1.1.5. + *

EXAMPLES

+ * @example + * // RSA signature generation + * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"}); + * sig.init(prvKeyPEM); + * sig.updateString('aaa'); + * var hSigVal = sig.sign(); + * + * // DSA signature validation + * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"}); + * sig2.init(certPEM); + * sig.updateString('aaa'); + * var isValid = sig2.verify(hSigVal); + * + * // ECDSA signing + * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); + * sig.init(prvKeyPEM); + * sig.updateString('aaa'); + * var sigValueHex = sig.sign(); + * + * // ECDSA verifying + * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); + * sig.init(certPEM); + * sig.updateString('aaa'); + * var isValid = sig.verify(sigValueHex); + */ +KJUR.crypto.Signature = function(params) { + var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing + var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying + + var md = null; // KJUR.crypto.MessageDigest object + var sig = null; + var algName = null; + var provName = null; + var algProvName = null; + var mdAlgName = null; + var pubkeyAlgName = null; // rsa,ecdsa,rsaandmgf1(=rsapss) + var state = null; + var pssSaltLen = -1; + var initParams = null; + + var sHashHex = null; // hex hash value for hex + var hDigestInfo = null; + var hPaddedDigestInfo = null; + var hSign = null; + + this._setAlgNames = function() { + if (this.algName.match(/^(.+)with(.+)$/)) { + this.mdAlgName = RegExp.$1.toLowerCase(); + this.pubkeyAlgName = RegExp.$2.toLowerCase(); + } + }; + + this._zeroPaddingOfSignature = function(hex, bitLength) { + var s = ""; + var nZero = bitLength / 4 - hex.length; + for (var i = 0; i < nZero; i++) { + s = s + "0"; + } + return s + hex; + }; + + /** + * set signature algorithm and provider + * @name setAlgAndProvider + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} alg signature algorithm name + * @param {String} prov provider name + * @description + * @example + * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa'); + */ + this.setAlgAndProvider = function(alg, prov) { + this._setAlgNames(); + if (prov != 'cryptojs/jsrsa') + throw "provider not supported: " + prov; + + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) { + try { + this.md = new KJUR.crypto.MessageDigest({'alg':this.mdAlgName}); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + + this.mdAlgName + "/" + ex; + } + + this.init = function(keyparam, pass) { + var keyObj = null; + try { + if (pass === undefined) { + keyObj = KEYUTIL.getKey(keyparam); + } else { + keyObj = KEYUTIL.getKey(keyparam, pass); + } + } catch (ex) { + throw "init failed:" + ex; + } + + if (keyObj.isPrivate === true) { + this.prvKey = keyObj; + this.state = "SIGN"; + } else if (keyObj.isPublic === true) { + this.pubKey = keyObj; + this.state = "VERIFY"; + } else { + throw "init failed.:" + keyObj; + } + }; + + this.initSign = function(params) { + if (typeof params['ecprvhex'] == 'string' && + typeof params['eccurvename'] == 'string') { + this.ecprvhex = params['ecprvhex']; + this.eccurvename = params['eccurvename']; + } else { + this.prvKey = params; + } + this.state = "SIGN"; + }; + + this.initVerifyByPublicKey = function(params) { + if (typeof params['ecpubhex'] == 'string' && + typeof params['eccurvename'] == 'string') { + this.ecpubhex = params['ecpubhex']; + this.eccurvename = params['eccurvename']; + } else if (params instanceof KJUR.crypto.ECDSA) { + this.pubKey = params; + } else if (params instanceof RSAKey) { + this.pubKey = params; + } + this.state = "VERIFY"; + }; + + this.initVerifyByCertificatePEM = function(certPEM) { + var x509 = new X509(); + x509.readCertPEM(certPEM); + this.pubKey = x509.subjectPublicKeyRSA; + this.state = "VERIFY"; + }; + + this.updateString = function(str) { + this.md.updateString(str); + }; + this.updateHex = function(hex) { + this.md.updateHex(hex); + }; + + this.sign = function() { + this.sHashHex = this.md.digest(); + if (typeof this.ecprvhex != "undefined" && + typeof this.eccurvename != "undefined") { + var ec = new KJUR.crypto.ECDSA({'curve': this.eccurvename}); + this.hSign = ec.signHex(this.sHashHex, this.ecprvhex); + } else if (this.pubkeyAlgName == "rsaandmgf1") { + this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex, + this.mdAlgName, + this.pssSaltLen); + } else if (this.pubkeyAlgName == "rsa") { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex, + this.mdAlgName); + } else if (this.prvKey instanceof KJUR.crypto.ECDSA) { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); + } else if (this.prvKey instanceof KJUR.crypto.DSA) { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); + } else { + throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; + } + return this.hSign; + }; + this.signString = function(str) { + this.updateString(str); + this.sign(); + }; + this.signHex = function(hex) { + this.updateHex(hex); + this.sign(); + }; + this.verify = function(hSigVal) { + this.sHashHex = this.md.digest(); + if (typeof this.ecpubhex != "undefined" && + typeof this.eccurvename != "undefined") { + var ec = new KJUR.crypto.ECDSA({curve: this.eccurvename}); + return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex); + } else if (this.pubkeyAlgName == "rsaandmgf1") { + return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal, + this.mdAlgName, + this.pssSaltLen); + } else if (this.pubkeyAlgName == "rsa") { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else if (this.pubKey instanceof KJUR.crypto.ECDSA) { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else if (this.pubKey instanceof KJUR.crypto.DSA) { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else { + throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; + } + }; + } + }; + + /** + * Initialize this object for signing or verifying depends on key + * @name init + * @memberOf KJUR.crypto.Signature + * @function + * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object + * @param {String} pass (OPTION) passcode for encrypted private key + * @since crypto 1.1.3 + * @description + * This method is very useful initialize method for Signature class since + * you just specify key then this method will automatically initialize it + * using {@link KEYUTIL.getKey} method. + * As for 'key', following argument type are supported: + *
signing
+ *
    + *
  • PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"
  • + *
  • PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"
  • + *
  • PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"
  • + *
  • PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"
  • + *
  • RSAKey object of private key
  • + *
  • KJUR.crypto.ECDSA object of private key
  • + *
  • KJUR.crypto.DSA object of private key
  • + *
+ *
verification
+ *
    + *
  • PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"
  • + *
  • PEM formatted X.509 certificate with RSA/EC/DSA public key concluding + * "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".
  • + *
  • RSAKey object of public key
  • + *
  • KJUR.crypto.ECDSA object of public key
  • + *
  • KJUR.crypto.DSA object of public key
  • + *
+ * @example + * sig.init(sCertPEM) + */ + this.init = function(key, pass) { + throw "init(key, pass) not supported for this alg:prov=" + + this.algProvName; + }; + + /** + * Initialize this object for verifying with a public key + * @name initVerifyByPublicKey + * @memberOf KJUR.crypto.Signature + * @function + * @param {Object} param RSAKey object of public key or associative array for ECDSA + * @since 1.0.2 + * @deprecated from crypto 1.1.5. please use init() method instead. + * @description + * Public key information will be provided as 'param' parameter and the value will be + * following: + *
    + *
  • {@link RSAKey} object for RSA verification
  • + *
  • associative array for ECDSA verification + * (ex. {'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}) + *
  • + *
+ * @example + * sig.initVerifyByPublicKey(rsaPrvKey) + */ + this.initVerifyByPublicKey = function(rsaPubKey) { + throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" + + this.algProvName; + }; + + /** + * Initialize this object for verifying with a certficate + * @name initVerifyByCertificatePEM + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} certPEM PEM formatted string of certificate + * @since 1.0.2 + * @deprecated from crypto 1.1.5. please use init() method instead. + * @description + * @example + * sig.initVerifyByCertificatePEM(certPEM) + */ + this.initVerifyByCertificatePEM = function(certPEM) { + throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" + + this.algProvName; + }; + + /** + * Initialize this object for signing + * @name initSign + * @memberOf KJUR.crypto.Signature + * @function + * @param {Object} param RSAKey object of public key or associative array for ECDSA + * @deprecated from crypto 1.1.5. please use init() method instead. + * @description + * Private key information will be provided as 'param' parameter and the value will be + * following: + *
    + *
  • {@link RSAKey} object for RSA signing
  • + *
  • associative array for ECDSA signing + * (ex. {'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'})
  • + *
+ * @example + * sig.initSign(prvKey) + */ + this.initSign = function(prvKey) { + throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Updates the data to be signed or verified by a string + * @name updateString + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} str string to use for the update + * @description + * @example + * sig.updateString('aaa') + */ + this.updateString = function(str) { + throw "updateString(str) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Updates the data to be signed or verified by a hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} hex hexadecimal string to use for the update + * @description + * @example + * sig.updateHex('1f2f3f') + */ + this.updateHex = function(hex) { + throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Returns the signature bytes of all data updates as a hexadecimal string + * @name sign + * @memberOf KJUR.crypto.Signature + * @function + * @return the signature bytes as a hexadecimal string + * @description + * @example + * var hSigValue = sig.sign() + */ + this.sign = function() { + throw "sign() not supported for this alg:prov=" + this.algProvName; + }; + + /** + * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string + * @name signString + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} str string to final update + * @return the signature bytes of a hexadecimal string + * @description + * @example + * var hSigValue = sig.signString('aaa') + */ + this.signString = function(str) { + throw "digestString(str) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string + * @name signHex + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} hex hexadecimal string to final update + * @return the signature bytes of a hexadecimal string + * @description + * @example + * var hSigValue = sig.signHex('1fdc33') + */ + this.signHex = function(hex) { + throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * verifies the passed-in signature. + * @name verify + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} str string to final update + * @return {Boolean} true if the signature was verified, otherwise false + * @description + * @example + * var isValid = sig.verify('1fbcefdca4823a7(snip)') + */ + this.verify = function(hSigVal) { + throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName; + }; + + this.initParams = params; + + if (params !== undefined) { + if (params['alg'] !== undefined) { + this.algName = params['alg']; + if (params['prov'] === undefined) { + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + } else { + this.provName = params['prov']; + } + this.algProvName = this.algName + ":" + this.provName; + this.setAlgAndProvider(this.algName, this.provName); + this._setAlgNames(); + } + + if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen']; + + if (params['prvkeypem'] !== undefined) { + if (params['prvkeypas'] !== undefined) { + throw "both prvkeypem and prvkeypas parameters not supported"; + } else { + try { + var prvKey = new RSAKey(); + prvKey.readPrivateKeyFromPEMString(params['prvkeypem']); + this.initSign(prvKey); + } catch (ex) { + throw "fatal error to load pem private key: " + ex; + } + } + } + } +}; + +/** + * static object for cryptographic function utilities + * @name KJUR.crypto.OID + * @class static object for cryptography related OIDs + * @property {Array} oidhex2name key value of hexadecimal OID and its name + * (ex. '2a8648ce3d030107' and 'secp256r1') + * @since crypto 1.1.3 + * @description + */ + + +KJUR.crypto.OID = new function() { + this.oidhex2name = { + '2a864886f70d010101': 'rsaEncryption', + '2a8648ce3d0201': 'ecPublicKey', + '2a8648ce380401': 'dsa', + '2a8648ce3d030107': 'secp256r1', + '2b8104001f': 'secp192k1', + '2b81040021': 'secp224r1', + '2b8104000a': 'secp256k1', + '2b81040023': 'secp521r1', + '2b81040022': 'secp384r1', + '2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3 + '608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1 + '608648016503040302': 'SHA256withDSA', // 2.16.840.1.101.3.4.3.2 + }; +}; + +/*! rsasign-1.2.7.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license + */ +/* + * rsa-sign.js - adding signing functions to RSAKey class. + * + * version: 1.2.7 (2013 Aug 25) + * + * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsrsasign/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name rsasign-1.2.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version rsasign 1.2.7 + * @license MIT License + */ + +var _RE_HEXDECONLY = new RegExp(""); +_RE_HEXDECONLY.compile("[^0-9a-f]", "gi"); + +// ======================================================================== +// Signature Generation +// ======================================================================== + +function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) { + var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); }; + var sHashHex = hashFunc(s); + + return KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, keySize); +} + +function _zeroPaddingOfSignature(hex, bitLength) { + var s = ""; + var nZero = bitLength / 4 - hex.length; + for (var i = 0; i < nZero; i++) { + s = s + "0"; + } + return s + hex; +} + +/** + * sign for a message string with RSA private key.
+ * @name signString + * @memberOf RSAKey + * @function + * @param {String} s message string to be signed. + * @param {String} hashAlg hash algorithm name for signing.
+ * @return returns hexadecimal string of signature value. + */ +function _rsasign_signString(s, hashAlg) { + var hashFunc = function(s) { return KJUR.crypto.Util.hashString(s, hashAlg); }; + var sHashHex = hashFunc(s); + + return this.signWithMessageHash(sHashHex, hashAlg); +} + +/** + * sign hash value of message to be signed with RSA private key.
+ * @name signWithMessageHash + * @memberOf RSAKey + * @function + * @param {String} sHashHex hexadecimal string of hash value of message to be signed. + * @param {String} hashAlg hash algorithm name for signing.
+ * @return returns hexadecimal string of signature value. + * @since rsasign 1.2.6 + */ +function _rsasign_signWithMessageHash(sHashHex, hashAlg) { + var hPM = KJUR.crypto.Util.getPaddedDigestInfoHex(sHashHex, hashAlg, this.n.bitLength()); + var biPaddedMessage = parseBigInt(hPM, 16); + var biSign = this.doPrivate(biPaddedMessage); + var hexSign = biSign.toString(16); + return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); +} + +function _rsasign_signStringWithSHA1(s) { + return _rsasign_signString.call(this, s, 'sha1'); +} + +function _rsasign_signStringWithSHA256(s) { + return _rsasign_signString.call(this, s, 'sha256'); +} + +// PKCS#1 (PSS) mask generation function +function pss_mgf1_str(seed, len, hash) { + var mask = '', i = 0; + + while (mask.length < len) { + mask += hextorstr(hash(rstrtohex(seed + String.fromCharCode.apply(String, [ + (i & 0xff000000) >> 24, + (i & 0x00ff0000) >> 16, + (i & 0x0000ff00) >> 8, + i & 0x000000ff])))); + i += 1; + } + + return mask; +} + +/** + * sign for a message string with RSA private key by PKCS#1 PSS signing.
+ * @name signStringPSS + * @memberOf RSAKey + * @function + * @param {String} s message string to be signed. + * @param {String} hashAlg hash algorithm name for signing. + * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). + * There are two special values: + *
    + *
  • -1: sets the salt length to the digest length
  • + *
  • -2: sets the salt length to maximum permissible value + * (i.e. keybytelen - hashbytelen - 2)
  • + *
+ * DEFAULT is -1. (NOTE: OpenSSL's default is -2.) + * @return returns hexadecimal string of signature value. + */ +function _rsasign_signStringPSS(s, hashAlg, sLen) { + var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); } + var hHash = hashFunc(rstrtohex(s)); + + if (sLen === undefined) sLen = -1; + return this.signWithMessageHashPSS(hHash, hashAlg, sLen); +} + +/** + * sign hash value of message with RSA private key by PKCS#1 PSS signing.
+ * @name signWithMessageHashPSS + * @memberOf RSAKey + * @function + * @param {String} hHash hexadecimal hash value of message to be signed. + * @param {String} hashAlg hash algorithm name for signing. + * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). + * There are two special values: + *
    + *
  • -1: sets the salt length to the digest length
  • + *
  • -2: sets the salt length to maximum permissible value + * (i.e. keybytelen - hashbytelen - 2)
  • + *
+ * DEFAULT is -1. (NOTE: OpenSSL's default is -2.) + * @return returns hexadecimal string of signature value. + * @since rsasign 1.2.6 + */ +function _rsasign_signWithMessageHashPSS(hHash, hashAlg, sLen) { + var mHash = hextorstr(hHash); + var hLen = mHash.length; + var emBits = this.n.bitLength() - 1; + var emLen = Math.ceil(emBits / 8); + var i; + var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); } + + if (sLen === -1 || sLen === undefined) { + sLen = hLen; // same as hash length + } else if (sLen === -2) { + sLen = emLen - hLen - 2; // maximum + } else if (sLen < -2) { + throw "invalid salt length"; + } + + if (emLen < (hLen + sLen + 2)) { + throw "data too long"; + } + + var salt = ''; + + if (sLen > 0) { + salt = new Array(sLen); + new SecureRandom().nextBytes(salt); + salt = String.fromCharCode.apply(String, salt); + } + + var H = hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + salt))); + var PS = []; + + for (i = 0; i < emLen - sLen - hLen - 2; i += 1) { + PS[i] = 0x00; + } + + var DB = String.fromCharCode.apply(String, PS) + '\x01' + salt; + var dbMask = pss_mgf1_str(H, DB.length, hashFunc); + var maskedDB = []; + + for (i = 0; i < DB.length; i += 1) { + maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); + } + + var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff; + maskedDB[0] &= ~mask; + + for (i = 0; i < hLen; i++) { + maskedDB.push(H.charCodeAt(i)); + } + + maskedDB.push(0xbc); + + return _zeroPaddingOfSignature(this.doPrivate(new BigInteger(maskedDB)).toString(16), + this.n.bitLength()); +} + +// ======================================================================== +// Signature Verification +// ======================================================================== + +function _rsasign_getDecryptSignatureBI(biSig, hN, hE) { + var rsa = new RSAKey(); + rsa.setPublic(hN, hE); + var biDecryptedSig = rsa.doPublic(biSig); + return biDecryptedSig; +} + +function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) { + var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE); + var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); + return hDigestInfo; +} + +function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) { + for (var algName in KJUR.crypto.Util.DIGESTINFOHEAD) { + var head = KJUR.crypto.Util.DIGESTINFOHEAD[algName]; + var len = head.length; + if (hDigestInfo.substring(0, len) == head) { + var a = [algName, hDigestInfo.substring(len)]; + return a; + } + } + return []; +} + +function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) { + var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE); + var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); + if (digestInfoAry.length == 0) return false; + var algName = digestInfoAry[0]; + var diHashValue = digestInfoAry[1]; + var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); }; + var msgHashValue = ff(sMsg); + return (diHashValue == msgHashValue); +} + +function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) { + var biSig = parseBigInt(hSig, 16); + var result = _rsasign_verifySignatureWithArgs(sMsg, biSig, + this.n.toString(16), + this.e.toString(16)); + return result; +} + +/** + * verifies a sigature for a message string with RSA public key.
+ * @name verifyString + * @memberOf RSAKey# + * @function + * @param {String} sMsg message string to be verified. + * @param {String} hSig hexadecimal string of siganture.
+ * non-hexadecimal charactors including new lines will be ignored. + * @return returns 1 if valid, otherwise 0 + */ +function _rsasign_verifyString(sMsg, hSig) { + hSig = hSig.replace(_RE_HEXDECONLY, ''); + hSig = hSig.replace(/[ \n]+/g, ""); + var biSig = parseBigInt(hSig, 16); + if (biSig.bitLength() > this.n.bitLength()) return 0; + var biDecryptedSig = this.doPublic(biSig); + var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); + var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); + + if (digestInfoAry.length == 0) return false; + var algName = digestInfoAry[0]; + var diHashValue = digestInfoAry[1]; + var ff = function(s) { return KJUR.crypto.Util.hashString(s, algName); }; + var msgHashValue = ff(sMsg); + return (diHashValue == msgHashValue); +} + +/** + * verifies a sigature for a message string with RSA public key.
+ * @name verifyWithMessageHash + * @memberOf RSAKey + * @function + * @param {String} sHashHex hexadecimal hash value of message to be verified. + * @param {String} hSig hexadecimal string of siganture.
+ * non-hexadecimal charactors including new lines will be ignored. + * @return returns 1 if valid, otherwise 0 + * @since rsasign 1.2.6 + */ +function _rsasign_verifyWithMessageHash(sHashHex, hSig) { + hSig = hSig.replace(_RE_HEXDECONLY, ''); + hSig = hSig.replace(/[ \n]+/g, ""); + var biSig = parseBigInt(hSig, 16); + if (biSig.bitLength() > this.n.bitLength()) return 0; + var biDecryptedSig = this.doPublic(biSig); + var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); + var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); + + if (digestInfoAry.length == 0) return false; + var algName = digestInfoAry[0]; + var diHashValue = digestInfoAry[1]; + return (diHashValue == sHashHex); +} + +/** + * verifies a sigature for a message string with RSA public key by PKCS#1 PSS sign.
+ * @name verifyStringPSS + * @memberOf RSAKey + * @function + * @param {String} sMsg message string to be verified. + * @param {String} hSig hexadecimal string of signature value + * @param {String} hashAlg hash algorithm name + * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). + * There are two special values: + *
    + *
  • -1: sets the salt length to the digest length
  • + *
  • -2: sets the salt length to maximum permissible value + * (i.e. keybytelen - hashbytelen - 2)
  • + *
+ * DEFAULT is -1. (NOTE: OpenSSL's default is -2.) + * @return returns true if valid, otherwise false + */ +function _rsasign_verifyStringPSS(sMsg, hSig, hashAlg, sLen) { + var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }; + var hHash = hashFunc(rstrtohex(sMsg)); + + if (sLen === undefined) sLen = -1; + return this.verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen); +} + +/** + * verifies a sigature for a hash value of message string with RSA public key by PKCS#1 PSS sign.
+ * @name verifyWithMessageHashPSS + * @memberOf RSAKey + * @function + * @param {String} hHash hexadecimal hash value of message string to be verified. + * @param {String} hSig hexadecimal string of signature value + * @param {String} hashAlg hash algorithm name + * @param {Integer} sLen salt byte length from 0 to (keybytelen - hashbytelen - 2). + * There are two special values: + *
    + *
  • -1: sets the salt length to the digest length
  • + *
  • -2: sets the salt length to maximum permissible value + * (i.e. keybytelen - hashbytelen - 2)
  • + *
+ * DEFAULT is -1 (NOTE: OpenSSL's default is -2.) + * @return returns true if valid, otherwise false + * @since rsasign 1.2.6 + */ +function _rsasign_verifyWithMessageHashPSS(hHash, hSig, hashAlg, sLen) { + var biSig = new BigInteger(hSig, 16); + + if (biSig.bitLength() > this.n.bitLength()) { + return false; + } + + var hashFunc = function(sHex) { return KJUR.crypto.Util.hashHex(sHex, hashAlg); }; + var mHash = hextorstr(hHash); + var hLen = mHash.length; + var emBits = this.n.bitLength() - 1; + var emLen = Math.ceil(emBits / 8); + var i; + + if (sLen === -1 || sLen === undefined) { + sLen = hLen; // same as hash length + } else if (sLen === -2) { + sLen = emLen - hLen - 2; // recover + } else if (sLen < -2) { + throw "invalid salt length"; + } + + if (emLen < (hLen + sLen + 2)) { + throw "data too long"; + } + + var em = this.doPublic(biSig).toByteArray(); + + for (i = 0; i < em.length; i += 1) { + em[i] &= 0xff; + } + + while (em.length < emLen) { + em.unshift(0); + } + + if (em[emLen -1] !== 0xbc) { + throw "encoded message does not end in 0xbc"; + } + + em = String.fromCharCode.apply(String, em); + + var maskedDB = em.substr(0, emLen - hLen - 1); + var H = em.substr(maskedDB.length, hLen); + + var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff; + + if ((maskedDB.charCodeAt(0) & mask) !== 0) { + throw "bits beyond keysize not zero"; + } + + var dbMask = pss_mgf1_str(H, maskedDB.length, hashFunc); + var DB = []; + + for (i = 0; i < maskedDB.length; i += 1) { + DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i); + } + + DB[0] &= ~mask; + + var checkLen = emLen - hLen - sLen - 2; + + for (i = 0; i < checkLen; i += 1) { + if (DB[i] !== 0x00) { + throw "leftmost octets not zero"; + } + } + + if (DB[checkLen] !== 0x01) { + throw "0x01 marker not found"; + } + + return H === hextorstr(hashFunc(rstrtohex('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + + String.fromCharCode.apply(String, DB.slice(-sLen))))); +} + +RSAKey.prototype.signWithMessageHash = _rsasign_signWithMessageHash; +RSAKey.prototype.signString = _rsasign_signString; +RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1; +RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256; +RSAKey.prototype.sign = _rsasign_signString; +RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1; +RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256; + +RSAKey.prototype.signWithMessageHashPSS = _rsasign_signWithMessageHashPSS; +RSAKey.prototype.signStringPSS = _rsasign_signStringPSS; +RSAKey.prototype.signPSS = _rsasign_signStringPSS; +RSAKey.SALT_LEN_HLEN = -1; +RSAKey.SALT_LEN_MAX = -2; + +RSAKey.prototype.verifyWithMessageHash = _rsasign_verifyWithMessageHash; +RSAKey.prototype.verifyString = _rsasign_verifyString; +RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage; +RSAKey.prototype.verify = _rsasign_verifyString; +RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage; + +RSAKey.prototype.verifyWithMessageHashPSS = _rsasign_verifyWithMessageHashPSS; +RSAKey.prototype.verifyStringPSS = _rsasign_verifyStringPSS; +RSAKey.prototype.verifyPSS = _rsasign_verifyStringPSS; +RSAKey.SALT_LEN_RECOVER = -2; + +/** + * @name RSAKey + * @class key of RSA public key algorithm + * @description Tom Wu's RSA Key class and extension + */ + +// +// rsa-pem.js - adding function for reading/writing PKCS#1 & PKCS#8 PEM private key +// and reading/wriring x509 public key to RSAKey class +// +// version: 1.0 (2010-Jun-03) +// version: 1.1 (2012-Feb-21) +// version: 1.2 (2012-Jun-23) +// +// Copyright (c) 2010 Kenji Urushima (kenji.urushima@gmail.com) +// Copyright (c) 2012 Adrian Pasternak (["adrian", "pasternak", "@", "gmail", ".", "com"].join("")) +// +// This software is licensed under the terms of the MIT License. +// http://www.opensource.org/licenses/mit-license.php +// +// The above copyright and license notice shall be +// included in all copies or substantial portions of the Software. +// + +function _rsapem_extractEncodedData(sPEMPrivateKey) { + var s = sPEMPrivateKey; + s = s.replace(/[ \n]+/g, ""); + return s; +} + +function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) { + var a = new Array(); + var v1 = _asnhex_getStartPosOfV_AtObj(hPrivateKey, 0); + var n1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, v1); + var e1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, n1); + var d1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, e1); + var p1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, d1); + var q1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, p1); + var dp1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, q1); + var dq1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, dp1); + var co1 = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, dq1); + a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1); + return a; +} + +function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) { + var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey); + var v = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[0]); + var n = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[1]); + var e = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[2]); + var d = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[3]); + var p = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[4]); + var q = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[5]); + var dp = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[6]); + var dq = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[7]); + var co = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[8]); + var a = new Array(); + a.push(v, n, e, d, p, q, dp, dq, co); + return a; +} + +function _rsapem_getPosArrayOfChildrenFromPublicKeyHex(hPrivateKey) { + var a = new Array(); + var header = _asnhex_getStartPosOfV_AtObj(hPrivateKey, 0); + var keys = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, header); + a.push(header, keys); + return a; +} + +function _rsapem_getPosArrayOfChildrenFromPrivateKeyHex(hPrivateKey) { + var a = new Array(); + var integer = _asnhex_getStartPosOfV_AtObj(hPrivateKey, 0); + var header = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, integer); + var keys = _asnhex_getPosOfNextSibling_AtObj(hPrivateKey, header); + a.push(integer, header, keys); + return a; +} + +function _rsapem_getHexValueArrayOfChildrenFromPublicKeyHex(hPrivateKey) { + var posArray = _rsapem_getPosArrayOfChildrenFromPublicKeyHex(hPrivateKey); + var headerVal = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[0]); + var keysVal = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[1]); + + var keysSequence = keysVal.substring(2); + posArray = _rsapem_getPosArrayOfChildrenFromPublicKeyHex(keysSequence); + var modulus = _asnhex_getHexOfV_AtObj(keysSequence, posArray[0]); + var publicExp = _asnhex_getHexOfV_AtObj(keysSequence, posArray[1]); + + var a = new Array(); + a.push(modulus, publicExp); + return a; +} + + +function _rsapem_getHexValueArrayOfChildrenFromPrivateKeyHex(hPrivateKey) { + var posArray = _rsapem_getPosArrayOfChildrenFromPrivateKeyHex(hPrivateKey); + var integerVal = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[0]); + var headerVal = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[1]); + var keysVal = _asnhex_getHexOfV_AtObj(hPrivateKey, posArray[2]); + + var keysSequence = keysVal.substring(2); + return _rsapem_getHexValueArrayOfChildrenFromHex(keysSequence); +} + +function _rsapem_readPrivateKeyFromPkcs1PemString(keyPEM) { + var keyB64 = _rsapem_extractEncodedData(keyPEM); + var keyHex = b64tohex(keyB64) // depends base64.js + var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); + this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); +} + +function _rsapem_readPrivateKeyFromPkcs8PemString(keyPEM) { + var keyB64 = _rsapem_extractEncodedData(keyPEM); + var keyHex = b64tohex(keyB64) // depends base64.js + var a = _rsapem_getHexValueArrayOfChildrenFromPrivateKeyHex(keyHex); + this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); +} + +function _rsapem_readPublicKeyFromX509PemString(keyPEM) { + var keyB64 = _rsapem_extractEncodedData(keyPEM); + var keyHex = b64tohex(keyB64) // depends base64.js + var a = _rsapem_getHexValueArrayOfChildrenFromPublicKeyHex(keyHex); + this.setPublic(a[0],a[1]); +} + +/** +* Pad string with leading zeros, to use even number of bytes. +*/ +function _rsapem_padWithZero(numString) { + if (numString.length % 2 == 1) { + return "0" + numString; + } + return numString; +} + +/** +* Encode length in DER format (if length <0x80, then one byte, else first byte is 0x80 + length of length :) + n-bytes of length). +*/ +function _rsapem_encodeLength(length) { + if (length >= parseInt("80", 16)) { + var realLength = _rsapem_padWithZero(length.toString(16)); + var lengthOfLength = (realLength.length / 2); + return (parseInt("80", 16) + lengthOfLength).toString(16) + realLength; + } else { + return _rsapem_padWithZero(length.toString(16)); + } +} + +/** +* Encode number in DER encoding ("02" + length + number). +*/ +function _rsapem_derEncodeNumber(number) { + var numberString = _rsapem_padWithZero(number.toString(16)); + if (numberString[0] > '7') { + numberString = "00" + numberString; + } + var lenString = _rsapem_encodeLength(numberString.length / 2); + return "02" + lenString + numberString; +} + +/** +* Converts private & public part of given key to ASN1 Hex String. +*/ +function _rsapem_privateKeyToPkcs1HexString(rsaKey) { + var result = _rsapem_derEncodeNumber(0); + result += _rsapem_derEncodeNumber(rsaKey.n); + result += _rsapem_derEncodeNumber(rsaKey.e); + result += _rsapem_derEncodeNumber(rsaKey.d); + result += _rsapem_derEncodeNumber(rsaKey.p); + result += _rsapem_derEncodeNumber(rsaKey.q); + result += _rsapem_derEncodeNumber(rsaKey.dmp1); + result += _rsapem_derEncodeNumber(rsaKey.dmq1); + result += _rsapem_derEncodeNumber(rsaKey.coeff); + + var fullLen = _rsapem_encodeLength(result.length / 2); + return '30' + fullLen + result; +} + +/** +* Converts private & public part of given key to PKCS#8 Hex String. +*/ +function _rsapem_privateKeyToPkcs8HexString(rsaKey) { + var zeroInteger = "020100"; + var encodedIdentifier = "06092A864886F70D010101"; + var encodedNull = "0500"; + var headerSequence = "300D" + encodedIdentifier + encodedNull; + var keySequence = _rsapem_privateKeyToPkcs1HexString(rsaKey); + + var keyOctetString = "04" + _rsapem_encodeLength(keySequence.length / 2) + keySequence; + + var mainSequence = zeroInteger + headerSequence + keyOctetString; + return "30" + _rsapem_encodeLength(mainSequence.length / 2) + mainSequence; +} + +/** +* Converts public part of given key to ASN1 Hex String. +*/ +function _rsapem_publicKeyToX509HexString(rsaKey) { + var encodedIdentifier = "06092A864886F70D010101"; + var encodedNull = "0500"; + var headerSequence = "300D" + encodedIdentifier + encodedNull; + + var keys = _rsapem_derEncodeNumber(rsaKey.n); + keys += _rsapem_derEncodeNumber(rsaKey.e); + + var keySequence = "0030" + _rsapem_encodeLength(keys.length / 2) + keys; + var bitstring = "03" + _rsapem_encodeLength(keySequence.length / 2) + keySequence; + + var mainSequence = headerSequence + bitstring; + + return "30" + _rsapem_encodeLength(mainSequence.length / 2) + mainSequence; +} + +/** +* Output private & public part of the key in PKCS#1 PEM format. +*/ +function _rsapem_privateKeyToPkcs1PemString() { + return hex2b64(_rsapem_privateKeyToPkcs1HexString(this)); +} + +/** +* Output private & public part of the key in PKCS#8 PEM format. +*/ +function _rsapem_privateKeyToPkcs8PemString() { + return hex2b64(_rsapem_privateKeyToPkcs8HexString(this)); +} + +/** +* Output public part of the key in x509 PKCS#1 PEM format. +*/ +function _rsapem_publicKeyToX509PemString() { + return hex2b64(_rsapem_publicKeyToX509HexString(this)); +} + +function _rsa_splitKey(key, line) { + var splitKey = ""; + for (var i = 0; i < key.length; i++) { + if (i % line == 0 && i != 0 && i != (key.length - 1)) { + splitKey += "\n"; + } + splitKey += key[i]; + } + + return splitKey; +} + +RSAKey.prototype.readPrivateKeyFromPkcs1PemString = _rsapem_readPrivateKeyFromPkcs1PemString; +RSAKey.prototype.privateKeyToPkcs1PemString = _rsapem_privateKeyToPkcs1PemString; + +RSAKey.prototype.readPrivateKeyFromPkcs8PemString = _rsapem_readPrivateKeyFromPkcs8PemString; +RSAKey.prototype.privateKeyToPkcs8PemString = _rsapem_privateKeyToPkcs8PemString; + +RSAKey.prototype.readPublicKeyFromX509PEMString = _rsapem_readPublicKeyFromX509PemString; +RSAKey.prototype.publicKeyToX509PemString = _rsapem_publicKeyToX509PemString; + + + +/*global RSAKey: false, + ASN1HEX: false, + Uint8Array: false */ +/*jslint browser: true, nomen: true */ + +function SecureRandom() +{ + "use strict"; + return undefined; +} + +SecureRandom.prototype.nextBytes = function (ba) +{ + "use strict"; + + var ua = new Uint8Array(ba.length), i; + + window.crypto.getRandomValues(ua); + + for (i = 0; i < ba.length; i += 1) + { + ba[i] = ua[i]; + } +}; + +var _prvKeyHead = "-----BEGIN RSA PRIVATE KEY-----"; +var _prvKeyFoot = "-----END RSA PRIVATE KEY-----"; +var _pubKeyHead = "-----BEGIN PUBLIC KEY-----"; +var _pubKeyFoot = "-----END PUBLIC KEY-----"; +/*jslint regexp: true */ +var _re_pem = /(.{1,64})/g; +/*jslint regexp: false */ + +function _rsapem_extractEncodedData2(sPEMKey) +{ + "use strict"; + var s = sPEMKey; + s = s.replace(_prvKeyHead, ""); + s = s.replace(_prvKeyFoot, ""); + s = s.replace(_pubKeyHead, ""); + s = s.replace(_pubKeyFoot, ""); + s = s.replace(/[ \n]+/g, ""); + return s; +} + +RSAKey.prototype.readPrivateKeyFromPEMString = function (keyPEM) +{ + "use strict"; + return this.readPrivateKeyFromPkcs1PemString(_rsapem_extractEncodedData2(keyPEM)); +}; + +RSAKey.prototype.readPublicKeyFromPEMString = function (keyPEM) +{ + "use strict"; + return this.readPublicKeyFromX509PEMString(_rsapem_extractEncodedData2(keyPEM)); +}; + +function _asnhex_getStartPosOfV_AtObj(s, pos) +{ + "use strict"; + return ASN1HEX.getStartPosOfV_AtObj(s, pos); +} + +function _asnhex_getPosOfNextSibling_AtObj(s, pos) +{ + "use strict"; + return ASN1HEX.getPosOfNextSibling_AtObj(s, pos); +} + +function _asnhex_getHexOfV_AtObj(s, pos) +{ + "use strict"; + return ASN1HEX.getHexOfV_AtObj(s, pos); +} diff --git a/js-crypt-test/js/simple-crypt.js b/js-crypt-test/js/simple-crypt.js new file mode 100644 index 0000000..d92ba64 --- /dev/null +++ b/js-crypt-test/js/simple-crypt.js @@ -0,0 +1,1178 @@ +/*global require: false, + slowAES: false, + window: false, + exports: false, + rstr_hmac_sha256: false, + b64tohex: false, + hex2b64: false, + rstr_sha256: false, + Uint8Array: false, + escape: false, + unescape: false, + PBKDF2: false, + rstr_sha1: false, + Buffer: false, + RSAKey: false, + process: false */ +/*jslint nomen: true */ + +// Simple symmetric and asymmetric crypto. +// Note: Keep an eye on http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-02 + +var SHA1_SIZE = 20, + SHA256_SIZE = 32, + AES_BLOCK_SIZE = 16, + AES_128_KEY_SIZE = 16, + +Crypt = function (parsed_key, options) +{ + "use strict"; + + this.key = parsed_key; + + options = options || {}; + + this.options = {}; + this.options.json = options.json !== false; + this.options.check = options.check !== false; + this.options.pad = options.pad !== false; + this.options.custom = options.custom; +}; + +Crypt.make = function (key, options, cb) +{ + "use strict"; + + if (!cb) + { + cb = options; + options = {}; + } + + if (!cb) + { + cb = key; + key = undefined; + } + + if (typeof cb !== 'function') + { + options = cb; + cb = undefined; + } + + var This = this, + crypt = new This(undefined, options); + + This.parse_key(key, function (err, parsed_key) + { + if (err) + { + cb(err); + return; + } + + crypt.key = parsed_key; + + if (cb) + { + cb(null, crypt); + } + }); + + return crypt; +}; + +Crypt.get_version = function () +{ + "use strict"; + return 1; +}; + +Crypt.get_key_size = function () +{ + "use strict"; + return AES_128_KEY_SIZE; +}; + +Crypt.prototype.get_key = function () +{ + "use strict"; + return this.key; +}; + +Crypt.prototype.check_version = function (data, f) +{ + "use strict"; + + if (data.version > Crypt.get_version()) + { + f.call(this, 'unsupported version'); + return false; + } + + return true; +}; + +Crypt.prototype.maybe_encrypt = function (arg_encrypt, + arg_data, + arg_f, + arg_get_key) +{ + "use strict"; + + var ths = this, encrypt, data, f, get_key, get_key_data, + + encrypted = function (err, edata, key_data) + { + if (err) + { + f.call(this, err); + } + else + { + f.call(this, null, { encrypted: true, data: edata, key_data: key_data }); + } + }, + + not_encrypted = function () + { + f.call(this, null, { encrypted: false, data: data }); + }; + + if (typeof arg_data === 'function') + { + get_key_data = Array.prototype.slice.call(arguments, 3); + get_key = arg_f; + f = arg_data; + data = arg_encrypt; + encrypt = (get_key !== undefined) || this.key; + } + else + { + get_key_data = Array.prototype.slice.call(arguments, 4); + get_key = arg_get_key; + f = arg_f; + data = arg_data; + encrypt = arg_encrypt; + } + + if (encrypt) + { + if (get_key !== undefined) + { + get_key_data.push(function (err, key, key_data, iv) + { + if (err) + { + f.call(ths, err); + } + else if (key) + { + Crypt.make(key, ths.options, function (err, crypt) + { + if (err) + { + f.call(ths, err); + } + else + { + crypt.encrypt(data, iv, function (err, data) + { + encrypted.call(this, err, data, key_data); + }); + } + }); + } + else + { + not_encrypted.call(ths); + } + }); + + get_key.apply(this, get_key_data); + } + else + { + this.encrypt(data, encrypted); + } + } + else + { + not_encrypted.call(this); + } +}; + +Crypt.prototype.maybe_decrypt = function (data, f, get_key) +{ + "use strict"; + + if (data.encrypted) + { + if (get_key !== undefined) + { + var ths = this, + get_key_data = Array.prototype.slice.call(arguments, 3); + + get_key_data.push(function (err, key) + { + if (err) + { + f.call(ths, err); + } + else + { + Crypt.make(key, ths.options, function (err, crypt) + { + if (err) + { + f.call(ths, err); + } + else + { + crypt.decrypt(data.data, f); + } + }); + } + }); + + get_key_data.push(data.key_data); + + get_key.apply(this, get_key_data); + } + else + { + this.decrypt(data.data, f); + } + } + else + { + f.call(this, null, data.data); + } +}; + +Crypt.prototype.maybe_sign = function (arg_sign, arg_data, arg_f, arg_get_key) +{ + "use strict"; + + var ths = this, sign, data, f, get_key, get_key_data, + + signed = function (err, sdata, key_data) + { + if (err) + { + f.call(this, err); + } + else + { + f.call(this, null, { signed: true, data: sdata, key_data: key_data }); + } + }, + + not_signed = function () + { + f.call(this, null, { signed: false, data: data }); + }; + + if (typeof arg_data === 'function') + { + get_key_data = Array.prototype.slice.call(arguments, 3); + get_key = arg_f; + f = arg_data; + data = arg_sign; + sign = (get_key !== undefined) || this.key; + } + else + { + get_key_data = Array.prototype.slice.call(arguments, 4); + get_key = arg_get_key; + f = arg_f; + data = arg_data; + sign = arg_sign; + } + + if (sign) + { + if (get_key !== undefined) + { + get_key_data.push(function (err, key, key_data) + { + if (err) + { + f.call(ths, err); + } + else if (key) + { + Crypt.make(key, ths.options, function (err, crypt) + { + if (err) + { + f.call(ths, err); + } + else + { + crypt.sign(data, function (err, data) + { + signed.call(this, err, data, key_data); + }); + } + }); + } + else + { + not_signed.call(ths); + } + }); + + get_key.apply(this, get_key_data); + } + else + { + this.sign(data, signed); + } + } + else + { + not_signed.call(this); + } +}; + +Crypt.prototype.maybe_verify = function (data, f, get_key) +{ + "use strict"; + + if (data.signed) + { + if (get_key !== undefined) + { + var ths = this, + get_key_data = Array.prototype.slice.call(arguments, 3); + + get_key_data.push(function (err, key) + { + if (err) + { + f.call(ths, err); + } + else + { + Crypt.make(key, ths.options, function (err, crypt) + { + if (err) + { + f.call(ths, err); + } + else + { + crypt.verify(data.data, f); + } + }); + } + }); + + get_key_data.push(data.key_data); + + get_key.apply(this, get_key_data); + } + else + { + this.verify(data.data, f); + } + } + else + { + f.call(this, null, data.data); + } +}; + +Crypt.sign_encrypt_sign = function (signing_key, encryption_key, data, iv, f) +{ + "use strict"; + + if (!f) + { + f = iv; + iv = null; + } + + var This = this; + + This.make(signing_key, function (err, signer) + { + if (err) + { + f(err); + return; + } + + This.make(encryption_key, function (err, encrypter) + { + if (err) + { + f(err); + return; + } + + signer.sign(data, function (err, sv) + { + if (err) + { + f(err); + return; + } + + encrypter.encrypt(sv, iv, function (err, ev) + { + if (err) + { + f(err); + return; + } + + signer.sign(ev, f); + }); + }); + }); + }); +}; + +Crypt.verify_decrypt_verify = function (decryption_key, verifying_key, data, f) +{ + "use strict"; + + var This = this; + + This.make(verifying_key, function (err, verifier) + { + if (err) + { + f(err); + return; + } + + This.make(decryption_key, function (err, decrypter) + { + if (err) + { + f(err); + return; + } + + verifier.verify(data, function (err, vv) + { + if (err) + { + f(err); + return; + } + + decrypter.decrypt(vv, function (err, dv) + { + if (err) + { + f(err); + return; + } + + verifier.verify(dv, f); + }); + }); + }); + }); +}; + +var SlowCrypt; + +if (typeof require === 'function') +{ + var crypto = require('crypto'), + ursa = require('ursa'), + workaround = process.version.lastIndexOf('v0.8', 0) === 0; + + Crypt.parse_key = function (key, cb) + { + "use strict"; + + if ((typeof key === 'string') && + (key.lastIndexOf('-----BEGIN', 0) === 0)) + { + if (key.indexOf('PUBLIC KEY') > 0) + { + key = ursa.createPublicKey(key, 'utf8'); + } + else if (key.indexOf('PRIVATE KEY') > 0) + { + key = ursa.createPrivateKey(key, '', 'utf8'); + } + + cb(null, key); + } + else if (key && key.password) + { + var salt = key.salt || crypto.randomBytes(SHA1_SIZE), + hash; + + if (salt.length < SHA1_SIZE) + { + hash = crypto.createHash('sha1'); + hash.update(salt); + salt = hash.digest(); + } + + crypto.pbkdf2(key.password, salt, key.iterations, AES_128_KEY_SIZE, + function (err, derived_key) + { + if (err) + { + cb(err); + return; + } + + if (key.progress) + { + key.progress(100); + } + + cb(null, + { + key: derived_key, + salt: salt + }); + }); + } + else + { + cb(null, key); + } + }; + + Crypt.prototype.stringify = function (data) + { + "use strict"; + return this.options.json ? new Buffer(JSON.stringify(data), 'utf8') : data; + }; + + Crypt.prototype.parse = function (data) + { + "use strict"; + return this.options.json ? JSON.parse(data.toString('utf8')) : data; + }; + + Crypt.prototype.encrypt = function (data, iv, f) + { + "use strict"; + + var key, ekey, iv64, cipher, jdata, edata = '', + encoding = workaround ? 'hex' : 'base64'; + + try + { + if (!f) + { + f = iv; + iv = null; + } + + if (this.key.privateEncrypt) + { + f.call(this, "can't encrypt using private key"); + return; + } + + if (this.key.encrypt) + { + key = crypto.randomBytes(AES_128_KEY_SIZE); + ekey = this.key.encrypt(key, undefined, 'base64', ursa.RSA_PKCS1_OAEP_PADDING); + } + else + { + key = this.key.key || this.key; + } + + iv = iv || crypto.randomBytes(AES_BLOCK_SIZE); + iv64 = iv.toString('base64'); + + cipher = crypto.createCipheriv('AES-128-CBC', key, iv); + cipher.setAutoPadding(this.options.pad); + + jdata = this.stringify(data); + + if (this.options.check) + { + edata = cipher.update(crypto.createHash('sha256') + .update(jdata) + .digest(), null, encoding); + } + + edata += cipher.update(jdata, null, encoding); + + edata += cipher.final(encoding); + + if (workaround) + { + edata = new Buffer(edata, encoding).toString('base64'); + } + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, { iv: iv64, data: edata, ekey: ekey, version: Crypt.get_version() }); + }; + + Crypt.prototype.decrypt = function (data, f) + { + "use strict"; + + var key, decipher, ddata, jdata; + + try + { + if (!this.check_version(data, f)) + { + return; + } + + if (this.key.decrypt) + { + key = this.key.decrypt(data.ekey, 'base64', undefined, ursa.RSA_PKCS1_OAEP_PADDING); + } + else if (!this.key.publicDecrypt) + { + key = this.key.key || this.key; + } + else + { + f.call(this, "can't decrypt using public key"); + return; + } + + decipher = crypto.createDecipheriv( + 'AES-128-CBC', + key, + new Buffer(data.iv, 'base64')); + decipher.setAutoPadding(this.options.pad); + + ddata = decipher.update(data.data, 'base64'); + + if (workaround) + { + ddata = new Buffer(ddata + decipher.final(), 'binary'); + } + else + { + ddata = Buffer.concat([ddata, decipher.final()]); + } + + if (this.options.check) + { + jdata = ddata.slice(SHA256_SIZE); + + if (crypto.createHash('sha256') + .update(jdata) + .digest('base64') !== ddata.toString('base64', 0, SHA256_SIZE)) + { + f.call(this, 'digest mismatch'); + return; + } + } + else + { + jdata = ddata; + } + + jdata = this.parse(jdata); + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, jdata); + }; + + Crypt.prototype.sign = function (data, f) + { + "use strict"; + + var jdata, signature; + + try + { + jdata = this.stringify(data); + + if (this.key.hashAndSign) + { + signature = this.key.hashAndSign('sha256', jdata, null, 'base64', ursa.RSA_PKCS1_PSS_PADDING); + } + else if (!this.key.encrypt) + { + signature = crypto.createHmac('sha256', this.key.key || this.key) + .update(jdata) + .digest('base64'); + } + else + { + f.call(this, "can't sign using public key"); + return; + } + + jdata = jdata.toString('base64'); + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, { data: jdata, signature: signature, version: Crypt.get_version() }); + }; + + Crypt.prototype.verify = function (data, f) + { + "use strict"; + + var match, ddata, jdata; + + try + { + if (!this.check_version(data, f)) + { + return; + } + + ddata = new Buffer(data.data, 'base64'); + + if (this.key.decrypt) + { + f.call(this, "can't verify using private key"); + return; + } + + if (this.key.hashAndVerify) + { + match = this.key.hashAndVerify( + 'sha256', + data.data, + data.signature, + 'base64', + ursa.RSA_PKCS1_PSS_PADDING); + } + else + { + match = crypto.createHmac('sha256', this.key.key || this.key) + .update(ddata) + .digest('base64') === data.signature; + } + + if (match) + { + jdata = this.parse(ddata); + } + else + { + f.call(this, 'digest mismatch'); + return; + } + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, jdata); + }; + + SlowCrypt = function () + { + "use strict"; + Crypt.apply(this, arguments); + }; + + SlowCrypt.make = Crypt.make; + SlowCrypt.get_version = Crypt.get_version; + SlowCrypt.get_key_size = Crypt.get_key_size; + SlowCrypt.sign_encrypt_sign = Crypt.sign_encrypt_sign; + SlowCrypt.verify_decrypt_verify = Crypt.verify_decrypt_verify; + + SlowCrypt.prototype = Object.create(Crypt.prototype); +} +else +{ + SlowCrypt = Crypt; +} + +var get_char_codes = function(s) +{ + "use strict"; + + var r = [], i; + + for (i = 0; i < s.length; i += 1) + { + r.push(s.charCodeAt(i)); + } + + return r; +}; + +SlowCrypt.parse_key = function (key, cb) +{ + "use strict"; + + var rsa_key, salt, pbkdf2; + + if (typeof key === 'string') + { + if (key.lastIndexOf('-----BEGIN', 0) === 0) + { + if (key.indexOf('PUBLIC KEY') > 0) + { + rsa_key = new RSAKey(); + rsa_key.readPublicKeyFromPEMString(key); + cb(null, rsa_key); + return; + } + + if (key.indexOf('PRIVATE KEY') > 0) + { + rsa_key = new RSAKey(); + rsa_key.readPrivateKeyFromPEMString(key); + cb(null, rsa_key); + return; + } + } + + cb(null, get_char_codes(key)); + } + else if (key && key.password) + { + salt = key.salt; + + if (!salt) + { + salt = new Uint8Array(SHA1_SIZE); + window.crypto.getRandomValues(salt); + salt = String.fromCharCode.apply(String, Array.prototype.slice.call(salt)); + } + + if (salt.length < SHA1_SIZE) + { + salt = rstr_sha1(salt); + } + + pbkdf2 = new PBKDF2(key.password, + salt, + key.iterations, + AES_128_KEY_SIZE); + + pbkdf2.deriveKey( + key.progress || function () { return undefined; }, + function (derived_key) + { + var bytes = [], i; + + for (i = 0; i < derived_key.length; i += 2) + { + bytes.push(parseInt(derived_key.substr(i, 2), 16)); + } + + cb(null, + { + key: bytes, + salt: salt + }); + }); + } + else + { + cb(null, key); + } +}; + +SlowCrypt.prototype.stringify = function (data) +{ + "use strict"; + + // http://ecmanaut.blogspot.co.uk/2006/07/encoding-decoding-utf8-in-javascript.html + return this.options.json ? unescape(encodeURIComponent(JSON.stringify(data))) : data; +}; + +SlowCrypt.prototype.parse = function (data) +{ + "use strict"; + return this.options.json ? JSON.parse(decodeURIComponent(escape(data))) : data; +}; + +SlowCrypt.prototype.encrypt = function (data, iv, f) +{ + "use strict"; + + var key_arr, ekey, iv64, jdata, edata; + + try + { + if (!f) + { + f = iv; + iv = null; + } + + if (this.key.isPrivate) + { + f.call(this, "can't encrypt using private key"); + return; + } + + if (this.key.isPublic) + { + key_arr = new Uint8Array(AES_128_KEY_SIZE); + window.crypto.getRandomValues(key_arr); + ekey = hex2b64(this.key.encryptOAEP(String.fromCharCode.apply(String, Array.prototype.slice.call(key_arr))/*, rstr_sha256, 32*/)); + } + else + { + key_arr = this.key.key || this.key; + } + + if (!iv) + { + iv = new Uint8Array(AES_BLOCK_SIZE); + window.crypto.getRandomValues(iv); + } + + iv64 = window.btoa(String.fromCharCode.apply(String, Array.prototype.slice.call(iv))); + + jdata = this.stringify(data); + + if (!this.options.pad) + { + slowAES._padBytesIn_save = slowAES.padBytesIn; + slowAES.padBytesIn = function (data) + { + return data; + }; + } + + if (this.options.check) + { + if (typeof jdata !== 'string') + { + jdata = String.fromCharCode.apply(String, jdata); + } + + jdata = get_char_codes(rstr_sha256(jdata) + jdata); + } + else if (typeof jdata === 'string') + { + jdata = get_char_codes(jdata); + } + + try + { + edata = slowAES.encrypt( + jdata, + slowAES.modeOfOperation.CBC, + key_arr, + iv); + } + finally + { + if (!this.options.pad) + { + slowAES.padBytesIn = slowAES._padBytesIn_save; + } + } + + edata = window.btoa(String.fromCharCode.apply(String, edata)); + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, { iv: iv64, data: edata, ekey: ekey, version: SlowCrypt.get_version() }); +}; + +SlowCrypt.prototype.decrypt = function (data, f) +{ + "use strict"; + + var key_arr, ddata, jdata; + + try + { + if (!this.check_version(data, f)) + { + return; + } + + if (this.key.isPublic) + { + f.call(this, "can't decrypt using public key"); + return; + } + + if (this.key.isPrivate) + { + key_arr = get_char_codes(this.key.decryptOAEP(b64tohex(data.ekey)/*, rstr_sha256, 32*/)); + } + else + { + key_arr = this.key.key || this.key; + } + + if (!this.options.pad) + { + slowAES._unpadBytesOut_save = slowAES.unpadBytesOut; + slowAES.unpadBytesOut = function (data) + { + return data; + }; + } + + try + { + ddata = String.fromCharCode.apply(String, slowAES.decrypt( + get_char_codes(window.atob(data.data)), + slowAES.modeOfOperation.CBC, + key_arr, + get_char_codes(window.atob(data.iv)))); + } + finally + { + if (!this.options.pad) + { + slowAES.unpadBytesOut = slowAES._unpadBytesOut_save; + } + } + + if (this.options.check) + { + jdata = ddata.substr(SHA256_SIZE); + + if (rstr_sha256(jdata) !== ddata.substr(0, SHA256_SIZE)) + { + f.call(this, 'digest mismatch'); + return; + } + } + else + { + jdata = ddata; + } + + jdata = this.parse(jdata); + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, jdata); +}; + +SlowCrypt.prototype.sign = function (data, f) +{ + "use strict"; + + var jdata, signature; + + try + { + if (this.key.isPublic) + { + f.call(this, "can't sign using public key"); + return; + } + + jdata = this.stringify(data); + + if (typeof jdata !== 'string') + { + jdata = String.fromCharCode.apply(String, jdata); + } + + if (this.key.isPrivate) + { + signature = hex2b64(this.key.signPSS(jdata, 'sha256')); + } + else + { + signature = window.btoa(rstr_hmac_sha256(String.fromCharCode.apply( + String, this.key.key || this.key), jdata)); + } + + jdata = window.btoa(jdata); + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, { data: jdata, signature: signature, version: SlowCrypt.get_version() }); +}; + +SlowCrypt.prototype.verify = function (data, f) +{ + "use strict"; + + var match, ddata, jdata; + + try + { + if (!this.check_version(data, f)) + { + return; + } + + ddata = window.atob(data.data); + + if (this.key.isPrivate) + { + f.call(this, "can't verify using private key"); + return; + } + + if (this.key.isPublic) + { + match = this.key.verifyPSS(ddata, b64tohex(data.signature), 'sha256'); + } + else + { + match = window.btoa(rstr_hmac_sha256(String.fromCharCode.apply( + String, this.key.key || this.key), ddata)) === + data.signature; + } + + if (match) + { + jdata = this.parse(ddata); + } + else + { + f.call(this, 'digest mismatch'); + return; + } + } + catch (ex) + { + f.call(this, ex); + return; + } + + f.call(this, null, jdata); +}; + +if (typeof exports === 'object') +{ + exports.Crypt = Crypt; + exports.SlowCrypt = SlowCrypt; +} diff --git a/js-crypt-test/test.html b/js-crypt-test/test.html new file mode 100644 index 0000000..8adb78b --- /dev/null +++ b/js-crypt-test/test.html @@ -0,0 +1,44 @@ + + + + + + +... + diff --git a/meshenger_roadmap b/meshenger_roadmap index f3e8af3..4478dbf 100644 --- a/meshenger_roadmap +++ b/meshenger_roadmap @@ -7,3 +7,10 @@ -file deletion or time to live (client side?) +# Cryptoshit + +encrypt / decrypt: +http://www.davedoesdev.com/a-simple-and-consistent-wrapper-for-javascript-crypto/ + +generating keys: +https://bitbucket.org/adrianpasternak/js-rsa-pem/wiki/Home