Java - Cipher custom provider - java

I have an android app with decrypt function like this:
private static byte[] decrypt(byte[] keybytes, byte[] data)
{
SecretKeySpec key = new SecretKeySpec(keybytes, "AES");
Cipher localCipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
localCipher.init(2, key);
return localCipher.doFinal(data);
}
This works fine in the app, but I need an java application for my pc to be able to perform the decrypting too, but the following code gives me error:
"Exception in thread "main" java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/ECB/ZeroBytePadding"
I read that JRE doesn't have the correct provider to support this algorithm (I think it is Bouncy Castle).
So how can I add this provider or alternately a workaround to perform the same functionality?

You can add the Bouncycastle provider to your project and make certain you have registered the provider with the Security class prior to calling Cipher.getInstance(). You can do this by something like:
Security.addProvider(new BouncyCastleProvider());

Related

Java 8 using ECIES cipher with a SealedObject fails with 'NullPointerException' - string cannot be null

I am trying to use a ECIES cipher to instantiate a SealedObject, but it fails with a NullPointerException. I am using Java JDK1.8.0_72 with Bouncy Castle bcprov-jdk15on v1.53 running on Windows 10. The code looks like this:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECIES");
kpg.initialize(new ECGenParameterSpec("secp256r1"));
KeyPair keyPair = kpg.generateKeyPair();
Cipher cipher = Cipher.getInstance("ECIES");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
String toEncrypt = "Hello";
// Check that cipher works ok
cipher.doFinal(toEncrypt.getBytes());
// Using a SealedObject to encrypt the same string fails with a NullPointerException
SealedObject sealedObject = new SealedObject(toEncrypt, cipher);
The code successfully calls 'cipher.doFinal()' but fails when instantiating the SealedObject. The stack trace is:
java.lang.NullPointerException: string cannot be null
at org.bouncycastle.asn1.ASN1OctetString.<init>(Unknown Source)
at org.bouncycastle.asn1.DEROctetString.<init>(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.ies.AlgorithmParametersSpi.engineGetEncoded(Unknown Source)
at java.security.AlgorithmParameters.getEncoded(AlgorithmParameters.java:362)
at javax.crypto.SealedObject.<init>(SealedObject.java:179)
I'm trying to avoid specifying a particular provider (i.e. Bouncy Castle) and avoiding any provider-specific classes such as IESParameterSpec because the component uses external configuration to specify the algorithms to be used. The component is intended to be used as part of a messaging library in a fluid cluster of nodes where each node may use a different algorithm for encryption, so a SealedObject seems like a reasonable choice because it can be used to pass the algorithm used (any message that uses encryption uses the receiver's public key so the receiver must have the corresponding private key to decrypt the message).
Any thoughts or suggestions would be most welcome.
David Hook at Bouncy Castle had a look and identified an issue in org.bouncycastle.jcajce.provider.asymmetric.ies.AlgorithmParametersSpi.engineGetEncoded and provided a fix in 1.55b04. I tested this out and it has resolved this issue.
Thanks again for your help Maarten.

How to store a SecretKey within a Java KeyStore protected by a PublicKey (RSAPasswordProtection)?

I want to store a SecretKey within a Java KeyStore protected by a PublicKey. When loading the protected KeyEntry i would like to
get the protected key byte-array to manually unwrap it later on with a PrivateKey.
let the KeyStore handle the unwrapping when handing over the PrivateKey.
Using the setEntry()-Method with an already wrapped byte-Array is possible. Also getting the wrapped byte-Array back can be done by using the getEntry()-Method. To encrypt a SecretKey the setEntry()-Method supports the usage of a ProtectionParameter. The only ProtectionParameter i could find was the PasswordProtection parameter.
Does anyone know about a RsaProtection for Java KeyStore? Or is there another way around to be able to wrap SecretKeys using a PublicKey and getting it back using a PrivateKey?
The Java key stores are certainly not able to handle this; they primarily use symmetric encryption to protect the key stores. It is possible to wrap and unwrap keys though. I've shown this using OAEP instead of the less safe "RSA" (PKCS#1) encryption:
Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
rsa.init(Cipher.WRAP_MODE, keyPair.getPublic());
byte[] wrapped = rsa.wrap(aesKey);
rsa.init(Cipher.UNWRAP_MODE, keyPair.getPrivate());
SecretKey unwrappedAESKey = (SecretKey) rsa.unwrap(wrapped, "RSA", Cipher.SECRET_KEY);

