001 package railo.runtime.crypt; 002 003 import java.util.Random; 004 005 //package maddany.crypto; 006 007 008 009 /* Coding by maddany@madloutre.org 010 011 * 01-01-2000 012 013 * 014 015 * This program is free software; you can redistribute it and/or modify 016 017 * it under the terms of the GNU General Public License as published by 018 019 * the Free Software Foundation; either version 2 of the License, or 020 021 * (at your option) any later version. 022 023 * 024 025 * This program is distributed in the hope that it will be useful, 026 027 * but WITHOUT ANY WARRANTY; without even the implied warranty of 028 029 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 030 031 * GNU General Public License for more details. 032 033 * 034 035 * You should have received a copy of the GNU General Public License 036 037 * along with this program; if not, write to the Free Software 038 039 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 040 041 * 042 043 */ 044 045 046 047 048 049 050 051 052 public final class BlowfishEasy { 053 054 055 056 057 058 // the Blowfish CBC instance 059 060 BlowfishCBC m_bfish; 061 062 063 064 // one random generator for all simple callers... 065 066 static Random m_rndGen; 067 068 069 070 // ...and created early 071 072 static { 073 074 m_rndGen = new Random(); 075 076 }; 077 078 079 080 081 082 083 084 /** 085 086 * constructor to set up a string as the key (oversized password will be cut) 087 088 * @param sPassword the password (treated as a real unicode array) 089 090 */ 091 092 public BlowfishEasy(String sPassword) { 093 094 095 096 // hash down the password to a 160bit key 097 098 SHA1 hasher = new SHA1(); 099 100 hasher.update(sPassword); 101 102 hasher.finalize(); 103 104 105 106 // setup the encryptor (use a dummy IV) 107 108 m_bfish = new BlowfishCBC(hasher.getDigest(), 0); 109 110 hasher.clear(); 111 112 }; 113 114 115 116 117 118 119 120 /** 121 122 * encrypts a string (treated in UNICODE) using the 123 124 * standard Java random generator, which isn't that 125 126 * great for creating IVs 127 128 * @param sPlainText string to encrypt 129 130 * @return encrypted string in binhex format 131 132 */ 133 134 public String encryptString(String sPlainText) { 135 136 137 138 // get the IV 139 140 long lCBCIV; 141 142 synchronized (m_rndGen) { 143 144 lCBCIV = m_rndGen.nextLong(); 145 146 } 147 148 149 150 // map the call; 151 152 return encStr(sPlainText, lCBCIV); 153 154 }; 155 156 157 158 159 160 161 162 /** 163 164 * encrypts a string (treated in UNICODE) 165 166 * @param sPlainText string to encrypt 167 168 * @param rndGen random generator (usually a java.security.SecureRandom instance) 169 170 * @return encrypted string in binhex format 171 172 */ 173 174 public String encryptString(String sPlainText, 175 176 Random rndGen) { 177 178 179 180 // get the IV 181 182 long lCBCIV = rndGen.nextLong(); 183 184 185 186 // map the call; 187 188 return encStr(sPlainText, lCBCIV); 189 190 }; 191 192 193 194 195 196 197 198 // internal routine for string encryption 199 200 201 202 private String encStr(String sPlainText, 203 204 long lNewCBCIV) { 205 206 207 208 // allocate the buffer (align to the next 8 byte border plus padding) 209 210 int nStrLen = sPlainText.length(); 211 212 byte[] buf = new byte [((nStrLen << 1) & 0xfffffff8) + 8]; 213 214 215 216 // copy all bytes of the string into the buffer (use network byte order) 217 218 int nI; 219 220 int nPos = 0; 221 222 for (nI = 0; nI < nStrLen; nI++) { 223 224 char cActChar = sPlainText.charAt(nI); 225 226 buf[nPos++] = (byte) ((cActChar >> 8) & 0x0ff); 227 228 buf[nPos++] = (byte) (cActChar & 0x0ff) ; 229 230 }; 231 232 233 234 // pad the rest with the PKCS5 scheme 235 236 byte bPadVal = (byte)(buf.length - (nStrLen << 1)); 237 238 while (nPos < buf.length) 239 240 buf[nPos++] = bPadVal; 241 242 243 244 // create the encryptor 245 246 m_bfish.setCBCIV(lNewCBCIV); 247 248 249 250 // encrypt the buffer 251 252 m_bfish.encrypt(buf); 253 254 255 256 // return the binhex string 257 258 byte[] newCBCIV = new byte[BlowfishECB.BLOCKSIZE]; 259 260 BinConverter.longToByteArray(lNewCBCIV, 261 262 newCBCIV, 263 264 0); 265 266 return BinConverter.bytesToBinHex(newCBCIV, 267 268 0, 269 270 BlowfishECB.BLOCKSIZE) + 271 272 BinConverter.bytesToBinHex(buf, 273 274 0, 275 276 buf.length); 277 278 }; 279 280 281 282 283 284 /** 285 286 * decrypts a hexbin string (handling is case sensitive) 287 288 * @param sCipherText hexbin string to decrypt 289 290 * @return decrypted string (null equals an error) 291 292 */ 293 294 public String decryptString(String sCipherText) { 295 296 297 298 // get the number of estimated bytes in the string (cut off broken blocks) 299 300 int nLen = (sCipherText.length() >> 1) & ~7; 301 302 303 304 // does the given stuff make sense (at least the CBC IV)? 305 306 if (nLen < BlowfishECB.BLOCKSIZE) 307 308 return null; 309 310 311 312 // get the CBC IV 313 314 byte[] cbciv = new byte[BlowfishECB.BLOCKSIZE]; 315 316 int nNumOfBytes = BinConverter.binHexToBytes(sCipherText, 317 318 cbciv, 319 320 0, 321 322 0, 323 324 BlowfishECB.BLOCKSIZE); 325 326 if (nNumOfBytes < BlowfishECB.BLOCKSIZE) 327 328 return null; 329 330 // (got it) 331 332 m_bfish.setCBCIV(cbciv); 333 334 335 336 // something left to decrypt? 337 338 nLen -= BlowfishECB.BLOCKSIZE; 339 340 if (nLen == 0) 341 342 return ""; 343 344 345 346 // get all data bytes now 347 348 byte[] buf = new byte[nLen]; 349 350 nNumOfBytes = BinConverter.binHexToBytes(sCipherText, 351 352 buf, 353 354 BlowfishECB.BLOCKSIZE * 2, 355 356 0, 357 358 nLen); 359 360 361 362 // we cannot accept broken binhex sequences due to padding 363 364 // and decryption 365 366 if (nNumOfBytes < nLen) 367 368 return null; 369 370 371 372 // decrypt the buffer 373 374 m_bfish.decrypt(buf); 375 376 377 378 // get the last padding byte 379 380 int nPadByte = buf[buf.length - 1] & 0x0ff; 381 382 // ( try to get all information if the padding doesn't seem to be correct) 383 384 if ((nPadByte > 8) || (nPadByte < 0)) 385 386 nPadByte = 0; 387 388 389 390 // calculate the real size of this message 391 392 nNumOfBytes -= nPadByte; 393 394 if (nNumOfBytes < 0) 395 396 return ""; 397 398 399 400 // success 401 402 return BinConverter.byteArrayToUNCString(buf, 0, nNumOfBytes); 403 404 }; 405 406 407 408 409 410 /** 411 412 * destroys (clears) the encryption engine, 413 414 * after that the instance is not valid anymore 415 416 */ 417 418 public void destroy() { 419 420 m_bfish.cleanUp(); 421 422 }; 423 424 }; 425 426