how to generate ValueLink merchant working keys - java

I am trying to generate ValueLink merchant working keys using a modified version of the apache ofbiz ValueLinkApi Class - src
I've modified it only to the extent of making it a standalone class that I can run from outside the context of the ofbiz framework.
My program runs without error but my keys are not being accepted by the api.
Have you ever implemented this? Did you use this library or something else like openSSL? If you used this library did you have to modify it at all?
heres my version:
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyAgreement;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPrivateKeySpec;
import javax.crypto.spec.DHPublicKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.StringUtil;
public class diffHel {
public static final String module = "diffHel";
//were in props
public String publicValue = "6B0276780D3E07911D744F545833005E8C2F755E0FE59A8660527F7B7E070A45EEB853DA70C6EFE2B8BF278F0B4A334A49DF0985635745A3DAD2E85A9C0EEFAE657CC382A0B3EAE9C3F85B0A2305282612CFD2857801131EC9FE313DB9DADFB914A30EE077E8A97E5574CE5BD56661B021C39116913710947FAA38FFCB4FC045";
public String format = "ddMMyyyyHHmmss";
public String primeHex = "e516e43e5457b2f66f6ca367b335ead8319939fa4df6c1b7f86e73e922a6d19393255e419096668174e35c818a66117f799e8666c8050ee436f9801351606c55d45faba03f39e2923ba926a9cd75d4bdbca9de78b62a9b847a781c692c063eaacb43a396f01d121d042755d0b7c0b2dfa8b498a57e4d90c30ca049a7ac2b7f73";
public String genString = "05";
//were generic values
public String exchangeKey;
public String privateKey = "";
protected SecretKey kek = null;
protected SecretKey mwk = null;
protected String merchantId = null;
protected String terminalId = null;
protected Long mwkIndex = null;
protected boolean debug = false;
public StringBuffer buf = new StringBuffer();
public diffHel() {}
/**
* Output the creation of public/private keys + KEK to the console for manual database update
*/
public StringBuffer outputKeyCreation(boolean kekOnly, String kekTest) {
return this.outputKeyCreation(0, kekOnly, kekTest);
}
private StringBuffer outputKeyCreation(int loop, boolean kekOnly, String kekTest) {
//StringBuffer buf = new StringBuffer();
loop++;
if (loop > 100) {
// only loop 100 times; then throw an exception
throw new IllegalStateException("Unable to create 128 byte keys in 100 tries");
}
// place holder for the keys
DHPrivateKey privateKey = null;
DHPublicKey publicKey = null;
if (!kekOnly) {
KeyPair keyPair = null;
try {
keyPair = this.createKeys();
} catch (NoSuchAlgorithmException e) {
Debug.logError(e, module);
} catch (InvalidAlgorithmParameterException e) {
Debug.logError(e, module);
} catch (InvalidKeySpecException e) {
Debug.logError(e, module);
}
if (keyPair != null) {
publicKey = (DHPublicKey) keyPair.getPublic();
privateKey = (DHPrivateKey) keyPair.getPrivate();
buf.append("privateKeyLenth=" + privateKey.getX().toByteArray().length);
if (publicKey == null || publicKey.getY().toByteArray().length != 128) {
// run again until we get a 128 byte public key for VL
return this.outputKeyCreation(loop, kekOnly, kekTest);
}
} else {
Debug.log("Returned a null KeyPair", module);
return this.outputKeyCreation(loop, kekOnly, kekTest);
}
} else {
// use our existing private key to generate a KEK
try {
privateKey = (DHPrivateKey) this.getPrivateKey();
} catch (Exception e) {
Debug.logError(e, module);
}
}
// the KEK
byte[] kekBytes = null;
try {
kekBytes = this.generateKek(privateKey);
} catch (NoSuchAlgorithmException e) {
Debug.logError(e, module);
} catch (InvalidKeySpecException e) {
Debug.logError(e, module);
} catch (InvalidKeyException e) {
Debug.logError(e, module);
}
// the 3DES KEK value
SecretKey loadedKek = this.getDesEdeKey(kekBytes);
byte[] loadKekBytes = loadedKek.getEncoded();
// test the KEK
//Cipher cipher = this.getCipher(this.getKekKey(), Cipher.ENCRYPT_MODE);
Cipher cipher = this.getCipher(loadedKek, Cipher.ENCRYPT_MODE);
byte[] kekTestB = { 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] kekTestC = new byte[0];
if (kekTest != null) {
kekTestB = StringUtil.fromHexString(kekTest);
}
// encrypt the test bytes
try {
kekTestC = cipher.doFinal(kekTestB);
} catch (Exception e) {
Debug.logError(e, module);
}
kek = loadedKek;
byte[] newMwk = generateMwk(loadedKek);
byte[] decyptedMwk = decryptViaKek(newMwk);
if (!kekOnly) {
// public key (just Y)
BigInteger y = publicKey.getY();
byte[] yBytes = y.toByteArray();
String yHex = StringUtil.toHexString(yBytes);
buf.append("======== Begin Public Key (Y # " + yBytes.length + " / " + yHex.length() + ") ========\n");
buf.append(yHex + "\n");
buf.append("======== End Public Key ========\n\n");
// private key (just X)
BigInteger x = privateKey.getX();
byte[] xBytes = x.toByteArray();
String xHex = StringUtil.toHexString(xBytes);
buf.append("======== Begin Private Key (X # " + xBytes.length + " / " + xHex.length() + ") ========\n");
buf.append(xHex + "\n");
buf.append("======== End Private Key ========\n\n");
// private key (full)
byte[] privateBytes = privateKey.getEncoded();
String privateHex = StringUtil.toHexString(privateBytes);
buf.append("======== Begin Private Key (Full # " + privateBytes.length + " / " + privateHex.length() + ") ========\n");
buf.append(privateHex + "\n");
buf.append("======== End Private Key ========\n\n");
}
if (kekBytes != null) {
buf.append("======== Begin KEK aka decrypted MWK (" + kekBytes.length + ") ========\n");
buf.append(StringUtil.toHexString(kekBytes) + "\n");
buf.append("======== End KEK ========\n\n");
buf.append("======== Begin KEK (DES) (" + loadKekBytes.length + ") ========\n");
buf.append(StringUtil.toHexString(loadKekBytes) + "\n");
buf.append("======== End KEK (DES) ========\n\n");
buf.append("======== Begin KEK Test (" + kekTestC.length + ") ========\n");
buf.append(StringUtil.toHexString(kekTestC) + "\n");
buf.append("======== End KEK Test ========\n\n");
} else {
Debug.logError("KEK came back empty", module);
}
if (newMwk != null) {
buf.append("======== Begin MWK (" + newMwk.length + ") ========\n");
buf.append(StringUtil.toHexString(newMwk) + "\n");
buf.append("======== End MWK ========\n\n");
}
if (decyptedMwk != null) {
buf.append("======== Begin Decrypted MWK (" + decyptedMwk.length + ") ========\n");
buf.append(StringUtil.toHexString(decyptedMwk) + "\n");
buf.append("======== End Decrypted MWK ========\n\n");
}
return buf;
}
/**
* Create a set of public/private keys using ValueLinks defined parameters
* #return KeyPair object containing both public and private keys
* #throws NoSuchAlgorithmException
* #throws InvalidAlgorithmParameterException
*/
public KeyPair createKeys() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException {
// initialize the parameter spec
DHPublicKey publicKey = (DHPublicKey) this.getValueLinkPublicKey();
DHParameterSpec dhParamSpec = publicKey.getParams();
//Debug.log(dhParamSpec.getP().toString() + " / " + dhParamSpec.getG().toString(), module);
// create the public/private key pair using parameters defined by valuelink
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
keyGen.initialize(dhParamSpec);
KeyPair keyPair = keyGen.generateKeyPair();
return keyPair;
}
/**
* Generate a key exchange key for use in encrypting the mwk
* #param privateKey The private key for the merchant
* #return byte array containing the kek
* #throws NoSuchAlgorithmException
* #throws InvalidKeySpecException
* #throws InvalidKeyException
*/
public byte[] generateKek(PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
// get the ValueLink public key
PublicKey vlPublic = this.getValueLinkPublicKey();
// generate shared secret key
KeyAgreement ka = KeyAgreement.getInstance("DH");
ka.init(privateKey);
ka.doPhase(vlPublic, true);
byte[] secretKey = ka.generateSecret();
buf.append("======== Secret Key (" + secretKey.length + ") ========\n");
buf.append(StringUtil.toHexString(secretKey) + "\n");
buf.append("======== End Secret Key ========\n\n");
if (debug) {
Debug.log("Secret Key : " + StringUtil.toHexString(secretKey) + " / " + secretKey.length, module);
}
// generate 3DES from secret key using VL algorithm (KEK)
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(secretKey);
byte[] des2 = getByteRange(digest, 0, 16);
byte[] first8 = getByteRange(des2, 0, 8);
byte[] kek = copyBytes(des2, first8, 0);
if (debug) {
Debug.log("Generated KEK : " + StringUtil.toHexString(kek) + " / " + kek.length, module);
}
return kek;
}
/**
* Get a public key object for the ValueLink supplied public key
* #return PublicKey object of ValueLinks's public key
* #throws NoSuchAlgorithmException
* #throws InvalidKeySpecException
*/
public PublicKey getValueLinkPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
// read the valuelink public key
//String publicValue = (String) props.get("payment.valuelink.publicValue");
byte[] publicKeyBytes = StringUtil.fromHexString(publicValue);
// initialize the parameter spec
DHParameterSpec dhParamSpec = this.getDHParameterSpec();
// load the valuelink public key
KeyFactory keyFactory = KeyFactory.getInstance("DH");
BigInteger publicKeyInt = new BigInteger(publicKeyBytes);
DHPublicKeySpec dhPublicSpec = new DHPublicKeySpec(publicKeyInt, dhParamSpec.getP(), dhParamSpec.getG());
PublicKey vlPublic = keyFactory.generatePublic(dhPublicSpec);
return vlPublic;
}
/**
* Get merchant Private Key
* #return PrivateKey object for the merchant
*/
public PrivateKey getPrivateKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
byte[] privateKeyBytes = this.getPrivateKeyBytes();
// initialize the parameter spec
DHParameterSpec dhParamSpec = this.getDHParameterSpec();
// load the private key
KeyFactory keyFactory = KeyFactory.getInstance("DH");
BigInteger privateKeyInt = new BigInteger(privateKeyBytes);
DHPrivateKeySpec dhPrivateSpec = new DHPrivateKeySpec(privateKeyInt, dhParamSpec.getP(), dhParamSpec.getG());
PrivateKey privateKey = keyFactory.generatePrivate(dhPrivateSpec);
return privateKey;
}
/**
* Generate a new MWK
* #return Hex String of the new encrypted MWK ready for transmission to ValueLink
*/
public byte[] generateMwk() {
KeyGenerator keyGen = null;
try {
keyGen = KeyGenerator.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
Debug.logError(e, module);
}
// generate the DES key 1
SecretKey des1 = keyGen.generateKey();
SecretKey des2 = keyGen.generateKey();
if (des1 != null && des2 != null) {
byte[] desByte1 = des1.getEncoded();
byte[] desByte2 = des2.getEncoded();
byte[] desByte3 = des1.getEncoded();
// check for weak keys
try {
if (DESKeySpec.isWeak(des1.getEncoded(), 0) || DESKeySpec.isWeak(des2.getEncoded(), 0)) {
return generateMwk();
}
} catch (Exception e) {
Debug.logError(e, module);
}
byte[] des3 = copyBytes(desByte1, copyBytes(desByte2, desByte3, 0), 0);
return generateMwk(des3);
} else {
Debug.log("Null DES keys returned", module);
}
return null;
}
/**
* Generate a new MWK
* #param desBytes byte array of the DES key (24 bytes)
* #return Hex String of the new encrypted MWK ready for transmission to ValueLink
*/
public byte[] generateMwk(byte[] desBytes) {
if (debug) {
Debug.log("DES Key : " + StringUtil.toHexString(desBytes) + " / " + desBytes.length, module);
}
SecretKeyFactory skf1 = null;
SecretKey mwk = null;
try {
skf1 = SecretKeyFactory.getInstance("DESede");
} catch (NoSuchAlgorithmException e) {
Debug.logError(e, module);
}
DESedeKeySpec desedeSpec2 = null;
try {
desedeSpec2 = new DESedeKeySpec(desBytes);
} catch (InvalidKeyException e) {
Debug.logError(e, module);
}
if (skf1 != null && desedeSpec2 != null) {
try {
mwk = skf1.generateSecret(desedeSpec2);
} catch (InvalidKeySpecException e) {
Debug.logError(e, module);
}
}
if (mwk != null) {
return generateMwk(mwk);
} else {
return null;
}
}
/**
* Generate a new MWK
* #param mwkdes3 pre-generated DES3 SecretKey
* #return Hex String of the new encrypted MWK ready for transmission to ValueLink
*/
public byte[] generateMwk(SecretKey mwkdes3) {
// zeros for checksum
byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 };
// 8 bytes random data
byte[] random = new byte[8];
Random ran = new Random();
ran.nextBytes(random);
// open a cipher using the new mwk
Cipher cipher = this.getCipher(mwkdes3, Cipher.ENCRYPT_MODE);
// make the checksum - encrypted 8 bytes of 0's
byte[] encryptedZeros = new byte[0];
try {
encryptedZeros = cipher.doFinal(zeros);
} catch (IllegalStateException e) {
Debug.logError(e, module);
} catch (IllegalBlockSizeException e) {
Debug.logError(e, module);
} catch (BadPaddingException e) {
Debug.logError(e, module);
}
// make the 40 byte MWK - random 8 bytes + key + checksum
byte[] newMwk = copyBytes(mwkdes3.getEncoded(), encryptedZeros, 0);
newMwk = copyBytes(random, newMwk, 0);
if (debug) {
Debug.log("Random 8 byte : " + StringUtil.toHexString(random), module);
Debug.log("Encrypted 0's : " + StringUtil.toHexString(encryptedZeros), module);
Debug.log("Decrypted MWK : " + StringUtil.toHexString(mwkdes3.getEncoded()) + " / " + mwkdes3.getEncoded().length, module);
Debug.log("Encrypted MWK : " + StringUtil.toHexString(newMwk) + " / " + newMwk.length, module);
}
return newMwk;
}
/**
* Use the KEK to encrypt a value usually the MWK
* #param content byte array to encrypt
* #return encrypted byte array
*/
public byte[] encryptViaKek(byte[] content) {
return cryptoViaKek(content, Cipher.ENCRYPT_MODE);
}
/**
* Ue the KEK to decrypt a value
* #param content byte array to decrypt
* #return decrypted byte array
*/
public byte[] decryptViaKek(byte[] content) {
return cryptoViaKek(content, Cipher.DECRYPT_MODE);
}
/**
* Returns a date string formatted as directed by ValueLink
* #return ValueLink formatted date String
*/
public String getDateString() {
//String format = (String) props.get("payment.valuelink.timestamp");
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(new Date());
}
// using the prime and generator provided by valuelink; create a parameter object
protected DHParameterSpec getDHParameterSpec() {
//String primeHex = (String) props.get("payment.valuelink.prime");
//String genString = (String) props.get("payment.valuelink.generator");
// convert the p/g hex values
byte[] primeByte = StringUtil.fromHexString(this.primeHex);
BigInteger prime = new BigInteger(1, primeByte); // force positive (unsigned)
BigInteger generator = new BigInteger(this.genString);
// initialize the parameter spec
DHParameterSpec dhParamSpec = new DHParameterSpec(prime, generator, 1024);
return dhParamSpec;
}
// actual kek encryption/decryption code
protected byte[] cryptoViaKek(byte[] content, int mode) {
// open a cipher using the kek for transport
Cipher cipher = this.getCipher(this.getKekKey(), mode);
byte[] dec = new byte[0];
try {
dec = cipher.doFinal(content);
} catch (IllegalStateException e) {
Debug.logError(e, module);
} catch (IllegalBlockSizeException e) {
Debug.logError(e, module);
} catch (BadPaddingException e) {
Debug.logError(e, module);
}
return dec;
}
// return a cipher for a key - DESede/CBC/NoPadding IV = 0
protected Cipher getCipher(SecretKey key, int mode) {
byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec iv = new IvParameterSpec(zeros);
// create the Cipher - DESede/CBC/NoPadding
Cipher mwkCipher = null;
try {
mwkCipher = Cipher.getInstance("DESede/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
Debug.logError(e, module);
return null;
} catch (NoSuchPaddingException e) {
Debug.logError(e, module);
}
try {
mwkCipher.init(mode, key, iv);
} catch (InvalidKeyException e) {
Debug.logError(e, "Invalid key", module);
} catch (InvalidAlgorithmParameterException e) {
Debug.logError(e, module);
}
return mwkCipher;
}
protected SecretKey getKekKey() {
if (kek == null) {
kek = this.getDesEdeKey(getKek());
}
if (debug) {
Debug.log("Raw KEK : " + StringUtil.toHexString(getKek()), module);
Debug.log("KEK : " + StringUtil.toHexString(kek.getEncoded()), module);
}
return kek;
}
protected SecretKey getDesEdeKey(byte[] rawKey) {
SecretKeyFactory skf = null;
try {
skf = SecretKeyFactory.getInstance("DESede");
} catch (NoSuchAlgorithmException e) {
// should never happen since DESede is a standard algorithm
Debug.logError(e, module);
return null;
}
// load the raw key
if (rawKey.length > 0) {
DESedeKeySpec desedeSpec1 = null;
try {
desedeSpec1 = new DESedeKeySpec(rawKey);
} catch (InvalidKeyException e) {
Debug.logError(e, "Not a valid DESede key", module);
return null;
}
// create the SecretKey Object
SecretKey key = null;
try {
key = skf.generateSecret(desedeSpec1);
} catch (InvalidKeySpecException e) {
Debug.logError(e, module);
}
return key;
} else {
throw new RuntimeException("No valid DESede key available");
}
}
protected byte[] getKek() {
//return StringUtil.fromHexString(this.getGenericValue().getString("exchangeKey"));
return StringUtil.fromHexString(this.exchangeKey);
}
protected byte[] getPrivateKeyBytes() {
//return StringUtil.fromHexString(this.getGenericValue().getString("privateKey"));
return StringUtil.fromHexString(this.privateKey);
}
/**
* Returns a new byte[] from the offset of the defined byte[] with a specific number of bytes
* #param bytes The byte[] to extract from
* #param offset The starting postition
* #param length The number of bytes to copy
* #return a new byte[]
*/
public static byte[] getByteRange(byte[] bytes, int offset, int length) {
byte[] newBytes = new byte[length];
for (int i = 0; i < length; i++) {
newBytes[i] = bytes[offset + i];
}
return newBytes;
}
/**
* Copies a byte[] into another byte[] starting at a specific position
* #param source byte[] to copy from
* #param target byte[] coping into
* #param position the position on target where source will be copied to
* #return a new byte[]
*/
public static byte[] copyBytes(byte[] source, byte[] target, int position) {
byte[] newBytes = new byte[target.length + source.length];
for (int i = 0, n = 0, x = 0; i < newBytes.length; i++) {
if (i < position || i > (position + source.length - 2)) {
newBytes[i] = target[n];
n++;
} else {
for (; x < source.length; x++) {
newBytes[i] = source[x];
if (source.length - 1 > x) {
i++;
}
}
}
}
return newBytes;
}
}

