0% found this document useful (0 votes)
55 views

Java Implementation of Elliptic Curve Integrated Encryption Scheme

This document presents a Java implementation of the Elliptic Curve Integrated Encryption Scheme (ECIES). ECIES is a hybrid encryption scheme that performs encryption on an elliptic curve using a public key, derives a symmetric secret key from a shared secret, and encrypts the plaintext using the symmetric key. The document includes Java code for ECIES encryption and decryption along with test classes, and discusses various cryptographic concepts and algorithms implemented including elliptic curves, public/private keys, hash functions, symmetric ciphers, and encoding. This is intended as a proof of concept for educational purposes only and not for production use.

Uploaded by

Hugo Flores
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
55 views

Java Implementation of Elliptic Curve Integrated Encryption Scheme

This document presents a Java implementation of the Elliptic Curve Integrated Encryption Scheme (ECIES). ECIES is a hybrid encryption scheme that performs encryption on an elliptic curve using a public key, derives a symmetric secret key from a shared secret, and encrypts the plaintext using the symmetric key. The document includes Java code for ECIES encryption and decryption along with test classes, and discusses various cryptographic concepts and algorithms implemented including elliptic curves, public/private keys, hash functions, symmetric ciphers, and encoding. This is intended as a proof of concept for educational purposes only and not for production use.

Uploaded by

Hugo Flores
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 41

JAVA IMPLEMENTATION OF ELLIPTIC CURVE INTEGRATED ENCRYPTION SCHEME

This document presents a JAVA implementation of Elliptic Curve Integrated Encryption


Scheme (ECIES)

ECIES is a hybrid encryption scheme that performs 3 important steps:

 Step 1: Encryption on an elliptic curve by using a public key on an elliptic curve


 Step 2: Derivation of a symmetric secret key from a shared secret
 Step 3: Encryption of a plaintext by using the symmetric secret key calculated above

Main mathematic notions that you need to analyze ECIEs are: Prime numbers, finite fields and
Elliptic Curve Discrete Logarithm Problem (ECDLP)

To understand what ECIES is, you will first find an extract (3 pages) of elliptic curve cryptography
from the book: '' Cryptography guide on elliptic curves ''

Then you will find in JAVA language, codes for ECIES encryption and decryption algorithms with
some tests classes.

This imperfect implementation does not respond to performance requirements or optimized


memory management.

These are school proofs of concept. They can serve as illustrations to those interested in
mathematics, computer programming and cryptography. They must not be used in production.

It is NEVER recommended to re-invent the wheel, especially in a field as sensitive and delicate
as cryptography.

But to understand how it works, I have not found a better way than having fun defining and
programming myself, in JAVA all the following cryptographic notions or primitives:
 Elliptic curve
 Point of an elliptic curve
 Infinite point on an elliptic curve
 Fast addition, multiplication and inversion on an elliptic curve
 Domain Parameters generation of an Elliptic Curve and domain parameters validation
 Public key
 Private key
 Key pair generation for elliptic curve cryptography and public key validation
 Digest messages functions SHA1, SHA256, SHA384, SHA512
 Key derivation function

~1~
JAVA IMPLEMENTATION OF ELLIPTIC CURVE INTEGRATED ENCRYPTION SCHEME

 HMAC function
 Symmetric encryptions XOR, DES, 3DES
 CBC encryption mode
 Base64 encoding
 PKCS5Padding

Key pairs used in my proof of concept are generated on the fly and used in a raw state. Public
keys are not created by a trusted entity and presented in a certificate. In real life, public keys are
transmitted by using certificates. I chose to use raw data because I did not want to deal with chain
of certificates validation issues.

Elliptic curves are also not generated randomly, I chose to use those proposed by the National
Institute of Standards (NIST) because these curves are generated with good mathematic
properties. I did not want to generate my own curves and face security issues.

JAVA classes presented in this document below are:

 ECIESEncryptionUtils.java: JAVA code for ECIES encryption and decryption

 TestEncryption2.java: Abstract super class of tests classes.

 Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_DESCbcPKCS5Padding: Test class with DES


symmetric encryption, SHA1 as digest, CBC as encryption mode and PKCS5 as padding scheme

 Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_Triple_DESCbcPKCS5Padding: Test class with


DESede symmetric encryption, SHA256 as digest, CBC as encryption mode and PKCS5 as
padding scheme

 Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_Triple_DESCbcPKCS5Padding: Test class with


DESede symmetric encryption, SHA1 as digest, CBC as encryption mode and PKCS5 as padding
scheme

 Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_XOR: Test class with DESede symmetric


encryption, SHA256 as digest, CBC as encryption mode and PKCS5 as padding scheme.

JAVA object-oriented programming makes very easy to add support and tests of new
symmetric encryptions like AES, TDEA or CAST5 to my implementation

I wish you good reading and analysis of all this. Please have no hesitation to call or mail me if
you have any questions or remarks. I would be very happy to discuss about elliptic curve
cryptography or any topic related to cryptography or computer security.

Best Regards,

Jules-Florent EYA, software architect

Email: [email protected]

Tel: 1-514-802-1003, Canada

~2~
package LibCrypto.ECCImpls.ECIES;

import LibCrypto.Common.CryptoExceptions.DecryptionFailureException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.InvalidEmbeddedECCPubKeyException;
import LibCrypto.Common.CryptoExceptions.EncryptionFailureException;
import LibCrypto.Common.CryptoExceptions.InvalidCipherTextException;
import LibCrypto.Common.CryptoExceptions.KDFExceptions.KDFInputCheckFailureException;
import LibCrypto.Common.CryptoExceptions.UnsupportedCryptoOperationException;
import LibCrypto.CryptoImpls.EncryptionProcessInfo;
import LibCrypto.CryptoImpls.SymetricCipherText;
import LibCrypto.Common.Interfaces.HMACIntf;
import LibCrypto.Common.Interfaces.KDFIntf;
import LibCrypto.Common.Interfaces.MessageDigestIntf;
import AllCommon.Interfaces.TLVSerializableIntf;
import LibCrypto.Common.CryptoUtilities.CryptoUtils;
import LibCrypto.AlgoImpls.DESImpls.Base64DesCipherText;
import LibCrypto.AlgoImpls.DESImpls.DesUtils;
import LibCrypto.AlgoImpls.DESImpls.Base64TripleDesCipherText;
import LibCrypto.AlgoImpls.DESImpls.TripleDesUtils;
import LibCrypto.ECCImpls.ECCArithCalculator;
import LibCrypto.CryptoImpls.KeysImpls.ECCImpls.ECCPrivateKey;
import LibCrypto.CryptoImpls.KeysImpls.ECCImpls.ECCPublicKey;
import LibCrypto.ECCImpls.ECCUtils;
import LibCrypto.ECCImpls.ECCpoint;
import LibCrypto.ECCImpls.InfinityPoint;
import LibCrypto.AlgoImpls.XORImpls.XORCipherText;
import LibCrypto.AlgoImpls.XORImpls.XOREncryptionUtils;
import AllCommon.Interfaces.FormatsIdentifiersIntf;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLEllipticCurveException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLPointException;
import LibCrypto.Common.Exceptions.HMACFailureException;
import LibCrypto.Common.Interfaces.Identifiers.NamesIdentifiersIntf;
import LibCrypto.ECCImpls.Curves.ECCurve;
import LibCrypto.ECCImpls.ECCParams;
import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;

/**
* <p>
* This class implements encryption and decryption for ECIES. The Elliptic Curve
* Integrated Encryption Scheme(ECIES) is a variant of the ELGAMAL public-key
* encryption scheme. It has been standardized in ANSI X9.63 and ISO/IEC
* 15946-3, and is in the IEEE P1363a draft Standard.</p>
*
* <p>
* Implementation below does not aim to be very speed.It is a scholar
* implementation of ECIES to show how elliptic curve cryptography can be be
* implemented in JAVA</p>
*
* <p>
* You can find useful information about some cryptographic algorithms
* implemented : Recommendation for Pair-Wise Key Establishment Schemes : NIST
* Special publication 800-56A Triple DES specification : ANSI X9.52-1998
* Recommendation for Key Derivation Using Pseudorandom Functions : NIST Special
* publication 800-108 Secure Hash Standard (SHS) : FIPS PUB 180-3 Approved
* encryption modes of operations are defined in NIST Special publications
* 800-38A, 800-38B, 800-38C, 800-38D. In this implementation we use only CBC
* (Cipher Block Chaining)</p>
*
* @author Jules-Florent EYA
* @mail [email protected]
* @tel 1-514-802-1003, Canada
*/
public class ECIESEncryptionUtils {

/**
* This method allows to encrypt a plaintext by using ECIES and to retrieve
* the cipherText produced by the whole encryption process
*
* @param eccPubKey Public key that will be used to encrypted the plaintext
* with ECIES
* @param plaintext Plaintext to be encrypted in a TLV serializable format
* @param kdf Key Derivation Function used during encryption step of ECIES
* @param hmac HMAC used for authentication
* @param hmacKeyDesiredLength
* @param hmacTagDesiredlength
* @param hmacHashAlgo
* @param kdfHashAlgo HASH engine that will be used by the Key Derivation
* Function
* @param SymEncAlgo Name of underlying symmetric encryption that will be
* used by ECIES
* @param iv Initialization Vector if it is required by the underlying
* symmetric encryption
* @param compressPoint A boolean that show if points on elliptic curve are
* compressed or not.FOR NOW, compression point is not supported so this
* parameter is passed to the method with a false value.
* @return the cipherText
* @throws EncryptionFailureException
*/
public static ECIESCipherText encrypt(ECCPublicKey eccPubKey, TLVSerializableIntf plaintext,
KDFIntf kdf, HMACIntf hmac, int hmacKeyDesiredLength,
int hmacTagDesiredlength, MessageDigestIntf hmacHashAlgo,
MessageDigestIntf kdfHashAlgo, String SymEncAlgo, byte[] iv,
boolean compressPoint)
throws EncryptionFailureException {
if (plaintext == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because the plaintext to be"
+ " encrypted is a TLVSerializableIntf NULL instance");
}
byte[] tlvPlaintext = null;
try {
//TLV means Tag||Length||Value
tlvPlaintext = plaintext.getTagLengthValue();
} catch (IOException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme." + ex.getClass().getSimpleName()
+ " has been thrown during TLV serialization of the plaintext"
+ " to be encrypted");
}
ECIESCipherText cipherText = encrypt(eccPubKey, tlvPlaintext, kdf, hmac,
hmacKeyDesiredLength, hmacTagDesiredlength, hmacHashAlgo,
kdfHashAlgo, SymEncAlgo, iv, compressPoint, null);
return cipherText;
}

