package railo.runtime.security; import java.util.Random; import railo.runtime.crypt.BinConverter; import railo.runtime.crypt.BlowfishCBC; import railo.runtime.crypt.BlowfishECB; import railo.runtime.crypt.SHA1; /** * support class for easy string encryption with the Blowfish algorithm, * now in CBC mode with a SHA-1 key setup and correct padding */ public final class SerialDecoder { BlowfishCBC m_bfish; // one random generator for all simple callers... static Random m_rndGen; // ...and created early static { m_rndGen = new Random(); }; /** * constructor to set up a string as the key (oversized password will be cut) * @param sPassword the password (treated as a real unicode array) */ public SerialDecoder(String sPassword) { // hash down the password to a 160bit key SHA1 hasher = new SHA1(); hasher.update(sPassword); hasher.finalize(); // setup the encryptor (use a dummy IV) m_bfish = new BlowfishCBC(hasher.getDigest(), 0); hasher.clear(); }; /** * decrypts a hexbin string (handling is case sensitive) * @param sCipherText hexbin string to decrypt * @return decrypted string (null equals an error) */ public String decrypt(String sCipherText) { // get the number of estimated bytes in the string (cut off broken blocks) int nLen = (sCipherText.length() >> 1) & ~7; // does the given stuff make sense (at least the CBC IV)? if (nLen < BlowfishECB.BLOCKSIZE) return null; // get the CBC IV byte[] cbciv = new byte[BlowfishECB.BLOCKSIZE]; int nNumOfBytes = BinConverter.binHexToBytes(sCipherText, cbciv, 0, 0, BlowfishECB.BLOCKSIZE); if (nNumOfBytes < BlowfishECB.BLOCKSIZE) return null; // (got it) m_bfish.setCBCIV(cbciv); // something left to decrypt? nLen -= BlowfishECB.BLOCKSIZE; if (nLen == 0) return ""; // get all data bytes now byte[] buf = new byte[nLen]; nNumOfBytes = BinConverter.binHexToBytes(sCipherText, buf, BlowfishECB.BLOCKSIZE * 2, 0, nLen); // we cannot accept broken binhex sequences due to padding // and decryption if (nNumOfBytes < nLen) return null; // decrypt the buffer m_bfish.decrypt(buf); // get the last padding byte int nPadByte = buf[buf.length - 1] & 0x0ff; // ( try to get all information if the padding doesn't seem to be correct) if ((nPadByte > 8) || (nPadByte < 0)) nPadByte = 0; // calculate the real size of this message nNumOfBytes -= nPadByte; if (nNumOfBytes < 0) return ""; // success return BinConverter.byteArrayToUNCString(buf, 0, nNumOfBytes); }; /** * destroys (clears) the encryption engine, * after that the instance is not valid anymore */ public void destroy() { m_bfish.cleanUp(); }; };