package com.eucalyptus.auth.crypto;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.zip.Adler32;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Logger;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.util.encoders.UrlBase64;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import com.eucalyptus.auth.SystemCredentialProvider;
import com.eucalyptus.auth.api.CertificateProvider;
import com.eucalyptus.auth.api.CryptoProvider;
import com.eucalyptus.auth.api.HmacProvider;
import com.eucalyptus.bootstrap.Component;
import com.eucalyptus.records.EventType;
import com.eucalyptus.records.EventRecord;
public class DefaultCryptoProvider implements CryptoProvider, CertificateProvider, HmacProvider {
public static String KEY_ALGORITHM = "RSA";
public static String KEY_SIGNING_ALGORITHM = "SHA512WithRSA";
public static int KEY_SIZE = 2048;
public static String PROVIDER = "BC";
private static Logger LOG = Logger.getLogger( DefaultCryptoProvider.class );
public DefaultCryptoProvider( ) {}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#generateHashedPassword(java.lang.String)
*/
@Override
public String generateHashedPassword( String password ) {
byte[] data = Digest.MD5.get( ).digest( password.getBytes( ) );
StringBuffer buf = new StringBuffer( );
for ( int i = 0; i < data.length; i++ ) {
int halfbyte = ( data[i] >>> 4 ) & 0x0F;
int two_halfs = 0;
do {
if ( ( 0 <= halfbyte ) && ( halfbyte <= 9 ) )
buf.append( ( char ) ( '0' + halfbyte ) );
else buf.append( ( char ) ( 'a' + ( halfbyte - 10 ) ) );
halfbyte = data[i] & 0x0F;
} while ( two_halfs++ < 1 );
}
return buf.toString( ).toLowerCase( );
}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#generateQueryId(java.lang.String)
*/
@Override
public String generateQueryId( String userName ) {
return this.getDigestBase64( userName, Digest.SHA224, false ).replaceAll( "\\p{Punct}", "" );
}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#generateSecretKey(java.lang.String)
*/
@Override
public String generateSecretKey( String userName ) {
return this.getDigestBase64( userName, Digest.SHA224, true ).replaceAll( "\\p{Punct}", "" );
}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#generateCertificateCode(java.lang.String)
*/
@Override
public String generateCertificateCode( String userName ) {
return this.getDigestBase64( userName, Digest.SHA512, true ).replaceAll( "\\p{Punct}", "" );
}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#generateConfirmationCode(java.lang.String)
*/
@Override
public String generateConfirmationCode( String userName ) {
return this.getDigestBase64( userName, Digest.SHA512, true ).replaceAll( "\\p{Punct}", "" );
}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#generateSessionToken(java.lang.String)
*/
@Override
public String generateSessionToken( String userName ) {
return this.getDigestBase64( userName, Digest.SHA512, true ).replaceAll( "\\p{Punct}", "" );
}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#getDigestBase64(java.lang.String, com.eucalyptus.auth.crypto.Digest, boolean)
*/
@Override
public String getDigestBase64( String input, Digest hash, boolean randomize ) {
byte[] inputBytes = input.getBytes( );
byte[] digestBytes = null;
MessageDigest digest = hash.get( );
digest.update( inputBytes );
if ( randomize ) {
SecureRandom random = new SecureRandom( );
//TODO: RELEASE: random.setSeed( System.currentTimeMillis( ) );
byte[] randomBytes = random.generateSeed( inputBytes.length );
digest.update( randomBytes );
}
digestBytes = digest.digest( );
return new String( UrlBase64.encode( digestBytes ) );
}
public X509Certificate generateServiceCertificate( KeyPair keys, String serviceName ) {
X500Principal x500 = new X500Principal( String.format( "CN=%s, OU=Eucalyptus, O=Cloud, C=US", serviceName ) );
SystemCredentialProvider sys = SystemCredentialProvider.getCredentialProvider( Component.eucalyptus );
// if( sys.getCertificate( ) != null ) {
// return generateCertificate( keys, x500, sys.getCertificate( ).getSubjectX500Principal( ), sys.getPrivateKey( ) );
// } else {
return generateCertificate( keys, x500, x500, null );
// }
}
public X509Certificate generateCertificate( KeyPair keys, String userName ) {
return generateCertificate( keys, new X500Principal( String.format( "CN=%s, OU=Eucalyptus, O=User, C=US", userName ) ) );
}
public X509Certificate generateCertificate( KeyPair keys, X500Principal dn ) {
return generateCertificate( keys, dn, dn, null );
}
@Override
public X509Certificate generateCertificate( KeyPair keys, X500Principal subjectDn, X500Principal signer, PrivateKey signingKey ) {
signer = ( signingKey == null ? signer : subjectDn );
signingKey = ( signingKey == null ? keys.getPrivate( ) : signingKey );
EventRecord.caller( DefaultCryptoProvider.class, EventType.GENERATE_CERTIFICATE, signer.toString( ), subjectDn.toString( ) ).info();
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator( );
certGen.setSerialNumber( BigInteger.valueOf( System.nanoTime( ) ).shiftLeft( 4 ).add( BigInteger.valueOf( ( long ) Math.rint( Math.random( ) * 1000 ) ) ) );
certGen.setIssuerDN( signer );
certGen.addExtension( X509Extensions.BasicConstraints, true, new BasicConstraints( true ) );
Calendar cal = Calendar.getInstance( );
certGen.setNotBefore( cal.getTime( ) );
cal.add( Calendar.YEAR, 5 );
certGen.setNotAfter( cal.getTime( ) );
certGen.setSubjectDN( subjectDn );
certGen.setPublicKey( keys.getPublic( ) );
certGen.setSignatureAlgorithm( KEY_SIGNING_ALGORITHM );
try {
X509Certificate cert = certGen.generate( signingKey, PROVIDER );
cert.checkValidity( );
return cert;
} catch ( Exception e ) {
LOG.fatal( e, e );
System.exit( -3 );
return null;
}
}
/**
* @see com.eucalyptus.auth.api.CryptoProvider#generateKeyPair()
*/
@Override
public KeyPair generateKeyPair( ) {
KeyPairGenerator keyGen = null;
try {
EventRecord.caller( DefaultCryptoProvider.class, EventType.GENERATE_KEYPAIR );
keyGen = KeyPairGenerator.getInstance( KEY_ALGORITHM, "BC" );
SecureRandom random = new SecureRandom( );
random.setSeed( System.currentTimeMillis( ) );
keyGen.initialize( KEY_SIZE, random );
KeyPair keyPair = keyGen.generateKeyPair( );
return keyPair;
} catch ( Exception e ) {
LOG.fatal( e, e );
System.exit( -3 );
return null;
}
}
@Override
public String generateSystemSignature( ) {
return this.generateSystemToken( Component.eucalyptus.name( ).getBytes( ) );
}
@Override
public String generateSystemToken( byte[] data ) {
PrivateKey pk = SystemCredentialProvider.getCredentialProvider( Component.eucalyptus ).getPrivateKey( );
return Signatures.SHA256withRSA.trySign( pk, data );
}
@Override
public String generateId( final String userId, final String prefix ) {
Adler32 hash = new Adler32( );
String key = userId + (System.currentTimeMillis( ) * Math.random( ));
hash.update( key.getBytes( ) );
String imageId = String.format( "%s-%08X", prefix, hash.getValue( ) );
return imageId;
}
@Override
public String getFingerPrint( Key privKey ) {
try {
byte[] fp = Digest.SHA1.get( ).digest( privKey.getEncoded( ) );
StringBuffer sb = new StringBuffer( );
for ( byte b : fp )
sb.append( String.format( "%02X:", b ) );
return sb.substring( 0, sb.length( ) - 1 ).toLowerCase( );
} catch ( Exception e ) {
LOG.error( e, e );
return null;
}
}
}