/**
* This method allows to encrypt a plaintext by using ECIES and to retrieve
* the cipherText produced by the whole encryption process
*
* @param eccPubKey
* @param plaintext
* @param kdf
* @param hmac
* @param hmacKeyDesiredLength
* @param hmacTagDesiredlength
* @param hmacHashAlgo
* @param kdfHashAlgo
* @param SymEncAlgo
* @param iv
* @param compressPoint
* @return
* @throws EncryptionFailureException
*/
public static ECIESCipherText encrypt(ECCPublicKey eccPubKey, String plaintext,
KDFIntf kdf, HMACIntf hmac, int hmacKeyDesiredLength,
int hmacTagDesiredlength, MessageDigestIntf hmacHashAlgo,
MessageDigestIntf kdfHashAlgo, String SymEncAlgo, byte[] iv,
boolean compressPoint)
throws EncryptionFailureException {
byte[] byteArrayPlaintext = CryptoUtils.stringToByteArray(plaintext);
ECIESCipherText cipherText = encrypt(eccPubKey, byteArrayPlaintext,
kdf, hmac, hmacKeyDesiredLength, hmacTagDesiredlength, hmacHashAlgo,
kdfHashAlgo, SymEncAlgo, iv, compressPoint, null);
return cipherText;
}

/**
* This method allows to encrypt a plaintext by using ECIES and to retrieve
* the cipherText produced by the whole encryption process
*
* @param eccPubKey
* @param plaintext
* @param kdf
* @param hmac
* @param hmacKeyDesiredLength
* @param hmacTagDesiredlength
* @param hmacHashAlgo
* @param kdfHashAlgo
* @param SymEncAlgo
* @param iv
* @param compressPoint
* @param eciesEpi
* @return
* @throws EncryptionFailureException
*/
public static ECIESCipherText encrypt(ECCPublicKey eccPubKey,
TLVSerializableIntf plaintext,
KDFIntf kdf, HMACIntf hmac, int hmacKeyDesiredLength,
int hmacTagDesiredlength, MessageDigestIntf hmacHashAlgo,
MessageDigestIntf kdfHashAlgo, String SymEncAlgo, byte[] iv,
boolean compressPoint, ECIESEncryptionProcessInfo eciesEpi)
throws EncryptionFailureException {
if (plaintext == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because the plaintext to be"
+ " encrypted is a TLVSerializableIntf NULL instance");
}
byte[] tlvPlaintext = null;
try {
tlvPlaintext = plaintext.getTagLengthValue();
} catch (IOException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme." + ex.getClass().getSimpleName()
+ " has been thrown during TLV serialization of the plaintext"
+ " to be encrypted");
}
ECIESCipherText cipherText = encrypt(eccPubKey, tlvPlaintext, kdf, hmac,
hmacKeyDesiredLength, hmacTagDesiredlength, hmacHashAlgo,
kdfHashAlgo, SymEncAlgo, iv, compressPoint, eciesEpi);
return cipherText;
}

/**
* This method allows to encrypt a plaintext by using ECIES and to retrieve
* the cipherText produced by the whole encryption process
*
* @param eccPubKey
* @param plaintext
* @param kdf
* @param hmac
* @param hmacKeyDesiredLength
* @param hmacTagDesiredlength
* @param hmacHashAlgo
* @param kdfHashAlgo
* @param SymEncAlgo
* @param iv
* @param compressPoint
* @param eciesEpi
* @return
* @throws EncryptionFailureException
*/
public static ECIESCipherText encrypt(ECCPublicKey eccPubKey, String plaintext,
KDFIntf kdf, HMACIntf hmac, int hmacKeyDesiredLength,
int hmacTagDesiredlength, MessageDigestIntf hmacHashAlgo,
MessageDigestIntf kdfHashAlgo, String SymEncAlgo, byte[] iv,
boolean compressPoint, ECIESEncryptionProcessInfo eciesEpi)
throws EncryptionFailureException {
byte[] byteArrayPlaintext = CryptoUtils.stringToByteArray(plaintext);
ECIESCipherText cipherText = encrypt(eccPubKey, byteArrayPlaintext,
kdf, hmac, hmacKeyDesiredLength, hmacTagDesiredlength, hmacHashAlgo,
kdfHashAlgo, SymEncAlgo, iv, compressPoint, eciesEpi);
return cipherText;
}

