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