Related

Implementing CRYSTALS-Kyber using BouncyCastle Java

Could anyone help lead me in the right direction to even just generate a keypair using Kyber? I've tried to search for BouncyCastle examples but I am unable to find any to go off.
I'm trying to benchmark some current algorithms such as AES/RSA, which I have working perfectly, but I am unable to make any progress on even getting started on Kyber. Any help would be greatly appreciated.
I've tried to search it on Google for examples, the developers have implementations C# and even Java without BouncyCastle on their website. They mention it is available on BouncyCastle but I cannot find any documentation for it even to help implement it.
I can provide a complete example for CHRYSTALS-KYBER using Bouncy Castle. It generates a keypair, calculates an encryption key and decryption key.
There are three parameter specs available:
KyberParameterSpec.kyber512
KyberParameterSpec.kyber768
KyberParameterSpec.kyber1024
As the class was used in a larger Android project it may not work properly stand alone.
I tested the algorithm using Bouncy Castle version 1.72.
This is the full code:
import org.bouncycastle.jcajce.SecretKeyWithEncapsulation;
import org.bouncycastle.jcajce.spec.KEMExtractSpec;
import org.bouncycastle.jcajce.spec.KEMGenerateSpec;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.pqc.jcajce.spec.KyberParameterSpec;
import org.bouncycastle.util.Arrays;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.KeyGenerator;
public class PqcChrystalsKyberKem {
public static void main(String[] args) {
// Security.addProvider(new BouncyCastleProvider());
// we do need the regular Bouncy Castle file that includes the PQC provider
// get Bouncy Castle here: https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk18on
// tested with BC version 1.72
if (Security.getProvider("BCPQC") == null) {
Security.addProvider(new BouncyCastlePQCProvider());
}
String print = run(false);
System.out.println(print);
}
public static String run(boolean truncateKeyOutput) {
String out = "PQC Chrystals-Kyber KEM";
out += "\n" + "\n************************************\n" +
"* # # SERIOUS SECURITY WARNING # # *\n" +
"* This program is a CONCEPT STUDY *\n" +
"* for the algorithm *\n" +
"* Chrystals-Kyber [key exchange *\n" +
"* mechanism] *\n" +
"* The program is using an *\n" +
"* parameter set that I cannot *\n" +
"* check for the correctness of the *\n" +
"* output and other details *\n" +
"* *\n" +
"* DO NOT USE THE PROGRAM IN *\n" +
"* ANY PRODUCTION ENVIRONMENT *\n" +
"************************************";
// as there are 3 parameter sets available the program runs all of them
KyberParameterSpec[] kyberParameterSpecs = {
KyberParameterSpec.kyber512,
KyberParameterSpec.kyber768,
KyberParameterSpec.kyber1024
};
// statistics
int nrOfSpecs = kyberParameterSpecs.length;
String[] parameterSpecName = new String[nrOfSpecs];
int[] privateKeyLength = new int[nrOfSpecs];
int[] publicKeyLength = new int[nrOfSpecs];
int[] encryptionKeyLength = new int[nrOfSpecs];
int[] encapsulatedKeyLength = new int[nrOfSpecs];
boolean[] encryptionKeysEquals = new boolean[nrOfSpecs];
out += "\n\n****************************************\n";
for (int i = 0; i < nrOfSpecs; i++) {
// generation of the Chrystals-Kyber key pair
KyberParameterSpec kyberParameterSpec = kyberParameterSpecs[i];
String kyberParameterSpecName = kyberParameterSpec.getName();
parameterSpecName[i] = kyberParameterSpecName;
out += "\n" + "Chrystals-Kyber KEM with parameterset " + kyberParameterSpecName;
KeyPair keyPair = generateChrystalsKyberKeyPair(kyberParameterSpec);
// get private and public key
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// storing the key as byte array
byte[] privateKeyByte = privateKey.getEncoded();
byte[] publicKeyByte = publicKey.getEncoded();
out += "\n" + "\ngenerated private key length: " + privateKeyByte.length;
out += "\n" + "generated public key length: " + publicKeyByte.length;
privateKeyLength[i] = privateKeyByte.length;
publicKeyLength[i] = publicKeyByte.length;
// generate the keys from a byte array
PrivateKey privateKeyLoad = getChrystalsKyberPrivateKeyFromEncoded(privateKeyByte);
PublicKey publicKeyLoad = getChrystalsKyberPublicKeyFromEncoded(publicKeyByte);
// generate the encryption key and the encapsulated key
out += "\n" + "\nEncryption side: generate the encryption key and the encapsulated key";
SecretKeyWithEncapsulation secretKeyWithEncapsulationSender = pqcGenerateChrystalsKyberEncryptionKey(publicKeyLoad);
byte[] encryptionKey = secretKeyWithEncapsulationSender.getEncoded();
out += "\n" + "encryption key length: " + encryptionKey.length
+ " key: " + bytesToHex(secretKeyWithEncapsulationSender.getEncoded());
byte[] encapsulatedKey = secretKeyWithEncapsulationSender.getEncapsulation();
out += "\n" + "encapsulated key length: " + encapsulatedKey.length + " key: " + (truncateKeyOutput ?shortenString(bytesToHex(encapsulatedKey)):bytesToHex(encapsulatedKey));
encryptionKeyLength[i] = encryptionKey.length;
encapsulatedKeyLength[i] = encapsulatedKey.length;
out += "\n" + "\nDecryption side: receive the encapsulated key and generate the decryption key";
byte[] decryptionKey = pqcGenerateChrystalsKyberDecryptionKey(privateKeyLoad, encapsulatedKey);
out += "\n" + "decryption key length: " + decryptionKey.length + " key: " + bytesToHex(decryptionKey);
boolean keysAreEqual = Arrays.areEqual(encryptionKey, decryptionKey);
out += "\n" + "decryption key is equal to encryption key: " + keysAreEqual;
encryptionKeysEquals[i] = keysAreEqual;
out += "\n\n****************************************\n";
}
out += "\n" + "Test results";
out += "\n" + "parameter spec name priKL pubKL encKL capKL keyE" + "\n";
for (int i = 0; i < nrOfSpecs; i++) {
String out1 = String.format("%-20s%6d%8d%6d%6d%6b%n", parameterSpecName[i], privateKeyLength[i], publicKeyLength[i], encryptionKeyLength[i], encapsulatedKeyLength[i], encryptionKeysEquals[i]);
out += out1;
}
out += "\n" + "Legend: priKL privateKey length, pubKL publicKey length, encKL encryption key length, "
+ "capKL encapsulated key length" + "\n";
out += "****************************************\n";
return out;
}
private static String shortenString (String input) {
if (input != null && input.length() > 32) {
return input.substring(0, 32) + " ...";
} else {
return input;
}
}
private static KeyPair generateChrystalsKyberKeyPair(KyberParameterSpec kyberParameterSpec) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("KYBER", "BCPQC");
kpg.initialize(kyberParameterSpec, new SecureRandom());
KeyPair kp = kpg.generateKeyPair();
return kp;
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
return null;
}
}
public static SecretKeyWithEncapsulation pqcGenerateChrystalsKyberEncryptionKey(PublicKey publicKey) {
KeyGenerator keyGen = null;
try {
keyGen = KeyGenerator.getInstance("KYBER", "BCPQC");
keyGen.init(new KEMGenerateSpec((PublicKey) publicKey, "AES"), new SecureRandom());
SecretKeyWithEncapsulation secEnc1 = (SecretKeyWithEncapsulation) keyGen.generateKey();
return secEnc1;
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
return null;
}
}
public static byte[] pqcGenerateChrystalsKyberDecryptionKey(PrivateKey privateKey, byte[] encapsulatedKey) {
KeyGenerator keyGen = null;
try {
keyGen = KeyGenerator.getInstance("KYBER", "BCPQC");
keyGen.init(new KEMExtractSpec((PrivateKey) privateKey, encapsulatedKey, "AES"), new SecureRandom());
SecretKeyWithEncapsulation secEnc2 = (SecretKeyWithEncapsulation) keyGen.generateKey();
return secEnc2.getEncoded();
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
return null;
}
}
private static PrivateKey getChrystalsKyberPrivateKeyFromEncoded(byte[] encodedKey) {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedKey);
KeyFactory keyFactory = null;
try {
keyFactory = KeyFactory.getInstance("KYBER", "BCPQC");
return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException e) {
e.printStackTrace();
return null;
}
}
private static PublicKey getChrystalsKyberPublicKeyFromEncoded(byte[] encodedKey) {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedKey);
try {
KeyFactory keyFactory = KeyFactory.getInstance("KYBER", "BCPQC");
return keyFactory.generatePublic(x509EncodedKeySpec);
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException e) {
e.printStackTrace();
return null;
}
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}