/**
* This method allows to encrypt an octet string plaintext with ECIES. This
* implementation is inspired by the algorithm no 4.42 page 189 of the book
* Guide To Elliptic Curve Cryptography of Darrel HANKERSON, Alfred MENEZES,
* Scott VANSTONE. For Now the CERTICOM compression point is not supported
* so you MUST Always use this method with the parameter compressPoint set
* to false . Future implementations will erase this limitation!
*
* @param eccPubKey The public key
* @param plaintext The plaintext to be encrypted
* @param kdf The Key Derivation Function used during ECIES process
* @param hmac The MAC used for authentication during ECIES process
* @param hmacKeyDesiredLength Expected length of the output of the
* symmetric key after HMAC
* @param hmacTagExpectedLength
* @param hmacHashAlgo
* @param kdfHashAlgo Hash engine that will be used by the Key Derivation
* Function
* @param SymEncAlgo Algorithm to be used to perform the underlying
* symmetric encryption of the ECIES
* @param iv Initialization Vector in a byte array format when it is
* required by the symmetric underlying encryption
* @param compressPoint A boolean that shows if point compression should be
* used or not
* @param eciesEpi
* @return The result of the ECIES encryption process in an ECIESCiphertext
* instance object.
* @throws EncryptionFailureException
*/
public static ECIESCipherText encrypt(ECCPublicKey eccPubKey, byte[] plaintext,
KDFIntf kdf, HMACIntf hmac, int hmacKeyDesiredLength,
int hmacTagExpectedLength, MessageDigestIntf hmacHashAlgo,
MessageDigestIntf kdfHashAlgo, String SymEncAlgo, byte[] iv,
boolean compressPoint, ECIESEncryptionProcessInfo eciesEpi)
throws EncryptionFailureException {
//We check the ECCPublicKey provided that will be used for encryption
if (eccPubKey == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because the ECCPublicKey"
+ " provided is NULL");
}
if (eccPubKey.getParams() == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.ECCPublicKey provided"
+ " contains no internal ECC parameters");
}
ECCpoint basePoint = eccPubKey.getParams().getBasePoint();
if (basePoint == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.NULL basePoint has been"
+ " retrieved from the ECC parameters extracted from the "
+ "ECCPublicKey");
}
//The qPoint of the point of the elliptic curve will be used as REAL
//public key
ECCpoint qPoint = eccPubKey.getQ();
if (qPoint == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.NULL Q point has been"
+ " retrieved from the ECCPublicKey");
}
ECCurve ecCurve = eccPubKey.getParams().getCurve();
if (ecCurve == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.NULL ecCurve has been"
+ " retrieved from the ECC parameters extracted from the "
+ "ECCPublicKey");
}
BigInteger h_BasePointCofactor = ecCurve.getH();
if (h_BasePointCofactor == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.The cofactor of the base"
+ " point of the ECCcurve is a NULL BigInteger instance");
}
//We check the plaintext
if (plaintext == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because the plaintext to be"
+ " encrypted is NULL");
}
if (plaintext.length == 0) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because the plaintext to be"
+ " encrypted is an empty byte array");
}
//We check the Key Derivation Function
if (kdf == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because the key derivative"
+ " function engine to be used is NULL");
}
if (hmac == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because HMACIntf instance"
+ " provided as argument is NULL");
}
if (hmacHashAlgo == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because MessageDigestIntf"
+ " instance for HASH for HMAC provided as argument is NULL");
}
if (kdfHashAlgo == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because MessageDigestIntf"
+ " instance for HASH for KDF provided as argument is NULL");
}
if (compressPoint) {
UnsupportedCryptoOperationException ex = new UnsupportedCryptoOperationException(
"Elliptic Curve Point compression is not supported for"
+ " ECIES encryption!");
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because compression point"
+ " is not yet supported", ex);
}
BigInteger k;//The secret K value is created by the sender
//R point of the elliptic curve is a part of the cipherText produced
//by the ECIES process
ECCpoint R = null;
ECCpoint Z = null;
ECCpoint temp = null;
boolean found = false;
EncryptionProcessInfo symetricEncrProcessInfo = new EncryptionProcessInfo();
InfinityPoint inf = new InfinityPoint();
do {
//We find the secret value K that will be used to set the Elliptic
//Curve Discrete Logarithm Problem (ECDLP)
k = ECCUtils.selectRandomValue(eccPubKey.getParams().getN(),
new SecureRandom());
if (k == null) {
//We jump directly to next iteration of the loop, because it means
//that we did not find the good K value.So we continue the research
continue;
}
try {
//We compute R = (K * basePoint) on the curve
R = ECCArithCalculator.multiply(basePoint, k, ecCurve);
} catch (NULLEllipticCurveException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because NULLEllipticCurveException"
+ " has been thrown during basePoint multiplication with"
+ " the k randomly selected value", ex);
} catch (NULLPointException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because NULLPointException"
+ " has been thrown during basePoint multiplication with"
+ " the k randomly selected value", ex);
}
try {
//We compute temp = (K * Q) on the curve
temp = ECCArithCalculator.multiply(qPoint, k, ecCurve);
} catch (NULLEllipticCurveException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because NULLEllipticCurveException"
+ " has been thrown during Q point multiplication with"
+ " the k randomly selected value", ex);
} catch (NULLPointException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because NULLPointException"
+ " has been thrown during Q point multiplication with"
+ " the k randomly selected value", ex);
}
if (BigInteger.ONE.compareTo(ecCurve.getH()) != 0) {
try {
// Z = H * temp = H * K * Q
Z = ECCArithCalculator.multiply(temp, h_BasePointCofactor, ecCurve);
} catch (NULLEllipticCurveException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because NULLEllipticCurveException"
+ " has been thrown during (qPoint * K) multiplication with"
+ " the h_BasePointCofactor", ex);
} catch (NULLPointException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because NULLPointException"
+ " has been thrown during (qPoint * K) multiplication with"
+ " the h_BasePointCofactor", ex);
}
} else {
Z = temp;
}
//We we want to be sure that Z is not the infinity point of the curve
if (!(Z.compareTo(inf, ecCurve))) {
//If Z is not the infinity, we have found what we were looking for
//so we can exit from the loop
found = true;
break;
}
} while (!found);
if (!found) {
//This is a very defensive defensive check. We could remove this check
//We should NEVER enter into this check
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.Could not find ECCPoint"
+ " Z");
}
//We compute the secret value that will be shared
//Z = (Xz, Yz)
BigInteger Xz = Z.getX(); //We retrieve the Xz the horizontal coordonate
byte[] sharedSecretValue = CryptoUtils.bigIntegerToByteArray(Xz);
int symmetricEncryptionKeyExpectedLenght = 0;
//According to the type of symmetric encryption that we want to perform
//we decide the expected length of the secret key that will be used
if (NamesIdentifiersIntf.XOR_NAME.equals(SymEncAlgo)) {
//For XOR encryption, we do not need initialization vector so we do
//not check it out
//In this case, the expected length of the key for XOR encryption is
//the length of the plaintext to be encrypted
symmetricEncryptionKeyExpectedLenght = plaintext.length;
} else if (NamesIdentifiersIntf.DESede_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
//DESede requires an 8 bytes initialization vector, so we check the IV
if (iv == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process because NULL initialization"
+ " vector for " + SymEncAlgo + " encryption has been"
+ " provided");
}
if (iv.length != 8) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process.Initialization"
+ " vector for " + SymEncAlgo + " provided is "
+ (iv.length * 8) + " bits long. It should be "
+ " 64 bits long");
}
//In this case, the expected length of the key for
//3DES_CBC_PKCS5Padding encryption is 24 bytes = 192 bits
symmetricEncryptionKeyExpectedLenght = 24;
} else if (NamesIdentifiersIntf.DES_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
//DES requires an 8 bytes initialization vector, so we check the IV
if (iv == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process because NULL initialization"
+ " vector for " + SymEncAlgo + " encryption has been"
+ " provided");
}
if (iv.length != 8) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process.Initialization"
+ " vector for " + SymEncAlgo + " provided is "
+ (iv.length * 8) + " bits long. It should be "
+ " 64 bits long");
}
//In this case, the expected length of the key for
//3DES_CBC_PKCS5Padding encryption is 8 bytes = 64 bits
symmetricEncryptionKeyExpectedLenght = 8;
} else {
//FOR NOW, we do not support other symmetric encryption algorithms
//for ECIES.(We will add support of AES256, TDEA later)
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process." + SymEncAlgo
+ " is not yet supported as symmetric encryption");
}
//key = symmetricEncryptionKey||hashMacKey
int keyDataLength = symmetricEncryptionKeyExpectedLenght + hmacKeyDesiredLength;
byte[] keyingMaterial;
try {
//From the share secret value, we derive a symmetric encryption key
byte[] sharedInfo = null;//We do not provid shared informations
keyingMaterial = kdf.deriveKey(sharedSecretValue, keyDataLength,
sharedInfo, kdfHashAlgo);
} catch (KDFInputCheckFailureException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because KDFInputCheckFailureException"
+ " has been thrown during a key derivation operation. "
+ "Could not extract a keying material to continue the"
+ " ECIES process", ex);
}
//We make sure that key derivation function returned a byte array with
//the expected lenght
if (keyingMaterial == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because Key Derivation Function"
+ " return a NULL byte array");
}
if (keyingMaterial.length != keyDataLength) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.Key Derivation Function"
+ " returned a byte array that is " + keyingMaterial.length
+ " bytes long.But expected lenght is "
+ keyDataLength);
}
/*We compute and extract the key no 1 for symmetric encryption and the
key no 2 for the HashMac computation,
//keyingMaterial = symmetricEncryptionKey||hmacAuthenticationKey */
byte[] symmetricEncryptionKey = new byte[symmetricEncryptionKeyExpectedLenght];
//From the keying material , we copy the bytes into the buffer symmetricEncryptionKey
System.arraycopy(keyingMaterial, 0, symmetricEncryptionKey, 0,
symmetricEncryptionKey.length);

byte[] hmacAuthenticationKey = new byte[hmacKeyDesiredLength];


//From the keying material , we copy the bytes into the buffer hmacAuthenticationKey
System.arraycopy(keyingMaterial, symmetricEncryptionKey.length,
hmacAuthenticationKey, 0, hmacAuthenticationKey.length);

EncryptionProcessInfo epi = null;


SymetricCipherText symCipherText = null;
byte[] ciphertextForHMACInput = null;
ECIESCipherText eciesCipherText = null;

/*We do the symmetric encryption of the plaintext.The encryption is done


with the symmetric key that has been derived by using the Key Derivation
Process defined by the parameter kdf*/
if (NamesIdentifiersIntf.XOR_NAME.equals(SymEncAlgo)) {
byte[] xorCipherText = XOREncryptionUtils.encrypt(keyingMaterial,
plaintext);
if (xorCipherText == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.XOR encryption of the plaintext"
+ " returned a NULL byte array");
}
if (xorCipherText.length != plaintext.length) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.XOR encryption returned a"
+ " cipherText that is " + xorCipherText.length
+ " bytes long.XOR CipherText and plainText MUSTE have"
+ " exactly the same size : " + plaintext.length);
}
symCipherText = new XORCipherText(xorCipherText);
if (eciesEpi != null) {
symetricEncrProcessInfo.setDataEncryptionAlgorithm(NamesIdentifiersIntf.XOR_NAME);
if (eciesEpi.getDataEncodingAlgorithm() != null) {
symetricEncrProcessInfo.setDataEncodingAlgorithm(eciesEpi.getDataEncodingAlgorithm());
} else {

symetricEncrProcessInfo.setDataEncodingAlgorithm(FormatsIdentifiersIntf.BASE64_FORMAT);
}
}
//The input for HMAC will be the cipherText produced by the symmetric
//encryption
ciphertextForHMACInput = xorCipherText;
} else if (NamesIdentifiersIntf.DES_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
symCipherText = new Base64DesCipherText();
symetricEncrProcessInfo = ECCUtils.encryptWith_DES_CBC_PKCS5Padding(plaintext,
keyingMaterial, iv, (Base64DesCipherText) symCipherText);
if (symetricEncrProcessInfo == null) {
throw new EncryptionFailureException("Could not generate"
+ " EncryptionProcessInfo because"
+ " DES/CBC/PKCS5Padding encryption process failed!");
}
//The input for HMAC will be the cipherText produced by the symmetric
//encryption
ciphertextForHMACInput = ((Base64DesCipherText) symCipherText).getDecodedCipherText();
} else if (NamesIdentifiersIntf.DESede_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
symCipherText = new Base64TripleDesCipherText();
symetricEncrProcessInfo = ECCUtils.encryptWith_DESede_CBC_PKCS5Padding(plaintext,
keyingMaterial, iv, (Base64TripleDesCipherText) symCipherText);
if (symetricEncrProcessInfo == null) {
throw new EncryptionFailureException("Could not generate"
+ " EncryptionProcessInfo because"
+ " DESede/CBC/PKCS5Padding encryption process failed!");
}
//The input for HMAC will be the cipherText produced by the symmetric
//encryption
ciphertextForHMACInput = ((Base64TripleDesCipherText)
symCipherText).getDecodedCipherText();
}

