Package com.aelitis.azureus.core.security.impl

Source Code of com.aelitis.azureus.core.security.impl.CryptoHandlerECC$InternalECIES

/*
* Created on 15 Jun 2006
* Created by Paul Gardner
* Copyright (C) 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/

package com.aelitis.azureus.core.security.impl;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;

import org.bouncycastle.jce.provider.JCEIESCipher;
import org.bouncycastle.jce.spec.IEKeySpec;
import org.bouncycastle.jce.spec.IESParameterSpec;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.util.Base32;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.RandomUtils;
import org.gudy.azureus2.core3.util.SystemTime;

import com.aelitis.azureus.core.security.CryptoECCUtils;
import com.aelitis.azureus.core.security.CryptoHandler;
import com.aelitis.azureus.core.security.CryptoManager;
import com.aelitis.azureus.core.security.CryptoManagerException;
import com.aelitis.azureus.core.security.CryptoManagerPasswordException;
import com.aelitis.azureus.core.security.CryptoManagerPasswordHandler;
import com.aelitis.azureus.core.security.CryptoSTSEngine;

public class
CryptoHandlerECC
  implements CryptoHandler
  private static final String  DEFAULT_PASSWORD  = "";
  private static final Long  DEFAULT_TIMEOUT    = Long.MAX_VALUE;
 

  private static final int  TIMEOUT_DEFAULT_SECS    = 60*60;

 
  private CryptoManagerImpl    manager;
 
  private String        CONFIG_PREFIX = CryptoManager.CRYPTO_CONFIG_PREFIX + "ecc.";

  private PrivateKey      use_method_private_key;
  private PublicKey      use_method_public_key;
 
  private long  last_unlock_time;
 
  protected
  CryptoHandlerECC(
    CryptoManagerImpl    _manager,
    int            _instance_id )
  {
    manager  = _manager;
   
    CONFIG_PREFIX += _instance_id + ".";
   
      // migration away from system managed keys
       
    if ( getDefaultPasswordHandlerType() != CryptoManagerPasswordHandler.HANDLER_TYPE_USER ){
   
      COConfigurationManager.setParameter( CONFIG_PREFIX + "default_pwtype", CryptoManagerPasswordHandler.HANDLER_TYPE_USER );
    }
   
    if (   getCurrentPasswordType() == CryptoManagerPasswordHandler.HANDLER_TYPE_SYSTEM ||
        COConfigurationManager.getByteParameter( CONFIG_PREFIX + "publickey", null ) == null ){
     
      try{
        createAndStoreKeys(
          manager.setPassword(
            CryptoManager.HANDLER_ECC,
            CryptoManagerPasswordHandler.HANDLER_TYPE_USER,
            DEFAULT_PASSWORD.toCharArray(),
            DEFAULT_TIMEOUT ));
       
        Debug.outNoStack( "Successfully migrated key management" );
       
      }catch( Throwable e ){
       
        Debug.out( "Failed to migrate key management", e );
      }
    }
  }
 
  public int
  getType()
  {
    return( CryptoManager.HANDLER_ECC );
  }
 
  public void
  unlock()
 
    throws CryptoManagerException
  {
    getMyPrivateKey( "unlock" );
  }
 
  public synchronized boolean
  isUnlocked()
  {
    return( use_method_private_key != null );
  }
 
  public void
  lock()
  {
    boolean  changed = false;
   
    synchronized( this ){
     
      changed = use_method_private_key != null;
   
      use_method_private_key  = null;
    }
   
    if ( changed ){
   
      manager.lockChanged( this );
    }
  }
 
  public int
  getUnlockTimeoutSeconds()
  {
    return( COConfigurationManager.getIntParameter( CONFIG_PREFIX + "timeout", TIMEOUT_DEFAULT_SECS ));
  }
 
  public void
  setUnlockTimeoutSeconds(
    int    secs )
  {
    COConfigurationManager.setParameter( CONFIG_PREFIX + "timeout", secs );
  }
   
  public byte[]
  sign(
    byte[]    data,
    String    reason )
 
    throws CryptoManagerException
  {
    PrivateKey  priv = getMyPrivateKey( reason );
   
    Signature sig = CryptoECCUtils.getSignature( priv );
   
    try{
      sig.update( data );
     
      return( sig.sign());
     
    }catch( Throwable e ){
     
      throw( new CryptoManagerException( "Signature failed", e ));
    }
  }
  
  public boolean
  verify(
    byte[]    public_key,
    byte[]    data,
    byte[]    signature )
 
    throws CryptoManagerException
  {
    PublicKey  pub = CryptoECCUtils.rawdataToPubkey( public_key );
   
    Signature sig = CryptoECCUtils.getSignature( pub );
   
    try{
      sig.update( data );
     
      return( sig.verify( signature ));
     
    }catch( Throwable e ){
     
      throw( new CryptoManagerException( "Signature failed", e ));
    }
  }
 
  public byte[]
  encrypt(
    byte[]    other_public_key,
    byte[]    data,
    String    reason )
   
    throws CryptoManagerException
  {         
    try{
      IEKeySpec   key_spec = new IEKeySpec( getMyPrivateKey( reason ), CryptoECCUtils.rawdataToPubkey( other_public_key ));
  
      byte[]  d = new byte[16];
      byte[]  e = new byte[16];
     
      RandomUtils.nextSecureBytes( d );
      RandomUtils.nextSecureBytes( e );
     
      IESParameterSpec param = new IESParameterSpec( d, e, 128);
   
      InternalECIES  cipher = new InternalECIES();
 
      cipher.internalEngineInit( Cipher.ENCRYPT_MODE, key_spec, param, null );
   
      byte[]  encrypted = cipher.internalEngineDoFinal(data, 0, data.length );
     
      byte[] result = new byte[32+encrypted.length];
     
      System.arraycopy( d, 0, result, 0, 16 );
      System.arraycopy( e, 0, result, 16, 16 );
      System.arraycopy( encrypted, 0, result, 32, encrypted.length );
     
      return( result );
     
    }catch( CryptoManagerException e ){
     
      throw( e );
     
    }catch( Throwable e){
     
      throw( new CryptoManagerException( "Encrypt failed", e ));
    }
  }
 
  public byte[]
  decrypt(
    byte[]    other_public_key,
    byte[]    data,
    String    reason )
   
    throws CryptoManagerException
  {         
    try{
      IEKeySpec   key_spec = new IEKeySpec( getMyPrivateKeyreason ), CryptoECCUtils.rawdataToPubkey( other_public_key ));
    
      byte[]  d = new byte[16];
      byte[]  e = new byte[16];
     
      System.arraycopy( data, 0, d, 0, 16 );
      System.arraycopy( data, 16, e, 0, 16 );
     
      IESParameterSpec param = new IESParameterSpec( d, e, 128);
   
      InternalECIES  cipher = new InternalECIES();
 
      cipher.internalEngineInit( Cipher.DECRYPT_MODE, key_spec, param, null );
   
      return( cipher.internalEngineDoFinal( data, 32, data.length - 32 ));
     
    }catch( CryptoManagerException e ){
     
      throw( e );
     
    }catch( Throwable e){
     
      throw( new CryptoManagerException( "Decrypt failed", e ));
    }
  }
   
  public CryptoSTSEngine
  getSTSEngine(
    String    reason )
 
    throws CryptoManagerException
  {
    return( new CryptoSTSEngineImpl( getMyPublicKeyreason, true ), getMyPrivateKey( reason )));
  }
 
  public byte[]
  peekPublicKey()
  {
    try{
   
      return( CryptoECCUtils.keyToRawdata( getMyPublicKey( "peek", false )));
     
    }catch( Throwable e ){
     
      return( null );
    }
  }
 
  public byte[]
  getPublicKey(
    String    reason )
 
    throws CryptoManagerException
  {
    return( CryptoECCUtils.keyToRawdata( getMyPublicKey( reason, true )));
  }
 
  public byte[]
  getEncryptedPrivateKey(
    String    reason )
 
    throws CryptoManagerException
  {
    getMyPrivateKey( reason );
   
    byte[]  pk = COConfigurationManager.getByteParameter( CONFIG_PREFIX + "privatekey", null );

    if ( pk == null ){
     
      throw( new CryptoManagerException( "Private key unavailable" ));
    }
   
    int  pw_type = getCurrentPasswordType();
   
    byte[] res = new byte[pk.length+1];
   
    res[0] = (byte)pw_type;
   
    System.arraycopy( pk, 0, res, 1, pk.length );
   
    return( res );
  }
 
  public void
  recoverKeys(
    byte[]    public_key,
    byte[]    encrypted_private_key_and_type )
 
    throws CryptoManagerException
  {
    boolean  lock_changed = false;
   
    synchronized( this ){
     
      lock_changed = use_method_private_key != null;
     
      use_method_private_key  = null;
      use_method_public_key  = null;
     
      manager.clearPassword( CryptoManager.HANDLER_ECC, CryptoManagerPasswordHandler.HANDLER_TYPE_ALL );
     
      COConfigurationManager.setParameter( CONFIG_PREFIX + "publickey", public_key );
       
      int  type = (int)encrypted_private_key_and_type[0]&0xff;
     
      COConfigurationManager.setParameter( CONFIG_PREFIX + "pwtype", type );
 
      byte[] encrypted_private_key = new byte[encrypted_private_key_and_type.length-1];
     
      System.arraycopy( encrypted_private_key_and_type, 1, encrypted_private_key, 0, encrypted_private_key.length );
     
      COConfigurationManager.setParameter( CONFIG_PREFIX + "privatekey", encrypted_private_key );
     
      COConfigurationManager.save();
    }   
   
    manager.keyChanged( this );

    if ( lock_changed ){
   
      manager.lockChanged( this );
    }
  }
 
  public void
  resetKeys(
    String    reason )
 
    throws CryptoManagerException
  {
    boolean  lock_changed = false;

    synchronized( this ){
     
      lock_changed = use_method_private_key != null;

      use_method_private_key  = null;
      use_method_public_key  = null;
     
      manager.clearPassword( CryptoManager.HANDLER_ECC, CryptoManagerPasswordHandler.HANDLER_TYPE_ALL );
     
      COConfigurationManager.removeParameter( CONFIG_PREFIX + "publickey" );
       
      COConfigurationManager.removeParameter( CONFIG_PREFIX + "privatekey" );
     
      COConfigurationManager.save();
    }
   
    if ( lock_changed ){

      manager.lockChanged( this );
    }
   
    try{
   
      createAndStoreKeys( "resetting keys" );
     
    }catch( CryptoManagerException e ){
     
      manager.keyChanged( this );
       
      throw( e );
    }
  }
 
  protected PrivateKey
  getMyPrivateKey(
    String    reason )
 
    throws CryptoManagerException
  {
    boolean  lock_change = false;
   
    try{
      synchronized( this ){
       
        if ( use_method_private_key != null ){
         
          int  timeout_secs = getUnlockTimeoutSeconds();
         
          if ( timeout_secs > 0 ){
           
            if ( SystemTime.getCurrentTime() - last_unlock_time >= timeout_secs * 1000 ){
             
              lock_change = true;
             
              use_method_private_key = null;
            }
          }
        }
       
        if ( use_method_private_key != null ){
         
          return( use_method_private_key );
        }
      }
     
      final byte[]  encoded = COConfigurationManager.getByteParameter( CONFIG_PREFIX + "privatekey", null );
     
      if ( encoded == null ){
       
        return((PrivateKey)createAndStoreKeys( reason )[1]);
       
      }else{
       
        CryptoManagerImpl.passwordDetails password_details =
          manager.getPassword(
              CryptoManager.HANDLER_ECC,
              CryptoManagerPasswordHandler.ACTION_DECRYPT,
              reason,
              new CryptoManagerImpl.passwordTester()
              {
                public boolean
                testPassword(
                  char[] password )
                {
                  try{
                    manager.decryptWithPBE( encoded, password );
                   
                    return( true );
                   
                  }catch( Throwable e ){
                   
                    return( false );
                  }
                }
              },
              getCurrentPasswordType());
 
        synchronized( this ){
         
          boolean    ok = false;
         
          try{
            use_method_private_key = CryptoECCUtils.rawdataToPrivkey( manager.decryptWithPBE( encoded, password_details.getPassword()));
         
            lock_change = true;
           
            last_unlock_time = SystemTime.getCurrentTime();
         
            if ( !checkKeysOK( reason )){
                       
              throw( new CryptoManagerPasswordException( true, "Password incorrect" ));
            }
           
            ok = true;
           
          }catch( CryptoManagerException e ){
           
            throw( e );
           
          }catch( Throwable e ){
           
            throw( new CryptoManagerException( "Password incorrect", e ));
           
          }finally{
           
            if ( !ok ){
                           
              manager.clearPassword( CryptoManager.HANDLER_ECC, CryptoManagerPasswordHandler.HANDLER_TYPE_ALL );
             
              lock_change = true;
             
              use_method_private_key  = null;
            }
          }
        }
     
        if ( use_method_private_key == null ){
         
          throw( new CryptoManagerException( "Failed to get private key" ));
        }
       
        return( use_method_private_key );
      }
    }finally{
     
      if ( lock_change ){

        manager.lockChanged( this );
      }
    }
  }
 
  protected boolean
  checkKeysOK(
    String  reason )
 
    throws CryptoManagerException
  {
    byte[]  test_data = "test".getBytes();
   
    return( verify( CryptoECCUtils.keyToRawdata( getMyPublicKey( reason, true )), test_data,  sign( test_data, reason )));
  }
 
  protected PublicKey
  getMyPublicKey(
    String    reason,
    boolean    create_if_needed )
 
    throws CryptoManagerException
  {
    boolean  create_new = false;
   
    synchronized( this ){
     
      if ( use_method_public_key == null ){
       
        byte[]  key_bytes = COConfigurationManager.getByteParameter( CONFIG_PREFIX + "publickey", null );
       
        if ( key_bytes == null ){
         
          if ( create_if_needed ){
           
            create_new = true;
           
          }else{
           
            return( null );
          }
        }else{
         
          use_method_public_key = CryptoECCUtils.rawdataToPubkey( key_bytes );
        }
      }
     
      if ( !create_new ){
       
        if ( use_method_public_key == null ){
         
          throw( new CryptoManagerException( "Failed to get public key" ));
        }
       
        return( use_method_public_key );
      }
    }
   
    return((PublicKey)createAndStoreKeys( reason )[0] );
  }
 
  public int
  getDefaultPasswordHandlerType()
  {
    return( COConfigurationManager.getIntParameter( CONFIG_PREFIX + "default_pwtype", CryptoManagerPasswordHandler.HANDLER_TYPE_USER ));
  }
 
  public void
  setDefaultPasswordHandlerType(
    int    new_type )
 
    throws CryptoManagerException
  {
    String reason = "Changing password handler";
   
    boolean  have_existing_keys = COConfigurationManager.getByteParameter( CONFIG_PREFIX + "privatekey", null ) != null;
   
      // ensure we unlock the private key so we can then re-persist it with new password

    if ( have_existing_keys ){
     
      if ( new_type == getCurrentPasswordType()){
       
        return;
      }
     
      getMyPrivateKey( reason );
   
      CryptoManagerImpl.passwordDetails password_details =
        manager.getPassword(
                CryptoManager.HANDLER_ECC,
                CryptoManagerPasswordHandler.ACTION_ENCRYPT,
                reason,
                null,
                new_type );
     
     
      synchronized( this ){
       
        if ( use_method_private_key == null ){
         
          throw( new CryptoManagerException( "Private key not available" ));
        }
       
        byte[]  priv_raw = CryptoECCUtils.keyToRawdata( use_method_private_key );
       
        byte[]  priv_enc = manager.encryptWithPBE( priv_raw, password_details.getPassword());
       
        COConfigurationManager.setParameter( CONFIG_PREFIX + "privatekey", priv_enc );
 
        COConfigurationManager.setParameter( CONFIG_PREFIX + "pwtype", password_details.getHandlerType());
 
        COConfigurationManager.setParameter( CONFIG_PREFIX + "default_pwtype", password_details.getHandlerType());
       
        COConfigurationManager.save();
      }
    }else{
     
        // not much to do as keys not yet created
     
      synchronized( this ){
       
        if ( COConfigurationManager.getByteParameter( CONFIG_PREFIX + "privatekey", null ) == null ){
         
          COConfigurationManager.setParameter( CONFIG_PREFIX + "default_pwtype", new_type );
       
          COConfigurationManager.save();
        }
      }
    }
  }
 
  protected Key[]
    createAndStoreKeys(
      String    reason )
   
      throws CryptoManagerException
   
    CryptoManagerImpl.passwordDetails password_details =
        manager.getPassword(
                CryptoManager.HANDLER_ECC,
                CryptoManagerPasswordHandler.ACTION_ENCRYPT,
                reason,
                null,
                getDefaultPasswordHandlerType());
   
    return( createAndStoreKeys( password_details ));
    }
 
  protected Key[]
  createAndStoreKeys(
    CryptoManagerImpl.passwordDetails  password_details )
 
    throws CryptoManagerException
  {   
    try{
      synchronized( this ){
       
        if ( use_method_public_key == null || use_method_private_key == null ){
         
          KeyPair  keys = CryptoECCUtils.createKeys();
         
          use_method_public_key  = keys.getPublic();
         
          use_method_private_key  = keys.getPrivate();
         
          last_unlock_time = SystemTime.getCurrentTime();
         
          COConfigurationManager.setParameter( CONFIG_PREFIX + "publickey", CryptoECCUtils.keyToRawdata( use_method_public_key ));
         
          byte[]  priv_raw = CryptoECCUtils.keyToRawdata( use_method_private_key );
         
          byte[]  priv_enc = manager.encryptWithPBE( priv_raw, password_details.getPassword());
         
          COConfigurationManager.setParameter( CONFIG_PREFIX + "privatekey", priv_enc );
   
          COConfigurationManager.setParameter( CONFIG_PREFIX + "pwtype", password_details.getHandlerType());
   
          COConfigurationManager.save();
        }
       
        return( new Key[]{ use_method_public_key, use_method_private_key });
      }
    }finally{
       
      manager.keyChanged( this );
     
      manager.lockChanged( this );
    }
  }
 
  public boolean
  verifyPublicKey(
    byte[]  encoded )
  {
    try{
      CryptoECCUtils.rawdataToPubkey( encoded );
     
        // we can't actually verify the key size as although it should be 192 bits
        // it can be less due to leading bits being 0
     
      return( true );
     
    }catch( Throwable e ){
     
      return( false );
    }
  }
 
  public String
  exportKeys()
 
    throws CryptoManagerException
  {
    return( "id:      " + Base32.encode(manager.getSecureID()) + "\r\n" +
        "public:  " + Base32.encode(getPublicKey( "Key export" )) + "\r\n" +
        "private: " + Base32.encode(getEncryptedPrivateKey( "Key export" )));
  }
 
  public boolean
  importKeys(
    String  str )
 
    throws CryptoManagerException
  {
    String  reason = "Key import";
 
    byte[]  existing_id       = manager.getSecureID();
    byte[]  existing_public_key    = peekPublicKey();
    byte[]  existing_private_key  = existing_public_key==null?null:getEncryptedPrivateKey( reason );
   
    byte[]    recovered_id       = null;
    byte[]    recovered_public_key   = null;
    byte[]    recovered_private_key   = null;
       
    String[]  bits = str.split( "\n" );
   
    for (int i=0;i<bits.length;i++){
     
      String  bit = bits[i].trim();
     
      if ( bit.length() == 0 ){
       
        continue;
      }
     
      String[] x = bit.split(":");
     
      if ( x.length != 2 ){
       
        continue;
      }
     
      String  lhs = x[0].trim();
      String  rhs = x[1].trim();
     
      byte[]  rhs_val = Base32.decode( rhs );
     
      if ( lhs.equals( "id" )){
       
        recovered_id = rhs_val;
       
      }else if ( lhs.equals( "public" )){
       
        recovered_public_key = rhs_val;
       
      }else if ( lhs.equals( "private" )){
       
        recovered_private_key = rhs_val;
      }
    }
   
    if ( recovered_id == null || recovered_public_key == null || recovered_private_key == null ){
     
      throw( new CryptoManagerException( "Invalid input file" ));
    }
   
    boolean  ok = false;
   
    boolean  result = false;
   
    try{
     
      result = !Arrays.equals( existing_id, recovered_id );
     
      if ( result ){
     
        manager.setSecureID( recovered_id );
      }
     
      recoverKeys( recovered_public_key, recovered_private_key );
         
      if ( !checkKeysOK( reason )){
     
        throw( new CryptoManagerException( "Invalid key pair" ));
      }
     
      ok = true;
           
    }finally{
     
      if ( !ok ){
     
        result = false;
       
        manager.setSecureID( existing_id );
       
        if ( existing_public_key != null ){
         
          recoverKeys( existing_public_key, existing_private_key );
        }
      }
    }
   
    return( result );
  }
 
  protected int
  getCurrentPasswordType()
  {
    return((int)COConfigurationManager.getIntParameter( CONFIG_PREFIX + "pwtype", CryptoManagerPasswordHandler.HANDLER_TYPE_USER ));
  }
 
  class InternalECIES
    extends JCEIESCipher.ECIES
  {
      // we use this class to obtain compatability with BC

    public void
    internalEngineInit(
      int                     opmode,
      Key                     key,
      AlgorithmParameterSpec  params,
      SecureRandom            random )
   
      throws InvalidKeyException, InvalidAlgorithmParameterException
    {
      engineInit(opmode, key, params, random);
    }

    protected byte[]
    internalEngineDoFinal(
      byte[]  input,
      int     inputOffset,
      int     inputLen )
   
      throws IllegalBlockSizeException, BadPaddingException
    {
      return engineDoFinal(input, inputOffset, inputLen);
    }
  }
}
TOP

Related Classes of com.aelitis.azureus.core.security.impl.CryptoHandlerECC$InternalECIES

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.