package org.openslx.satellitedaemon;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Properties;
import java.util.Random;
import org.apache.log4j.Logger;
import org.openslx.encryption.AsymKeyHolder;
import org.openslx.satellitedaemon.util.Util;
public class Identity
{
private static Logger log = Logger.getLogger( Identity.class );
private static final Properties properties = new Properties();
private static String organizationName = null;
private static BigInteger privExponent = null;
private static BigInteger pubExponent = null;
private static BigInteger modulus = null;
private static AsymKeyHolder akh = null;
public static String getOrganizationName()
{
return organizationName = properties.getProperty( "ORGANIZATION_NAME" );
}
private static BigInteger getModulus()
{
return modulus = toBigInt( properties.getProperty( "MODULUS" ) );
}
private static BigInteger getPublicExponent()
{
return pubExponent = toBigInt( properties.getProperty( "PUBLIC_EXPONENT" ) );
}
private static BigInteger getPrivateExponent()
{
return privExponent = toBigInt( properties.getProperty( "PRIVATE_EXPONENT" ) );
}
/**
* Load properties
*/
static {
InputStreamReader stream = null;
try {
// Load all entries of the config file into properties
stream = new InputStreamReader(
new FileInputStream( "config/identity.properties" ), StandardCharsets.UTF_8 );
properties.load( stream );
stream.close();
} catch ( IOException e ) {
log.error( "Could not load identity.properties. Exiting." );
System.exit( 2 );
} finally {
Util.streamClose( stream );
}
Util.notNullOrEmptyFatal( getOrganizationName(), "Organiziation Name must not be empty!" );
try {
akh = new AsymKeyHolder( getPrivateExponent(), getPublicExponent(), getModulus() );
} catch ( InvalidKeySpecException e ) {
log.error( "InvalidKeySpecException", e );
} catch ( NoSuchAlgorithmException e ) {
log.error( "NoSuchAlgorithmException", e );
}
}
/**
* Get private key for this server. If none exists yet, create a new one.
*
* @return
*/
public static PrivateKey getPrivateKey()
{
if ( akh != null ) {
return akh.getPrivateKey();
}
akh = new AsymKeyHolder();
return akh.getPrivateKey();
}
/**
* Get public key for this server. If none exists yet, create a new one.
*
* @return
*/
public static PublicKey getPublicKey()
{
if ( akh != null )
return akh.getPublicKey();
akh = new AsymKeyHolder();
return akh.getPublicKey();
}
/**
* Get bit - length of key.
*
* @return
*/
public static int keySize( BigInteger modulus )
{
return modulus.bitLength();
}
/**
* Checks if given modulus, private exponent and public exponent are valid
* values for key pair. Idea is to encrypt and decrypt random text and compare
* the result with initial text.
*
* @param mod
* @param privExp
* @param pubExp
* @return True, if mod, privExp and pubExp are valid values.
*/
public static boolean isValidKeyPair( BigInteger mod, BigInteger privExp, BigInteger pubExp )
{
// First check given values (modulus, privExp, pubExp).
if ( ( mod == null ) || ( privExp == null ) || ( pubExp == null ) ) {
log.error( "Given arguments not valid: got NULL for modulus, private or public exponent." );
return false;
}
// Testing encryption and description with given public and private key.
// Idea: creating random text for encrypting and decrypting again.
Random rnd = new Random();
int size = rnd.nextInt( keySize( mod ) - 1 );
BigInteger text = new BigInteger( size, rnd );
// Encrypt.
BigInteger cipher = text.modPow( pubExp, mod );
// Decrypt again.
BigInteger decrypted = cipher.modPow( privExp, mod );
boolean isPassed = text.equals( decrypted );
return isPassed;
}
public static boolean generateIdentity( String organizationName )
{
Identity.organizationName = organizationName;
// generate new key pair.
Identity.akh = new AsymKeyHolder();
Identity.modulus = akh.getModulus();
Identity.privExponent = akh.getPrivateExponent();
Identity.pubExponent = akh.getPublicExponent();
return writeIdToFile(
Identity.organizationName,
Identity.modulus,
Identity.privExponent,
Identity.pubExponent );
}
private static boolean writeIdToFile( String organizationName, BigInteger modulus, BigInteger privateExp, BigInteger publicExp )
{
File configFile = new File( "config/identity.properties" );
FileOutputStream stream = null;
try {
stream = new FileOutputStream( configFile );
} catch ( FileNotFoundException e ) {
log.error( "FileNotFoundException", e );
return false;
}
// create strings for writing to file.
String orgNameString = "ORGANIZATION_NAME=" + organizationName + "\n";
String modString = "MODULUS=" + modulus.toString() + "\n";
String privExpString = "PRIVATE_EXPONENT=" + privateExp.toString() + "\n";
String pubExpString = "PUBLIC_EXPONENT=" + publicExp.toString() + "\n";
try {
stream.write( orgNameString.getBytes() );
stream.write( modString.getBytes() );
stream.write( privExpString.getBytes() );
stream.write( pubExpString.getBytes() );
return true;
} catch ( IOException e ) {
log.error( "IOException", e );
return false;
} finally {
try {
stream.close();
} catch ( IOException e ) {
}
}
}
/**
* Check modulus, privExp and pubExp for not being null.
*
* @return
*/
private static boolean checkMembers()
{
return ( ( getModulus() != null ) &&
( getPrivateExponent() != null ) && ( getPublicExponent() != null ) );
}
/**
* Get BigInteger of read String number.
*
* @param str
* @return
*/
private static BigInteger toBigInt( String str )
{
try {
return new BigInteger( str );
} catch ( Exception e ) {
return null;
}
}
}