/*We compute the HashMac tag of the symmetric encryption result of the
previous step */
byte[] hmacResultTag;
try {
hmacResultTag = hmac.doHmac(hmacAuthenticationKey, ciphertextForHMACInput,
hmacTagExpectedLength, hmacHashAlgo);
} catch (HMACFailureException ex) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme because HMACFailureException"
+ " has been thrown.We could not compute the HashMac of the"
+ " symmetric encryption result of the previous step", ex);
}
if (hmacResultTag == null) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.HashMac computation of"
+ " symmetric encryption result of the previous step returned"
+ " a NULL result");
}
if (hmacResultTag.length == 0) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.HashMac computation of"
+ " symmetric encryption result of the previous step returned"
+ " an empty byte array");
}
if (hmacResultTag.length != hmacTagExpectedLength) {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme.HashMac computation of"
+ " symmetric encryption result of the previous step returned"
+ " a byte array that is " + hmacResultTag.length
+ " bytes long.Expected length is " + hmacTagExpectedLength);
}
if (eciesEpi != null) {//We set all fields of instance of
//EncryptionProcessInformation
eciesEpi.setKdfAlgoName(kdf.getKeyDerivationFunctionAlgorithm());
eciesEpi.setMacAlgoName(NamesIdentifiersIntf.HMAC_NAME + "with"
+ hmacHashAlgo.getAlgorithm());
eciesEpi.setHmacHashAlgoName(hmacHashAlgo.getAlgorithm());
eciesEpi.setKdfHashAlgoName(kdfHashAlgo.getAlgorithm());
eciesEpi.setMacTagDesiredlength(hmacTagExpectedLength);
eciesEpi.setMacKeyDesiredLength(hmacKeyDesiredLength);
eciesEpi.setUsedCompressionPoint(false);
eciesEpi.setSymEncProcessInfo(symetricEncrProcessInfo);
String dataEncodingAlgorithm;
if (eciesEpi.getDataEncodingAlgorithm() != null) {
dataEncodingAlgorithm = eciesEpi.getDataEncodingAlgorithm();
} else {
dataEncodingAlgorithm = FormatsIdentifiersIntf.BASE64_FORMAT;
}
eciesCipherText = new ECIESCipherText(dataEncodingAlgorithm, R,
symCipherText, hmacResultTag);
}
return eciesCipherText;
}

/**
* This method allows to decrypt a cipherText produced by ECIES and to
* retrieve the original plaintext
*
* @param eccPrivKey The private secret key to be used to decrypt cipherText
* @param cipherText The cipherText to be decrypted
* @param eciesEpi Contains additional informations that are needed to
* decrypt the cipherText
* @return A plaintext in a byte array format.The result MUST not be NULL
* @throws DecryptionFailureException
*/
public static byte[] decrypt(ECCPrivateKey eccPrivKey, ECIESCipherText cipherText,
ECIESEncryptionProcessInfo eciesEpi) throws DecryptionFailureException {
//We can not continue the decryption process if there is no information
//about the encryption process that has produced the cipherText that we
//want to decrypt.So we throw an exception
if (eciesEpi == null) {
//Throw an exception and exit right now
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because eciesEpi is a NULL"
+ " ECIESEncryptionProcessInfo instance.We do not know how"
+ " to decrypt the cipherText");
}
//We can not continue the decryption process if there is no information
//about the underlying symmetric encryption process.So we throw an exception
if (eciesEpi.getSymEncProcessInfo() == null) {
//Throw an exception and exit right now
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because encryptionInfo"
+ " related to the symmetric encryption is NULL. We do not "
+ "know ho to perform the symmetric decryption");
}
KDFIntf kdf;
try {
//From additional informations, we can retrieve the suitable Key
//Derivation Function Engine to continue the decryption process
kdf = eciesEpi.getKdfEngine();
} catch (UnsupportedCryptoOperationException ex) {
//Throw an exception and exit right now if something went wrong
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme." + ex.getClass().getSimpleName()
+ " has been thrown when attempt to retrieve the Key"
+ " Derivation Function engine from ECIES encryption"
+ " process information object", ex);
}
HMACIntf hmac = null;
try {
//From additional informations, we can retrieve the suitable HASH
//MAC Engine to continue the decryption process
hmac = eciesEpi.getHashMacEngine();
} catch (UnsupportedCryptoOperationException ex) {
//Throw an exception and exit right now if something went wrong
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme." + ex.getClass().getSimpleName()
+ " has been thrown when attempt to retrieve the HMAC"
+ " engine from ECIES encryption process information object", ex);
}
//From additional informations, we retrieve the suitable length for
//HASH MAC of the secret key
int hmacKeyDesiredLength = eciesEpi.getMacKeyDesiredLength();
//From additional informations, we retrieve the expected length for
//HASH MAC of the Tag
int hmacTagDesiredlength = eciesEpi.getMacTagDesiredlength();
MessageDigestIntf hmacHashAlgo = null;
try {
//From additional informations, we retrieve the suitable HASH engine for
//HMAC
hmacHashAlgo = eciesEpi.getHashMacHashEngine();
} catch (UnsupportedCryptoOperationException ex) {
//Throw an exception and exit right now if something went wrong
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme." + ex.getClass().getSimpleName()
+ " has been thrown when attempt to retrieve the MessageDigest"
+ " (that will be used for HMAC computation) engine from"
+ " ECIES encryption process information object", ex);
}
MessageDigestIntf kdfHashAlgo = null;
try {
//From additional informations, we retrieve the suitable HASH engine for
//Key Derivation Function
kdfHashAlgo = eciesEpi.getKdfHashEngine();
} catch (UnsupportedCryptoOperationException ex) {
//Throw an exception and exit right now if something went wrong
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme." + ex.getClass().getSimpleName()
+ " has been thrown when attempt to retrieve the MessageDigest"
+ " (that will be used for KDF computation) engine from"
+ " ECIES encryption process information object", ex);
}
//NOW, we call the ad-hoc decrypt method with the good signature to
//continue the process
byte[] computedPlaintext = decrypt(eccPrivKey, cipherText, kdf, hmac,
hmacKeyDesiredLength, hmacTagDesiredlength, hmacHashAlgo,
kdfHashAlgo, eciesEpi.getSymEncProcessInfo().
getDataEncryptionAlgorithm(),
eciesEpi.getSymEncProcessInfo().getDecodedIinitializationVector(),
eciesEpi.isUsedCompressionPoint());
return computedPlaintext;
}

