I have been given some Python code from the backend that decrypts some data. On my side, the Android app, I need to also decrypt it.
Here are some snippets of the Python code which I believe are the most relevant.
cipher = PKCS1_OAEP.new(privkey)
And this is the module that it comes from
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Cipher import PKCS1_OAEP
Looking at the documentation for PKCS1_OAEP.new
https://www.dlitz.net/software/pycrypto/api/2.6/Crypto.Cipher.PKCS1_OAEP-module.html
And then comparing with the JavaDoc for Cipher
https://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#Cipher
I deduced that this Python algorithm can be expressed as follows using the Java Cipher class (Note the code is in Kotlin)
val cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC")
Note that BC is the provider. I found out that BouncyCastle is popular and is included in the Android framework
So what is the error?
The backend returns me a 404 when the answer to the challenge is wrong.
When I execute the Python code (which hits the same endpoints) it works.
In terms of the POST request, I compared both and I am sending it in the correct way.
What would I like to know
Am I using the correct algorithm? I am trying to systematically cross out potential issues before moving onto another
Note that I also tried
val cipher = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC")
Related
I am trying to encrypt a string using Jasypt 1.9.3 and my JDK version is 1.8.0_281.
This is the code I am have written:
Security.setProperty("crypto.policy", "unlimited");
if (pooledPBEStringEncryptor == null) {
pooledPBEStringEncryptor = new PooledPBEStringEncryptor();
pooledPBEStringEncryptor.setPassword(encryptionKey);
pooledPBEStringEncryptor.setAlgorithm("PBEWITHHMACSHA512ANDAES256");
pooledPBEStringEncryptor.setPoolSize(4);
pooledPBEStringEncryptor.setSaltGenerator(new RandomSaltGenerator());
}
encrypted = pooledPBEStringEncryptor.encrypt(cValue);
But when I run it, I get the error
Exception in thread "main" java.lang.RuntimeException: Security Error in doEncrypt: org.jasypt.exceptions.EncryptionInitializationException: java.security.NoSuchAlgorithmException: PBEWITHHMACSHA512ANDAES256 SecretKeyFactory not available
I ran the AlgorithmRegistry.getAllPBEAlgorithms() and my output is:
PBEWITHHMACSHA1ANDAES_128, PBEWITHHMACSHA1ANDAES_256, PBEWITHHMACSHA224ANDAES_128, PBEWITHHMACSHA224ANDAES_256, PBEWITHHMACSHA256ANDAES_128, PBEWITHHMACSHA256ANDAES_256, PBEWITHHMACSHA384ANDAES_128, PBEWITHHMACSHA384ANDAES_256, PBEWITHHMACSHA512ANDAES_128, PBEWITHHMACSHA512ANDAES_256, PBEWITHMD5ANDDES, PBEWITHMD5ANDTRIPLEDES, PBEWITHSHA1ANDDESEDE, PBEWITHSHA1ANDRC2_128, PBEWITHSHA1ANDRC2_40, PBEWITHSHA1ANDRC4_128, PBEWITHSHA1ANDRC4_40
When I use the algorithm PBEWITHHMACSHA256ANDAES_256 I get a different error.
Exception in thread "main" java.lang.RuntimeException: Security Error in doEncrypt: org.jasypt.exceptions.EncryptionOperationNotPossibleException
I am a little lost as to what to do.
I have downloaded the unlimited policy jars from Oracle and saved them in JAVA_HOME\jre\lib\security\ folder. And I am on Windows.
The code lacks the specification of the IV generator with setIvGenerator(), e.g.:
pooledPBEStringEncryptor.setIvGenerator(new RandomIvGenerator());
By default, NoIvGenerator is used, which causes the exception because the algorithm applies the CBC mode, which requires an IV.
The default salt generator, by the way, is RandomSaltGenerator, so this would not necessarily need to be specified with setSaltGenerator().
The PooledPBEStringEncryptor#encrypt() method returns the Base64 encoded concatenation of salt (16 bytes), IV (16 bytes) and ciphertext.
The exception org.jasypt.exceptions.EncryptionOperationNotPossibleException is a general exception that is generated in many error situations and is therefore not very meaningful, see here. This includes e.g. the missing of the JCE Unlimited Strength Jurisdiction Policy (which however seems to be installed on your system).
For completeness: The algorithm is called PBEWITHHMACSHA512ANDAES_256 (which you have already figured out yourself).
PBEWITHHMACSHA512ANDAES_256 derives a 32 bytes key for AES-256 from password and salt using PBKDF2. HMAC/SHA512 is applied. Since not explicitly specified, the default iteration count of 1000 is used. The algorithm applies the CBC mode for encryption (which is why the IV is needed).
According to the Java 12 security specs here the RSASSA-PSS signature scheme should be supported (actually as of Java 11).
However, if I try to use a signature with PS256 algorithm in my JWT using e.g. the nimbus jose+jwt library, then it doesn't work unless I use BouncyCastle.
val signer = RSASSASigner(signKey)
val jwsObject = JWSObject(
JWSHeader.Builder(JWSAlgorithm.PS256) // PS256 gives error; RS256 will work
.keyID(signKeyId)
.build(),
Payload(json)
jwsObject.sign(signer)
This gives an error:
java.security.NoSuchAlgorithmException: SHA256withRSAandMGF1 Signature not available
And indeed JCASupport.isSupported(JWSAlgorithm.PS256) is false
If I include BouncyCastle then it does work:
Security.addProvider(BouncyCastleProviderSingleton.getInstance())
JCASupport.isSupported(JWSAlgorithm.PS256) == true
I would have thought that BouncyCastle is not necessary anymore in Java 12 (I'm actually using Kotlin 1.3 with Java 12 and Spring Boot 2.2 and com.nimbusds 8.4 to be precise).
I would like to be independent from BouncyCastle.
What am I missing?
I've been trying to programatically generate OpenSSH host keys in my Java application, but I'm unable to get a working Ed25519 key in the OpenSSH v1 key format. My current thought is that there's a problem with OpenSSHPrivateKeyUtil, but I'm not sure how to verify that. Here's my current attempt:
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
import java.util.Base64;
...
Ed25519PrivateKeyParamters keyParamters = new Ed25519PrivateKeyParamters(new SecureRandom());
byte[] encodedPrivateKey = OpenSSHPrivateKeyUtil.encodePrivateKey(keyParameters);
System.out.println(Base64.getEncoder().encodeToString(encodedPrivateKey));
The output looks like what I'm expecting (similar to the results of an ssh-keygen -t ed25519), but when I put the results into /etc/ssh/sshd_host_ed25519_key (and the corresponding public key into /etc/ssh/sshd_host_ed25519_key.pub), I get the following error from sshd in /var/log/messages:
auth.err: error: Could not load host key: /etc/ssh/sshd_host_ed25519_key
I'm using the following:
centos 7.6
java 1.8.0_212
openssh 7.4p1-16.e17
bouncycastle 1.63
Any help would be appreciated, thanks.
import org.junit.Test;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
public class EncryptorTest {
#Test
public void testEncryption() {
TextEncryptor te = Encryptors.text("password", "abcdef");
te.encrypt("Hello World!");
}
}
I get this error:
java.lang.IllegalArgumentException: Unable to initialize due to invalid secret key
It seems that I have to download some policy file JCE extension to get this to work: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
I want to avoid this added dependency during deployment, and honestly I don't need 256 bit encryption for this.
Is it possible to lower the level to something that works w/o having to download this JCE extension?
No the value 256 is hard coded into the source:
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt), 1024, 256);
This can be found in AesBytesEncryptor on line 54 at least up to release 3.2.5.
Note that Spring uses the Apache license, so there is nothing stopping you from creating your own implementation that uses 128 as constant.
MessageDigest.getInstance("SHA") seems to work and gives me a MessageDigest, but I can't tell what algorithm it's giving me.
Is it SHA-1 or SHA-0 or ..?
I'm not interested in what happens on my machine. I want to know whether it will return sha0 or sha1 for all valid implementations of Java (or it's undefined).
The JCE Specification lists standard names that an implementation is expected to support. "SHA-1" is specified, as are SHA-256, SHA-384, and SHA-512. "SHA", "SHA-0" and SHA-2" are not standard names and therefore may not be supported at all. You cannot guarantee what "SHA" will return, if anything at all, because it is not in the standard.
SHA-0 is obsolete. For use with the Java JCE MessageDigest, SHA == SHA-1 for some JCE providers. By the way, SHA-1 is not considered to be secure with today's computers and technology. SHA-512 is still secure for pretty much anything. SHA-256 is ok for most things, still.
You can list the protocols available in the Java version you are using with this code. (I got it here ):
import java.security.Provider;
import java.security.Security;
public class JceLook {
public static void main(String[] args) {
System.out.println("Algorithms Supported in this JCE.");
System.out.println("====================");
// heading
System.out.println("Provider: type.algorithm -> className" + "\n aliases:" + "\n attributes:\n");
// discover providers
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
System.out.println("<><><>" + provider + "<><><>\n");
// discover services of each provider
for (Provider.Service service : provider.getServices()) {
System.out.println(service);
}
System.out.println();
}
}
}
It will show information like this for all the various algorithms available. (Note that this is actual output from the program above for some update level of Oracle/Sun Java 6 and it shows that SHA is equivalent to SHA-1 and SHA1. You can pass any of the three strings to MessageDigest and get the same result. But this depends on the Cryptography Provider (the JCE) and might not be the same.)
SUN: MessageDigest.SHA -> sun.security.provider.SHA
aliases: [SHA-1, SHA1]
attributes: {ImplementedIn=Software}
If you load additional providers (e.g. BouncyCastle) it will show those too.