6857 lines
210 KiB
JavaScript
6857 lines
210 KiB
JavaScript
/*
|
|
* 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:
|
|
*
|
|
* <script src="sha1.js"></script>
|
|
* <script src="pbkdf2.js"></script>
|
|
* <script>
|
|
* var mypbkdf2 = new PBKDF2("mypassword", "saltines", 1000, 16);
|
|
* var status_callback = function(percent_done) {
|
|
* document.getElementById("status").innerHTML = "Computed " + percent_done + "%"};
|
|
* var result_callback = function(key) {
|
|
* document.getElementById("status").innerHTML = "The derived key is: " + key};
|
|
* mypbkdf2.deriveKey(status_callback, result_callback);
|
|
* </script>
|
|
* <div id="status"></div>
|
|
*
|
|
*/
|
|
|
|
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<iterations; ++i)
|
|
{
|
|
// compute HMAC-SHA1
|
|
if (m_iterations_done == 0)
|
|
{
|
|
var salt_block = m_salt +
|
|
String.fromCharCode(m_current_block >> 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<m_hash.length; ++j)
|
|
m_buffer[j] ^= m_hash[j];
|
|
|
|
m_iterations_done++;
|
|
}
|
|
|
|
// Call the status callback function
|
|
m_status_func( (m_current_block - 1 + m_iterations_done/m_total_iterations) / m_total_blocks * 100);
|
|
|
|
if (m_iterations_done < m_total_iterations)
|
|
{
|
|
setTimeout(function() { m_this_object.do_PBKDF2_iterations() }, 0);
|
|
}
|
|
else
|
|
{
|
|
if (m_current_block < m_total_blocks)
|
|
{
|
|
// Compute the next block (T_i in RFC 2898)
|
|
|
|
m_key += rstr2hex(binb2rstr(m_buffer));
|
|
|
|
m_current_block++;
|
|
m_buffer = new Array(0x0,0x0,0x0,0x0,0x0);
|
|
m_iterations_done = 0;
|
|
|
|
setTimeout(function() { m_this_object.do_PBKDF2_iterations() }, 0);
|
|
}
|
|
else
|
|
{
|
|
// We've computed the final block T_l; we're done.
|
|
|
|
var tmp = rstr2hex(binb2rstr(m_buffer));
|
|
m_key += tmp.substr(0, (m_key_length - (m_total_blocks - 1) * m_hash_length) * 2 );
|
|
|
|
// Call the result callback function
|
|
m_result_func(m_key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
|
|
*/
|
|
// Copyright (c) 2005 Tom Wu
|
|
// All Rights Reserved.
|
|
// See "LICENSE" for details.
|
|
|
|
// Basic JavaScript BN library - subset useful for RSA encryption.
|
|
|
|
// Bits per digit
|
|
var dbits;
|
|
|
|
// JavaScript engine analysis
|
|
var canary = 0xdeadbeefcafe;
|
|
var j_lm = ((canary&0xffffff)==0xefcafe);
|
|
|
|
// (public) Constructor
|
|
function BigInteger(a,b,c) {
|
|
if(a != null)
|
|
if("number" == typeof a) this.fromNumber(a,b,c);
|
|
else if(b == null && "string" != typeof a) this.fromString(a,256);
|
|
else this.fromString(a,b);
|
|
}
|
|
|
|
// return new, unset BigInteger
|
|
function nbi() { return new BigInteger(null); }
|
|
|
|
// am: Compute w_j += (x*this_i), propagate carries,
|
|
// c is initial carry, returns final carry.
|
|
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
|
|
// We need to select the fastest one that works in this environment.
|
|
|
|
// am1: use a single mult and divide to get the high bits,
|
|
// max digit bits should be 26 because
|
|
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
|
|
function am1(i,x,w,j,c,n) {
|
|
while(--n >= 0) {
|
|
var v = x*this[i++]+w[j]+c;
|
|
c = Math.floor(v/0x4000000);
|
|
w[j++] = v&0x3ffffff;
|
|
}
|
|
return c;
|
|
}
|
|
// am2 avoids a big mult-and-extract completely.
|
|
// Max digit bits should be <= 30 because we do bitwise ops
|
|
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
|
|
function am2(i,x,w,j,c,n) {
|
|
var xl = x&0x7fff, xh = x>>15;
|
|
while(--n >= 0) {
|
|
var l = this[i]&0x7fff;
|
|
var h = this[i++]>>15;
|
|
var m = xh*l+h*xl;
|
|
l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
|
|
c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
|
|
w[j++] = l&0x3fffffff;
|
|
}
|
|
return c;
|
|
}
|
|
// Alternately, set max digit bits to 28 since some
|
|
// browsers slow down when dealing with 32-bit numbers.
|
|
function am3(i,x,w,j,c,n) {
|
|
var xl = x&0x3fff, xh = x>>14;
|
|
while(--n >= 0) {
|
|
var l = this[i]&0x3fff;
|
|
var h = this[i++]>>14;
|
|
var m = xh*l+h*xl;
|
|
l = xl*l+((m&0x3fff)<<14)+w[j]+c;
|
|
c = (l>>28)+(m>>14)+xh*h;
|
|
w[j++] = l&0xfffffff;
|
|
}
|
|
return c;
|
|
}
|
|
if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
|
|
BigInteger.prototype.am = am2;
|
|
dbits = 30;
|
|
}
|
|
else if(j_lm && (navigator.appName != "Netscape")) {
|
|
BigInteger.prototype.am = am1;
|
|
dbits = 26;
|
|
}
|
|
else { // Mozilla/Netscape seems to prefer am3
|
|
BigInteger.prototype.am = am3;
|
|
dbits = 28;
|
|
}
|
|
|
|
BigInteger.prototype.DB = dbits;
|
|
BigInteger.prototype.DM = ((1<<dbits)-1);
|
|
BigInteger.prototype.DV = (1<<dbits);
|
|
|
|
var BI_FP = 52;
|
|
BigInteger.prototype.FV = Math.pow(2,BI_FP);
|
|
BigInteger.prototype.F1 = BI_FP-dbits;
|
|
BigInteger.prototype.F2 = 2*dbits-BI_FP;
|
|
|
|
// Digit conversions
|
|
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
var BI_RC = new Array();
|
|
var rr,vv;
|
|
rr = "0".charCodeAt(0);
|
|
for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
|
|
rr = "a".charCodeAt(0);
|
|
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
|
rr = "A".charCodeAt(0);
|
|
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
|
|
|
function int2char(n) { return BI_RM.charAt(n); }
|
|
function intAt(s,i) {
|
|
var c = BI_RC[s.charCodeAt(i)];
|
|
return (c==null)?-1:c;
|
|
}
|
|
|
|
// (protected) copy this to r
|
|
function bnpCopyTo(r) {
|
|
for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
|
|
r.t = this.t;
|
|
r.s = this.s;
|
|
}
|
|
|
|
// (protected) set from integer value x, -DV <= x < DV
|
|
function bnpFromInt(x) {
|
|
this.t = 1;
|
|
this.s = (x<0)?-1:0;
|
|
if(x > 0) this[0] = x;
|
|
else if(x < -1) this[0] = x+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))<<sh;
|
|
this[this.t++] = (x>>(this.DB-sh));
|
|
}
|
|
else
|
|
this[this.t-1] |= x<<sh;
|
|
sh += k;
|
|
if(sh >= this.DB) sh -= this.DB;
|
|
}
|
|
if(k == 8 && (s[0]&0x80) != 0) {
|
|
this.s = -1;
|
|
if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
|
|
}
|
|
this.clamp();
|
|
if(mi) BigInteger.ZERO.subTo(this,this);
|
|
}
|
|
|
|
// (protected) clamp off excess high words
|
|
function bnpClamp() {
|
|
var c = this.s&this.DM;
|
|
while(this.t > 0 && this[this.t-1] == c) --this.t;
|
|
}
|
|
|
|
// (public) return string representation in given radix
|
|
function bnToString(b) {
|
|
if(this.s < 0) return "-"+this.negate().toString(b);
|
|
var k;
|
|
if(b == 16) k = 4;
|
|
else if(b == 8) k = 3;
|
|
else if(b == 2) k = 1;
|
|
else if(b == 32) k = 5;
|
|
else if(b == 4) k = 2;
|
|
else return this.toRadix(b);
|
|
var km = (1<<k)-1, d, m = false, r = "", i = this.t;
|
|
var p = this.DB-(i*this.DB)%k;
|
|
if(i-- > 0) {
|
|
if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
|
|
while(i >= 0) {
|
|
if(p < k) {
|
|
d = (this[i]&((1<<p)-1))<<(k-p);
|
|
d |= this[--i]>>(p+=this.DB-k);
|
|
}
|
|
else {
|
|
d = (this[i]>>(p-=k))&km;
|
|
if(p <= 0) { p += this.DB; --i; }
|
|
}
|
|
if(d > 0) m = true;
|
|
if(m) r += int2char(d);
|
|
}
|
|
}
|
|
return m?r:"0";
|
|
}
|
|
|
|
// (public) -this
|
|
function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
|
|
|
|
// (public) |this|
|
|
function bnAbs() { return (this.s<0)?this.negate():this; }
|
|
|
|
// (public) return + if this > a, - if this < a, 0 if equal
|
|
function bnCompareTo(a) {
|
|
var r = this.s-a.s;
|
|
if(r != 0) return r;
|
|
var i = this.t;
|
|
r = i-a.t;
|
|
if(r != 0) return (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<<cbs)-1;
|
|
var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
|
|
for(i = this.t-1; i >= 0; --i) {
|
|
r[i+ds+1] = (this[i]>>cbs)|c;
|
|
c = (this[i]&bm)<<bs;
|
|
}
|
|
for(i = ds-1; i >= 0; --i) r[i] = 0;
|
|
r[ds] = c;
|
|
r.t = this.t+ds+1;
|
|
r.s = this.s;
|
|
r.clamp();
|
|
}
|
|
|
|
// (protected) r = this >> n
|
|
function bnpRShiftTo(n,r) {
|
|
r.s = this.s;
|
|
var ds = Math.floor(n/this.DB);
|
|
if(ds >= this.t) { r.t = 0; return; }
|
|
var bs = n%this.DB;
|
|
var cbs = this.DB-bs;
|
|
var bm = (1<<bs)-1;
|
|
r[0] = this[ds]>>bs;
|
|
for(var i = ds+1; i < this.t; ++i) {
|
|
r[i-ds-1] |= (this[i]&bm)<<cbs;
|
|
r[i-ds] = this[i]>>bs;
|
|
}
|
|
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
|
|
r.t = this.t-ds;
|
|
r.clamp();
|
|
}
|
|
|
|
// (protected) r = this - a
|
|
function bnpSubTo(a,r) {
|
|
var i = 0, c = 0, m = Math.min(a.t,this.t);
|
|
while(i < m) {
|
|
c += this[i]-a[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= this.DB;
|
|
}
|
|
if(a.t < this.t) {
|
|
c -= a.s;
|
|
while(i < this.t) {
|
|
c += this[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= this.DB;
|
|
}
|
|
c += this.s;
|
|
}
|
|
else {
|
|
c += this.s;
|
|
while(i < a.t) {
|
|
c -= a[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= this.DB;
|
|
}
|
|
c -= a.s;
|
|
}
|
|
r.s = (c<0)?-1:0;
|
|
if(c < -1) r[i++] = this.DV+c;
|
|
else if(c > 0) r[i++] = c;
|
|
r.t = i;
|
|
r.clamp();
|
|
}
|
|
|
|
// (protected) r = this * a, r != this,a (HAC 14.12)
|
|
// "this" should be the larger one if appropriate.
|
|
function bnpMultiplyTo(a,r) {
|
|
var x = this.abs(), y = a.abs();
|
|
var i = x.t;
|
|
r.t = i+y.t;
|
|
while(--i >= 0) r[i] = 0;
|
|
for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
|
|
r.s = 0;
|
|
r.clamp();
|
|
if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
|
|
}
|
|
|
|
// (protected) r = this^2, r != this (HAC 14.16)
|
|
function bnpSquareTo(r) {
|
|
var x = this.abs();
|
|
var i = r.t = 2*x.t;
|
|
while(--i >= 0) r[i] = 0;
|
|
for(i = 0; i < x.t-1; ++i) {
|
|
var c = x.am(i,x[i],r,2*i,0,1);
|
|
if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
|
|
r[i+x.t] -= x.DV;
|
|
r[i+x.t+1] = 1;
|
|
}
|
|
}
|
|
if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
|
|
r.s = 0;
|
|
r.clamp();
|
|
}
|
|
|
|
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
|
|
// r != q, this != m. q or r may be null.
|
|
function bnpDivRemTo(m,q,r) {
|
|
var pm = m.abs();
|
|
if(pm.t <= 0) return;
|
|
var pt = this.abs();
|
|
if(pt.t < pm.t) {
|
|
if(q != null) q.fromInt(0);
|
|
if(r != null) this.copyTo(r);
|
|
return;
|
|
}
|
|
if(r == null) r = nbi();
|
|
var y = nbi(), ts = this.s, ms = m.s;
|
|
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
|
|
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
|
|
else { pm.copyTo(y); pt.copyTo(r); }
|
|
var ys = y.t;
|
|
var y0 = y[ys-1];
|
|
if(y0 == 0) return;
|
|
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
|
|
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
|
|
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
|
|
y.dlShiftTo(j,t);
|
|
if(r.compareTo(t) >= 0) {
|
|
r[r.t++] = 1;
|
|
r.subTo(t,r);
|
|
}
|
|
BigInteger.ONE.dlShiftTo(ys,t);
|
|
t.subTo(y,y); // "negative" y so we can replace sub with am later
|
|
while(y.t < ys) y[y.t++] = 0;
|
|
while(--j >= 0) {
|
|
// Estimate quotient digit
|
|
var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
|
|
if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
|
|
y.dlShiftTo(j,t);
|
|
r.subTo(t,r);
|
|
while(r[i] < --qd) r.subTo(t,r);
|
|
}
|
|
}
|
|
if(q != null) {
|
|
r.drShiftTo(ys,q);
|
|
if(ts != ms) BigInteger.ZERO.subTo(q,q);
|
|
}
|
|
r.t = ys;
|
|
r.clamp();
|
|
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
|
|
if(ts < 0) BigInteger.ZERO.subTo(r,r);
|
|
}
|
|
|
|
// (public) this mod a
|
|
function bnMod(a) {
|
|
var r = nbi();
|
|
this.abs().divRemTo(a,null,r);
|
|
if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
|
|
return r;
|
|
}
|
|
|
|
// Modular reduction using "classic" algorithm
|
|
function Classic(m) { this.m = m; }
|
|
function cConvert(x) {
|
|
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
|
|
else return x;
|
|
}
|
|
function cRevert(x) { return x; }
|
|
function cReduce(x) { x.divRemTo(this.m,null,x); }
|
|
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
|
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
|
|
|
Classic.prototype.convert = cConvert;
|
|
Classic.prototype.revert = cRevert;
|
|
Classic.prototype.reduce = cReduce;
|
|
Classic.prototype.mulTo = cMulTo;
|
|
Classic.prototype.sqrTo = cSqrTo;
|
|
|
|
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
|
|
// justification:
|
|
// xy == 1 (mod m)
|
|
// xy = 1+km
|
|
// xy(2-xy) = (1+km)(1-km)
|
|
// x[y(2-xy)] = 1-k^2m^2
|
|
// x[y(2-xy)] == 1 (mod m^2)
|
|
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
|
|
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
|
|
// JS multiply "overflows" differently from C/C++, so care is needed here.
|
|
function bnpInvDigit() {
|
|
if(this.t < 1) return 0;
|
|
var x = this[0];
|
|
if((x&1) == 0) return 0;
|
|
var y = x&3; // y == 1/x mod 2^2
|
|
y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
|
|
y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
|
|
y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
|
|
// last step - calculate inverse mod DV directly;
|
|
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
|
|
y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
|
|
// we really want the negative inverse, and -DV < y < DV
|
|
return (y>0)?this.DV-y:-y;
|
|
}
|
|
|
|
// Montgomery reduction
|
|
function Montgomery(m) {
|
|
this.m = m;
|
|
this.mp = m.invDigit();
|
|
this.mpl = this.mp&0x7fff;
|
|
this.mph = this.mp>>15;
|
|
this.um = (1<<(m.DB-15))-1;
|
|
this.mt2 = 2*m.t;
|
|
}
|
|
|
|
// xR mod m
|
|
function montConvert(x) {
|
|
var r = nbi();
|
|
x.abs().dlShiftTo(this.m.t,r);
|
|
r.divRemTo(this.m,null,r);
|
|
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
|
|
return r;
|
|
}
|
|
|
|
// x/R mod m
|
|
function montRevert(x) {
|
|
var r = nbi();
|
|
x.copyTo(r);
|
|
this.reduce(r);
|
|
return r;
|
|
}
|
|
|
|
// x = x/R mod m (HAC 14.32)
|
|
function montReduce(x) {
|
|
while(x.t <= this.mt2) // pad x so am has enough room later
|
|
x[x.t++] = 0;
|
|
for(var i = 0; i < this.m.t; ++i) {
|
|
// faster way of calculating u0 = x[i]*mp mod DV
|
|
var j = x[i]&0x7fff;
|
|
var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
|
|
// use am to combine the multiply-shift-add into one call
|
|
j = i+this.m.t;
|
|
x[j] += this.m.am(0,u0,x,i,0,this.m.t);
|
|
// propagate carry
|
|
while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
|
|
}
|
|
x.clamp();
|
|
x.drShiftTo(this.m.t,x);
|
|
if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
|
}
|
|
|
|
// r = "x^2/R mod m"; x != r
|
|
function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
|
|
|
// r = "xy/R mod m"; x,y != r
|
|
function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
|
|
|
Montgomery.prototype.convert = montConvert;
|
|
Montgomery.prototype.revert = montRevert;
|
|
Montgomery.prototype.reduce = montReduce;
|
|
Montgomery.prototype.mulTo = montMulTo;
|
|
Montgomery.prototype.sqrTo = montSqrTo;
|
|
|
|
// (protected) true iff this is even
|
|
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
|
|
|
|
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
|
|
function bnpExp(e,z) {
|
|
if(e > 0xffffffff || e < 1) return BigInteger.ONE;
|
|
var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
|
|
g.copyTo(r);
|
|
while(--i >= 0) {
|
|
z.sqrTo(r,r2);
|
|
if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
|
|
else { var t = r; r = r2; r2 = t; }
|
|
}
|
|
return z.revert(r);
|
|
}
|
|
|
|
// (public) this^e % m, 0 <= e < 2^32
|
|
function bnModPowInt(e,m) {
|
|
var z;
|
|
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
|
|
return this.exp(e,z);
|
|
}
|
|
|
|
// protected
|
|
BigInteger.prototype.copyTo = bnpCopyTo;
|
|
BigInteger.prototype.fromInt = bnpFromInt;
|
|
BigInteger.prototype.fromString = bnpFromString;
|
|
BigInteger.prototype.clamp = bnpClamp;
|
|
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
|
|
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
|
|
BigInteger.prototype.lShiftTo = bnpLShiftTo;
|
|
BigInteger.prototype.rShiftTo = bnpRShiftTo;
|
|
BigInteger.prototype.subTo = bnpSubTo;
|
|
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
|
|
BigInteger.prototype.squareTo = bnpSquareTo;
|
|
BigInteger.prototype.divRemTo = bnpDivRemTo;
|
|
BigInteger.prototype.invDigit = bnpInvDigit;
|
|
BigInteger.prototype.isEven = bnpIsEven;
|
|
BigInteger.prototype.exp = bnpExp;
|
|
|
|
// public
|
|
BigInteger.prototype.toString = bnToString;
|
|
BigInteger.prototype.negate = bnNegate;
|
|
BigInteger.prototype.abs = bnAbs;
|
|
BigInteger.prototype.compareTo = bnCompareTo;
|
|
BigInteger.prototype.bitLength = bnBitLength;
|
|
BigInteger.prototype.mod = bnMod;
|
|
BigInteger.prototype.modPowInt = bnModPowInt;
|
|
|
|
// "constants"
|
|
BigInteger.ZERO = nbv(0);
|
|
BigInteger.ONE = nbv(1);
|
|
|
|
/*! (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))<<this.DB)|this[0];
|
|
}
|
|
|
|
// (public) return value as byte
|
|
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
|
|
|
|
// (public) return value as short (assumes DB>=16)
|
|
function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
|
|
|
|
// (protected) return x s.t. r^x < DV
|
|
function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
|
|
|
|
// (public) 0 if this == 0, 1 if this > 0
|
|
function bnSigNum() {
|
|
if(this.s < 0) return -1;
|
|
else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
|
|
else return 1;
|
|
}
|
|
|
|
// (protected) convert to radix string
|
|
function bnpToRadix(b) {
|
|
if(b == null) b = 10;
|
|
if(this.signum() == 0 || b < 2 || b > 36) return "0";
|
|
var cs = this.chunkSize(b);
|
|
var a = Math.pow(b,cs);
|
|
var d = nbv(a), y = nbi(), z = nbi(), r = "";
|
|
this.divRemTo(d,y,z);
|
|
while(y.signum() > 0) {
|
|
r = (a+z.intValue()).toString(b).substr(1) + r;
|
|
y.divRemTo(d,y,z);
|
|
}
|
|
return z.intValue().toString(b) + r;
|
|
}
|
|
|
|
// (protected) convert from radix string
|
|
function bnpFromRadix(s,b) {
|
|
this.fromInt(0);
|
|
if(b == null) b = 10;
|
|
var cs = this.chunkSize(b);
|
|
var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
|
|
for(var i = 0; i < s.length; ++i) {
|
|
var x = intAt(s,i);
|
|
if(x < 0) {
|
|
if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
|
|
continue;
|
|
}
|
|
w = b*w+x;
|
|
if(++j >= cs) {
|
|
this.dMultiply(d);
|
|
this.dAddOffset(w,0);
|
|
j = 0;
|
|
w = 0;
|
|
}
|
|
}
|
|
if(j > 0) {
|
|
this.dMultiply(Math.pow(b,j));
|
|
this.dAddOffset(w,0);
|
|
}
|
|
if(mi) BigInteger.ZERO.subTo(this,this);
|
|
}
|
|
|
|
// (protected) alternate constructor
|
|
function bnpFromNumber(a,b,c) {
|
|
if("number" == typeof b) {
|
|
// new BigInteger(int,int,RNG)
|
|
if(a < 2) this.fromInt(1);
|
|
else {
|
|
this.fromNumber(a,c);
|
|
if(!this.testBit(a-1)) // force MSB set
|
|
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
|
|
if(this.isEven()) this.dAddOffset(1,0); // force odd
|
|
while(!this.isProbablePrime(b)) {
|
|
this.dAddOffset(2,0);
|
|
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// new BigInteger(int,RNG)
|
|
var x = new Array(), t = a&7;
|
|
x.length = (a>>3)+1;
|
|
b.nextBytes(x);
|
|
if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
|
|
this.fromString(x,256);
|
|
}
|
|
}
|
|
|
|
// (public) convert to bigendian byte array
|
|
function bnToByteArray() {
|
|
var i = this.t, r = new Array();
|
|
r[0] = this.s;
|
|
var p = this.DB-(i*this.DB)%8, d, k = 0;
|
|
if(i-- > 0) {
|
|
if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
|
|
r[k++] = d|(this.s<<(this.DB-p));
|
|
while(i >= 0) {
|
|
if(p < 8) {
|
|
d = (this[i]&((1<<p)-1))<<(8-p);
|
|
d |= this[--i]>>(p+=this.DB-8);
|
|
}
|
|
else {
|
|
d = (this[i]>>(p-=8))&0xff;
|
|
if(p <= 0) { p += this.DB; --i; }
|
|
}
|
|
if((d&0x80) != 0) d |= -256;
|
|
if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
|
|
if(k > 0 || d != this.s) r[k++] = d;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
function bnEquals(a) { return(this.compareTo(a)==0); }
|
|
function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
|
|
function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
|
|
|
|
// (protected) r = this op a (bitwise)
|
|
function bnpBitwiseTo(a,op,r) {
|
|
var i, f, m = Math.min(a.t,this.t);
|
|
for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
|
|
if(a.t < this.t) {
|
|
f = a.s&this.DM;
|
|
for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
|
|
r.t = this.t;
|
|
}
|
|
else {
|
|
f = this.s&this.DM;
|
|
for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
|
|
r.t = a.t;
|
|
}
|
|
r.s = op(this.s,a.s);
|
|
r.clamp();
|
|
}
|
|
|
|
// (public) this & a
|
|
function op_and(x,y) { return x&y; }
|
|
function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
|
|
|
|
// (public) this | a
|
|
function op_or(x,y) { return x|y; }
|
|
function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
|
|
|
|
// (public) this ^ a
|
|
function op_xor(x,y) { return x^y; }
|
|
function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
|
|
|
|
// (public) this & ~a
|
|
function op_andnot(x,y) { return x&~y; }
|
|
function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
|
|
|
|
// (public) ~this
|
|
function bnNot() {
|
|
var r = nbi();
|
|
for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
|
|
r.t = this.t;
|
|
r.s = ~this.s;
|
|
return r;
|
|
}
|
|
|
|
// (public) this << n
|
|
function bnShiftLeft(n) {
|
|
var r = nbi();
|
|
if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
|
|
return r;
|
|
}
|
|
|
|
// (public) this >> n
|
|
function bnShiftRight(n) {
|
|
var r = nbi();
|
|
if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
|
|
return r;
|
|
}
|
|
|
|
// return index of lowest 1-bit in x, x < 2^31
|
|
function lbit(x) {
|
|
if(x == 0) return -1;
|
|
var r = 0;
|
|
if((x&0xffff) == 0) { x >>= 16; r += 16; }
|
|
if((x&0xff) == 0) { x >>= 8; r += 8; }
|
|
if((x&0xf) == 0) { x >>= 4; r += 4; }
|
|
if((x&3) == 0) { x >>= 2; r += 2; }
|
|
if((x&1) == 0) ++r;
|
|
return r;
|
|
}
|
|
|
|
// (public) returns index of lowest 1-bit (or -1 if none)
|
|
function bnGetLowestSetBit() {
|
|
for(var i = 0; i < this.t; ++i)
|
|
if(this[i] != 0) return i*this.DB+lbit(this[i]);
|
|
if(this.s < 0) return this.t*this.DB;
|
|
return -1;
|
|
}
|
|
|
|
// return number of 1 bits in x
|
|
function cbit(x) {
|
|
var r = 0;
|
|
while(x != 0) { x &= x-1; ++r; }
|
|
return r;
|
|
}
|
|
|
|
// (public) return number of set bits
|
|
function bnBitCount() {
|
|
var r = 0, x = this.s&this.DM;
|
|
for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
|
|
return r;
|
|
}
|
|
|
|
// (public) true iff nth bit is set
|
|
function bnTestBit(n) {
|
|
var j = Math.floor(n/this.DB);
|
|
if(j >= this.t) return(this.s!=0);
|
|
return((this[j]&(1<<(n%this.DB)))!=0);
|
|
}
|
|
|
|
// (protected) this op (1<<n)
|
|
function bnpChangeBit(n,op) {
|
|
var r = BigInteger.ONE.shiftLeft(n);
|
|
this.bitwiseTo(r,op,r);
|
|
return r;
|
|
}
|
|
|
|
// (public) this | (1<<n)
|
|
function bnSetBit(n) { return this.changeBit(n,op_or); }
|
|
|
|
// (public) this & ~(1<<n)
|
|
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
|
|
|
|
// (public) this ^ (1<<n)
|
|
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
|
|
|
|
// (protected) r = this + a
|
|
function bnpAddTo(a,r) {
|
|
var i = 0, c = 0, m = Math.min(a.t,this.t);
|
|
while(i < m) {
|
|
c += this[i]+a[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= this.DB;
|
|
}
|
|
if(a.t < this.t) {
|
|
c += a.s;
|
|
while(i < this.t) {
|
|
c += this[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= this.DB;
|
|
}
|
|
c += this.s;
|
|
}
|
|
else {
|
|
c += this.s;
|
|
while(i < a.t) {
|
|
c += a[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= this.DB;
|
|
}
|
|
c += a.s;
|
|
}
|
|
r.s = (c<0)?-1:0;
|
|
if(c > 0) r[i++] = c;
|
|
else if(c < -1) r[i++] = this.DV+c;
|
|
r.t = i;
|
|
r.clamp();
|
|
}
|
|
|
|
// (public) this + a
|
|
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
|
|
|
|
// (public) this - a
|
|
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
|
|
|
|
// (public) this * a
|
|
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
|
|
|
|
// (public) this^2
|
|
function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
|
|
|
|
// (public) this / a
|
|
function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
|
|
|
|
// (public) this % a
|
|
function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
|
|
|
|
// (public) [this/a,this%a]
|
|
function bnDivideAndRemainder(a) {
|
|
var q = nbi(), r = nbi();
|
|
this.divRemTo(a,q,r);
|
|
return new Array(q,r);
|
|
}
|
|
|
|
// (protected) this *= n, this >= 0, 1 < n < DV
|
|
function bnpDMultiply(n) {
|
|
this[this.t] = this.am(0,n-1,this,0,0,this.t);
|
|
++this.t;
|
|
this.clamp();
|
|
}
|
|
|
|
// (protected) this += n << w words, this >= 0
|
|
function bnpDAddOffset(n,w) {
|
|
if(n == 0) return;
|
|
while(this.t <= w) this[this.t++] = 0;
|
|
this[w] += n;
|
|
while(this[w] >= this.DV) {
|
|
this[w] -= this.DV;
|
|
if(++w >= this.t) this[this.t++] = 0;
|
|
++this[w];
|
|
}
|
|
}
|
|
|
|
// A "null" reducer
|
|
function NullExp() {}
|
|
function nNop(x) { return x; }
|
|
function nMulTo(x,y,r) { x.multiplyTo(y,r); }
|
|
function nSqrTo(x,r) { x.squareTo(r); }
|
|
|
|
NullExp.prototype.convert = nNop;
|
|
NullExp.prototype.revert = nNop;
|
|
NullExp.prototype.mulTo = nMulTo;
|
|
NullExp.prototype.sqrTo = nSqrTo;
|
|
|
|
// (public) this^e
|
|
function bnPow(e) { return this.exp(e,new NullExp()); }
|
|
|
|
// (protected) r = lower n words of "this * a", a.t <= n
|
|
// "this" should be the larger one if appropriate.
|
|
function bnpMultiplyLowerTo(a,n,r) {
|
|
var i = Math.min(this.t+a.t,n);
|
|
r.s = 0; // assumes a,this >= 0
|
|
r.t = i;
|
|
while(i > 0) r[--i] = 0;
|
|
var j;
|
|
for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
|
|
for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
|
|
r.clamp();
|
|
}
|
|
|
|
// (protected) r = "this * a" without lower n words, n > 0
|
|
// "this" should be the larger one if appropriate.
|
|
function bnpMultiplyUpperTo(a,n,r) {
|
|
--n;
|
|
var i = r.t = this.t+a.t-n;
|
|
r.s = 0; // assumes a,this >= 0
|
|
while(--i >= 0) r[i] = 0;
|
|
for(i = Math.max(n-this.t,0); i < a.t; ++i)
|
|
r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
|
|
r.clamp();
|
|
r.drShiftTo(1,r);
|
|
}
|
|
|
|
// Barrett modular reduction
|
|
function Barrett(m) {
|
|
// setup Barrett
|
|
this.r2 = nbi();
|
|
this.q3 = nbi();
|
|
BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
|
|
this.mu = this.r2.divide(m);
|
|
this.m = m;
|
|
}
|
|
|
|
function barrettConvert(x) {
|
|
if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
|
|
else if(x.compareTo(this.m) < 0) return x;
|
|
else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
|
|
}
|
|
|
|
function barrettRevert(x) { return x; }
|
|
|
|
// x = x mod m (HAC 14.42)
|
|
function barrettReduce(x) {
|
|
x.drShiftTo(this.m.t-1,this.r2);
|
|
if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
|
|
this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
|
|
this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
|
|
while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
|
|
x.subTo(this.r2,x);
|
|
while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
|
}
|
|
|
|
// r = x^2 mod m; x != r
|
|
function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
|
|
|
// r = x*y mod m; x,y != r
|
|
function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
|
|
|
Barrett.prototype.convert = barrettConvert;
|
|
Barrett.prototype.revert = barrettRevert;
|
|
Barrett.prototype.reduce = barrettReduce;
|
|
Barrett.prototype.mulTo = barrettMulTo;
|
|
Barrett.prototype.sqrTo = barrettSqrTo;
|
|
|
|
// (public) this^e % m (HAC 14.85)
|
|
function bnModPow(e,m) {
|
|
var i = e.bitLength(), k, r = nbv(1), z;
|
|
if(i <= 0) return r;
|
|
else if(i < 18) k = 1;
|
|
else if(i < 48) k = 3;
|
|
else if(i < 144) k = 4;
|
|
else if(i < 768) k = 5;
|
|
else k = 6;
|
|
if(i < 8)
|
|
z = new Classic(m);
|
|
else if(m.isEven())
|
|
z = new Barrett(m);
|
|
else
|
|
z = new Montgomery(m);
|
|
|
|
// precomputation
|
|
var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
|
|
g[1] = z.convert(this);
|
|
if(k > 1) {
|
|
var g2 = nbi();
|
|
z.sqrTo(g[1],g2);
|
|
while(n <= km) {
|
|
g[n] = nbi();
|
|
z.mulTo(g2,g[n-2],g[n]);
|
|
n += 2;
|
|
}
|
|
}
|
|
|
|
var j = e.t-1, w, is1 = true, r2 = nbi(), t;
|
|
i = nbits(e[j])-1;
|
|
while(j >= 0) {
|
|
if(i >= k1) w = (e[j]>>(i-k1))&km;
|
|
else {
|
|
w = (e[j]&((1<<(i+1))-1))<<(k1-i);
|
|
if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
|
|
}
|
|
|
|
n = k;
|
|
while((w&1) == 0) { w >>= 1; --n; }
|
|
if((i -= n) < 0) { i += this.DB; --j; }
|
|
if(is1) { // ret == 1, don't bother squaring or multiplying it
|
|
g[w].copyTo(r);
|
|
is1 = false;
|
|
}
|
|
else {
|
|
while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
|
|
if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
|
|
z.mulTo(r2,g[w],r);
|
|
}
|
|
|
|
while(j >= 0 && (e[j]&(1<<i)) == 0) {
|
|
z.sqrTo(r,r2); t = r; r = r2; r2 = t;
|
|
if(--i < 0) { i = this.DB-1; --j; }
|
|
}
|
|
}
|
|
return z.revert(r);
|
|
}
|
|
|
|
// (public) gcd(this,a) (HAC 14.54)
|
|
function bnGCD(a) {
|
|
var x = (this.s<0)?this.negate():this.clone();
|
|
var y = (a.s<0)?a.negate():a.clone();
|
|
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
|
|
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
|
|
if(g < 0) return x;
|
|
if(i < g) g = i;
|
|
if(g > 0) {
|
|
x.rShiftTo(g,x);
|
|
y.rShiftTo(g,y);
|
|
}
|
|
while(x.signum() > 0) {
|
|
if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
|
|
if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
|
|
if(x.compareTo(y) >= 0) {
|
|
x.subTo(y,x);
|
|
x.rShiftTo(1,x);
|
|
}
|
|
else {
|
|
y.subTo(x,y);
|
|
y.rShiftTo(1,y);
|
|
}
|
|
}
|
|
if(g > 0) y.lShiftTo(g,y);
|
|
return y;
|
|
}
|
|
|
|
// (protected) this % n, n < 2^26
|
|
function bnpModInt(n) {
|
|
if(n <= 0) return 0;
|
|
var d = this.DV%n, r = (this.s<0)?n-1:0;
|
|
if(this.t > 0)
|
|
if(d == 0) r = this[0]%n;
|
|
else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
|
|
return r;
|
|
}
|
|
|
|
// (public) 1/this % m (HAC 14.61)
|
|
function bnModInverse(m) {
|
|
var ac = m.isEven();
|
|
if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
|
|
var u = m.clone(), v = this.clone();
|
|
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
|
|
while(u.signum() != 0) {
|
|
while(u.isEven()) {
|
|
u.rShiftTo(1,u);
|
|
if(ac) {
|
|
if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
|
|
a.rShiftTo(1,a);
|
|
}
|
|
else if(!b.isEven()) b.subTo(m,b);
|
|
b.rShiftTo(1,b);
|
|
}
|
|
while(v.isEven()) {
|
|
v.rShiftTo(1,v);
|
|
if(ac) {
|
|
if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
|
|
c.rShiftTo(1,c);
|
|
}
|
|
else if(!d.isEven()) d.subTo(m,d);
|
|
d.rShiftTo(1,d);
|
|
}
|
|
if(u.compareTo(v) >= 0) {
|
|
u.subTo(v,u);
|
|
if(ac) a.subTo(c,a);
|
|
b.subTo(d,b);
|
|
}
|
|
else {
|
|
v.subTo(u,v);
|
|
if(ac) c.subTo(a,c);
|
|
d.subTo(b,d);
|
|
}
|
|
}
|
|
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
|
|
if(d.compareTo(m) >= 0) return d.subtract(m);
|
|
if(d.signum() < 0) d.addTo(m,d); else return d;
|
|
if(d.signum() < 0) return d.add(m); else return d;
|
|
}
|
|
|
|
var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];
|
|
var lplim = (1<<26)/lowprimes[lowprimes.length-1];
|
|
|
|
// (public) test primality with certainty >= 1-.5^t
|
|
function bnIsProbablePrime(t) {
|
|
var i, x = this.abs();
|
|
if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
|
|
for(i = 0; i < lowprimes.length; ++i)
|
|
if(x[0] == lowprimes[i]) return true;
|
|
return false;
|
|
}
|
|
if(x.isEven()) return false;
|
|
i = 1;
|
|
while(i < lowprimes.length) {
|
|
var m = lowprimes[i], j = i+1;
|
|
while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
|
|
m = x.modInt(m);
|
|
while(i < j) if(m%lowprimes[i++] == 0) return false;
|
|
}
|
|
return x.millerRabin(t);
|
|
}
|
|
|
|
// (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 <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
|
|
*/
|
|
|
|
/*
|
|
* 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.<br/>
|
|
* 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.
|
|
* <ul>
|
|
* <li>(ASCII) String</li>
|
|
* <li>UTF8 String including CJK, Latin and other characters</li>
|
|
* <li>byte array</li>
|
|
* <li>hexadecimal encoded String</li>
|
|
* <li>Full URIComponent encoded String (such like "%69%94")</li>
|
|
* <li>Base64 encoded String</li>
|
|
* <li>Base64URL encoded String</li>
|
|
* </ul>
|
|
* 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 <a href="http://kjur.github.com/jsjws/">'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/</a>
|
|
* @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
|
|
*/
|
|
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.<br/>
|
|
* @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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* 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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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".<br/>
|
|
* @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".<br/>
|
|
* Note that these "<code>0-9A-Za-z!'()*-._~</code>" 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 <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
|
|
*/
|
|
|
|
/**
|
|
* 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
|
|
* <p>
|
|
* This namespace privides following crytpgrahic classes.
|
|
* <ul>
|
|
* <li>{@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class</li>
|
|
* <li>{@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class</li>
|
|
* <li>{@link KJUR.crypto.Util} - cryptographic utility functions and properties</li>
|
|
* </ul>
|
|
* NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2.
|
|
* </p>
|
|
* @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
|
|
* <br/>
|
|
* Currently this supports following algorithm and providers combination:
|
|
* <ul>
|
|
* <li>md5 - cryptojs</li>
|
|
* <li>sha1 - cryptojs</li>
|
|
* <li>sha224 - cryptojs</li>
|
|
* <li>sha256 - cryptojs</li>
|
|
* <li>sha384 - cryptojs</li>
|
|
* <li>sha512 - cryptojs</li>
|
|
* <li>ripemd160 - cryptojs</li>
|
|
* <li>sha256 - sjcl (NEW from crypto.js 1.0.4)</li>
|
|
* </ul>
|
|
* @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
|
|
* <br/>
|
|
* Currently this supports following algorithm and providers combination:
|
|
* <ul>
|
|
* <li>hmacmd5 - cryptojs</li>
|
|
* <li>hmacsha1 - cryptojs</li>
|
|
* <li>hmacsha224 - cryptojs</li>
|
|
* <li>hmacsha256 - cryptojs</li>
|
|
* <li>hmacsha384 - cryptojs</li>
|
|
* <li>hmacsha512 - cryptojs</li>
|
|
* </ul>
|
|
* 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
|
|
* <br/>
|
|
* As for params of constructor's argument, it can be specify following attributes:
|
|
* <ul>
|
|
* <li>alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})</li>
|
|
* <li>provider - currently 'cryptojs/jsrsa' only</li>
|
|
* </ul>
|
|
* <h4>SUPPORTED ALGORITHMS AND PROVIDERS</h4>
|
|
* This Signature class supports following signature algorithm and provider names:
|
|
* <ul>
|
|
* <li>MD5withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA1withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA224withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA256withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA384withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA512withRSA - cryptojs/jsrsa</li>
|
|
* <li>RIPEMD160withRSA - cryptojs/jsrsa</li>
|
|
* <li>MD5withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA1withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA224withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA256withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA384withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA512withECDSA - cryptojs/jsrsa</li>
|
|
* <li>RIPEMD160withECDSA - cryptojs/jsrsa</li>
|
|
* <li>MD5withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA1withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA224withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA256withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA384withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA512withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>RIPEMD160withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA1withDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA224withDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA256withDSA - cryptojs/jsrsa</li>
|
|
* </ul>
|
|
* Here are supported elliptic cryptographic curve names and their aliases for ECDSA:
|
|
* <ul>
|
|
* <li>secp256k1</li>
|
|
* <li>secp256r1, NIST P-256, P-256, prime256v1</li>
|
|
* <li>secp384r1, NIST P-384, P-384</li>
|
|
* </ul>
|
|
* NOTE1: DSA signing algorithm is also supported since crypto 1.1.5.
|
|
* <h4>EXAMPLES</h4>
|
|
* @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:
|
|
* <h5>signing</h5>
|
|
* <ul>
|
|
* <li>PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"</li>
|
|
* <li>PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"</li>
|
|
* <li>PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"</li>
|
|
* <li>PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"</li>
|
|
* <li>RSAKey object of private key</li>
|
|
* <li>KJUR.crypto.ECDSA object of private key</li>
|
|
* <li>KJUR.crypto.DSA object of private key</li>
|
|
* </ul>
|
|
* <h5>verification</h5>
|
|
* <ul>
|
|
* <li>PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"</li>
|
|
* <li>PEM formatted X.509 certificate with RSA/EC/DSA public key concluding
|
|
* "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".</li>
|
|
* <li>RSAKey object of public key</li>
|
|
* <li>KJUR.crypto.ECDSA object of public key</li>
|
|
* <li>KJUR.crypto.DSA object of public key</li>
|
|
* </ul>
|
|
* @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:
|
|
* <ul>
|
|
* <li>{@link RSAKey} object for RSA verification</li>
|
|
* <li>associative array for ECDSA verification
|
|
* (ex. <code>{'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}</code>)
|
|
* </li>
|
|
* </ul>
|
|
* @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:
|
|
* <ul>
|
|
* <li>{@link RSAKey} object for RSA signing</li>
|
|
* <li>associative array for ECDSA signing
|
|
* (ex. <code>{'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'}</code>)</li>
|
|
* </ul>
|
|
* @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 <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
|
|
*/
|
|
|
|
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.<br/>
|
|
* @name signString
|
|
* @memberOf RSAKey
|
|
* @function
|
|
* @param {String} s message string to be signed.
|
|
* @param {String} hashAlg hash algorithm name for signing.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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:
|
|
* <ul>
|
|
* <li>-1: sets the salt length to the digest length</li>
|
|
* <li>-2: sets the salt length to maximum permissible value
|
|
* (i.e. keybytelen - hashbytelen - 2)</li>
|
|
* </ul>
|
|
* 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.<br/>
|
|
* @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:
|
|
* <ul>
|
|
* <li>-1: sets the salt length to the digest length</li>
|
|
* <li>-2: sets the salt length to maximum permissible value
|
|
* (i.e. keybytelen - hashbytelen - 2)</li>
|
|
* </ul>
|
|
* 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.<br/>
|
|
* @name verifyString
|
|
* @memberOf RSAKey#
|
|
* @function
|
|
* @param {String} sMsg message string to be verified.
|
|
* @param {String} hSig hexadecimal string of siganture.<br/>
|
|
* 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.<br/>
|
|
* @name verifyWithMessageHash
|
|
* @memberOf RSAKey
|
|
* @function
|
|
* @param {String} sHashHex hexadecimal hash value of message to be verified.
|
|
* @param {String} hSig hexadecimal string of siganture.<br/>
|
|
* 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.<br/>
|
|
* @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:
|
|
* <ul>
|
|
* <li>-1: sets the salt length to the digest length</li>
|
|
* <li>-2: sets the salt length to maximum permissible value
|
|
* (i.e. keybytelen - hashbytelen - 2)</li>
|
|
* </ul>
|
|
* 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.<br/>
|
|
* @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:
|
|
* <ul>
|
|
* <li>-1: sets the salt length to the digest length</li>
|
|
* <li>-2: sets the salt length to maximum permissible value
|
|
* (i.e. keybytelen - hashbytelen - 2)</li>
|
|
* </ul>
|
|
* 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);
|
|
}
|