/**
* This method allows to decrypt a cipherText produced by ECIES and to
* retrieve the original plaintext
*
* @param eccPrivKey Private key to decrypt the cipherText
* @param cipherText The cipherText to be decrypted
* @param kdf Key Derivation Function to retrieve the symmetric encryption
* key
* @param hmac HMAC engine used for authentication
* @param hmacKeyDesiredLength
* @param hmacTagExpectedLength
* @param hmacHashAlgo
* @param kdfHashAlgo
* @param SymEncAlgo The underlying symmetric encryption
* @param iv An initialization Vector in a byte array format
* @param compressPoint A Boolean that shows if compression point is used or
* not
* @return A plaintext in a byte array format.The result MUST not be NULL
* @throws DecryptionFailureException
*/
public static byte[] decrypt(ECCPrivateKey eccPrivKey, ECIESCipherText cipherText,
KDFIntf kdf, HMACIntf hmac, int hmacKeyDesiredLength,
int hmacTagExpectedLength, MessageDigestIntf hmacHashAlgo,
MessageDigestIntf kdfHashAlgo, String SymEncAlgo, byte[] iv,
boolean compressPoint) throws DecryptionFailureException {
//We check the ECCPrivateKey provided that will be used for decryption
if (eccPrivKey == null) {
//Throw an exception and exit right
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because the ECCPrivateKey"
+ " provided is NULL");
}
//We retrieve the domain parameters and check them out
ECCParams params = eccPrivKey.getParams();
if (params == null) {
//Throw an exception and exit right now because we can not continue the
//decryption process without the ECC domain parameters
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.ECCPrivateKey provided"
+ " contains no internal ECC parameters");
}
ECCurve ecCurve = eccPrivKey.getParams().getCurve();
if (ecCurve == null) {
//Throw an exception and exit right now because we can not continue the
//decryption process without the elliptic curve
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.Retrieved a NULL ECCurve"
+ " instance from the internal parameters of the ECCPrivateKey");
}
BigInteger h_BasePointCofactor = eccPrivKey.getParams().getCurve().getH();
//We check the cipherText consistency
if (cipherText == null) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because the cipherText is"
+ " a NULL ECIESCipherText instance");
}
if (kdf == null) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because the Key Derivation"
+ " Function engine provided is a NULL KDFIntf instance");
}
if (hmac == null) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because the HMAC engine"
+ " provided is a NULL HMACIntf instance");
}
if (compressPoint) {
UnsupportedCryptoOperationException ex = new UnsupportedCryptoOperationException(
"Elliptic Curve Point compression is not supported for"
+ " ECIES decryption!");
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because compression point"
+ " is not yet supported", ex);
}
//We build an embedded ECCPublicKey with the cipherText and the internal
//parameters of the ECCPrivateKey provided for the decryption
ECCPublicKey embeddedPublicKey = new ECCPublicKey(
cipherText.getPoint(), eccPrivKey.getParams());
//We check the embedded public key consistency
boolean validEmbeddedPubKey = ECCUtils.embeddedPublicKeyValidation(embeddedPublicKey);
if (!validEmbeddedPubKey) {
InvalidEmbeddedECCPubKeyException ex = new InvalidEmbeddedECCPubKeyException(
"Embedded ECCPublic Key invalid for its associated domain parameters");
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because embedded ECCPublic"
+ " Key is not valid for its associated domain parameters", ex);
}
InfinityPoint inf = new InfinityPoint();
ECCpoint Z = null;
ECCpoint temp;
try {
temp = ECCArithCalculator.multiply(cipherText.getPoint(),
eccPrivKey.getD(), ecCurve);
} catch (NULLEllipticCurveException ex) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because"
+ " NULLEllipticCurveException has been thrown.", ex);
} catch (NULLPointException ex) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because"
+ " NULLPointException has been thrown.", ex);
}
if (BigInteger.ONE.compareTo(h_BasePointCofactor) != 0) {
try {
Z = ECCArithCalculator.multiply(temp, h_BasePointCofactor, ecCurve);
} catch (NULLEllipticCurveException ex) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because"
+ " NULLEllipticCurveException has been thrown.", ex);
} catch (NULLPointException ex) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because"
+ " NULLPointException has been thrown.", ex);
}
} else {
Z = temp;
}
//Checking that Z is not inifinity point of the decryption procedure
//confirms that Z is a point in the subgroup generated by the base point
//of the curve noted as <basePoint>
if (Z.compareTo(inf, ecCurve)) {
InvalidCipherTextException ex = new InvalidCipherTextException("Could not decrypt the"
+ " ECIES CipherText because the computed Shared Secret is the "
+ " infinity point!");
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because"
+ " InvalidCipherTextException has been thrown.", ex);
}
BigInteger Xz = Z.getX();
byte[] sharedSecretValue = CryptoUtils.bigIntegerToByteArray(Xz);
int symmetricEncryptionExpectedLenght = 0;
byte[] symetricCipherText = (cipherText.getSymetricCipherText()).getDecodedCipherText();
if (NamesIdentifiersIntf.XOR_NAME.equals(SymEncAlgo)) {
//XOR decryption requires a key that has the same lenght than the
//cipherText to be decrypted.
//Take note that with XOR encryption, plaintext, key encryption and
//ciphertext have the same lenght
symmetricEncryptionExpectedLenght = symetricCipherText.length;
} else if (NamesIdentifiersIntf.DESede_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
//DESede requires an 8 bytes initialization vector, so we check it out
if (iv == null) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.IV provided for underlying"
+ " decryption " + SymEncAlgo + " is NULL");
}
if (iv.length != 8) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.IV provided for underlying"
+ " decryption " + SymEncAlgo + " is " + iv.length
+ " bytes long.But the expected lenght is 8 ");
}
//DESede performs DESencryption-DESdecryption-DESencryption,
//so we need 3 DES keys for each step of DESede.A DES key must be 8
//bytes long.So DESede requires a key that is (8 * 3 = 24) bytes long
symmetricEncryptionExpectedLenght = 24;
} else if (NamesIdentifiersIntf.DES_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
//DES requires an 8 bytes initialization vector, so we check it out
if (iv == null) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.IV provided for underlying"
+ " decryption " + SymEncAlgo + " is NULL");
}
if (iv.length != 8) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.IV provided for underlying"
+ " decryption " + SymEncAlgo + " is " + iv.length
+ " bytes long.But the expected lenght is 8 ");
}
//A DES key must be 8 bytes long.
symmetricEncryptionExpectedLenght = 8;
} else {
UnsupportedCryptoOperationException ex
= new UnsupportedCryptoOperationException("Could not decrypt the"
+ " ECIES CipherText because " + SymEncAlgo + " is not "
+ " still supported for ECIES encryption!");
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme." + SymEncAlgo
+ " is not yet supported for ECIES underlying"
+ " decryption algorithm", ex);
}
//Key = Key1 || Key2
int keyDataLength = symmetricEncryptionExpectedLenght + hmacKeyDesiredLength;
byte[] keyingMaterial;
try {
//We compute the keying material by using the shared secret value
byte[] sharedInfo = null;//We do not provid shared informations
keyingMaterial = kdf.deriveKey(sharedSecretValue, keyDataLength,
sharedInfo, kdfHashAlgo);
} catch (KDFInputCheckFailureException ex) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme."
+ ex.getClass().getSimpleName() + " has been thrown"
+ " during key derivation process", ex);
}
/*We compute and extract the key no 1 for symmetric encryption and the
key no 2 for the HashMac computation, keyingMaterial =
symmetricEncryptionKey||hmacAuthenticationKey*/
byte[] symmetricEncryptionKey = new byte[symmetricEncryptionExpectedLenght];
System.arraycopy(keyingMaterial, 0, symmetricEncryptionKey, 0,
symmetricEncryptionKey.length);//Key no 1 is recovered
byte[] hmacKey = new byte[hmacKeyDesiredLength];
System.arraycopy(keyingMaterial, symmetricEncryptionKey.length, hmacKey,
0, hmacKey.length);//Key no 2 is recovered
byte[] hmacResult_2;
try {
hmacResult_2 = hmac.doHmac(hmacKey, symetricCipherText, hmacTagExpectedLength,
hmacHashAlgo);
} catch (HMACFailureException ex) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme."
+ ex.getClass().getSimpleName() + " has been thrown"
+ " during HMAC generation process", ex);
}
if (hmacResult_2 == null) {
InvalidCipherTextException ex = new InvalidCipherTextException("The HashMac computation of"
+ " the symetric ciphertext extracted from the provided"
+ " ECIES ciphertext returned a null value!");
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because an HMAC generation"
+ " returned a NULL byte array instance.", ex);
}
if (hmacResult_2.length != hmacTagExpectedLength) {
InvalidCipherTextException ex = new InvalidCipherTextException("The HashMac computation of"
+ " the symetric ciphertext extracted from the provided"
+ " ECIES ciphertext returned a non expected length!");
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.HMAC computation returned"
+ " a byte array that is " + hmacResult_2.length
+ " bytes long. The expected length is "
+ hmacTagExpectedLength, ex);
}
byte[] hashMacOutputExtractedFromCiphertext = cipherText.getMacOutputInByteArray();
//We check the consistency of the HashMAC output of the cipherText to be decrypted
if (hashMacOutputExtractedFromCiphertext == null) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme because HASH MAC output"
+ " of the cipherText to be decrypted is a NULL byte array");
}
if (hashMacOutputExtractedFromCiphertext.length != hmacResult_2.length) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.HASH MAC output"
+ " of the cipherText to be decrypted is a "
+ hashMacOutputExtractedFromCiphertext.length
+ " bytes long array.The expected length is " + hmacResult_2.length);
}
//We perform the HMAC TAG authentication
boolean hmacOutputsComparisonResult = CryptoUtils.compareTwoBytesArrays(
hashMacOutputExtractedFromCiphertext, hmacResult_2);
if (!hmacOutputsComparisonResult) {
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme.Comparison between HMAC of"
+ " cipherText to be decrypted and its expected byte array"
+ " value show that they are not the same");
}
byte[] computedPlaintext = null;
//We process the symmetric decryption
if (NamesIdentifiersIntf.XOR_NAME.equals(SymEncAlgo)) {
computedPlaintext = XOREncryptionUtils.decrypt(symmetricEncryptionKey, symetricCipherText);
} else if (NamesIdentifiersIntf.DESede_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
computedPlaintext = TripleDesUtils.tripleDesDecryptBlocks_Cbc_PKCS5Padding(iv,
symetricCipherText, symmetricEncryptionKey);
} else if (NamesIdentifiersIntf.DES_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
computedPlaintext = DesUtils.desDecryptBlocks_Cbc_PKCS5Padding(iv,
symetricCipherText, symmetricEncryptionKey, false);
} else {
//FOR NOW, we do not support other symmetric encryption algorithms
//for ECIES.(We will add support of AES256, TDEA later)
throw new DecryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Decryption Scheme process." + SymEncAlgo
+ " is not yet supported as symmetric encryption algorithm");
}

if (computedPlaintext == null) {
//SHOULD NEVER happen.This is a very defensive check that could be removed
throw new DecryptionFailureException("Elliptic Curve Integrated"
+ " Decryption Scheme returned a NULL byte array");
}
if (computedPlaintext.length == 0) {
//SHOULD NEVER happen.This is a very defensive check that could be removed
throw new DecryptionFailureException("Elliptic Curve Integrated"
+ " Decryption Scheme returned an empty byte array");
}
return computedPlaintext;
}
}
package LibCrypto.Tests.ECIES;

import LibCrypto.Common.CryptoExceptions.DecryptionFailureException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLEllipticCurveException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLPointException;
import LibCrypto.Common.CryptoExceptions.EncryptionFailureException;
import LibCrypto.Common.CryptoUtilities.CryptoUtils;
import LibCrypto.Common.Exceptions.CryptoTestException;
import LibCrypto.Common.Interfaces.HMACIntf;
import LibCrypto.Common.Interfaces.KDFIntf;
import LibCrypto.Common.Interfaces.MessageDigestIntf;
import LibCrypto.CryptoImpls.KeysImpls.ECCImpls.ECCKeyPairGenerator;
import LibCrypto.CryptoImpls.KeysImpls.ECCImpls.ECCPrivateKey;
import LibCrypto.CryptoImpls.KeysImpls.ECCImpls.ECCPublicKey;
import LibCrypto.CryptoImpls.KeysImpls.KeyPair;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurve;
import LibCrypto.ECCImpls.ECCParams;
import LibCrypto.ECCImpls.ECCUtils;
import LibCrypto.ECCImpls.ECIES.ECIESCipherText;
import LibCrypto.ECCImpls.ECIES.ECIESEncryptionProcessInfo;
import LibCrypto.ECCImpls.ECIES.ECIESEncryptionUtils;
import java.security.NoSuchAlgorithmException;

