1 /* 2 * Created on 19-Jan-2006 3 * Created by Paul Gardner 4 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 */ 19 20 package com.aelitis.azureus.core.networkmanager.impl; 21 22 import java.io.IOException; 23 import java.nio.ByteBuffer; 24 import java.security.spec.AlgorithmParameterSpec; 25 26 import javax.crypto.Cipher; 27 import javax.crypto.spec.SecretKeySpec; 28 29 import org.gudy.azureus2.core3.util.Debug; 30 import org.gudy.bouncycastle.crypto.CipherParameters; 31 import org.gudy.bouncycastle.crypto.engines.RC4Engine; 32 import org.gudy.bouncycastle.crypto.params.KeyParameter; 33 34 public class 35 TransportCipher 36 { 37 private static boolean internal_rc4 = true; // force internal as we want 160 bit and JCE no supports it 38 39 private Cipher cipher; 40 private RC4Engine rc4_engine; 41 42 public TransportCipher( String algorithm, int mode, SecretKeySpec key_spec, AlgorithmParameterSpec params )43 TransportCipher( 44 String algorithm, 45 int mode, 46 SecretKeySpec key_spec, 47 AlgorithmParameterSpec params ) 48 49 throws Exception 50 { 51 cipher = Cipher.getInstance( algorithm ); 52 53 cipher.init( mode, key_spec, params ); 54 } 55 TransportCipher( String algorithm, int mode, SecretKeySpec key_spec )56 TransportCipher( 57 String algorithm, 58 int mode, 59 SecretKeySpec key_spec ) 60 61 throws Exception 62 { 63 if ( algorithm.equals( "RC4" )){ 64 65 if ( !internal_rc4 ){ 66 67 try{ 68 cipher = Cipher.getInstance( algorithm ); 69 70 cipher.init( mode, key_spec ); 71 72 }catch( Throwable e ){ 73 74 internal_rc4 = true; 75 } 76 } 77 78 if ( internal_rc4 ){ 79 80 rc4_engine = new RC4Engine(); 81 82 CipherParameters params = new KeyParameter(key_spec.getEncoded()); 83 84 rc4_engine.init( mode == Cipher.ENCRYPT_MODE, params ); 85 } 86 87 //System.out.println( "RC4 key: " + ByteFormatter.encodeString( key_spec.getEncoded())); 88 89 // skip first 1024 bytes of stream to protected against a Fluhrer, Mantin and Shamir attack 90 91 byte[] temp = new byte[1024]; 92 93 temp = update( temp ); 94 95 //System.out.println( "RC4: first discard = " + ByteFormatter.encodeString( temp, 0, 4 )); 96 }else{ 97 98 cipher = Cipher.getInstance( algorithm ); 99 100 cipher.init( mode, key_spec ); 101 } 102 } 103 104 protected byte[] update( byte[] data )105 update( 106 byte[] data ) 107 { 108 return( update( data, 0, data.length )); 109 } 110 111 protected byte[] update( byte[] data, int offset, int length )112 update( 113 byte[] data, 114 int offset, 115 int length ) 116 { 117 byte[] result; 118 119 if ( length == 0 ){ 120 121 // watch out, cipher.update returns NULL with 0 length input 122 123 result = new byte[0]; 124 125 }else if ( cipher != null ){ 126 127 result = cipher.update( data, offset, length ); 128 129 }else{ 130 131 result = new byte[length]; 132 133 rc4_engine.processBytes( data, offset, length, result, 0 ); 134 } 135 136 return( result ); 137 } 138 139 protected void update( ByteBuffer source_buffer, ByteBuffer target_buffer )140 update( 141 ByteBuffer source_buffer, 142 ByteBuffer target_buffer ) 143 144 throws IOException 145 { 146 try{ 147 // TODO: 1.5 supports update( ByteBuffer, ByteBuffer ) 148 149 byte[] source_bytes; 150 int offset; 151 int length = source_buffer.remaining(); 152 153 if ( source_buffer.hasArray()){ 154 155 source_bytes = source_buffer.array(); 156 157 offset = source_buffer.arrayOffset() + source_buffer.position(); 158 159 }else{ 160 161 source_bytes = new byte[length]; 162 163 offset = 0; 164 165 source_buffer.get( source_bytes ); 166 } 167 168 byte[] target_bytes = update( source_bytes, offset, length ); 169 170 source_buffer.position( source_buffer.limit()); 171 172 target_buffer.put( target_bytes ); 173 174 }catch( Throwable e ){ 175 176 throw( new IOException( Debug.getNestedExceptionMessage( e ))); 177 } 178 } 179 180 public String getName()181 getName() 182 { 183 if ( cipher != null ){ 184 185 String s = cipher.getAlgorithm(); 186 187 int pos = s.indexOf("/"); 188 189 if ( pos != -1 ){ 190 191 s = s.substring(0,pos); 192 } 193 194 if ( s.equals( "RC4" )){ 195 196 s = "RC4-160"; 197 198 }else{ 199 200 s += "-" + cipher.getBlockSize()*8; 201 } 202 203 return( s ); 204 }else{ 205 206 return( "RC4-160" ); 207 } 208 } 209 } 210