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() |