/**
* <p>This class sets a suitable environment that will be helpful to test Elliptic
* Curve Integrated Encryption Scheme. The chosen elliptic curve is P192 from
* NIST An EcnryptionProcessInfo object that contains all information about the
* whole ECIES process is created.</p>
*
* <p>Here is the logic of the test : Step1 :
* cipherText = ECIESencryption (originalPlaintext) Step2 : computedPlaintext =
* ECIESdecryption (cipherText) Step3 : if computedPlaintext equals
* originalPlaintext, the test is OK, otherwise the test is KO</p>
*
* @author Jules-Florent EYA
* @mail [email protected]
* @tel 1-514-802-1003, Canada
*/
public abstract class TestECIESEncryption2 {

/**
* The plaintext to be encrypted and decrypted by ECIES for the test in a
* String format is a poem of EDGAR ALLAN POE, "A dream within a dream",
* published in 1850.
*/
protected static final String PLAINTEXT = "Take this kiss upon the brow!"
+ "And, in parting from you now,\n"
+ "Thus much let me avow --\n"
+ "You are not wrong, who deem\n"
+ "That my days have been a dream;\n"
+ "Yet if hope has flown away\n"
+ "In a night, or in a day,\n"
+ "In a vision, or in none,\n"
+ "Is it therefore the less gone?\n"
+ "All that we see or seem\n"
+ "Is but a dream within a dream.\n"
+ "\n"
+ "I stand amid the roar\n"
+ "Of a surf-tormented shore,\n"
+ "And I hold within my hand\n"
+ "Grains of the golden sand --\n"
+ "How few! yet how they creep\n"
+ "Through my fingers to the deep,\n"
+ "While I weep -- while I weep!\n"
+ "O God! can I not grasp\n"
+ "Them with a tighter clasp?\n"
+ "O God! can I not save\n"
+ "One from the pitiless wave?\n"
+ "Is all that we see or seem\n"
+ "But a dream within a dream?";

/**
* A encryption-decryption process will be executed in a for loop according
* to this field.It will be used to be sure that encryption-decryption
* process always returns the same result no matter the values of the
* public, private and secret keys that are used to perform ECIES
*/
protected int loopSize;

/**
* When an initialization vector is required by the underlying symmetric
* encryption used by ECIES, the following boolean field must be set to true
* otherwise it must be set to false
*/
protected boolean checkInitializationVector;

/**
* Class Constructor
*/
public TestECIESEncryption2() {
//By default, the loop size is 100.
//I ran tests with the maximum value of 100000
this.loopSize = 100;
//By default, the symmetric encryption that will be used by ECIES is supposed
//to use an Initialization Vector (e.g DES, 3DES, AES256), so we should check out
//its value
this.checkInitializationVector = true;
}

/**
* This method allows to generate a random initialization vector Depend on
* the case, sub classes should implement this method in a particular way
*
* @param SymEncAlgo The underlying symmetric encryption that will be used
* by ECIES in a String format.
* @return Initialization vector in a byte array format or NULL
* @throws EncryptionFailureException
*/
protected abstract byte[] getInitializationVector(String SymEncAlgo)
throws EncryptionFailureException;
/**
* This method performs the encryption_decryption process. If no exception
* is thrown during the execution of this method, it means that
* encryption_decryption process was complete.
*
* This method implements the following scenario : Bob creates an Elliptic
* Curve Key Pair and a secret key for a symmetric encryption. With his
* public and secret keys, he encrypts the plaintext and creates a cipherText.
* Bob decrypts the cipherText with his secret key and elliptic curve
* private key.Bod recovers the original plaintext.
*
* @param curve The NIST curve that will be used by the encryption_decryption
* process. It could be P-192, P-256, P-384, P-521
* @param kdf Key Derivation Function
* @param hmac HMAC engine for authentication
* @param hmacKeyDesiredLength
* @param hmacTagDesiredlength
* @param hmacHashAlgo
* @param kdfHashAlgo HASH engine to be used by Key Derivation Function
* @param SymEncAlgo Name of symmetric encryption that will be used by ECIES
* @param compressPoint A boolean that shows if compression point is used or
* not
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws CryptoTestException
* @throws DecryptionFailureException
*/
protected void ecies_encrypt_decrypt(NistCurve curve,
KDFIntf kdf, HMACIntf hmac, int hmacKeyDesiredLength,
int hmacTagDesiredlength, MessageDigestIntf hmacHashAlgo,
MessageDigestIntf kdfHashAlgo, String SymEncAlgo,
boolean compressPoint)
throws NoSuchAlgorithmException, NULLEllipticCurveException,
NULLPointException, EncryptionFailureException, CryptoTestException,
DecryptionFailureException {
//If no curve is provided, you can not start ECIES process
if (curve == null) {
throw new CryptoTestException("Must stop the test because the"
+ " provided NistCurve is NULL");
}
//Generation of Elliptic Curve Domain Parameters
ECCParams params = new ECCParams(curve);
if (params == null) {
throw new CryptoTestException("Could not create domain parameters "
+ "for " + curve.getName());
}
//Bob validates the elliptic curve domain parameters before trying to
//create a public and a private key with the curve and its domain parameters
if (!(params.validationOfEllipticCurveDomainParameters())) {
throw new CryptoTestException("Must stop the test.Could not validate"
+ " domain parameters for " + curve.getName());
}
//ECCKeyPairGenerator can generate a key pair for ECIES
ECCKeyPairGenerator gen = ECCKeyPairGenerator.getInstance(0, params);
if (gen == null) {
throw new CryptoTestException("ECCKeyPairGenerator.getInstance() returned"
+ " NULL ECCKeyPairGenerator instance");
}
//Bob is the owner of the keys that will be used to encrypt and decrypt data
String owner = "Bob";
String creationDate = CryptoUtils.giveTheHour();
//Bob generates a Key pair : A public and a private key for ECIES encryption
//and decryption
KeyPair keyPair = gen.generateKeyPair(owner, creationDate);
if (keyPair == null) {
throw new CryptoTestException("ECCKeyPairGenerator.generateKeyPair() returned"
+ " NULL KeyPair instance");
}
//The ECC public key of Bob to encrypt data
ECCPublicKey eccPubKey = (ECCPublicKey) keyPair.getPublicKey();
//The ECC private key of Bob to decrypt data
ECCPrivateKey eccPrivKey = (ECCPrivateKey) keyPair.getPrivateKey();
if (eccPubKey.getReference().compareTo(eccPrivKey.getReference()) != 0) {
throw new CryptoTestException("The generated public and private"
+ " keys are not mathematically related");
}
//Bob checks the ECC public key by performing a validation
//Page 38 of SEC1 Version 2 "Elliptic Curve Cryptography", you can find
//information about how to perform public key validation for ECC
boolean validPubKey = ECCUtils.publicKeyValidation(eccPubKey);
if (!validPubKey) {
throw new CryptoTestException("The public elliptic curve key"
+ " validation failed ");
}
//Generation of a random initialization vector if the symmetric encryption that
//will be used for ECIES requires an initialization vector
byte[] iv = getInitializationVector(SymEncAlgo);
if (checkInitializationVector) {
if (iv == null) {
throw new CryptoTestException("Initialization Vector provided for"
+ SymEncAlgo + " is NULL");
}
if (iv.length == 0) {
throw new CryptoTestException("Initialization Vector provided for"
+ SymEncAlgo + " is an empty byte array");
}
}
//Bob creates an empty container that will hold all informations about the
//whole ECIES encryption process.These informations will be used after in
//the decryption step
ECIESEncryptionProcessInfo eciesEpi = new ECIESEncryptionProcessInfo();
//Bob convert the original string plaintext in a byte array plaintext
byte[] byteArrayPlaintext = CryptoUtils.stringToByteArray(PLAINTEXT);
//If the byte array plaintext is NULL, we exit right away
if (byteArrayPlaintext == null) {
throw new CryptoTestException("The conversion in a byte array of"
+ " the string plaintext to be encrypted is NULL");
}
//If the byte array plaintext empty, we exit right away
if (byteArrayPlaintext.length == 0) {
throw new CryptoTestException("The conversion in a byte array of"
+ " the string plaintext to be encrypted is an EMPTY byte"
+ " array");
}
//Bob calls ECIES encryption utility tool to perform the ECIES encryption
ECIESCipherText cipherText = ECIESEncryptionUtils.encrypt(eccPubKey,
byteArrayPlaintext, kdf, hmac, hmacKeyDesiredLength,
hmacTagDesiredlength, hmacHashAlgo, kdfHashAlgo, SymEncAlgo,
iv, compressPoint, eciesEpi);
//Bob checks that a cipherText has been produced
if (cipherText == null) {
throw new CryptoTestException("The cipherText produced by the ECIES"
+ " encryption process is NULL");
}
/*Bob is done with encryption part of the test, now he is starting the
decryption part*/
//Bob uses his private key and tries to decrypt the cipherText with
//some aditionnal informations about the way the encryption process
//has been done
byte[] decryptedByteArrayPlaintext = ECIESEncryptionUtils.decrypt(
eccPrivKey, cipherText, eciesEpi);
//Check : The result of ECIES decryption is not a NULL byte array
if (decryptedByteArrayPlaintext == null) {
throw new CryptoTestException("ECIES decryption returned a NULL"
+ " byte array");
}
//Check : The result of ECIES decryption is not an EMPTY byte array
if (decryptedByteArrayPlaintext.length == 0) {
throw new CryptoTestException("ECIES decryption returned an empty"
+ " byte array");
}
//Check : The result of ECIES decryption is a byte array with the
//same size than the byte array plaintext
if (decryptedByteArrayPlaintext.length != byteArrayPlaintext.length) {
throw new CryptoTestException("ECIES decryption returned a array"
+ " that is " + decryptedByteArrayPlaintext.length
+ " bytes long.Original plaintext is "
+ byteArrayPlaintext.length + " bytes long");
}
//Conversion of the decrypted byte array plaintext that has been
//returned by the ECIES decryption process in a String
String decryptedStringPlaintext = CryptoUtils.bytesToString(
decryptedByteArrayPlaintext);
//Check : The decrypted string is not NULL
if (decryptedStringPlaintext == null) {
throw new CryptoTestException("Conversion in String of the byte"
+ " array returned from ECIES decryption process is NULL");
}
//Check : The decrypted string is not EMPTY
if (decryptedStringPlaintext.isEmpty()) {
throw new CryptoTestException("Conversion in String of the byte"
+ " array returned from ECIES decryption process is an"
+ " empty string");
}
//We compare the decrypted string to the original plaintext string
//If they do not match, we throw a CryptoTestException
if (!decryptedStringPlaintext.equals(PLAINTEXT)) {
throw new CryptoTestException("Conversion in String of the byte"
+ " array returned from ECIES decryption does not match the"
+ " original string plaintext");
}
}

}
package LibCrypto.Tests.ECIES;

