KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > SnowMailClient > crypto > Utilities


1 package SnowMailClient.crypto;
2
3 import snow.crypto.*;
4 import sun.misc.BASE64Encoder;
5 import sun.misc.BASE64Decoder;
6
7 import java.io.*;
8 import java.math.*;
9 import java.net.*;
10
11 import java.security.*;
12 import java.security.spec.*;
13 import javax.crypto.spec.*;
14 import javax.crypto.*;
15
16 /** specific to snowmail
17 */

18 public final class Utilities
19 {
20    public static final SecureRandom secureRandom = new SecureRandom();
21
22    /** This create a SHA-1 160 bit hashcode (message digest) of the given password
23        @return the hashed password, in base64 format or null if a the hash could not be performed
24    */

25    public static String JavaDoc hashPassword( String JavaDoc thePassword )
26    {
27       return encodeSingleLineBase64( CryptoUtilities.SHA1Hash(thePassword.getBytes()));
28    }
29
30    /** a base64 sha-1 hash is 28 chars long and ends with a '=',
31     * @return true if the passed string is in this "format",
32     * this condition is necesssary but not sufficient,
33     * we do not test that all chars are in the base64 base...
34     * this method is just here to avoid rehashing hashs in the
35     * gui password input fields...
36     */

37    public static boolean isValidHashPasswordFormat(String JavaDoc hash)
38    {
39       if(hash.length()!=28) return false;
40       if(hash.charAt(27)!='=') return false;
41       return true;
42    }
43
44
45    /** BE CAREFUL, normally, Base64 make lines of 76 chars max and add
46     * cariage returns !, we remove them, because data is sent with
47     * println, 1 command per line and these \n here will break our
48     * commands
49     */

50     public static String JavaDoc encodeSingleLineBase64(byte bytes[])
51     {
52         BASE64Encoder enc = new BASE64Encoder();
53         //System.out.println("BASE64 encoder bytes per line="+ enc.bytesPerLine());
54
String JavaDoc base64 = enc.encode(bytes);
55         return suppressLineFeeds(base64);
56     }
57
58
59    /** BE CAREFUL, normally, Base64 make lines of 76 chars max and add
60     * cariage returns ! here they are present...
61     * use EncodeSingleLineBase64 to ensure sending single lines...
62     */

63     public static String JavaDoc encodeBase64(byte bytes[])
64     {
65         BASE64Encoder enc = new BASE64Encoder();
66         //System.out.println("BASE64 encoder bytes per line="+ enc.bytesPerLine());
67
String JavaDoc base64 = enc.encode(bytes);
68         return base64;
69     }
70
71
72     public static String JavaDoc suppressLineFeeds(String JavaDoc in)
73     {
74         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
75         for(int i=0; i<in.length(); i++)
76         {
77             char c = in.charAt(i);
78             if(c !='\n' && c != '\r') sb.append(c);
79         }
80         return sb.toString();
81     }
82
83     public static byte[] decodeBase64(String JavaDoc coded)
84         throws IOException
85     {
86         BASE64Decoder dec = new BASE64Decoder();
87         byte original[] = null;
88         original = dec.decodeBuffer(new ByteArrayInputStream(coded.getBytes()));
89         return original;
90     }
91
92
93   public static String JavaDoc stringReplace(String JavaDoc s, String JavaDoc replace, String JavaDoc n)
94   {
95      StringBuffer JavaDoc str = new StringBuffer JavaDoc(s);
96      int pos = -1;
97      while( (pos=s.indexOf(replace,pos+1)) >= 0 )
98      { // Make your replace here
99
str.replace(pos, pos+replace.length(), n);
100         s = str.toString();
101      }
102      return s;
103   }
104
105
106   /**
107    * encrypt a single line/message in
108    * Base64encoder explicitely puts line feeds each 78 chars.
109    * This is bad for our purpose here we just wand to encrypt a SINGLE line and
110    * send it through a printWriter...
111    * additional line feed would destroy our synchronous data handshake
112    * with the server. So we removed the line feeds...
113    */

114   public static String JavaDoc encryptSingleLineBlowfishFormat64(String JavaDoc mess, byte[] pass) throws Exception JavaDoc
115   {
116       // free mode
117
/*
118       FreeCipher fc = new ECBCipher( new BlowfishBase(pass), new PKCS5Padding() );
119       fc.setMode(FreeCipher.ENCRYPT_MODE);
120       */

121
122       // JDK mode (requires unrestricted policy)
123
Cipher fc = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
124       SecretKeySpec skeySpec = new SecretKeySpec(pass, "Blowfish");
125       fc.init(Cipher.ENCRYPT_MODE, skeySpec);
126
127       return encodeSingleLineBase64(fc.doFinal(mess.getBytes()));
128   }
129
130   /**
131    * decrypt a single line/message in
132    */

133   public static String JavaDoc decryptSingleLineBlowfishFormat64(String JavaDoc mess, byte[] pass) throws Exception JavaDoc
134   {
135      /* free mode
136       FreeCipher fc = new ECBCipher( new BlowfishBase(pass), new PKCS5Padding() );
137       fc.setMode(FreeCipher.DECRYPT_MODE);
138      */

139
140       // JDK mode (requires unrestricted policy)
141
Cipher fc = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
142       SecretKeySpec skeySpec = new SecretKeySpec(pass, "Blowfish");
143       fc.init(Cipher.DECRYPT_MODE, skeySpec);
144
145       return new String JavaDoc(fc.doFinal(decodeBase64(mess)));
146   }
147
148
149     //
150
// some byte array utils
151
//
152

153   /** @return {a0, a1, ..., an, b0, b1, ..., bm}
154    * the elements of the n length array a and m length array b.
155    */

156   public static byte[] concatenate(byte[] a, byte[] b)
157   {
158       byte[] c = new byte[a.length+b.length];
159       // copy a
160
for(int i=0; i<a.length; i++)
161       {
162           c[i]=a[i];
163       }
164       //copy b
165
int lena = a.length;
166       for(int i=0; i<b.length; i++)
167       {
168           c[i+lena] = b[i];
169       }
170       return c;
171   }
172
173  public static String JavaDoc printBytes(byte[] b)
174  {
175     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
176     for(int i=0; i<b.length; i++)
177     {
178        sb.append(" ");
179        int val = (int)b[i];
180        if(Math.abs(val)<10) sb.append(" ");
181        if(Math.abs(val)<100) sb.append(" ");
182        if(val>=0) sb.append(" ");
183        sb.append((int)b[i]);
184        if(i%20==19) sb.append("\n");
185     }
186     return sb.toString();
187  }
188
189  public static byte[] extract(byte[] b, int off, int len)
190  {
191     byte[] rep = new byte[len];
192     for(int i=0; i<len; i++)
193     {
194        rep[i] = b[i+off];
195     }
196     return rep;
197  }
198
199
200
201     /** @return a random big number, not prime...
202      * very good for blowfish,
203      * but not for RSA that require quasi prime numbers.
204      */

205     public static BigInteger generateRandomBlowfishSecretKey(int bitlen)
206     {
207        return new BigInteger(bitlen, secureRandom);
208     }
209
210
211     /** CRAM-MD5 as described in rfc2195
212       compute
213          hash = H( k XOR opad, H( k XOR ipad, b));
214       return
215          base64( username + " " + hash_hex )
216     */

217     public static String JavaDoc HMAC_KEYED_CRAM_MD5(byte[] _key, byte[] b, String JavaDoc username)
218     {
219        byte[] key = _key;
220        if(key.length>64)
221        {
222          key = CryptoUtilities.hashMD5(key);
223        }
224
225        byte[] ipad = new byte[64];
226        byte[] opad = new byte[64];
227
228        for(int i=0; i<64; i++)
229        {
230           ipad[i] = 0x36;
231           opad[i] = 0x5C;
232        }
233        byte[] hash = CryptoUtilities.hashMD5(
234                       concatenate( XOR(opad,key),
235                                    CryptoUtilities.hashMD5( concatenate( XOR(ipad,key), b ) )
236                       ));
237
238        return encodeSingleLineBase64((username+" "+asHex(hash)).getBytes());
239     }
240
241
242
243   /**
244    */

245   public static String JavaDoc asHex (byte[] bytes)
246   {
247     StringBuffer JavaDoc buf = new StringBuffer JavaDoc(2*bytes.length);
248
249     for(int i = 0; i < bytes.length; i++)
250     {
251       if (((int) bytes[i] & 0xff) < 0x10)
252       {
253         buf.append("0");
254       }
255       buf.append(Long.toString((int) bytes[i] & 0xff, 16));
256     }
257     return buf.toString();
258   }
259
260
261     /** a length should be greater then b length,
262       if b length is smaller then a length, missing b elements are handled as zero bytes
263       @return an a length byte array
264     */

265     public static byte[] XOR(byte[] a, byte[] b)
266     {
267        if(a.length < b.length)
268        {
269          throw new RuntimeException JavaDoc("Bad lengths la<lb, a="+a.length+", b="+b.length);
270        }
271
272        byte[] rep = a.clone();
273        for(int i=0; i<b.length; i++)
274        {
275           rep[i] = (byte) (a[i] ^ b[i]);
276        }
277        return rep;
278     }
279
280
281
282 }
Popular Tags