2016-11-28 10:42:58 +00:00
/* globals CryptoJS, blowfish */
/ * *
* Cipher operations .
*
2016-12-03 20:54:28 +00:00
* @ author n1474335 [ n1474335 @ gmail . com ] & Matt C [ matt @ artemisbot . pw ]
2016-11-28 10:42:58 +00:00
* @ copyright Crown Copyright 2016
* @ license Apache - 2.0
*
* @ namespace
* /
var Cipher = {
/ * *
* @ constant
* @ default
* /
IO _FORMAT1 : [ "Hex" , "Base64" , "UTF8" , "UTF16" , "UTF16LE" , "UTF16BE" , "Latin1" ] ,
/ * *
* @ constant
* @ default
* /
IO _FORMAT2 : [ "UTF8" , "UTF16" , "UTF16LE" , "UTF16BE" , "Latin1" , "Hex" , "Base64" ] ,
/ * *
* @ constant
* @ default
* /
IO _FORMAT3 : [ "Hex" , "Base64" , "UTF16" , "UTF16LE" , "UTF16BE" , "Latin1" ] ,
/ * *
* @ constant
* @ default
* /
IO _FORMAT4 : [ "Latin1" , "UTF8" , "UTF16" , "UTF16LE" , "UTF16BE" , "Hex" , "Base64" ] ,
/ * *
* @ constant
* @ default
* /
MODES : [ "CBC" , "CFB" , "CTR" , "OFB" , "ECB" ] ,
/ * *
* @ constant
* @ default
* /
PADDING : [ "Pkcs7" , "Iso97971" , "AnsiX923" , "Iso10126" , "ZeroPadding" , "NoPadding" ] ,
/ * *
* @ constant
* @ default
* /
RESULT _TYPE : [ "Show all" , "Ciphertext" , "Key" , "IV" , "Salt" ] ,
/ * *
* Runs encryption operations using the CryptoJS framework .
*
* @ private
* @ param { function } algo - The CryptoJS algorithm to use
* @ param { byte _array } input
* @ param { function } args
* @ returns { string }
* /
_enc : function ( algo , input , args ) {
var key = Utils . format [ args [ 0 ] . option ] . parse ( args [ 0 ] . string || "" ) ,
iv = Utils . format [ args [ 1 ] . option ] . parse ( args [ 1 ] . string || "" ) ,
salt = Utils . format [ args [ 2 ] . option ] . parse ( args [ 2 ] . string || "" ) ,
mode = CryptoJS . mode [ args [ 3 ] ] ,
padding = CryptoJS . pad [ args [ 4 ] ] ,
result _option = args [ 5 ] . toLowerCase ( ) ,
output _format = args [ 6 ] ;
if ( iv . sigBytes === 0 ) {
// Use passphrase rather than key. Need to convert it to a string.
key = key . toString ( CryptoJS . enc . Latin1 ) ;
}
var encrypted = algo . encrypt ( input , key , {
salt : salt . sigBytes > 0 ? salt : false ,
iv : iv . sigBytes > 0 ? iv : null ,
mode : mode ,
padding : padding
} ) ;
var result = "" ;
if ( result _option == "show all" ) {
result += "Key: " + encrypted . key . toString ( Utils . format [ output _format ] ) ;
result += "\nIV: " + encrypted . iv . toString ( Utils . format [ output _format ] ) ;
if ( encrypted . salt ) result += "\nSalt: " + encrypted . salt . toString ( Utils . format [ output _format ] ) ;
result += "\n\nCiphertext: " + encrypted . ciphertext . toString ( Utils . format [ output _format ] ) ;
} else {
result = encrypted [ result _option ] . toString ( Utils . format [ output _format ] ) ;
}
return result ;
} ,
/ * *
* Runs decryption operations using the CryptoJS framework .
*
* @ private
* @ param { function } algo - The CryptoJS algorithm to use
* @ param { byte _array } input
* @ param { function } args
* @ returns { string }
* /
_dec : function ( algo , input , args ) {
var key = Utils . format [ args [ 0 ] . option ] . parse ( args [ 0 ] . string || "" ) ,
iv = Utils . format [ args [ 1 ] . option ] . parse ( args [ 1 ] . string || "" ) ,
salt = Utils . format [ args [ 2 ] . option ] . parse ( args [ 2 ] . string || "" ) ,
mode = CryptoJS . mode [ args [ 3 ] ] ,
padding = CryptoJS . pad [ args [ 4 ] ] ,
input _format = args [ 5 ] ,
output _format = args [ 6 ] ;
// The ZeroPadding option causes a crash when the input length is 0
if ( ! input . length ) {
return "No input" ;
}
var ciphertext = Utils . format [ input _format ] . parse ( input ) ;
if ( iv . sigBytes === 0 ) {
// Use passphrase rather than key. Need to convert it to a string.
key = key . toString ( CryptoJS . enc . Latin1 ) ;
}
var decrypted = algo . decrypt ( {
ciphertext : ciphertext ,
salt : salt . sigBytes > 0 ? salt : false
} , key , {
iv : iv . sigBytes > 0 ? iv : null ,
mode : mode ,
padding : padding
} ) ;
var result ;
try {
result = decrypted . toString ( Utils . format [ output _format ] ) ;
} catch ( err ) {
result = "Decrypt error: " + err . message ;
}
return result ;
} ,
/ * *
* AES Encrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _aes _enc : function ( input , args ) {
return Cipher . _enc ( CryptoJS . AES , input , args ) ;
} ,
/ * *
* AES Decrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _aes _dec : function ( input , args ) {
return Cipher . _dec ( CryptoJS . AES , input , args ) ;
} ,
/ * *
* DES Encrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _des _enc : function ( input , args ) {
return Cipher . _enc ( CryptoJS . DES , input , args ) ;
} ,
/ * *
* DES Decrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _des _dec : function ( input , args ) {
return Cipher . _dec ( CryptoJS . DES , input , args ) ;
} ,
/ * *
* Triple DES Encrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _triple _des _enc : function ( input , args ) {
return Cipher . _enc ( CryptoJS . TripleDES , input , args ) ;
} ,
/ * *
* Triple DES Decrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _triple _des _dec : function ( input , args ) {
return Cipher . _dec ( CryptoJS . TripleDES , input , args ) ;
} ,
/ * *
* Rabbit Encrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _rabbit _enc : function ( input , args ) {
return Cipher . _enc ( CryptoJS . Rabbit , input , args ) ;
} ,
/ * *
* Rabbit Decrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _rabbit _dec : function ( input , args ) {
return Cipher . _dec ( CryptoJS . Rabbit , input , args ) ;
} ,
/ * *
* @ constant
* @ default
* /
BLOWFISH _MODES : [ "ECB" , "CBC" , "PCBC" , "CFB" , "OFB" , "CTR" ] ,
/ * *
* @ constant
* @ default
* /
BLOWFISH _OUTPUT _TYPES : [ "Base64" , "Hex" , "String" , "Raw" ] ,
/ * *
* Blowfish Encrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _blowfish _enc : function ( input , args ) {
var key = Utils . format [ args [ 0 ] . option ] . parse ( args [ 0 ] . string ) . toString ( Utils . format . Latin1 ) ,
mode = args [ 1 ] ,
output _format = args [ 2 ] ;
if ( key . length === 0 ) return "Enter a key" ;
var enc _hex = blowfish . encrypt ( input , key , {
outputType : 1 ,
cipherMode : Cipher . BLOWFISH _MODES . indexOf ( mode )
} ) ,
enc = CryptoJS . enc . Hex . parse ( enc _hex ) ;
return enc . toString ( Utils . format [ output _format ] ) ;
} ,
/ * *
* Blowfish Decrypt operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _blowfish _dec : function ( input , args ) {
var key = Utils . format [ args [ 0 ] . option ] . parse ( args [ 0 ] . string ) . toString ( Utils . format . Latin1 ) ,
mode = args [ 1 ] ,
input _format = args [ 2 ] ;
if ( key . length === 0 ) return "Enter a key" ;
input = Utils . format [ input _format ] . parse ( input ) ;
return blowfish . decrypt ( input . toString ( CryptoJS . enc . Base64 ) , key , {
outputType : 0 , // This actually means inputType. The library is weird.
cipherMode : Cipher . BLOWFISH _MODES . indexOf ( mode )
} ) ;
} ,
/ * *
* @ constant
* @ default
* /
KDF _KEY _SIZE : 256 ,
/ * *
* @ constant
* @ default
* /
KDF _ITERATIONS : 1 ,
/ * *
* Derive PBKDF2 key operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _pbkdf2 : function ( input , args ) {
var key _size = args [ 0 ] / 32 ,
iterations = args [ 1 ] ,
salt = CryptoJS . enc . Hex . parse ( args [ 2 ] || "" ) ,
input _format = args [ 3 ] ,
output _format = args [ 4 ] ,
passphrase = Utils . format [ input _format ] . parse ( input ) ,
key = CryptoJS . PBKDF2 ( passphrase , salt , { keySize : key _size , iterations : iterations } ) ;
return key . toString ( Utils . format [ output _format ] ) ;
} ,
/ * *
* Derive EVP key operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _evpkdf : function ( input , args ) {
var key _size = args [ 0 ] / 32 ,
iterations = args [ 1 ] ,
salt = CryptoJS . enc . Hex . parse ( args [ 2 ] || "" ) ,
input _format = args [ 3 ] ,
output _format = args [ 4 ] ,
passphrase = Utils . format [ input _format ] . parse ( input ) ,
key = CryptoJS . EvpKDF ( passphrase , salt , { keySize : key _size , iterations : iterations } ) ;
return key . toString ( Utils . format [ output _format ] ) ;
} ,
/ * *
* RC4 operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _rc4 : function ( input , args ) {
var message = Utils . format [ args [ 1 ] ] . parse ( input ) ,
passphrase = Utils . format [ args [ 0 ] . option ] . parse ( args [ 0 ] . string ) ,
encrypted = CryptoJS . RC4 . encrypt ( message , passphrase ) ;
return encrypted . ciphertext . toString ( Utils . format [ args [ 2 ] ] ) ;
} ,
/ * *
* @ constant
* @ default
* /
RC4DROP _BYTES : 768 ,
/ * *
* RC4 Drop operation .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _rc4drop : function ( input , args ) {
var message = Utils . format [ args [ 1 ] ] . parse ( input ) ,
passphrase = Utils . format [ args [ 0 ] . option ] . parse ( args [ 0 ] . string ) ,
drop = args [ 3 ] ,
encrypted = CryptoJS . RC4Drop . encrypt ( message , passphrase , { drop : drop } ) ;
return encrypted . ciphertext . toString ( Utils . format [ args [ 2 ] ] ) ;
} ,
2016-12-03 20:54:28 +00:00
/ * *
* @ constant
* @ default
* /
VIG _ENC _KEY : "cipher" ,
/ * *
* Vigenere cipher encode .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _vigenc : function ( input , args ) {
var alphabet = "abcdefghijklmnopqrstuvwxyz" ,
keyword = args [ 0 ] . toLowerCase ( ) ,
output = "" ,
fail = 0 ,
keyIndex ,
msgIndex ,
chr ;
if ( keyword ) {
if ( /^[a-zA-Z]+$/ . test ( keyword ) ) {
for ( var i = 0 ; i < input . length ; i ++ ) {
if ( alphabet . indexOf ( input [ i ] ) >= 0 ) {
chr = keyword [ ( i - fail ) % keyword . length ] ; //Gets the corresponding character of keyword for current letter, accounting for chars not in alphabet
keyIndex = alphabet . indexOf ( chr ) ; //Gets location in vigenere square of keyword char
msgIndex = alphabet . indexOf ( input [ i ] ) ; //Gets location in vigenere square of message char
output += alphabet [ ( keyIndex + msgIndex ) % 26 ] ; //Gets encoded letter by finding sum of indexes modulo 26 and finding the letter corresponding to that
} else if ( alphabet . indexOf ( input [ i ] . toLowerCase ( ) ) >= 0 ) {
chr = keyword [ ( i - fail ) % keyword . length ] . toLowerCase ( ) ;
keyIndex = alphabet . indexOf ( chr ) ;
msgIndex = alphabet . indexOf ( input [ i ] . toLowerCase ( ) ) ;
output += alphabet [ ( keyIndex + msgIndex ) % 26 ] . toUpperCase ( ) ;
} else {
output += input [ i ] ;
2016-12-03 21:33:19 +00:00
fail ++ ;
2016-12-03 20:54:28 +00:00
}
}
} else {
throw "Keyword can only consist of letters." ;
}
} else {
throw "A keyword is required." ;
}
return output ;
} ,
/ * *
* @ constant
* @ default
* /
VIG _DEC _KEY : "cipher" ,
/ * *
* Vigenere cipher decode .
*
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run _vigdec : function ( input , args ) {
var alphabet = "abcdefghijklmnopqrstuvwxyz" ,
keyword = args [ 0 ] . toLowerCase ( ) ,
output = "" ,
fail = 0 ,
keyIndex ,
msgIndex ,
chr ;
if ( keyword ) {
if ( /^[a-zA-Z]+$/ . test ( keyword ) ) {
for ( var i = 0 ; i < input . length ; i ++ ) {
if ( alphabet . indexOf ( input [ i ] ) >= 0 ) {
chr = keyword [ ( i - fail ) % keyword . length ] ;
keyIndex = alphabet . indexOf ( chr ) ;
msgIndex = alphabet . indexOf ( input [ i ] ) ;
output += alphabet [ ( msgIndex - keyIndex + alphabet . length ) % 26 ] ; //subtract indexes from each other, add 26 just in case the value is negative, modulo to remove if neccessary
} else if ( alphabet . indexOf ( input [ i ] . toLowerCase ( ) ) >= 0 ) {
chr = keyword [ ( i - fail ) % keyword . length ] . toLowerCase ( ) ;
keyIndex = alphabet . indexOf ( chr ) ;
msgIndex = alphabet . indexOf ( input [ i ] . toLowerCase ( ) ) ;
output += alphabet [ ( msgIndex + alphabet . length - keyIndex ) % 26 ] . toUpperCase ( ) ;
} else {
output += input [ i ] ;
2016-12-03 21:33:19 +00:00
fail ++ ;
2016-12-03 20:54:28 +00:00
}
}
} else {
throw "Keyword can only consist of letters." ;
}
} else {
throw "A keyword is required." ;
}
return output ;
}
2016-11-28 10:42:58 +00:00
} ;
/ * *
* Overwriting the CryptoJS OpenSSL key derivation function so that it is possible to not pass a
* salt in .
* @ param { string } password - The password to derive from .
* @ param { number } keySize - The size in words of the key to generate .
* @ param { number } ivSize - The size in words of the IV to generate .
* @ param { WordArray | string } salt ( Optional ) A 64 - bit salt to use . If omitted , a salt will be
* generated randomly . If set to false , no salt will be added .
*
* @ returns { CipherParams } A cipher params object with the key , IV , and salt .
*
* @ static
*
* @ example
* // Randomly generates a salt
* var derivedParams = CryptoJS . kdf . OpenSSL . execute ( 'Password' , 256 / 32 , 128 / 32 ) ;
* // Uses the salt 'saltsalt'
* var derivedParams = CryptoJS . kdf . OpenSSL . execute ( 'Password' , 256 / 32 , 128 / 32 , 'saltsalt' ) ;
* // Does not use a salt
* var derivedParams = CryptoJS . kdf . OpenSSL . execute ( 'Password' , 256 / 32 , 128 / 32 , false ) ;
* /
CryptoJS . kdf . OpenSSL . execute = function ( password , keySize , ivSize , salt ) {
// Generate random salt if no salt specified and not set to false
// This line changed from `if (!salt) {` to the following
if ( salt === undefined || salt === null ) {
salt = CryptoJS . lib . WordArray . random ( 64 / 8 ) ;
}
// Derive key and IV
var key = CryptoJS . algo . EvpKDF . create ( { keySize : keySize + ivSize } ) . compute ( password , salt ) ;
// Separate key and IV
var iv = CryptoJS . lib . WordArray . create ( key . words . slice ( keySize ) , ivSize * 4 ) ;
key . sigBytes = keySize * 4 ;
// Return params
return CryptoJS . lib . CipherParams . create ( { key : key , iv : iv , salt : salt } ) ;
} ;