2 * This file is part of NeverNote
\r
3 * Copyright 2009 Randy Baumgarte
\r
5 * This file may be licensed under the terms of of the
\r
6 * GNU General Public License Version 2 (the ``GPL'').
\r
8 * Software distributed under the License is distributed
\r
9 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
\r
10 * express or implied. See the GPL for the specific language
\r
11 * governing rights and limitations.
\r
13 * You should have received a copy of the GPL along with this
\r
14 * program. If not, go to http://www.gnu.org/licenses/gpl.html
\r
15 * or write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
19 package cx.fbn.nevernote.evernote;
\r
21 //**********************************************
\r
22 //**********************************************
\r
23 //* Utility used to encript or decrypt the
\r
25 //**********************************************
\r
26 //**********************************************
\r
28 import java.io.IOException;
\r
29 import java.security.InvalidAlgorithmParameterException;
\r
30 import java.security.InvalidKeyException;
\r
31 import java.security.MessageDigest;
\r
32 import java.security.NoSuchAlgorithmException;
\r
33 import java.util.zip.CRC32;
\r
35 import javax.crypto.BadPaddingException;
\r
36 import javax.crypto.Cipher;
\r
37 import javax.crypto.IllegalBlockSizeException;
\r
38 import javax.crypto.NoSuchPaddingException;
\r
39 import javax.crypto.spec.RC2ParameterSpec;
\r
40 import javax.crypto.spec.SecretKeySpec;
\r
42 import cx.fbn.nevernote.utilities.Base64;
\r
44 public class EnCrypt {
\r
46 // Convert a string of text to a hex string
\r
47 public static String asHex (byte buf[]) {
\r
48 StringBuffer strbuf = new StringBuffer(buf.length * 2);
\r
51 for (i = 0; i < buf.length; i++) {
\r
52 if ((buf[i] & 0xff) < 0x10)
\r
55 strbuf.append(Long.toString(buf[i] & 0xff, 16));
\r
58 return strbuf.toString();
\r
60 // Encrypte the text and return the base64 string
\r
61 public String encrypt(String text, String passphrase, int keylen) {
\r
62 RC2ParameterSpec parm = new RC2ParameterSpec(keylen);
\r
65 int len = text.length()+4;
\r
68 for (; mod !=0; len++) {
\r
74 StringBuffer textBuffer = new StringBuffer(text);
\r
75 textBuffer.setLength(len);
\r
76 // Get a MD5 for the passphrase
\r
77 md = MessageDigest.getInstance("MD5");
\r
78 md.update(passphrase.getBytes());
\r
80 // Setup parms for the cipher
\r
81 SecretKeySpec skeySpec = new SecretKeySpec(md.digest(), "RC2");
\r
82 Cipher cipher = Cipher.getInstance("RC2/ECB/NoPadding");
\r
83 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, parm);
\r
84 String encoded = crcHeader(textBuffer.toString()) +textBuffer;
\r
85 byte[] d = cipher.doFinal(encoded.getBytes());
\r
86 return Base64.encodeBytes(d);
\r
87 } catch (NoSuchAlgorithmException e) {
\r
88 e.printStackTrace();
\r
89 } catch (NoSuchPaddingException e) {
\r
90 e.printStackTrace();
\r
91 } catch (InvalidKeyException e) {
\r
92 e.printStackTrace();
\r
93 } catch (InvalidAlgorithmParameterException e) {
\r
94 e.printStackTrace();
\r
95 } catch (IllegalBlockSizeException e) {
\r
96 e.printStackTrace();
\r
97 } catch (BadPaddingException e) {
\r
98 e.printStackTrace();
\r
103 // Decrypt the base64 text and return the unsecure text
\r
104 public String decrypt(String text, String passphrase, int keylen) {
\r
105 RC2ParameterSpec parm = new RC2ParameterSpec(keylen);
\r
108 // Get a MD5 for the passphrase
\r
109 md = MessageDigest.getInstance("MD5");
\r
110 StringBuffer p = new StringBuffer(passphrase);
\r
111 md.update(p.toString().getBytes());
\r
113 // Setup parms for the cipher
\r
114 SecretKeySpec skeySpec = new SecretKeySpec(md.digest(), "RC2");
\r
115 Cipher cipher = Cipher.getInstance("RC2/ECB/NOPADDING");
\r
116 cipher.init(Cipher.DECRYPT_MODE, skeySpec, parm);
\r
118 // Decode the encrypted text and decrypt
\r
119 byte[] dString = Base64.decode(text);
\r
120 byte[] d = cipher.doFinal(dString);
\r
122 // We have a result. Separate it into the 4 byte header and the decrypted text
\r
123 StringBuffer buffer = new StringBuffer(new String(d));
\r
124 String cryptCRC = buffer.substring(0,4);
\r
125 String clearText = buffer.substring(4);
\r
126 String realCRC = crcHeader(clearText);
\r
127 // We need to get the real CRC of the decrypted text
\r
128 if (realCRC.equalsIgnoreCase(cryptCRC)) {
\r
129 int endPos = clearText.length();
\r
130 for (int i=buffer.length()-1; i>=0; i--) {
\r
131 if (buffer.charAt(i) == 0)
\r
136 clearText = clearText.substring(0,endPos);
\r
139 } catch (NoSuchAlgorithmException e) {
\r
140 e.printStackTrace();
\r
141 } catch (NoSuchPaddingException e) {
\r
142 e.printStackTrace();
\r
143 } catch (InvalidKeyException e) {
\r
144 e.printStackTrace();
\r
145 } catch (InvalidAlgorithmParameterException e) {
\r
146 e.printStackTrace();
\r
147 } catch (IllegalBlockSizeException e) {
\r
148 e.printStackTrace();
\r
149 } catch (BadPaddingException e) {
\r
150 e.printStackTrace();
\r
151 } catch (IOException e) {
\r
152 // TODO Auto-generated catch block
\r
153 e.printStackTrace();
\r
157 // Utility function to return the CRC header of an encoded string. This is
\r
158 // used to verify good decryption and put in front of a new encrypted string
\r
159 private String crcHeader(String text) {
\r
160 CRC32 crc = new CRC32();
\r
161 crc.update(text.getBytes());
\r
162 int realCRC = (int)crc.getValue();
\r
164 // The first 4 chars of the hex string will equal the first
\r
165 // 4 chars of the decyphered text. If they match we have a
\r
166 // good password. This is what we return
\r
167 realCRC = realCRC ^ (-1);
\r
168 realCRC = realCRC >>> 0;
\r
169 String hexCRC = Integer.toHexString(realCRC).substring(0,4);
\r
170 return hexCRC.toString().toUpperCase();
\r