includes/clientside/static/crypto.js
changeset 830 79fb483807f6
parent 712 331e009416d5
child 843 4415e50e4e84
equal deleted inserted replaced
829:87fcc7175c61 830:79fb483807f6
  1730     InverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1)));
  1730     InverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1)));
  1731   addRoundKey(block, expandedKey);
  1731   addRoundKey(block, expandedKey);
  1732   return unpackBytes(block);
  1732   return unpackBytes(block);
  1733 }
  1733 }
  1734 
  1734 
       
  1735 // This function packs an array of bytes into the four row form defined by
       
  1736 // Rijndael. It assumes the length of the array of bytes is divisible by
       
  1737 // four. Bytes are filled in according to the Rijndael spec (starting with
       
  1738 // column 0, row 0 to 3). This function returns a 2d array.
       
  1739 
       
  1740 function packBytes(octets) {
       
  1741   var state = new Array();
       
  1742   if (!octets || octets.length % 4)
       
  1743     return;
       
  1744 
       
  1745   state[0] = new Array();  state[1] = new Array(); 
       
  1746   state[2] = new Array();  state[3] = new Array();
       
  1747   for (var j=0; j<octets.length; j+= 4) {
       
  1748      state[0][j/4] = octets[j];
       
  1749      state[1][j/4] = octets[j+1];
       
  1750      state[2][j/4] = octets[j+2];
       
  1751      state[3][j/4] = octets[j+3];
       
  1752   }
       
  1753   return state;  
       
  1754 }
       
  1755 
       
  1756 // This function unpacks an array of bytes from the four row format preferred
       
  1757 // by Rijndael into a single 1d array of bytes. It assumes the input "packed"
       
  1758 // is a packed array. Bytes are filled in according to the Rijndael spec. 
       
  1759 // This function returns a 1d array of bytes.
       
  1760 
       
  1761 function unpackBytes(packed) {
       
  1762   var result = new Array();
       
  1763   for (var j=0; j<packed[0].length; j++) {
       
  1764     result[result.length] = packed[0][j];
       
  1765     result[result.length] = packed[1][j];
       
  1766     result[result.length] = packed[2][j];
       
  1767     result[result.length] = packed[3][j];
       
  1768   }
       
  1769   return result;
       
  1770 }
       
  1771 
       
  1772 // This function takes a prospective plaintext (string or array of bytes)
       
  1773 // and pads it with zero bytes if its length is not a multiple of the block 
       
  1774 // size. If plaintext is a string, it is converted to an array of bytes
       
  1775 // in the process. The type checking can be made much nicer using the 
       
  1776 // instanceof operator, but this operator is not available until IE5.0 so I 
       
  1777 // chose to use the heuristic below. 
       
  1778 
       
  1779 function formatPlaintext(plaintext) {
       
  1780   var bpb = blockSizeInBits / 8;               // bytes per block
       
  1781   var i;
       
  1782 
       
  1783   // if primitive string or String instance
       
  1784   if (typeof plaintext == "string" || plaintext.split) {
       
  1785     // alert('AUUGH you idiot it\'s NOT A STRING ITS A '+typeof(plaintext)+'!!!');
       
  1786     // return false;
       
  1787     plaintext = plaintext.split("");
       
  1788     // Unicode issues here (ignoring high byte)
       
  1789     for (i=0; i<plaintext.length; i++)
       
  1790       plaintext[i] = plaintext[i].charCodeAt(0) & 0xFF;
       
  1791   } 
       
  1792 
       
  1793   for (i = bpb - (plaintext.length % bpb); i > 0 && i < bpb; i--) 
       
  1794     plaintext[plaintext.length] = 0;
       
  1795   
       
  1796   return plaintext;
       
  1797 }
       
  1798 
       
  1799 // Returns an array containing "howMany" random bytes. YOU SHOULD CHANGE THIS
       
  1800 // TO RETURN HIGHER QUALITY RANDOM BYTES IF YOU ARE USING THIS FOR A "REAL"
       
  1801 // APPLICATION.
       
  1802 
       
  1803 function getRandomBytes(howMany) {
       
  1804   var i;
       
  1805   var bytes = new Array();
       
  1806   for (i=0; i<howMany; i++)
       
  1807     bytes[i] = Math.round(Math.random()*255);
       
  1808   return bytes;
       
  1809 }
       
  1810 
       
  1811 // rijndaelEncrypt(plaintext, key, mode)
       
  1812 // Encrypts the plaintext using the given key and in the given mode. 
       
  1813 // The parameter "plaintext" can either be a string or an array of bytes. 
       
  1814 // The parameter "key" must be an array of key bytes. If you have a hex 
       
  1815 // string representing the key, invoke hexToByteArray() on it to convert it 
       
  1816 // to an array of bytes. The third parameter "mode" is a string indicating
       
  1817 // the encryption mode to use, either "ECB" or "CBC". If the parameter is
       
  1818 // omitted, ECB is assumed.
       
  1819 // 
       
  1820 // An array of bytes representing the cihpertext is returned. To convert 
       
  1821 // this array to hex, invoke byteArrayToHex() on it. If you are using this 
       
  1822 // "for real" it is a good idea to change the function getRandomBytes() to 
       
  1823 // something that returns truly random bits.
       
  1824 
       
  1825 function rijndaelEncrypt(plaintext, key, mode) {
       
  1826   var expandedKey, i, aBlock;
       
  1827   var bpb = blockSizeInBits / 8;          // bytes per block
       
  1828   var ct;                                 // ciphertext
       
  1829 
       
  1830   if (typeof plaintext != 'object' || typeof key != 'object')
       
  1831   {
       
  1832     alert( 'Invalid params\nplaintext: '+typeof(plaintext)+'\nkey: '+typeof(key) );
       
  1833     return false;
       
  1834   }
       
  1835   if (key.length*8 == keySizeInBits+8)
       
  1836     key.length = keySizeInBits / 8;
       
  1837   if (key.length*8 != keySizeInBits)
       
  1838   {
       
  1839     alert( 'Key length is bad!\nLength: '+key.length+'\nExpected: '+keySizeInBits / 8 );
       
  1840     return false;
       
  1841   }
       
  1842   if (mode == "CBC")
       
  1843     ct = getRandomBytes(bpb);             // get IV
       
  1844   else {
       
  1845     mode = "ECB";
       
  1846     ct = new Array();
       
  1847   }
       
  1848 
       
  1849   // convert plaintext to byte array and pad with zeros if necessary. 
       
  1850   plaintext = formatPlaintext(plaintext);
       
  1851 
       
  1852   expandedKey = keyExpansion(key);
       
  1853   
       
  1854   for (var block=0; block<plaintext.length / bpb; block++) {
       
  1855     aBlock = plaintext.slice(block*bpb, (block+1)*bpb);
       
  1856     if (mode == "CBC")
       
  1857       for (var i=0; i<bpb; i++) 
       
  1858         aBlock[i] ^= ct[block*bpb + i];
       
  1859     ct = ct.concat(encrypt(aBlock, expandedKey));
       
  1860   }
       
  1861 
       
  1862   return ct;
       
  1863 }
       
  1864 
       
  1865 // rijndaelDecrypt(ciphertext, key, mode)
       
  1866 // Decrypts the using the given key and mode. The parameter "ciphertext" 
       
  1867 // must be an array of bytes. The parameter "key" must be an array of key 
       
  1868 // bytes. If you have a hex string representing the ciphertext or key, 
       
  1869 // invoke hexToByteArray() on it to convert it to an array of bytes. The
       
  1870 // parameter "mode" is a string, either "CBC" or "ECB".
       
  1871 // 
       
  1872 // An array of bytes representing the plaintext is returned. To convert 
       
  1873 // this array to a hex string, invoke byteArrayToHex() on it. To convert it 
       
  1874 // to a string of characters, you can use byteArrayToString().
       
  1875 
       
  1876 function rijndaelDecrypt(ciphertext, key, mode) {
       
  1877   var expandedKey;
       
  1878   var bpb = blockSizeInBits / 8;          // bytes per block
       
  1879   var pt = new Array();                   // plaintext array
       
  1880   var aBlock;                             // a decrypted block
       
  1881   var block;                              // current block number
       
  1882 
       
  1883   if (!ciphertext || !key || typeof ciphertext == "string")
       
  1884     return;
       
  1885   if (key.length*8 != keySizeInBits)
       
  1886     return; 
       
  1887   if (!mode)
       
  1888     mode = "ECB";                         // assume ECB if mode omitted
       
  1889 
       
  1890   expandedKey = keyExpansion(key);
       
  1891  
       
  1892   // work backwards to accomodate CBC mode 
       
  1893   for (block=(ciphertext.length / bpb)-1; block>0; block--) {
       
  1894     aBlock = 
       
  1895      decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey);
       
  1896     if (mode == "CBC") 
       
  1897       for (var i=0; i<bpb; i++) 
       
  1898         pt[(block-1)*bpb + i] = aBlock[i] ^ ciphertext[(block-1)*bpb + i];
       
  1899     else 
       
  1900       pt = aBlock.concat(pt);
       
  1901   }
       
  1902 
       
  1903   // do last block if ECB (skips the IV in CBC)
       
  1904   if (mode == "ECB")
       
  1905     pt = decrypt(ciphertext.slice(0, bpb), expandedKey).concat(pt);
       
  1906 
       
  1907   return pt;
       
  1908 }
       
  1909 
  1735 // This method takes a byte array (byteArray) and converts it to a string by
  1910 // This method takes a byte array (byteArray) and converts it to a string by
  1736 // applying String.fromCharCode() to each value and concatenating the result.
  1911 // applying String.fromCharCode() to each value and concatenating the result.
  1737 // The resulting string is returned. Note that this function SKIPS zero bytes
  1912 // The resulting string is returned. Note that this function SKIPS zero bytes
  1738 // under the assumption that they are padding added in formatPlaintext().
  1913 // under the assumption that they are padding added in formatPlaintext().
  1739 // Obviously, do not invoke this method on raw data that can contain zero
  1914 // Obviously, do not invoke this method on raw data that can contain zero
  1740 // bytes. It is really only appropriate for printable ASCII/Latin-1 
  1915 // bytes. It is really only appropriate for printable ASCII/Latin-1 
  1741 // values. Roll your own function for more robust functionality :)
  1916 // values. Roll your own function for more robust functionality :)
  1742 
  1917 
  1743 function byteArrayToString(byteArray) {
  1918 function byteArrayToString(byteArray) {
  1744   var result = "";
  1919   var result = "";
  1745   for(var i=0; i<byteArray.length; i++)
  1920   for ( var i=0; i < byteArray.length; i++ )
  1746     if (byteArray[i] != 0) 
  1921     if (byteArray[i] != 0) 
  1747       result += String.fromCharCode(byteArray[i]);
  1922       result += '%' + byteArray[i].toString(16);
  1748   return result;
  1923   return decodeURIComponent(result);
  1749 }
  1924 }
  1750 
  1925 
  1751 // This function takes an array of bytes (byteArray) and converts them
  1926 // This function takes an array of bytes (byteArray) and converts them
  1752 // to a hexadecimal string. Array element 0 is found at the beginning of 
  1927 // to a hexadecimal string. Array element 0 is found at the beginning of 
  1753 // the resulting string, high nibble first. Consecutive elements follow
  1928 // the resulting string, high nibble first. Consecutive elements follow
  1790   }
  1965   }
  1791   //alert(bytes.toString());
  1966   //alert(bytes.toString());
  1792   return bytes;
  1967   return bytes;
  1793 }
  1968 }
  1794 
  1969 
  1795 // This function packs an array of bytes into the four row form defined by
       
  1796 // Rijndael. It assumes the length of the array of bytes is divisible by
       
  1797 // four. Bytes are filled in according to the Rijndael spec (starting with
       
  1798 // column 0, row 0 to 3). This function returns a 2d array.
       
  1799 
       
  1800 function packBytes(octets) {
       
  1801   var state = new Array();
       
  1802   if (!octets || octets.length % 4)
       
  1803     return;
       
  1804 
       
  1805   state[0] = new Array();  state[1] = new Array(); 
       
  1806   state[2] = new Array();  state[3] = new Array();
       
  1807   for (var j=0; j<octets.length; j+= 4) {
       
  1808      state[0][j/4] = octets[j];
       
  1809      state[1][j/4] = octets[j+1];
       
  1810      state[2][j/4] = octets[j+2];
       
  1811      state[3][j/4] = octets[j+3];
       
  1812   }
       
  1813   return state;  
       
  1814 }
       
  1815 
       
  1816 // This function unpacks an array of bytes from the four row format preferred
       
  1817 // by Rijndael into a single 1d array of bytes. It assumes the input "packed"
       
  1818 // is a packed array. Bytes are filled in according to the Rijndael spec. 
       
  1819 // This function returns a 1d array of bytes.
       
  1820 
       
  1821 function unpackBytes(packed) {
       
  1822   var result = new Array();
       
  1823   for (var j=0; j<packed[0].length; j++) {
       
  1824     result[result.length] = packed[0][j];
       
  1825     result[result.length] = packed[1][j];
       
  1826     result[result.length] = packed[2][j];
       
  1827     result[result.length] = packed[3][j];
       
  1828   }
       
  1829   return result;
       
  1830 }
       
  1831 
       
  1832 // This function takes a prospective plaintext (string or array of bytes)
       
  1833 // and pads it with zero bytes if its length is not a multiple of the block 
       
  1834 // size. If plaintext is a string, it is converted to an array of bytes
       
  1835 // in the process. The type checking can be made much nicer using the 
       
  1836 // instanceof operator, but this operator is not available until IE5.0 so I 
       
  1837 // chose to use the heuristic below. 
       
  1838 
       
  1839 function formatPlaintext(plaintext) {
       
  1840   var bpb = blockSizeInBits / 8;               // bytes per block
       
  1841   var i;
       
  1842 
       
  1843   // if primitive string or String instance
       
  1844   if (typeof plaintext == "string" || plaintext.split) {
       
  1845     // alert('AUUGH you idiot it\'s NOT A STRING ITS A '+typeof(plaintext)+'!!!');
       
  1846     // return false;
       
  1847     plaintext = plaintext.split("");
       
  1848     // Unicode issues here (ignoring high byte)
       
  1849     for (i=0; i<plaintext.length; i++)
       
  1850       plaintext[i] = plaintext[i].charCodeAt(0) & 0xFF;
       
  1851   } 
       
  1852 
       
  1853   for (i = bpb - (plaintext.length % bpb); i > 0 && i < bpb; i--) 
       
  1854     plaintext[plaintext.length] = 0;
       
  1855   
       
  1856   return plaintext;
       
  1857 }
       
  1858 
       
  1859 // Returns an array containing "howMany" random bytes. YOU SHOULD CHANGE THIS
       
  1860 // TO RETURN HIGHER QUALITY RANDOM BYTES IF YOU ARE USING THIS FOR A "REAL"
       
  1861 // APPLICATION.
       
  1862 
       
  1863 function getRandomBytes(howMany) {
       
  1864   var i;
       
  1865   var bytes = new Array();
       
  1866   for (i=0; i<howMany; i++)
       
  1867     bytes[i] = Math.round(Math.random()*255);
       
  1868   return bytes;
       
  1869 }
       
  1870 
       
  1871 // rijndaelEncrypt(plaintext, key, mode)
       
  1872 // Encrypts the plaintext using the given key and in the given mode. 
       
  1873 // The parameter "plaintext" can either be a string or an array of bytes. 
       
  1874 // The parameter "key" must be an array of key bytes. If you have a hex 
       
  1875 // string representing the key, invoke hexToByteArray() on it to convert it 
       
  1876 // to an array of bytes. The third parameter "mode" is a string indicating
       
  1877 // the encryption mode to use, either "ECB" or "CBC". If the parameter is
       
  1878 // omitted, ECB is assumed.
       
  1879 // 
       
  1880 // An array of bytes representing the cihpertext is returned. To convert 
       
  1881 // this array to hex, invoke byteArrayToHex() on it. If you are using this 
       
  1882 // "for real" it is a good idea to change the function getRandomBytes() to 
       
  1883 // something that returns truly random bits.
       
  1884 
       
  1885 function rijndaelEncrypt(plaintext, key, mode) {
       
  1886   var expandedKey, i, aBlock;
       
  1887   var bpb = blockSizeInBits / 8;          // bytes per block
       
  1888   var ct;                                 // ciphertext
       
  1889 
       
  1890   if (typeof plaintext != 'object' || typeof key != 'object')
       
  1891   {
       
  1892     alert( 'Invalid params\nplaintext: '+typeof(plaintext)+'\nkey: '+typeof(key) );
       
  1893     return false;
       
  1894   }
       
  1895   if (key.length*8 == keySizeInBits+8)
       
  1896     key.length = keySizeInBits / 8;
       
  1897   if (key.length*8 != keySizeInBits)
       
  1898   {
       
  1899     alert( 'Key length is bad!\nLength: '+key.length+'\nExpected: '+keySizeInBits / 8 );
       
  1900     return false;
       
  1901   }
       
  1902   if (mode == "CBC")
       
  1903     ct = getRandomBytes(bpb);             // get IV
       
  1904   else {
       
  1905     mode = "ECB";
       
  1906     ct = new Array();
       
  1907   }
       
  1908 
       
  1909   // convert plaintext to byte array and pad with zeros if necessary. 
       
  1910   plaintext = formatPlaintext(plaintext);
       
  1911 
       
  1912   expandedKey = keyExpansion(key);
       
  1913   
       
  1914   for (var block=0; block<plaintext.length / bpb; block++) {
       
  1915     aBlock = plaintext.slice(block*bpb, (block+1)*bpb);
       
  1916     if (mode == "CBC")
       
  1917       for (var i=0; i<bpb; i++) 
       
  1918         aBlock[i] ^= ct[block*bpb + i];
       
  1919     ct = ct.concat(encrypt(aBlock, expandedKey));
       
  1920   }
       
  1921 
       
  1922   return ct;
       
  1923 }
       
  1924 
       
  1925 // rijndaelDecrypt(ciphertext, key, mode)
       
  1926 // Decrypts the using the given key and mode. The parameter "ciphertext" 
       
  1927 // must be an array of bytes. The parameter "key" must be an array of key 
       
  1928 // bytes. If you have a hex string representing the ciphertext or key, 
       
  1929 // invoke hexToByteArray() on it to convert it to an array of bytes. The
       
  1930 // parameter "mode" is a string, either "CBC" or "ECB".
       
  1931 // 
       
  1932 // An array of bytes representing the plaintext is returned. To convert 
       
  1933 // this array to a hex string, invoke byteArrayToHex() on it. To convert it 
       
  1934 // to a string of characters, you can use byteArrayToString().
       
  1935 
       
  1936 function rijndaelDecrypt(ciphertext, key, mode) {
       
  1937   var expandedKey;
       
  1938   var bpb = blockSizeInBits / 8;          // bytes per block
       
  1939   var pt = new Array();                   // plaintext array
       
  1940   var aBlock;                             // a decrypted block
       
  1941   var block;                              // current block number
       
  1942 
       
  1943   if (!ciphertext || !key || typeof ciphertext == "string")
       
  1944     return;
       
  1945   if (key.length*8 != keySizeInBits)
       
  1946     return; 
       
  1947   if (!mode)
       
  1948     mode = "ECB";                         // assume ECB if mode omitted
       
  1949 
       
  1950   expandedKey = keyExpansion(key);
       
  1951  
       
  1952   // work backwards to accomodate CBC mode 
       
  1953   for (block=(ciphertext.length / bpb)-1; block>0; block--) {
       
  1954     aBlock = 
       
  1955      decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey);
       
  1956     if (mode == "CBC") 
       
  1957       for (var i=0; i<bpb; i++) 
       
  1958         pt[(block-1)*bpb + i] = aBlock[i] ^ ciphertext[(block-1)*bpb + i];
       
  1959     else 
       
  1960       pt = aBlock.concat(pt);
       
  1961   }
       
  1962 
       
  1963   // do last block if ECB (skips the IV in CBC)
       
  1964   if (mode == "ECB")
       
  1965     pt = decrypt(ciphertext.slice(0, bpb), expandedKey).concat(pt);
       
  1966 
       
  1967   return pt;
       
  1968 }
       
  1969 
       
  1970 function stringToByteArray(text)
  1970 function stringToByteArray(text)
  1971 {
  1971 {
  1972   result = new Array();
  1972   // Modified for Enano 2009-02-16 to be Unicode-safe
  1973   for ( i=0; i<text.length; i++ )
  1973   var result = new Array();
       
  1974   text = encodeURIComponent(text);
       
  1975   for ( var i = 0; i < text.length; i++ )
  1974   {
  1976   {
  1975     result[result.length] = text.charCodeAt(i);
  1977     var ch = text.charCodeAt(i);
       
  1978     var a = false;
       
  1979     if ( ch == 37 ) // "%"
       
  1980     {
       
  1981       var hexch = text.substr(i, 3);
       
  1982       if ( hexch.match(/^%[a-f0-9][a-f0-9]$/i) )
       
  1983       {
       
  1984         console.debug('hexch: ', hexch);
       
  1985         result[result.length] = (unescape(hexch)).charCodeAt(0);
       
  1986         a = true;
       
  1987         i += 2;
       
  1988       }
       
  1989     }
       
  1990     if ( !a )
       
  1991     {
       
  1992       result[result.length] = ch;
       
  1993     }
  1976   }
  1994   }
  1977   return result;
  1995   return result;
  1978 }
  1996 }
  1979 
  1997 
  1980 function aes_self_test()
  1998 function aes_self_test()