import LibCrypto.AlgoImpls.HMACImpls.Hmac;
import LibCrypto.AlgoImpls.KDFImpls.AnsiX9_63KDF;
import LibCrypto.Common.CryptoExceptions.DecryptionFailureException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLEllipticCurveException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLPointException;
import LibCrypto.Common.CryptoExceptions.EncryptionFailureException;
import LibCrypto.Common.Exceptions.CryptoTestException;
import LibCrypto.Common.Interfaces.HMACIntf;
import LibCrypto.Common.Interfaces.Identifiers.CryptoIdentifiers;
import LibCrypto.Common.Interfaces.Identifiers.NamesIdentifiersIntf;
import LibCrypto.Common.Interfaces.KDFIntf;
import LibCrypto.Common.Interfaces.MessageDigestIntf;
import LibCrypto.CryptoImpls.KeysImpls.DESKeyGenerator;
import LibCrypto.DigestImpls.ShaImpls.Sha1;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurve;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurveP192;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
* <p>This class implements a test for ECIES encryption and decryption process</p>
*
* <p>Elliptic curve used : P192 from NIST. Key Derivation Function used :
* ANSI_X9_63KDF. Symmetric encryption used : DES_CBC_PKCS5Padding. Hash
* algorithm used for key derivation function : SHA1. HMAC algorithm used :
* HMAC with SHA1. CERTICOM compression point used : NO. Random Initialization
* vector used : YES. Data encoding algorithm : Base 64.</p>
*
* This class implements
* @author Jules-Florent EYA
* @mail [email protected]
* @tel 1-514-802-1003, Canada
*/
public class Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_DesCbcPKC5Padding extends
TestECIESEncryption2 {

/**
* Class Constructor
*/
public Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_DesCbcPKC5Padding() {
super();
}

@Override
protected byte[] getInitializationVector(String SymEncAlgo)
throws EncryptionFailureException {
byte[] iv = null;
if (NamesIdentifiersIntf.DES_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
iv = DESKeyGenerator.generateIVMaterial(new SecureRandom());
} else {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process." + SymEncAlgo
+ " is not yet supported as symmetric encryption");
}
return iv;
}

/**
*
* @param curve
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws CryptoTestException
* @throws DecryptionFailureException
*/
protected void test_ECIES_Encryption_Decryption(NistCurve curve)
throws NoSuchAlgorithmException,
NULLEllipticCurveException, NULLPointException,
EncryptionFailureException, CryptoTestException, DecryptionFailureException {
//We choose the Key Derivative Function algorithm
KDFIntf kdf = new AnsiX9_63KDF();
//We choose the HMAC algorithm
HMACIntf hmac = new Hmac();
int hmacKeyDesiredLength = CryptoIdentifiers.SHA1_BYTES_OUTPUTSIZE;
int hmacTagDesiredlength = CryptoIdentifiers.SHA1_BYTES_OUTPUTSIZE;
//HASH engine to do the HMAC
MessageDigestIntf hmacHashAlgo = new Sha1();
//HASH engine to do the Key Derivation Function
MessageDigestIntf kdfHashAlgo = new Sha1();
//We choose the underlying symmetric encryption
String SymEncAlgo = CryptoIdentifiers.DES_CBC_PKCS5_NAME;
//We choose to NOT compress elliptic curve points
boolean compressPoint = false;
ecies_encrypt_decrypt(curve, kdf, hmac, hmacKeyDesiredLength,
hmacTagDesiredlength, hmacHashAlgo, kdfHashAlgo, SymEncAlgo,
compressPoint);

/**
*
* @param args
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws CryptoTestException
* @throws DecryptionFailureException
*/
public static void main(String[] args)
throws NoSuchAlgorithmException, NULLEllipticCurveException,
NULLPointException, EncryptionFailureException, CryptoTestException,
DecryptionFailureException {
Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_DesCbcPKC5Padding testEngine
= new Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_DesCbcPKC5Padding();
for (int i = 0; i < testEngine.loopSize; i++) {
NistCurveP192 curve = NistCurveP192.getInstance();
testEngine.test_ECIES_Encryption_Decryption(curve);
}
}

}
package LibCrypto.Tests.ECIES;

import LibCrypto.AlgoImpls.HMACImpls.Hmac;
import LibCrypto.AlgoImpls.KDFImpls.AnsiX9_63KDF;
import LibCrypto.Common.CryptoExceptions.DecryptionFailureException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLEllipticCurveException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLPointException;
import LibCrypto.Common.CryptoExceptions.EncryptionFailureException;
import LibCrypto.Common.Exceptions.CryptoTestException;
import LibCrypto.Common.Interfaces.HMACIntf;
import LibCrypto.Common.Interfaces.Identifiers.CryptoIdentifiers;
import LibCrypto.Common.Interfaces.Identifiers.NamesIdentifiersIntf;
import LibCrypto.Common.Interfaces.KDFIntf;
import LibCrypto.Common.Interfaces.MessageDigestIntf;
import LibCrypto.CryptoImpls.KeysImpls.TripleDESKeyGenerator;
import LibCrypto.DigestImpls.ShaImpls.Sha1;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurve;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurveP192;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
* <p>
* This class implements a test for ECIES encryption and decryption process</p>
*
* <p>
* Elliptic curve used : P192 from NIST. Key Derivation Function used :
* ANSI_X9_63KDF. Symmetric encryption used : DESede_CBC_PKCS5Padding. Hash
* algorithm used for key derivation function : SHA1. HMAC algorithm used : HMAC
* with SHA1. CERTICOM compression point used : NO. Random Initialization vector
* used : YES. Data encoding algorithm : Base 64.</p>
*
* @author Jules-Florent EYA
* @mail [email protected]
* @tel 1-514-802-1003, Canada
*/
public class Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_Triple_DesCbcPKC5Padding
extends TestECIESEncryption2 {

/**
* Class Constructor
*/
public Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_Triple_DesCbcPKC5Padding() {
super();
}

@Override
protected byte[] getInitializationVector(String SymEncAlgo)
throws EncryptionFailureException {
byte[] iv = null;
if (NamesIdentifiersIntf.DESede_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
iv = TripleDESKeyGenerator.generateIVMaterial(new SecureRandom());
} else {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process." + SymEncAlgo
+ " is not yet supported as symmetric encryption");
}
return iv;
}

/**
* This method allows to test Elliptic Curve Integrated Encryption Scheme
* (ECIES) with DES_CBC_PKCS5Padding used as underlying symmetric
* encryption. The Key Derivation Function used for ECIES respects
* ANSI_X9_63 specification
*
* @param curve
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws LibCrypto.Common.Exceptions.CryptoTestException
* @throws LibCrypto.Common.CryptoExceptions.DecryptionFailureException
*/
protected void test_ECIES_Encryption_Decryption(NistCurve curve)
throws NoSuchAlgorithmException,
NULLEllipticCurveException, NULLPointException,
EncryptionFailureException, CryptoTestException,
DecryptionFailureException {
//We choose the Key Derivative Function algorithm
KDFIntf kdf = new AnsiX9_63KDF();
//We choose the HMAC algorithm
HMACIntf hmac = new Hmac();
int hmacKeyDesiredLength = CryptoIdentifiers.SHA1_BYTES_OUTPUTSIZE;
int hmacTagDesiredlength = CryptoIdentifiers.SHA1_BYTES_OUTPUTSIZE;
//HASH engine to do the HMAC
MessageDigestIntf hmacHashAlgo = new Sha1();
//HASH engine to do the Key Derivation Function
MessageDigestIntf kdfHashAlgo = new Sha1();
//We choose the underlying symmetric encryption
String SymEncAlgo = CryptoIdentifiers.DESede_CBC_PKCS5_NAME;
//We choose to NOT compress elliptic curve points
boolean compressPoint = false;
ecies_encrypt_decrypt(curve, kdf, hmac, hmacKeyDesiredLength,
hmacTagDesiredlength, hmacHashAlgo, kdfHashAlgo, SymEncAlgo,
compressPoint);

/**
*
* @param args
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws CryptoTestException
* @throws DecryptionFailureException
*/
public static void main(String[] args)
throws NoSuchAlgorithmException, NULLEllipticCurveException,
NULLPointException, EncryptionFailureException, CryptoTestException,
DecryptionFailureException {
Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_Triple_DesCbcPKC5Padding testEngine
= new Test_ECIES_AnsiX9_63KDF_Hmac_SHA1_Triple_DesCbcPKC5Padding();
for (int i = 0; i < testEngine.loopSize; i++) {
NistCurveP192 curve = NistCurveP192.getInstance();
testEngine.test_ECIES_Encryption_Decryption(curve);
}
}

}
package LibCrypto.Tests.ECIES;