Java or Spring: two-way encryption with salt?

I am doing a web project with Spring.
I am hoping to do a two-way encryption (and decryption) of a few url parameters. I don't need very strong encryption.
I googled but found many are related to one-way password encryption, which is not what wanted.
Can any expert out there point me to the right place?
Thanks!
I can recommend really nice library called bouncy castle. On their homepage is a few nice examples. See https://www.bouncycastle.org/java.html
Another possibility is java crypto api and something like
SecretKey keySpec = new SecretKeySpec(keyBytes, "AES");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher aesCbc = Cipher.getInstance("AES/CBC/NoPadding");
aesCbc.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encryptedBytes = aesCbc.doFinal(plainTextBytes);
return Base64.encodeBase64String(encryptedBytes);
You can you use classes from javax.crypto to perform encryption and decryption.

Configure Jasypt Encryptors using my own SecretKey, instead of setting String password using the 'setPassword' method of the PBEString encryptors?

I'm trying to configure Jasypt StandardPBEStringEncryptor using the following code.
StandardPBEStringEncryptor strongEncryptor = new StandardPBEStringEncryptor();
strongEncryptor.setAlgorithm(ALGORITHM);
strongEncryptor.setPassword(PASSWORD);
And then call the encrypt() and decrypt() methods of the 'strongEncryptor' to perform the encryption and decryption operations.
Is it possible or is there a way I can configure the Jasypt encryptor using my own SecretKey instead of setting a password?
Like in Java Cipher, we do...
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, MY_SECRET_KEY);
I see that Jasypt internally uses the String password to create the SecretKey and initiate the Java Cipher. Is it possible to provide my Key here?
PBE stands for Password Based Encryption.
That means instead of requiring a SecretKey it needs a passphrase which will then be used to generate the key by hashing it many times.
So manually settings the SecretKey for a PBE-encryption would invalidate it's purpose. For exactly that reason StandardPBEStringEncryptor does not allow this. (see it's doc for more information)
If you want to use your own SecretKey, simply use a standard encryption function.

What is the proper way to perform authenticated encryption in Java?

Authenticated encryption requires that we use some accepted standard for encrypting and authenticating a message. So we both encrypt the message and compute a MAC on the message to verify it has not been tampered with.
This question outlines a way to perform password based key strengthening and encryption:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
But as far as I can tell, this does not compute any MAC on the ciphertext and so would be insecure. What is the accepted standard for performing authenticated encryption in Java?
I would recommend using GCM mode encryption. It is included in the latest JDK (1.7) by default. It uses a counter mode encryption (a stream cipher, no padding required) and adds an authentication tag. One big advantage is that it requires only a single key, whereas HMAC adds another key to the mix. Bouncy Castle has an implementation as well, which is moslty compatible with one provided by Oracle.
GCM mode encryption is also features in a TLS RFC, and in XML encrypt 1.1 (both not final). GCM mode provides all three security features: confidentiality, integrity and authenticity of the data send. The String would be "AES/GCM/NoPadding" instead of the CBC one you are now deploying. As said, make sure you have the latest JDK from Oracle, or have Bouncy Castle provider installed.
Also check out my answer here, which is mostly about String encoding, but I've succesfully tried GCM mode too - see the comment.
When transferring files from one server to another through secure ftp, I use private/public key pairs with the private key residing on the "from" server and the public key residing on the "to" server.
Using private/public key pairs is a secure standard when transferring files.
I believe it would also be a secure means in the context of a Java application.
Check out Generating and Verifying Signatures and Generate Public and Private Keys
for more details on using a private/public key pair setup for digital signatures in Java.

Categories