Go to the documentation of this file.00001
00002 package crypto;
00003
00004 import java.io.BufferedReader;
00005 import java.io.ByteArrayOutputStream;
00006 import java.io.File;
00007 import java.io.FileNotFoundException;
00008 import java.io.FileReader;
00009 import java.io.IOException;
00010 import java.io.ObjectOutputStream;
00011 import java.io.Serializable;
00012 import java.security.NoSuchAlgorithmException;
00013 import java.security.PublicKey;
00014 import java.security.Signature;
00015 import java.security.SignedObject;
00016 import java.util.ArrayList;
00017
00018 import javax.crypto.Cipher;
00019 import javax.crypto.NoSuchPaddingException;
00020
00021 import utils.Log;
00022 import utils.Base64;
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 public class PublicEncryptor
00035 {
00036
00037
00038
00039
00040
00041 private final static String padding = "/ECB/PKCS1PADDING";
00042
00043
00044
00045
00046 private final static String digest = "SHA1";
00047
00048
00049
00050
00051 private final static String authorizedKeysFile = "mykf-authorized-keys.txt";
00052
00053
00054
00055
00056 private static ArrayList<NamedPublicKey> authorizedKeys = null;
00057
00058
00059
00060
00061 private PublicKey publicKey = null;
00062
00063
00064
00065
00066 private Cipher cipher = null;
00067
00068
00069
00070
00071 private String serializedPublicKey = null;
00072
00073
00074
00075
00076
00077
00078 private String verificator = null;
00079
00080
00081
00082
00083
00084 public PublicEncryptor( String serializedPublicKey, String remoteUserId )
00085 {
00086
00087
00088 this.serializedPublicKey = serializedPublicKey;
00089
00090 try
00091 {
00092 Object object = Base64.decodeToObject( this.serializedPublicKey );
00093 SignedObject signedObject = null;
00094
00095 if ( object instanceof SignedObject )
00096 {
00097 signedObject = (SignedObject) object;
00098 this.verificator = PublicEncryptor.verifyObject( signedObject );
00099 object = signedObject.getObject ();
00100 }
00101
00102 if ( object instanceof PublicKey )
00103 {
00104 this.publicKey = (PublicKey)object;
00105 String algorithm = this.publicKey.getAlgorithm ();
00106 this.cipher = Cipher.getInstance( algorithm + padding );
00107 }
00108 }
00109 catch( ClassNotFoundException e )
00110 {
00111 Log.exception( Log.WARN, e );
00112 }
00113 catch( NoSuchAlgorithmException e )
00114 {
00115 Log.exception( Log.WARN, e );
00116 }
00117 catch( NoSuchPaddingException e )
00118 {
00119 Log.exception( Log.WARN, e );
00120 }
00121 catch( IOException e )
00122 {
00123 Log.exception( Log.WARN, e );
00124 }
00125
00126
00127
00128 if ( this.publicKey == null )
00129 {
00130 this.cipher = null;
00131 }
00132 }
00133
00134
00135
00136
00137
00138 private static void createEmptyAuthorizedPublicKeys( String filename )
00139 {
00140 try
00141 {
00142 File file = new File( filename );
00143
00144 if ( ! file.exists () ) {
00145 file.createNewFile ();
00146 }
00147
00148 if ( file.exists () )
00149 {
00150
00151
00152
00153 String osName = System.getProperty( "os.name" ).toLowerCase();
00154 if ( ! osName.matches( "^.*windows.*$" ) )
00155 {
00156 try
00157 {
00158 Runtime.getRuntime().exec( new String[] { "chmod", "go=", filename } );
00159 }
00160 catch( IOException e )
00161 {
00162 Log.trace( "Failed to do chmod; OS = " + osName );
00163 Log.exception( Log.TRACE, e );
00164 }
00165 }
00166 }
00167 }
00168 catch( Exception e )
00169 {
00170 Log.exception( Log.ERROR, e );
00171 }
00172 }
00173
00174
00175
00176
00177 public static void loadAuthorizedPublicKeys ()
00178 {
00179 StringBuffer report = new StringBuffer ();
00180
00181 ArrayList<NamedPublicKey> newAuthKeys = new ArrayList<NamedPublicKey> ();
00182
00183 try
00184 {
00185 String filePath = CipherEngine.getPrivateKeyDirectory ()
00186 + authorizedKeysFile;
00187
00188 createEmptyAuthorizedPublicKeys( filePath );
00189
00190 FileReader inf = new FileReader( filePath );
00191 BufferedReader ins = new BufferedReader( inf );
00192
00193 String line;
00194 while ( ( line = ins.readLine () ) != null )
00195 {
00196
00197
00198 String[] parts = line.trim().split( "\\s{1,}" );
00199
00200
00201
00202 if ( parts.length < 1 || parts[0].length () <= 0 ) {
00203 continue;
00204 }
00205
00206
00207
00208 if ( parts[0].equals( "#" ) ) {
00209 continue;
00210 }
00211
00212
00213
00214 String encodedKey = parts[0];
00215 Object object = null;
00216
00217 try {
00218 object = Base64.decodeToObject( encodedKey.toString () );
00219 }
00220 catch( IOException e )
00221 {
00222 Log.warn( "Failed to deserialize authorized key at line: [" + encodedKey + "]" );
00223 Log.exception( Log.WARN, e );
00224 }
00225 catch( ClassNotFoundException e )
00226 {
00227 Log.warn( "Failed to deserialize authorized key at line: [" + encodedKey + "]" );
00228 Log.exception( Log.WARN, e );
00229 }
00230
00231 if ( object != null && ( object instanceof NamedPublicKey ) )
00232 {
00233 NamedPublicKey authKey = (NamedPublicKey) object;
00234 newAuthKeys.add( authKey );
00235 if ( report.length () != 0 ) {
00236 report.append( ", " );
00237 }
00238 report.append( authKey.comment );
00239 }
00240 else if ( object != null )
00241 {
00242 Log.warn( "Line: [" + encodedKey + "]" );
00243 Log.warn( "Ignored class: " + object.getClass().toString () );
00244 }
00245 }
00246 }
00247 catch( FileNotFoundException e )
00248 {
00249 Log.exception( Log.TRACE, e );
00250 }
00251 catch( IOException e )
00252 {
00253 Log.exception( Log.WARN, e );
00254 }
00255
00256 if ( newAuthKeys.size() > 1 )
00257 {
00258 report.insert( 0, "Loaded " + newAuthKeys.size() + " authorized keys: " );
00259 Log.attn( report.toString () );
00260 }
00261 else if ( newAuthKeys.size() == 1 )
00262 {
00263 report.insert( 0, "Loaded authorized key: " );
00264 Log.attn( report.toString () );
00265 }
00266
00267 authorizedKeys = newAuthKeys;
00268 }
00269
00270
00271
00272
00273
00274
00275 public static String verifyObject( SignedObject object )
00276 {
00277 if ( authorizedKeys == null ) {
00278 return null;
00279 }
00280
00281 String verificator = null;
00282
00283 for ( NamedPublicKey authKey : authorizedKeys )
00284 {
00285 try
00286 {
00287 String signAlgorithm = digest + "with" + authKey.publicKey.getAlgorithm ();
00288
00289 Signature signature = Signature.getInstance( signAlgorithm );
00290
00291 if ( object.verify( authKey.publicKey, signature ) ) {
00292 verificator = authKey.comment;
00293 break;
00294 }
00295 }
00296 catch( Exception e )
00297 {
00298
00299 }
00300 }
00301
00302 return verificator;
00303 }
00304
00305
00306
00307
00308 public boolean isActive ()
00309 {
00310 return this.cipher != null;
00311 }
00312
00313
00314
00315
00316 public boolean isVerified ()
00317 {
00318 return this.verificator != null;
00319 }
00320
00321
00322
00323
00324
00325
00326 public String getVerificatorName ()
00327 {
00328 return this.verificator;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 public byte[] encrypt( byte[] plainText )
00343 {
00344 if ( this.cipher == null ) {
00345 return null;
00346 }
00347
00348 byte[] output = null;
00349
00350 synchronized( this.cipher )
00351 {
00352 try
00353 {
00354 this.cipher.init( Cipher.ENCRYPT_MODE, publicKey );
00355
00356
00357
00358
00359
00360 int blockSize = cipher.getOutputSize( 1 ) - 11;
00361
00362 ByteArrayOutputStream bOut = new ByteArrayOutputStream ();
00363
00364 byte[] xorBlock = new byte[ blockSize ];
00365
00366 for ( int pos = 0; pos < plainText.length; pos += blockSize )
00367 {
00368 int len = Math.min( plainText.length - pos, blockSize );
00369
00370 for ( int i = 0; i < len; ++i ) {
00371 xorBlock[i] = (byte)( xorBlock[i] ^ plainText[ pos + i ] );
00372 }
00373
00374 byte[] cipherBlock = this.cipher.doFinal( xorBlock, 0, len );
00375 bOut.write( cipherBlock );
00376
00377 System.arraycopy( cipherBlock, 0, xorBlock, 0, blockSize );
00378 }
00379
00380 output = bOut.toByteArray ();
00381 }
00382 catch( Exception e )
00383 {
00384 Log.exception( Log.ERROR, e );
00385 }
00386 }
00387
00388 return output;
00389 }
00390
00391
00392
00393
00394 public String encryptAndSerialize( Serializable object )
00395 {
00396
00397
00398 String result = null;
00399
00400
00401
00402 ByteArrayOutputStream bOut = null;
00403 ObjectOutputStream oOut = null;
00404
00405 try
00406 {
00407 bOut = new ByteArrayOutputStream ();
00408 oOut = new ObjectOutputStream( bOut );
00409 oOut.writeObject( object );
00410
00411 byte[] plainText = bOut.toByteArray ();
00412
00413 oOut.close ();
00414 bOut.close ();
00415
00416 result = Base64.encodeBytes( encrypt( plainText ), Base64.GZIP );
00417 }
00418 catch( Exception e )
00419 {
00420 Log.exception( Log.ERROR, e );
00421 }
00422
00423 return result;
00424 }
00425 }