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