Ruby: Large data RSA Encryption

so I need to encrypt strings using RSA.
The example of the string (this is verified correct string):
"1658135277&{\"user_id\":\"f257bf74-8c14-4144-aca5-69e1d8819d9d\",\"user_id_type\":\"3\",\"user_name\":\"{\\\"first_name\\\":\\\"SEAN\\\",\\\"middle_name\\\":\\\"\\\",\\\"last_name\\\":\\\"YEO\\\",\\\"full_name\\\":\\\"SEAN YEO\\\"}\",\"user_dob\":\"1993-03-31\",\"nationality\":\"SG\",\"user_address\":\"{\\\"region\\\":\\\"SG\\\",\\\"address_line1\\\":\\\"200 Jalan Sultan, 03-02, Textile Centre\\\"}\"}"
The ruby code:
def get_base64_encryption(unix_timestamp, params)
str = "#{unix_timestamp}&#{params.to_json}"
public_key = OpenSSL::PKey::RSA.new(PUBLIC_KEY_PEM)
encrypted_str = public_key.public_encrypted(str, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
Base64.strict_encode64(encrypted_str)
end
But this way, it will raise error OpenSSL::PKey::RSAError (data too large for key size)
The thing is, I need to encrypt this for integration with 3rd party API. So there's no way I can use other encryption.
The partner actually gave example code, but in java:
public class RSAUtil {
private static final String KEY_ALGORITHM = "RSA";
private static final String RSA_ALGORITHM = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
// rsa secret key length 256 bytes(2048bit)
private static final int MAX_DECRYPT_BLOCK = 256;
// rsa encrypt data length
private static final int MAX_ENCRYPT_BLOCK = 200;
/**
* rsa encrypt data
* #param message
* #param publicKeyStr
* #return
*/
public static String rsaEncryptOAEP(String message, String publicKeyStr) {
try {
System.out.println("message_size:" + message.length());
Decoder decoder = Base64.getDecoder();
byte[] publicKeyStrByte = decoder.decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyStrByte);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] inputData = message.getBytes(StandardCharsets.UTF_8);
int inputLen = inputData.length;
byte[] cache = null;
byte[] out = null;
// split data by block size
for (int offSet = 0; offSet < inputLen; offSet += MAX_ENCRYPT_BLOCK) {
if (offSet + MAX_ENCRYPT_BLOCK < inputLen) {
cache = cipher.doFinal(inputData, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(inputData, offSet, inputLen - offSet);
}
out = mergeBytes(out, cache);
}
return Base64.getEncoder().encodeToString(out);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
System.out.println("current java env not support RSA v1.5/OAEP");
e.printStackTrace();
} catch (InvalidKeyException | InvalidKeySpecException e) {
System.out.println("invalid key");
e.printStackTrace();
} catch (IllegalBlockSizeException | BadPaddingException e) {
System.out.println("block size more than 214 ");
e.printStackTrace();
}
return "";
}
/**
* merge 2 bytes
*
* #param first
* #param last
* #return
*/
private static byte[] mergeBytes(byte[] first, byte[] last) {
if (first == null) {
return last;
}
byte[] result = new byte[first.length + last.length];
System.arraycopy(first, 0, result, 0, first.length);
System.arraycopy(last, 0, result, first.length, last.length);
return result;
}
}
But I still failed to translate the example code to ruby, especially because I couldn't find how to encrypt data in streaming fashion using RSA in ruby. Anyone can help? Thank you in advance.
For everyone who comes up with this problem, here is the answer:
def get_base64_encryption(unix_timestamp, params)
str = "#{unix_timestamp}&#{params.to_json}"
public_key = OpenSSL::PKey::RSA.new(PUBLIC_KEY_PEM)
encrypted_str = ''
io = StringIO.new(str)
until io.eof?
chunk = io.read(200)
encrypted_str << public_key.public_encrypt(chunk, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
end
Base64.strict_encode64(encrypted_str)
end
OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING is equal to RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING source

Working with AES Encryption Java to C#

We have the application done C# and passing parameter to Java application. To make it secure we Java application developer come up with AES encryption. The developer gave sample code in Java. Kindly somebody helps me. How can I encrypt same way in C#
// Cryptix imports
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import cryptix.provider.key.RawSecretKey;
import cryptix.util.core.Hex;
import xjava.security.Cipher;
public class AESEncryption {
private Cipher m_alg;
private RawSecretKey m_key;
private static final String RIJNDAEL = "Rijndael"; //mode of encryption
private static final String PROVIDER_CRYPTIX = "Cryptix"; // Cryptography algorithm providers
/**
* Must (once) be dynamically installed. - could alternatively be set
* statically in $JAVAHOME/lib/security by changing security provider.
*
*/
static {
java.security.Security.addProvider(new cryptix.provider.Cryptix());
System.out.println(" Java Security - Add security provider - Cryptix provider added");
}
public AESEncryption(String secretKey)
throws java.security.NoSuchProviderException, java.security.NoSuchAlgorithmException {
//System.out.println("Key used for encryption/decryption :- " + secretKey);
m_alg = Cipher.getInstance(RIJNDAEL, PROVIDER_CRYPTIX);
m_key = new RawSecretKey(RIJNDAEL, Hex.fromString(secretKey));
}
/**
* encrypt supplied string.
*
* #param str to encrypted
* #return encrypted String
*/
public String encrypt(String str) throws java.security.KeyException {
byte[] ect = null;
str = convert(str); // pad if necessary
//System.out.println("String to encrypt [ " + str + " ]");
m_alg.initEncrypt(m_key);
ect = m_alg.crypt(str.getBytes());
//System.out.println("Encrypted String [ " + Hex.toString(ect) + " ]");
return Hex.toString(ect);
}
public String decrypt(String str) throws java.security.KeyException {
byte[] dct = null;
String decryptedString;
//System.out.println("String to decrypt [ " + str + " ]");
m_alg.initDecrypt(m_key);
dct = m_alg.crypt(Hex.fromString(str));
decryptedString = new String(dct);
//System.out.println("Decrypted String [ " + decryptedString + " ]");
return decryptedString.trim();
}
/**
* Internal routine to convert a string to a byte array and to
* pad the byte array (with 0) in order ot fill out the final block.
*
* padding value based on Cipher's defined block size.
*
* #param str
* #return
*/
private String convert(String str) {
int padding = 0, sourceLength = 0, i, blockSize;
sourceLength = str.length();
blockSize = m_alg.blockSize();
padding = blockSize - (sourceLength % blockSize);
if (padding != blockSize) {
for (i = 0; i < padding; i++) {
str = str + " ";
}
}
return str;
}
public static void main(String[] args) {
try {
AESEncryption tcase = new AESEncryption("27323A0825226DDD316881852610DACB81210355C3117DAD83EF5EE9E8602915");
String params ="accentué";
System.out.println("Params Before:" + params);
String encrypted = tcase.encrypt(params);
System.out.println("Params Encrypted:" + encrypted);
String enc = "E669500CF68CCD88CBA54EDAA07E30A57E8C8518101D0D7C36323194222D6B4393AC2B22A914E902F47C89BC0CE1BCE67A14066219C3480875E1D75536AE0009899C23E644F0C701AE6EBB4DB0C1EDCF9A3A7FFA9BE117237083B5EC4B4EE7FBEBB94D7526C4C9E23EA38E2B2B526E8005265817FC505974DACAA55D3AA50FCE3440BFE79447135D071443DAE4013F2C32CDA00F4AFC2194B616FA50A1BF688F53336194B156E709818DD323F574CDA83A0716F7C22572278D9C162DC8DBC000AEF4C972E6FD203706CFFBE6143130CEB78D4F1CD77B64352766A9C2885AF66B1F81C11A4C71B2B1BF662AD854D429A8356B8FD91B1083ACDAD1DDE3BFF1353D108E2E133558324E63EE9DC13CB4B34BEE494C674BC7BB8C7E77B936AB16BC320E303A34B7510A438C9A9D7E212C3CA3F6771A7DD0CC1AB8A9D1B89FD850B343C7E8828A0155C1A30FA78B250EB073000C9D4F39EA8BF6AE8C19A0BA32EC222DF4BC59396F2396E4FBAB4599EE28E63F068E33614CF84D98D1FEF504E5DCC5940CF17294B6910845A9DDD8805833E1DB1C3CBF0658D1388A65546D58CE465E0E4FA941B6635E1A7042048C1B64456C3EAF9D331E3889E55E37CE71201C7B34526FF2C9297E52F7CBCC7603809566AE4AE3AE644BA826A130DA71DD201532C564F0B11E17306DF061DCF74AD6062931AD09D75345B11933D293945557755788E5C39D1485E87B8C20ED983EA977B9D9CDD7D8E3112D858061A6C376FB37A4E6292B0E4640A05A850175382E385F7F095CAFED9DFCBBEA6C10AA571EE8D01D6022CC240CCDD22EA374D619B4191F619DFB574EBFA80BAEC393F7FCD111789C96AA3DFA1E58E60EEB712F4C4A41506E38A7BF9CF24BFDEF2B7FE6E25C1D9ADAC11EA3CCF6F187A7446A9933D4C4BB25DE8467592D2457F7674E13D087B47221C0EBB8716F312FF52E46EA77566364346D2D899228F0C99737C4AD2A95C9CF892F89430CA1EEEFA68CE85321E5A4A44E71B6C4C62C8D3623E6103D9638A7DC0E66A249F130365773A3530F8F8F1FC4C57B4BEC296C1A0DD190646F2F3A427DE54155E6772FADF7A09488F45AE7CBA9C2F90BD3205D97E00C8CF62AB5FBEC774CA457A38E351FF110B8AA799918AE93E864862EE2F3B5D997D6C249613283337D83A60BDF3490BB73EB2A948A71D61E433F58A537693364D131DD7787D4D4A9C6EE891AB5B783A4F7B6009127D72A1F184ADA2BE20647EB6FE15FACDDF43A03BA9FE120E552A2BA14F568D65187C1F2E6108699C405018A3447A149C0A5196504201677E37CE789246D48A5270B59597D9F77F75E7CF23B18B51D5F25E37258BB231CE0E9FD3E5B21D14F1541A76F4875F231038751A36A79C84C4EBF9F2146506EC8DF6EBDD0CFECCBF388D9020CC5656322BF695D3ED716FAF0545040830815B550075F5D2301C6469F5DD99E5FD0093C4A";
//String decrypted = tcase.decrypt(encrypted);
String decrypted = tcase.decrypt(enc);
System.out.println("Params Decrypted:" + decrypted);
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (java.security.KeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
İf you used IV vector in c# while encrypted data with AES . You should use IV vector in Java
c#
using (var random = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
var key = new byte[16];
random.GetBytes(key);
using (System.Security.Cryptography.AesCryptoServiceProvider aesAlg = new System.Security.Cryptography.AesCryptoServiceProvider())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 128;
aesAlg.Key = key;
aesAlg.IV = key;
aesAlg.Mode = System.Security.Cryptography.CipherMode.CBC;
aesAlg.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
using (ICryptoTransform iCryptoper = aesAlg.CreateEncryptor())
{
byte[] encryptedData = iCryptoper.TransformFinalBlock(x509CertData, 0, x509CertData.Length);
string encodedCert = Convert.ToBase64String(encryptedData);
System.Security.Cryptography.X509Certificates.X509Certificate2 x509Cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(x509CertData);
System.Security.Cryptography.RSACryptoServiceProvider provider = (System.Security.Cryptography.RSACryptoServiceProvider)x509Cert.PublicKey.Key;
byte[] encrypted = provider.Encrypt(aesAlg.Key, false);
string test = Convert.ToBase64String(encrypted);
}
}
}
java
javax.crypto.SecretKey sc = new javax.crypto.spec.SecretKeySpec(secretKey, "AES");
Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
dcipher.init(Cipher.DECRYPT_MODE, sc, ivParameterSpec);
byte[] decyrptedCert = dcipher.doFinal(java.util.Base64.getDecoder().decode(stringToDecrypt));

AES in java can run in windows but not in linux [duplicate]

This question already has an answer here:
Better way to create AES keys than seeding SecureRandom
(1 answer)
Closed 6 years ago.
I just finished an AES Class for decrypt or encrpyt ,and it runs well on windows but can't run on linux throwing errors as following :
Given final block not properly padded
the full code as following :
/**
* AESTest.java
*
* #author liuyincan
* #Time 2013-12-12 下午1:25:44
*/
public class AES {
public static String generateKey(int len) {
try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(len);
Key key = keyGen.generateKey();
return ParserStringUtils.toHexString(key.getEncoded());
} catch (Exception e) {
return null;
}
}
/**
* 加密
*
* #param content
* 待加密内容
* #param key
* 加密的密钥
* #return
*/
public static String encode(String content, String key) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(key.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] byteRresult = cipher.doFinal(byteContent);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteRresult.length; i++) {
String hex = Integer.toHexString(byteRresult[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
*
* #param content
* 待解密内容
* #param key
* 解密的密钥
* #return
*/
public static String decode(String content, String key) {
if (content.length() < 1)
return null;
byte[] byteRresult = new byte[content.length() / 2];
for (int i = 0; i < content.length() / 2; i++) {
int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
byteRresult[i] = (byte) (high * 16 + low);
}
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(key.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] result = cipher.doFinal(byteRresult);
return new String(result);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
please help me to fix the problem or else my boss will fire me ,thanks a lot
Cipher.getInstance("AES"); - this gives the default implementation of AES.
Somewhere between Oracle Java 6 and late Java 7 this changed form AES/ECB/NoPadding to AES/ECB/PKCS5Padding.
Change such lines to:
Cipher.getInstance("AES/ECB/PKCS5Padding");

Java: fileoutputstream (access denied )

I am using AESCrypt open source library to encrypt file. This is my code
String password="asdfgh";
String frompath=new String("C:/Users/sabertooth/Desktop/error/pnberror.png");
String topath=new String("C:/Users/sabertooth/desktop/error/");
AESCrypt aes=new AESCrypt(false,password);
aes.encrypt(2, frompath, topath);
I am geeting access denied exception. Here is the stacktrace
Exception in thread "main" java.io.FileNotFoundException: C:\Users\sabertooth\desktop\error (Access is denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
at java.io.FileOutputStream.<init>(FileOutputStream.java:104)
at AESCrypt.encrypt(AESCrypt.java:284)
at NewClass.main(NewClass.java:28)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)
Posting the code for aescrypt.java
/*
* Copyright 2008 Vócali Sistemas Inteligentes
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.NetworkInterface;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Enumeration;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* This class provides methods to encrypt and decrypt files using
* aescrypt file format,
* version 1 or 2.
* <p>
* Requires Java 6 and <a href="http://java.sun.com/javase/downloads/index.jsp">Java
* Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files</a>.
* <p>
* Thread-safety and sharing: this class is not thread-safe.<br>
* <tt>AESCrypt</tt> objects can be used as Commands (create, use once and dispose),
* or reused to perform multiple operations (not concurrently though).
*
* #author Vócali Sistemas Inteligentes
*/
public class AESCrypt {
private static final String JCE_EXCEPTION_MESSAGE = "Please make sure "
+ "\"Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files\" "
+ "(http://java.sun.com/javase/downloads/index.jsp) is installed on your JRE.";
private static final String RANDOM_ALG = "SHA1PRNG";
private static final String DIGEST_ALG = "SHA-256";
private static final String HMAC_ALG = "HmacSHA256";
private static final String CRYPT_ALG = "AES";
private static final String CRYPT_TRANS = "AES/CBC/NoPadding";
private static final byte[] DEFAULT_MAC =
{0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab, (byte) 0xcd, (byte) 0xef};
private static final int KEY_SIZE = 32;
private static final int BLOCK_SIZE = 16;
private static final int SHA_SIZE = 32;
private final boolean DEBUG;
private byte[] password;
private Cipher cipher;
private Mac hmac;
private SecureRandom random;
private MessageDigest digest;
private IvParameterSpec ivSpec1;
private SecretKeySpec aesKey1;
private IvParameterSpec ivSpec2;
private SecretKeySpec aesKey2;
/*******************
* PRIVATE METHODS *
*******************/
/**
* Prints a debug message on standard output if DEBUG mode is turned on.
*/
protected void debug(String message) {
if (DEBUG) {
System.out.println("[DEBUG] " + message);
}
}
/**
* Prints a debug message on standard output if DEBUG mode is turned on.
*/
protected void debug(String message, byte[] bytes) {
if (DEBUG) {
StringBuilder buffer = new StringBuilder("[DEBUG] ");
buffer.append(message);
buffer.append("[");
for (int i = 0; i < bytes.length; i++) {
buffer.append(bytes[i]);
buffer.append(i < bytes.length - 1 ? ", " : "]");
}
System.out.println(buffer.toString());
}
}
/**
* Generates a pseudo-random byte array.
* #return pseudo-random byte array of <tt>len</tt> bytes.
*/
protected byte[] generateRandomBytes(int len) {
byte[] bytes = new byte[len];
random.nextBytes(bytes);
return bytes;
}
/**
* SHA256 digest over given byte array and random bytes.<br>
* <tt>bytes.length</tt> * <tt>num</tt> random bytes are added to the digest.
* <p>
* The generated hash is saved back to the original byte array.<br>
* Maximum array size is {#link #SHA_SIZE} bytes.
*/
protected void digestRandomBytes(byte[] bytes, int num) {
assert bytes.length <= SHA_SIZE;
digest.reset();
digest.update(bytes);
for (int i = 0; i < num; i++) {
random.nextBytes(bytes);
digest.update(bytes);
}
System.arraycopy(digest.digest(), 0, bytes, 0, bytes.length);
}
/**
* Generates a pseudo-random IV based on time and this computer's MAC.
* <p>
* This IV is used to crypt IV 2 and AES key 2 in the file.
* #return IV.
*/
protected byte[] generateIv1() {
byte[] iv = new byte[BLOCK_SIZE];
long time = System.currentTimeMillis();
byte[] mac = null;
try {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
while (mac == null && ifaces.hasMoreElements()) {
mac = ifaces.nextElement().getHardwareAddress();
}
} catch (Exception e) {
// Ignore.
}
if (mac == null) {
mac = DEFAULT_MAC;
}
for (int i = 0; i < 8; i++) {
iv[i] = (byte) (time >> (i * 8));
}
System.arraycopy(mac, 0, iv, 8, mac.length);
digestRandomBytes(iv, 256);
return iv;
}
/**
* Generates an AES key starting with an IV and applying the supplied user password.
* <p>
* This AES key is used to crypt IV 2 and AES key 2.
* #return AES key of {#link #KEY_SIZE} bytes.
*/
protected byte[] generateAESKey1(byte[] iv, byte[] password) {
byte[] aesKey = new byte[KEY_SIZE];
System.arraycopy(iv, 0, aesKey, 0, iv.length);
for (int i = 0; i < 8192; i++) {
digest.reset();
digest.update(aesKey);
digest.update(password);
aesKey = digest.digest();
}
return aesKey;
}
/**
* Generates the random IV used to crypt file contents.
* #return IV 2.
*/
protected byte[] generateIV2() {
byte[] iv = generateRandomBytes(BLOCK_SIZE);
digestRandomBytes(iv, 256);
return iv;
}
/**
* Generates the random AES key used to crypt file contents.
* #return AES key of {#link #KEY_SIZE} bytes.
*/
protected byte[] generateAESKey2() {
byte[] aesKey = generateRandomBytes(KEY_SIZE);
digestRandomBytes(aesKey, 32);
return aesKey;
}
/**
* Utility method to read bytes from a stream until the given array is fully filled.
* #throws IOException if the array can't be filled.
*/
protected void readBytes(InputStream in, byte[] bytes) throws IOException {
if (in.read(bytes) != bytes.length) {
throw new IOException("Unexpected end of file");
}
}
/**************
* PUBLIC API *
**************/
/**
* Builds an object to encrypt or decrypt files with the given password.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public AESCrypt(String password) throws GeneralSecurityException, UnsupportedEncodingException {
this(false, password);
}
/**
* Builds an object to encrypt or decrypt files with the given password.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public AESCrypt(boolean debug, String password) throws GeneralSecurityException, UnsupportedEncodingException {
try {
DEBUG = debug;
setPassword(password);
random = SecureRandom.getInstance(RANDOM_ALG);
digest = MessageDigest.getInstance(DIGEST_ALG);
cipher = Cipher.getInstance(CRYPT_TRANS);
hmac = Mac.getInstance(HMAC_ALG);
} catch (GeneralSecurityException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/**
* Changes the password this object uses to encrypt and decrypt.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public void setPassword(String password) throws UnsupportedEncodingException {
this.password = password.getBytes("UTF-16LE");
debug("Using password: ", this.password);
}
/**
* The file at <tt>fromPath</tt> is encrypted and saved at <tt>toPath</tt> location.
* <p>
* <tt>version</tt> can be either 1 or 2.
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void encrypt(int version, String fromPath, String toPath)
throws IOException, GeneralSecurityException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(fromPath));
debug("Opened for reading: " + fromPath);
out = new BufferedOutputStream(new FileOutputStream(toPath));
debug("Opened for writing: " + toPath);
encrypt(version, in, out);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
/**
* The input stream is encrypted and saved to the output stream.
* <p>
* <tt>version</tt> can be either 1 or 2.<br>
* None of the streams are closed.
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void encrypt(int version, InputStream in, OutputStream out)
throws IOException, GeneralSecurityException {
try {
byte[] text = null;
ivSpec1 = new IvParameterSpec(generateIv1());
aesKey1 = new SecretKeySpec(generateAESKey1(ivSpec1.getIV(), password), CRYPT_ALG);
ivSpec2 = new IvParameterSpec(generateIV2());
aesKey2 = new SecretKeySpec(generateAESKey2(), CRYPT_ALG);
debug("IV1: ", ivSpec1.getIV());
debug("AES1: ", aesKey1.getEncoded());
debug("IV2: ", ivSpec2.getIV());
debug("AES2: ", aesKey2.getEncoded());
out.write("AES".getBytes("UTF-8")); // Heading.
out.write(version); // Version.
out.write(0); // Reserved.
if (version == 2) { // No extensions.
out.write(0);
out.write(0);
}
out.write(ivSpec1.getIV()); // Initialization Vector.
text = new byte[BLOCK_SIZE + KEY_SIZE];
cipher.init(Cipher.ENCRYPT_MODE, aesKey1, ivSpec1);
cipher.update(ivSpec2.getIV(), 0, BLOCK_SIZE, text);
cipher.doFinal(aesKey2.getEncoded(), 0, KEY_SIZE, text, BLOCK_SIZE);
out.write(text); // Crypted IV and key.
debug("IV2 + AES2 ciphertext: ", text);
hmac.init(new SecretKeySpec(aesKey1.getEncoded(), HMAC_ALG));
text = hmac.doFinal(text);
out.write(text); // HMAC from previous cyphertext.
debug("HMAC1: ", text);
cipher.init(Cipher.ENCRYPT_MODE, aesKey2, ivSpec2);
hmac.init(new SecretKeySpec(aesKey2.getEncoded(), HMAC_ALG));
text = new byte[BLOCK_SIZE];
int len, last = 0;
while ((len = in.read(text)) > 0) {
cipher.update(text, 0, BLOCK_SIZE, text);
hmac.update(text);
out.write(text); // Crypted file data block.
last = len;
}
last &= 0x0f;
out.write(last); // Last block size mod 16.
debug("Last block size mod 16: " + last);
text = hmac.doFinal();
out.write(text); // HMAC from previous cyphertext.
debug("HMAC2: ", text);
} catch (InvalidKeyException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/**
* The file at <tt>fromPath</tt> is decrypted and saved at <tt>toPath</tt> location.
* <p>
* The input file can be encrypted using version 1 or 2 of aescrypt.<br>
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void decrypt(String fromPath, String toPath)
throws IOException, GeneralSecurityException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(fromPath));
debug("Opened for reading: " + fromPath);
out = new BufferedOutputStream(new FileOutputStream(toPath));
debug("Opened for writing: " + toPath);
decrypt(new File(fromPath).length(), in, out);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
/**
* The input stream is decrypted and saved to the output stream.
* <p>
* The input file size is needed in advance.<br>
* The input stream can be encrypted using version 1 or 2 of aescrypt.<br>
* None of the streams are closed.
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void decrypt(long inSize, InputStream in, OutputStream out)
throws IOException, GeneralSecurityException {
try {
byte[] text = null, backup = null;
long total = 3 + 1 + 1 + BLOCK_SIZE + BLOCK_SIZE + KEY_SIZE + SHA_SIZE + 1 + SHA_SIZE;
int version;
text = new byte[3];
readBytes(in, text); // Heading.
if (!new String(text, "UTF-8").equals("AES")) {
throw new IOException("Invalid file header");
}
version = in.read(); // Version.
if (version < 1 || version > 2) {
throw new IOException("Unsupported version number: " + version);
}
debug("Version: " + version);
in.read(); // Reserved.
if (version == 2) { // Extensions.
text = new byte[2];
int len;
do {
readBytes(in, text);
len = ((0xff & (int) text[0]) << 8) | (0xff & (int) text[1]);
if (in.skip(len) != len) {
throw new IOException("Unexpected end of extension");
}
total += 2 + len;
debug("Skipped extension sized: " + len);
} while (len != 0);
}
text = new byte[BLOCK_SIZE];
readBytes(in, text); // Initialization Vector.
ivSpec1 = new IvParameterSpec(text);
aesKey1 = new SecretKeySpec(generateAESKey1(ivSpec1.getIV(), password), CRYPT_ALG);
debug("IV1: ", ivSpec1.getIV());
debug("AES1: ", aesKey1.getEncoded());
cipher.init(Cipher.DECRYPT_MODE, aesKey1, ivSpec1);
backup = new byte[BLOCK_SIZE + KEY_SIZE];
readBytes(in, backup); // IV and key to decrypt file contents.
debug("IV2 + AES2 ciphertext: ", backup);
text = cipher.doFinal(backup);
ivSpec2 = new IvParameterSpec(text, 0, BLOCK_SIZE);
aesKey2 = new SecretKeySpec(text, BLOCK_SIZE, KEY_SIZE, CRYPT_ALG);
debug("IV2: ", ivSpec2.getIV());
debug("AES2: ", aesKey2.getEncoded());
hmac.init(new SecretKeySpec(aesKey1.getEncoded(), HMAC_ALG));
backup = hmac.doFinal(backup);
text = new byte[SHA_SIZE];
readBytes(in, text); // HMAC and authenticity test.
if (!Arrays.equals(backup, text)) {
throw new IOException("Message has been altered or password incorrect");
}
debug("HMAC1: ", text);
total = inSize - total; // Payload size.
if (total % BLOCK_SIZE != 0) {
throw new IOException("Input file is corrupt");
}
if (total == 0) { // Hack: empty files won't enter block-processing for-loop below.
in.read(); // Skip last block size mod 16.
}
debug("Payload size: " + total);
cipher.init(Cipher.DECRYPT_MODE, aesKey2, ivSpec2);
hmac.init(new SecretKeySpec(aesKey2.getEncoded(), HMAC_ALG));
backup = new byte[BLOCK_SIZE];
text = new byte[BLOCK_SIZE];
for (int block = (int) (total / BLOCK_SIZE); block > 0; block--) {
int len = BLOCK_SIZE;
if (in.read(backup, 0, len) != len) { // Cyphertext block.
throw new IOException("Unexpected end of file contents");
}
cipher.update(backup, 0, len, text);
hmac.update(backup, 0, len);
if (block == 1) {
int last = in.read(); // Last block size mod 16.
debug("Last block size mod 16: " + last);
len = (last > 0 ? last : BLOCK_SIZE);
}
out.write(text, 0, len);
}
out.write(cipher.doFinal());
backup = hmac.doFinal();
text = new byte[SHA_SIZE];
readBytes(in, text); // HMAC and authenticity test.
if (!Arrays.equals(backup, text)) {
throw new IOException("Message has been altered or password incorrect");
}
debug("HMAC2: ", text);
} catch (InvalidKeyException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/* public static void main(String[] args) {
try {
if (args.length < 4) {
System.out.println("AESCrypt e|d password fromPath toPath");
return;
}
AESCrypt aes = new AESCrypt(true, args[1]);
switch (args[0].charAt(0)) {
case 'e':
aes.encrypt(2, args[2], args[3]);
break;
case 'd':
aes.decrypt(args[2], args[3]);
break;
default:
System.out.println("Invalid operation: must be (e)ncrypt or (d)ecrypt.");
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
*/
}
There is a method encrypt which takes 3 arguments version frompath topath
You can't write to a folder. And C:/Users/sabertooth/desktop/error/ is a folder path.
Also, new String("...") is unnecessary. Just use "...".

Categories