package org.fnppl.opensdx.security;
/*
* Copyright (C) 2010-2015
* fine people e.V. <opensdx@fnppl.org>
* Henning Thieß <ht@fnppl.org>
*
* http://fnppl.org
*/
/*
* Software license
*
* As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied.
*
* This file is part of openSDX
* openSDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* openSDX 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 Lesser General Public License
* and GNU General Public License along with openSDX.
* If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Documentation license
*
* As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied.
*
* This file is part of openSDX.
* Permission is granted to copy, distribute and/or modify this document
* under the terms of the GNU Free Documentation License, Version 1.3
* or any later version published by the Free Software Foundation;
* with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
* A copy of the license is included in the section entitled "GNU
* Free Documentation License" resp. in the file called "FDL.txt".
*
*/
import java.io.*;
import java.math.*;
import java.security.*;
import java.util.*;
import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.engines.*;
import org.bouncycastle.crypto.generators.*;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.params.*;
/*
*
*/
public class AsymmetricKeyPair {
static {
SecurityHelper.ensureBC();
}
private PublicKey pubkey = null;
private PrivateKey privkey = null;
private int bitcount = 0;
private int type = 0; //TODO what for? algo? padding?
private AsymmetricKeyPair() {
}
String keyid = null;
public String getKeyID() {
if(keyid == null) {
keyid = SecurityHelper.HexDecoder.encode(SecurityHelper.getSHA1(pubkey.getModulus().toByteArray()), '\0', -1);
}
return keyid;
}
String keyhex = null;
public String getKeyIDHex() {
if(keyhex == null) {
keyhex = SecurityHelper.HexDecoder.encode(SecurityHelper.getSHA1(pubkey.getModulus().toByteArray()), ':', -1);
}
return keyhex;
}
public AsymmetricKeyPair(byte[] modulus, byte[] pub_exponent, byte[] priv_exponent) {
type = OSDXKey.ALGO_RSA;
//public key
org.bouncycastle.crypto.params.RSAKeyParameters rpub = new RSAKeyParameters(false, new BigInteger(modulus), new BigInteger(pub_exponent));
this.pubkey = new PublicKey(rpub.getModulus(), rpub.getExponent());
this.bitcount = rpub.getModulus().bitLength();
//private key
if (priv_exponent!=null) { //only if priv_exponent available
org.bouncycastle.crypto.params.RSAKeyParameters rpriv = new RSAKeyParameters(true, new BigInteger(modulus), new BigInteger(priv_exponent));
this.privkey = new PrivateKey(rpriv.getModulus(), rpriv.getExponent());
} else {
privkey = null;
}
}
public AsymmetricKeyPair(AsymmetricCipherKeyPair keyPair) {
type = OSDXKey.ALGO_RSA;
CipherParameters pub = keyPair.getPublic();
CipherParameters priv = keyPair.getPrivate();
RSAKeyParameters rpub = (RSAKeyParameters)pub;
RSAPrivateCrtKeyParameters rpriv = (RSAPrivateCrtKeyParameters)priv;
this.pubkey = new PublicKey(rpub.getModulus(), rpub.getExponent());
this.privkey = new PrivateKey(rpriv.getModulus(), rpriv.getExponent());
this.bitcount = rpub.getModulus().bitLength();
}
public boolean hasPrivateKey() {
if (privkey==null) return false;
return true;
}
// public AsymmetricKeyPair(PGPKeyPair kp) {
// keypair = kp;
// int algo = keypair.getPublicKey().getAlgorithm();
// if (algo == PGPPublicKey.RSA_GENERAL || algo == PGPPublicKey.RSA_SIGN || algo == PGPPublicKey.RSA_ENCRYPT) {
// type = TYPE_RSA;
// } else if (algo == PGPPublicKey.DSA) {
// type = TYPE_DSA;
// } else {
// type = TYPE_UNDEFINED;
// }
//
// }
//
// public PGPPublicKey getPGPPublicKey() {
// return keypair.getPublicKey();
// }
//
// public PGPPrivateKey getPGPPrivateKey() {
// return keypair.getPrivateKey();
// }
//
// public PGPKeyPair getPGPKeyPair() {
// return keypair;
// }
//
public int getType() {
return type;
}
public int getBitCount() {
return bitcount;
}
public String getPublicModulusAsHex() {
return "0x"+SecurityHelper.HexDecoder.encode(getPublicModulus(), '\0', -1);
}
public String getPublicExponentAsHex() {
return "0x"+SecurityHelper.HexDecoder.encode(getPublicExponent(), '\0', -1);
}
public byte[] getPublicModulus() {
return pubkey.getModulus().toByteArray();
}
public byte[] getPublicExponent() {
return pubkey.getExponent().toByteArray();
}
public byte[] getPrivateExponent() {
return privkey.getExponent().toByteArray();
}
public byte[] getPrivateModulus() {
return privkey.getModulus().toByteArray();
}
public String getPrivateModulusAsHex() {
return "0x"+SecurityHelper.HexDecoder.encode(getPrivateModulus(), '\0', -1);
}
public String getPrivateExponentAsHex() {
return "0x"+SecurityHelper.HexDecoder.encode(getPrivateExponent(), '\0', -1);
}
public boolean isRSA() {
if (type == OSDXKey.ALGO_RSA) {
return true;
}
return false;
}
// public byte[] encryptWithPubKey(byte[] in) throws Exception {
// //HT 20.02.2011 - to check wether this is encrypting-allowed RSA
//
// CipherParameters cp = new KeyParameter(ukey.getRawEncoded());
//// Key kkey = key.getKey("BC");
//
//// AsymmetricKeyParameter key = this.key.get;
// RSAEngine e = new RSAEngine();
// e.init(true, cp);
// int blockSize = e.getInputBlockSize();
// ByteArrayOutputStream bout = new ByteArrayOutputStream();
//
// for (int chunkPosition = 0; chunkPosition < in.length; chunkPosition += blockSize) {
// int chunkSize = Math.min(blockSize, in.length - (chunkPosition * blockSize));
// bout.write(
// e.processBlock(in, chunkPosition, chunkSize)
// );
// }
//
// return bout.toByteArray();
// }
public static AsymmetricKeyPair generateAsymmetricKeyPair() throws Exception {
SecurityHelper.ensureBC();
// SecureRandom sc = new SecureRandom();
// KeyGenerationParameters kp = new KeyGenerationParameters(sc, 256);
//
// RSAKeyPairGenerator rsak = new RSAKeyPairGenerator();
// rsak.init(kp);
RSAKeyGenerationParameters kk = new RSAKeyGenerationParameters(
BigInteger.valueOf(65537),//publicExponent
SecureRandom.getInstance("SHA1PRNG"),//prng
3072,//strength
80//certainty
);
RSAKeyPairGenerator generator = new RSAKeyPairGenerator();
generator.init(kk);
long j = System.currentTimeMillis();
System.out.println("Starting RSA keypairgeneration...");
AsymmetricCipherKeyPair keyPair = generator.generateKeyPair();
j = System.currentTimeMillis() - j;
System.out.println("ENDED RSA keypairgeneration... "+j+"ms -> "+keyPair.getClass().getName());
CipherParameters pub = keyPair.getPublic();
CipherParameters priv = keyPair.getPrivate();
RSAKeyParameters rpub = (RSAKeyParameters)pub;
RSAPrivateCrtKeyParameters rpriv = (RSAPrivateCrtKeyParameters)priv;
// System.out.println("***PRIV***\nEXP: "+rpriv.getExponent()+"\nMOD: "+rpriv.getModulus());
// System.out.println("\n\n***PUB***\nEXP: "+rpub.getExponent()+"\nMOD: "+rpub.getModulus());
// System.out.println("BITCOUNT_PRIV_EXP: "+rpriv.getExponent().bitLength());
// System.out.println("BITCOUNT_PRIV_MOD: "+rpriv.getModulus().bitLength());
// System.out.println("BITCOUNT_PUB_EXP: "+rpub.getExponent().bitLength());
// System.out.println("BITCOUNT_PUB_MOD: "+rpub.getModulus().bitLength());
return new AsymmetricKeyPair(keyPair );
}
public byte[] encryptWithPublicKey(byte[] me) throws Exception {
return pubkey.encrypt(me);
}
public byte[] decryptWithPrivateKey(byte[] me) throws Exception {
return privkey.decrypt(me);
}
public byte[] encryptBlocks(byte[] data) throws Exception {
int blockSize = 342;
if (blockSize>342) {
//max 342 bytes can be encrypted with asymmeric encryption -> use block sizes <= 342
throw new RuntimeException("max blocksize is 342");
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int pos = 0;
while (pos<data.length) {
byte[] crypt;
if (pos<data.length) {
crypt = pubkey.encrypt(Arrays.copyOfRange(data, pos, pos+blockSize));
} else {
crypt = pubkey.encrypt(Arrays.copyOfRange(data, pos, data.length));
}
pos += blockSize;
out.write(crypt);
}
out.close();
return out.toByteArray();
}
public byte[] decryptBlocks(byte[] data) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int blockSize = 384;
int pos = 0;
byte[] decrypt = null;
while (pos<data.length) {
if (pos+blockSize<data.length) {
decrypt = privkey.decrypt(Arrays.copyOfRange(data, pos, pos+blockSize));
} else {
decrypt = privkey.decrypt(Arrays.copyOfRange(data, pos, data.length));
}
pos += blockSize;
out.write(decrypt);
}
out.close();
return out.toByteArray();
}
// public byte[] sign(byte[] plain) throws Exception {
// return privkey.sign(plain);
// }
public byte[] sign(
byte[] md5, //16 bytes
byte[] sha1, //20 bytes
byte[] sha256, //32 bytes
long datetime //6 bytes
) throws Exception {
byte[] dd = new byte[16+20+32+6];
Arrays.fill(dd, (byte)0);
if(md5 != null) {
System.arraycopy(md5, 0, dd, 0, md5.length);
}
if(sha1 != null) {
System.arraycopy(sha1, 0, dd, 0+16, sha1.length);
}
if(sha256 != null) {
System.arraycopy(sha256, 0, dd, 0+16+20, sha256.length);
}
BigInteger b = BigInteger.valueOf(datetime);
byte[] ts = b.toByteArray();
System.arraycopy(ts, 0, dd, 0+16+20+32, ts.length);
return privkey.sign(dd);
}
// public byte[] signDirectly(byte[] data) throws Exception {
// return privkey.sign(data);
// }
// public boolean verify(byte[] signature, byte[] plain) throws Exception {
// return pubkey.verify(signature, plain);
// }
public boolean verify(
byte[] signature,
byte[] md5,
byte[] sha1,
byte[] sha256,
long timestamp
) throws Exception {
return pubkey.verify(
signature,
md5,
sha1,
sha256,
timestamp
);
}
// public boolean verifyDirectly(byte[] signature_bytes, byte[] compare) throws Exception {
// return pubkey.verifyDirectly(signature_bytes, compare);
// }
public byte[] getEncrytedPrivateKey(SymmetricKey sk) throws Exception {
return privkey.getEncrytedPrivateKey(sk);
}
public static void main(String[] args) throws Exception {
// BigInteger b = BigInteger.valueOf(System.currentTimeMillis());
// byte[] ts = b.toByteArray();
// System.out.println("long as byte-array.lenght: "+ts.length);
AsymmetricKeyPair ak = generateAsymmetricKeyPair();
System.out.println("BitCount: "+ak.getBitCount());
String tc = new String("I am to encode...");
byte[] data = ak.encryptWithPublicKey(tc.getBytes());
System.out.println("ENCODED: "+SecurityHelper.HexDecoder.encode(data, ':', 80));
byte[] dec = ak.decryptWithPrivateKey(data);
System.out.println("DECODED: "+SecurityHelper.HexDecoder.encode(dec, ':', 80)+" -> "+(new String(dec)));
System.out.println("\n\n\n");
byte[][] kk = SecurityHelper.getMD5SHA1SHA256(tc.getBytes());
byte[] md5sha1sha256 = kk[0];
byte[] md5 = kk[1];
byte[] sha1 = kk[2];
byte[] sha256 = kk[3];
long ll = System.currentTimeMillis();
String s = SecurityHelper.HexDecoder.encode(md5sha1sha256, ':', 80);
System.out.println("SHA1_AND_MD5 length:\t"+md5sha1sha256.length);//sollten 36 bytes sein
System.out.println("SHA1_AND_MD5:\t\t"+s);
System.out.println("\nSignature creation stage...");
byte[] signature = ak.sign(
md5,
sha1,
sha256,
ll
); //just show-off - could have also taken the full-array
System.out.println("SIGNATURE(md5sha1sha256).length: "+signature.length);
System.out.println("SIGNATURE(md5sha1sha256): "+SecurityHelper.HexDecoder.encode(signature, ':', 80));
System.out.println("\nVerification-Stage...");
System.out.println("SIGNATURE_VERIFIED: "+ak.verify(
signature,
md5,
sha1,
sha256,
ll
)
);
}
}