import LibCrypto.AlgoImpls.HMACImpls.Hmac;
import LibCrypto.AlgoImpls.KDFImpls.AnsiX9_63KDF;
import LibCrypto.Common.CryptoExceptions.DecryptionFailureException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLEllipticCurveException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLPointException;
import LibCrypto.Common.CryptoExceptions.EncryptionFailureException;
import LibCrypto.Common.Exceptions.CryptoTestException;
import LibCrypto.Common.Interfaces.HMACIntf;
import LibCrypto.Common.Interfaces.Identifiers.CryptoIdentifiers;
import LibCrypto.Common.Interfaces.Identifiers.NamesIdentifiersIntf;
import LibCrypto.Common.Interfaces.KDFIntf;
import LibCrypto.Common.Interfaces.MessageDigestIntf;
import LibCrypto.CryptoImpls.KeysImpls.TripleDESKeyGenerator;
import LibCrypto.DigestImpls.ShaImpls.Sha256;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurve;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurveP256;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
* <p>This class implements a test for ECIES encryption and decryption process<p>
*
* <p>Elliptic curve used : P256 from NIST. Key Derivation Function used :
* ANSI_X9_63. Symmetric encryption used : DESede_CBC_PKCS5Padding. Hash
* algorithm used for key derivation function : SHA256. HMAC algorithm used :
* HMAC with SHA256. CERTICOM compression point used : NO. Random Initialization
* vector used : YES. Data encoding algorithm : Base 64.<p>
*
* @author Jules-Florent EYA
* @mail [email protected]
* @tel 1-514-802-1003, Canada
*/
public class Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_Triple_DesCbcPKC5Padding
extends TestECIESEncryption2 {

/**
* Class Constructor
*/
public Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_Triple_DesCbcPKC5Padding() {
super();
}

@Override
protected byte[] getInitializationVector(String SymEncAlgo)
throws EncryptionFailureException {
byte[] iv = null;
if (NamesIdentifiersIntf.DESede_CBC_PKCS5_NAME.equals(SymEncAlgo)) {
iv = TripleDESKeyGenerator.generateIVMaterial(new SecureRandom());
} else {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process." + SymEncAlgo
+ " is not yet supported as symmetric encryption");
}
return iv;
}

/**
*
* @param curve
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws CryptoTestException
* @throws DecryptionFailureException
*/
protected void test_ECIES_Encryption_Decryption(NistCurve curve)
throws NoSuchAlgorithmException,
NULLEllipticCurveException, NULLPointException,
EncryptionFailureException, CryptoTestException, DecryptionFailureException {
//We choose the Key Derivative Function algorithm
KDFIntf kdf = new AnsiX9_63KDF();
//We choose the HMAC algorithm
HMACIntf hmac = new Hmac();
int hmacKeyDesiredLength = CryptoIdentifiers.SHA256_BYTES_OUTPUTSIZE;
int hmacTagDesiredlength = CryptoIdentifiers.SHA256_BYTES_OUTPUTSIZE;
//HASH engine to do the HMAC
MessageDigestIntf hmacHashAlgo = new Sha256();
//HASH engine to do the Key Derivation Function
MessageDigestIntf kdfHashAlgo = new Sha256();
//We choose the underlying symmetric encryption
String SymEncAlgo = CryptoIdentifiers.DESede_CBC_PKCS5_NAME;
//We choose to NOT compress elliptic curve points
boolean compressPoint = false;
ecies_encrypt_decrypt(curve, kdf, hmac, hmacKeyDesiredLength,
hmacTagDesiredlength, hmacHashAlgo, kdfHashAlgo, SymEncAlgo,
compressPoint);

/**
*
* @param args
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws CryptoTestException
* @throws DecryptionFailureException
*/
public static void main(String[] args)
throws NoSuchAlgorithmException, NULLEllipticCurveException,
NULLPointException, EncryptionFailureException, CryptoTestException,
DecryptionFailureException {
Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_Triple_DesCbcPKC5Padding testEngine
= new Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_Triple_DesCbcPKC5Padding();
for (int i = 0; i < testEngine.loopSize; i++) {
NistCurveP256 curve = NistCurveP256.getInstance();
testEngine.test_ECIES_Encryption_Decryption(curve);
}
}

}
package LibCrypto.Tests.ECIES;

import LibCrypto.AlgoImpls.HMACImpls.Hmac;
import LibCrypto.AlgoImpls.KDFImpls.AnsiX9_63KDF;
import LibCrypto.Common.CryptoExceptions.DecryptionFailureException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLEllipticCurveException;
import LibCrypto.Common.CryptoExceptions.EccExceptions.NULLPointException;
import LibCrypto.Common.CryptoExceptions.EncryptionFailureException;
import LibCrypto.Common.Exceptions.CryptoTestException;
import LibCrypto.Common.Interfaces.HMACIntf;
import LibCrypto.Common.Interfaces.Identifiers.CryptoIdentifiers;
import LibCrypto.Common.Interfaces.Identifiers.NamesIdentifiersIntf;
import LibCrypto.Common.Interfaces.KDFIntf;
import LibCrypto.Common.Interfaces.MessageDigestIntf;
import LibCrypto.DigestImpls.ShaImpls.Sha256;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurve;
import LibCrypto.ECCImpls.Curves.NistCurves.NistCurveP256;
import java.security.NoSuchAlgorithmException;

/**
*
* <p>
* This class implements a test for ECIES encryption and decryption process</p>
*
* <p>
* Elliptic curve used : P256 from NIST. Key Derivation Function used :
* ANSI_X9_63KDF. Symmetric encryption used : XOR. Hash algorithm used for key
* derivation function : SHA256. HMAC algorithm used : HMAC with SHA256.
* CERTICOM compression point used : NO. Random Initialization vector used : NO.
* Data encoding algorithm : Base 64.</p>
*
* @author Jules-Florent EYA
* @mail [email protected]
* @tel 1-514-802-1003, Canada
*/
public class Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_XOR
extends TestECIESEncryption2 {

/**
* Class Constructor
*/
public Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_XOR() {
super();
//FOR XOR encryption and decryption we do not need an initialization
//vector. This is why the check is not required and checkInitializationVector
//set to false
checkInitializationVector = false;
}

@Override
protected byte[] getInitializationVector(String SymEncAlgo)
throws EncryptionFailureException {
byte[] iv = null;
if (NamesIdentifiersIntf.XOR_NAME.equals(SymEncAlgo)) {
} else {
throw new EncryptionFailureException("Must abort Elliptic Curve"
+ " Integrated Encryption Scheme process." + SymEncAlgo
+ " is not yet supported as symmetric encryption");
}
return iv;
}

/**
* This method allows to test Elliptic Curve Integrated Encryption Scheme
* (ECIES) with XOR used as underlying symmetric encryption. The Key
* Derivation Function used for ECIES respects ANSI_X9_63 specification
*
* @param curve
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws LibCrypto.Common.Exceptions.CryptoTestException
* @throws LibCrypto.Common.CryptoExceptions.DecryptionFailureException
*/
protected void test_ECIES_Encryption_Decryption(NistCurve curve)
throws NoSuchAlgorithmException,
NULLEllipticCurveException, NULLPointException,
EncryptionFailureException, CryptoTestException, DecryptionFailureException {
//We choose the Key Derivative Function algorithm
KDFIntf kdf = new AnsiX9_63KDF();
//We choose the HMAC algorithm
HMACIntf hmac = new Hmac();
int hmacKeyDesiredLength = CryptoIdentifiers.SHA256_BYTES_OUTPUTSIZE;
int hmacTagDesiredlength = CryptoIdentifiers.SHA256_BYTES_OUTPUTSIZE;
//HASH engine to do the HMAC
MessageDigestIntf hmacHashAlgo = new Sha256();
//HASH engine to do the Key Derivation Function
MessageDigestIntf kdfHashAlgo = new Sha256();
//We choose the underlying symmetric encryption
String SymEncAlgo = CryptoIdentifiers.XOR_NAME;
//We choose to NOT compress elliptic curve points
boolean compressPoint = false;
ecies_encrypt_decrypt(curve, kdf, hmac, hmacKeyDesiredLength, hmacTagDesiredlength,
hmacHashAlgo, kdfHashAlgo, SymEncAlgo, compressPoint);

/**
* MAIN method that allows to perform the test
*
* @param args
* @throws NoSuchAlgorithmException
* @throws NULLEllipticCurveException
* @throws NULLPointException
* @throws EncryptionFailureException
* @throws CryptoTestException
* @throws DecryptionFailureException
*/
public static void main(String[] args)
throws NoSuchAlgorithmException, NULLEllipticCurveException,
NULLPointException, EncryptionFailureException, CryptoTestException,
DecryptionFailureException {
Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_XOR testEngine
= new Test_ECIES_AnsiX9_63KDF_Hmac_SHA256_XOR();
for (int i = 0; i < testEngine.loopSize; i++) {
//We create a NistCurve instance
NistCurveP256 curve = NistCurveP256.getInstance();
//We launch the encryption_decryption test
//If no exception is thrown, that means that everything was fine
testEngine.test_ECIES_Encryption_Decryption(curve);
}
}

You might also like