jcryption 3.0 encryption to java decryption - java

I am trying to use JCrytion 3.0.1 to encrypt data in javascript and then decrypt it on server by java. My question is how I can get the encrypted string to decrypt it in java using Cipher class which requires Byte[] to process.
This is how I generate my key from java
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
final KeyPair key = keyGen.generateKeyPair();
And then to decrypt data I used
public String decrypt(byte[] text, PrivateKey key) {
byte[] dectyptedText = null;
try {
final Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(text); // this is where I get error when trying to use getBytes() to convert encrypted string to byte[]
} catch (Exception ex) {
ex.printStackTrace();
}
return new String(dectyptedText);
}
This is my javascript on client side
var encryptedUser = $.jCryption.encrypt(username, keys);
var encryptedPassword = $.jCryption.encrypt(password, keys);
alert("Start Submiting");
$.ajax({
url: "LoginAuthentication",
data:{username:encryptedUser, password:encryptedPassword},
type:'POST'
}).done(function(){
alert("Successfully Access !!!");
});
I try to use getBytes() but it doesn't work
It works well with other texts I test. My Only problem is how to convert encrypted string from javascript using JCryption to byte[] to decrypt it in Java.
Thank You

Related

how to convert array byte[] to key?

I have information security project about encrypting file using AES. and the using key in this algorithm is also encrypted using RSA algorithm and public key,
the problem is: after encrypting the random key it returns array byte[], how this array byte converted into key so I can encrypt the file?
NOTE [public_Key is generated from user using JPasswordField
and this is the challenge I faced from my course project]
public void AESEncryption(File file) throws FileNotFoundException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String data;
SecretKey random_key;
int key_size=128;
Scanner myReader = new Scanner(file);
while (myReader.hasNextLine()) {
data = myReader.nextLine();
}
// create GenerateKey object to access public key
// GenerateKey is my personal class and contain public key
GenerateKey key = new GenerateKey();
// convert public key to string
String public_Key = key.PublicKey.getText();
// convert string public key to secret key
byte[] decodedKey = Base64.getDecoder().decode(public_Key);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
// generate random key
KeyGenerator g = KeyGenerator.getInstance("AES");
// give it size
g.init(key_size);
random_key = g.generateKey();
// encrypt the random key with RSA and public key
byte[] random_byteKey = random_key.getEncoded();
Cipher cipher_Key = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher_Key.init(Cipher.ENCRYPT_MODE, originalKey);
byte[] encrypted_key = cipher_Key.doFinal(random_byteKey); //RSA key
// after generating RSA key we will Encrypt file using RSA key
byte[] byte_message = data.getBytes();
Cipher cipherTxt = Cipher.getInstance("AES/GCM/NoPadding");
// the problem in here
cipherTxt.init(Cipher.ENCRYPT_MODE, encrypted_key);
byte[] encByte = cipherTxt.doFinal(byte_message);
}
You are not understanding what you need to do. First you generate a random AES key that is used solely for the data encryption. Then you encrypt that key with RSA using the trusted RSA public key which is part of the key pair of the receiver. So you never have to convert either the public key or the RSA ciphertext to a symmetric key.
As an aside, instead of using Cipher#doFinal() you should use Cipher#wrap() , which takes a symmetric key. That way you don't have to encode them to a byte array. It may also be more secure if a hardware module is used, for instance, depending on the Cipher implementation.
I'd strongly suggest you generate separate methods for these separate steps as well as for the file handling.
In the end, you'll need something more akin to this:
public static void hybridEncrypt(RSAPublicKey publicKey, File in, File out) throws IOException, InvalidKeyException {
int key_size=128;
try {
KeyGenerator g = KeyGenerator.getInstance("AES");
g.init(key_size);
SecretKey dataKey = g.generateKey();
// encrypt the random data key with the RSA public key
Cipher cipher_Key = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher_Key.init(Cipher.WRAP_MODE, publicKey);
byte[] encryptedKey = cipher_Key.wrap(dataKey);
Cipher cipherTxt = Cipher.getInstance("AES/GCM/NoPadding");
cipherTxt.init(Cipher.ENCRYPT_MODE, dataKey);
byte[] message = Files.readAllBytes(in.toPath());
byte[] encryptedMessage = cipherTxt.doFinal(message);
out.createNewFile();
Files.write(out.toPath(), encryptedKey);
Files.write(out.toPath(), encryptedMessage, StandardOpenOption.APPEND);
} catch(NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException e) {
throw new RuntimeException("RSA or AES/GCM not available", e);
} catch (BadPaddingException e) {
throw new RuntimeException("Padding failed for NoPadding", e);
}
}
public static void main(String[] args) throws Exception {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(3072);
KeyPair keyPairReceiver = kpGen.generateKeyPair();
RSAPublicKey publicKeyReceiver = (RSAPublicKey) keyPairReceiver.getPublic();
hybridEncrypt(publicKeyReceiver, new File("plain.txt"), new File("bla.bin"));
}
Beware that this is still not best practice code, for instance it uses the old PKCS#1 encryption instead of OAEP. Don't copy paste this guys - with encryption you need to understand what you are doing, and preferably use a well vetted high level library.

Decrypt message in swift encrypted in java using AES/GCM/NoPadding

I want to create secretKey(symmetricKey) using my EC privateKey and publicKey from backend(Java)
and decrypt message using that secretKey. How to achieve this? Here is implementation:
This is how backend creates sharedKey:
KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "BC");
keyAgreement.init(privateKey);
keyAgreement.doPhase(publicKey, true);
return keyAgreement.generateSecret("AES");
Here is how iOS creates sharedSecret->SymmetricKey not sure if this is right because comparing secretKeys with backend my key is different (by definition of ECDH should be same)
let serverPubKey = try P256.KeyAgreement.PublicKey(pemRepresentation: serverPublicKeyPEM)
let shared = try privateKey.sharedSecretFromKeyAgreement(with: serverPubKey)
let symetricKey = shared.hkdfDerivedSymmetricKey(using: SHA256.self,
salt: "".data(using: .utf8)!,
sharedInfo: Data(),
outputByteCount: 32)
here is how backend encrypts
byte[] plain = Base64.getEncoder().encodeToString(plainString.getBytes(StandardCharsets.UTF_8)).getBytes();
SecretKey key = generateSharedSecret(decodePrivateKey(sessionKey), decodePublicKey( devicePublicKey));
Cipher encryptor = Cipher.getInstance("AES/CTR/NoPadding", BouncyCastleProvider.PROVIDER_NAME);
IvParameterSpec ivSpec = new IvParameterSpec(INITIALIZATION_VECTOR);
encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec);
return Base64.getEncoder().encodeToString(encryptor.doFinal(plain, 0, plain.length));
and here is how iOS trying to decrypt
guard let payloadData = Data(base64Encoded: payload) else { return }
do {
//I know that sealedBox is wrong, should be just box? I'm not sure of this step
let sealedBox = try AES.GCM.SealedBox(combined: payloadData)
let decrypted = try AES.GCM.open(sealedBox, using: symmetricKey)
//here I'm getting authenticationFailure
} catch {
print("error: \(error)")
}

Decrypting byte array from Java in C++ using RSA with java generated keys

I need to decrypt file in C++. What I have is byte array and pair of keys generated in Java using KeyPairGenerator from java.security;
Java Code:
public void generateKeys() {
try {
final KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance(algorithmName);
pairGenerator.initialize(1024); //1024 - keysize
final KeyPair keyPair = pairGenerator.generateKeyPair();
savePublicKeyIntoFile(keyPair);
savePrivateKeyIntoFile(keyPair);
} catch (Exception e) {
System.err.println("Class EncryptionTool.generateKeys() ");
e.printStackTrace();
}
}
public static String encrypt() throws Exception {
// Encrypt the string using the public key
ObjectInputStream inputStream = null;
inputStream = new ObjectInputStream(new FileInputStream(publicKeyFilepath));
final PublicKey publicKey = (PublicKey) inputStream.readObject();
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(algorithmName);
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherText = null;
**cipherText = cipher.doFinal( loadPassword() );**
return changeByteArrayToString(cipherText);
}
I have generated keys saved in files and this cipherText array in C++.
What should I use to decrypt this ?

.NET equivalent of Java KeyFactory.getInstance "RSA"/"RSA/ECB/PKCS1Padding"

I have the following code,
public static String encrypt(String plainText, String key){
try{
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.decode(key, Base64.DEFAULT)));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeToString(cipher.doFinal(plainText.getBytes("UTF-8")),Base64.DEFAULT);
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
I want to convert this to C#. I have tried CryptUtils but it doesn't work https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Common/CryptUtils.cs
Sample key,
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ9AMIIBCgKCAQEAoqB1N9kugk4UKYnbh0fcg3qYyYKP0m4B
MjWd05ReeAdj+7JRYDEKO6xthDdVSdRO1/2V+YtY8DnXWnxRaICwu8235s3imZCyqgYnomPWdY+F
K540oTz/zug+9wbrlzt/WQFUU4lPlQbzm/Gjw8XfaCozT0e3bnWQcD7rORCOyuJgwSGgREjTv1ss
pgEaKTMknii9vpGZLeAXwoeIYROhuT4IoIkPDhtY0/UZiCi6v7Ja2dmy53VlWIkcm3rcnSJdvpXr
OgiHvaNABHmeymNycNqd6WUaysBRheluQ86nq/2nZPW0gcvmYt5zbMMYX3yY/n2WtAKeNQBAEW1q
b0s6MwIDAQAB
Possible encryped value,
Y3VTjghDnTrCeG8C/RklKsJ3Y0Mt89sSGGin28E4iQPQvKqeZBws7rBQEZaRamDWftxCkEYZs4Qh
V2l4IVlrawdtRmQlcQh8McrpqP/97Gz8pEDEYnqA7kqBTqZw0Z5o0WsshGSwiAQ9wNSym4xHejkq
zrKxWP8XCMkcT0NlKlRMoqKKICFKZbqWeSQkQM5y9OEcmB6inNNkJCoM1Ip48+cK3cOE6dqXNVrl
sSTZ8WQKwoB3dJmcYqexR3kAvBYdX6ZxEF+2+6b9h8+tc5G7Y5R2eqycyUossdkCcI3fNVhyc72P
axCjZFWZUgfDGCxg1WNhStrH9L8c59P35JKKug==
Since i don't have the private key, i can't decrypt, but at least this produces the right lengthed values.
So try this (you need bouncycastle for reading pem):
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
var keyBytes =
Convert.FromBase64String(
"MIIBI...."); // your key here
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
byte[] plaintext = Encoding.UTF8.GetBytes("amount=1&currency=AED");
byte[] ciphertext = rsa.Encrypt(plaintext, false);
string cipherresult = Convert.ToBase64String(ciphertext);

RSA Encryption Javascript and Decrypt Java

Spent almost 2 days with different combinations.I am generating a asymmetric key pair (public and private) in java using RSA algorithm and trying to use the public key in javascript to encrypt some text and decrypt back in java on server side. I am getting "javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes" exception while trying to decrypt back the string encrypted in javascript. Would appreciate some help...
Using thi Javascript library to encrypt.
https://github.com/wwwtyro/cryptico
var publicKeyString = ""// base64encoded public key string generated in java
Here is my javascript code
var EncryptionResult = cryptico.encrypt("somestring", publicKeyString);
console.log("Encrypted status-"+EncryptionResult.status);
console.log("Encrypted String-"+EncryptionResult.cipher);
It is successfully encrypting the string.
Java Key Generation and Decryption
Cipher cipher = Cipher.getInstance("RSA");
KeyFactory fact = KeyFactory.getInstance("RSA");
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024); // 1024 used for normal
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
FileOutputStream fos = null;
ObjectOutputStream oos = null;
Code to store the private key in file which is used to decrypt in decrypt method.
RSAPrivateKeySpec rsaPrivKeySpec = fact.getKeySpec(privateKey,
RSAPrivateKeySpec.class);
System.out.println("Writing private key...");
fos = new FileOutputStream(PRIVATE_KEY_FILE);
oos = new ObjectOutputStream(new BufferedOutputStream(fos));
oos = new ObjectOutputStream(new BufferedOutputStream(fos));
oos.writeObject(rsaPrivKeySpec.getModulus());
oos.writeObject(rsaPrivKeySpec.getPrivateExponent());
oos.close();
Decrypt method
public String decrypt(String ciphertext)
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException
{
if (ciphertext.length() == 0) return null;
byte[] dec = org.apache.commons.codec.binary.Base64.decodeBase64(ciphertext);
try {
System.out.println("Private Key file name----"+PRIVATE_KEY_FILE);
privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE);
} catch (IOException e) {
e.printStackTrace();
}
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(dec);
return new String(decrypted, PLAIN_TEXT_ENCODING);
}
//reading private key from file
public PrivateKey readPrivateKeyFromFile(String fileName)
throws IOException {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(new File(fileName));
ois = new ObjectInputStream(fis);
System.out.println("Private Key file-"+fileName);
BigInteger modulus = (BigInteger) ois.readObject();
BigInteger exponent = (BigInteger) ois.readObject();
// Get Private Key
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privateKey = fact.generatePrivate(rsaPrivateKeySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null) {
ois.close();
if (fis != null) {
fis.close();
}
}
}
return null;
}
From the Cryptico documentation it seems that it is not a simple RSA encryption, but a complex operation that generates AES key, encrypts it with RSA, encrypts the data with AES and outputs a concatenation of encrypted AES key and encrypted data. If you want to decrypt that in Java you will have to check the Cryptico source code and reimplement the same in Java.
As for your current attempt and javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes error:
When you do not specify the full transformation the default JCE transformation for RSA is RSA/ECB/PKCS1Padding.
In this mode the RSA encrypts or decrypts a single block of data which the length is not greater than the size of the key (more specifically, if the input sequence of bytes is interpreted as a big integer, its value should be less that the modulus used by the RSA). You can find additional information in this and this questions.
With the key size of 1024 bits the maximum data size is 128 bytes, and that is exactly what the exception says because the output of Cryptico is obviously not a single RSA block and its length is greater that expected by "plain" RSA. Trying to use some other cipher mode or padding mode in Java will not help in that situation either.
Thanks Oleg for the detailed information. I will definitely take a look into it.
For now I switched to jsencrypt and it seems to work fine.
https://github.com/travist/jsencrypt
EDIT
How you get the encoded public key for the js encrypt?
Here is the solution for data Encryption from JS and Decrypt on Java(server side). I have used Cryptico js library for encryption(http://wwwtyro.github.io/cryptico/).
First of all we have to generate the java Keystore file from your local system. Don't use other Keystore files such as online Keystore. For creating the java Keystore(JKS) you can use KeyStore Explorer tool.
Below is the config I have used, using KeyStore Explorer tool
Keystore type - JKS
RSA algorithm - Keysize 1024
Version - version 3
Signature algorithm - SHA256 with RSA
Validity period - 99 years(based on your requirement)
Name filed - Fill all the mandatory fields - remember the "alias" and "password" what you entered here.
Finally, save the file as .jks on your local system.
Step-1
we have to use this Keystore file on the java side and we send the public key to the frontend.
I have created the service class which is responsible to load Keystore from the keystore file path(string), Keypair and Decrypt. You have to provide the alias, password, keystore type.
public KeyPair getExistingKeyStoreKeyPair(String keystorePath){
KeyPair generateKeyPair = null
try {
File file = new File(keystorePath)
KeyStore keyStore = loadKeyStore(file, "password", "JKS")
generateKeyPair = getKeyPair(keyStore, "fin360", "password")
} catch (Exception ex){
println(ex)
}
return generateKeyPair
}
public KeyStore loadKeyStore(final File keystoreFile, final String password, final String keyStoreType) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
if (null == keystoreFile) {
throw new IllegalArgumentException("Keystore url may not be null")
}
final URI keystoreUri = keystoreFile.toURI()
final URL keystoreUrl = keystoreUri.toURL()
final KeyStore keystore = KeyStore.getInstance(keyStoreType)
InputStream is = null
try {
is = keystoreUrl.openStream();
keystore.load(is, null == password ? null : password.toCharArray())
} finally {
if (null != is) {
is.close()
}
}
return keystore;
}
public KeyPair getKeyPair(final KeyStore keystore, final String alias, final String password) {
PublicKey publicKey
PrivateKey privateKey
Key key
KeyPair keyPair
try {
key = (PrivateKey) keystore.getKey(alias, password.toCharArray())
final Certificate cert = keystore.getCertificate(alias)
publicKey = cert.getPublicKey()
privateKey = key
keyPair = new KeyPair(publicKey, privateKey)
} catch (Exception ex){
println(ex)
}
return keyPair;
}
public decryptData(String data, String keystorePath) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException{
try {
byte[] dectyptedText = new byte[1]
byte[] byteArray = new byte[256]
BigInteger passwordInt = new BigInteger(data, 16)
if (passwordInt.toByteArray().length > 256) {
for (int i=1; i<257; i++) {
byteArray[i-1] = passwordInt.toByteArray()[i]
}
} else {
byteArray = passwordInt.toByteArray();
}
KeyPair generateKeyPair = getExistingKeyStoreKeyPair(keystorePath)
PrivateKey privateKey = generateKeyPair.getPrivate()
Cipher cipher = Cipher.getInstance("RSA")
cipher.init(Cipher.DECRYPT_MODE, privateKey)
dectyptedText = cipher.doFinal(byteArray)
String txt2 = new String(dectyptedText)
return txt2
}
catch (Exception ex){
println(ex)
return null
}
}
decryptData() method will playing the main role here. When you send the value data.getBytes() directly to the dycrypt method cipher.doFinal(byteArray) you get the exception - IllegalBlockSizeException size should not more than 128 bytes. So we have get rid of the issue I get the workaroud here - [Getting 1 byte extra in the modulus RSA Key and sometimes for exponents also
Basically it adds the zero when we converting data from BigInteger to byteArray. So I removed the zero from the array.
Let's start use the service class to get the key values.
String publicKey= null
String keystorePath = your file path
KeyPair generateKeyPair = encryptDecryptService.getExistingKeyStoreKeyPair(keystorePath)
PublicKey publicKey1 = generateKeyPair.getPublic()
KeyFactory keyFactory;
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(BigInteger.ZERO, BigInteger.ZERO)
try {
keyFactory = KeyFactory.getInstance("RSA")
rsaPublicKeySpec = keyFactory.getKeySpec(publicKey1, RSAPublicKeySpec.class)
} catch(NoSuchAlgorithmException e1) {
println(e1)
} catch(InvalidKeySpecException e) {
println(e)
}
String testPublicKey = rsaPublicKeySpec.getModulus().toString(16)
publicKey = testPublicKey
Send you publicKey to JS.
In your HTML or servlet import all the required js and jar files(you will get it from the cryptico js library).
try{
var rsa = new RSAKey();
rsa.setPublic(pub, "10001");
password = rsa.encrypt(password);
formdata = "password="+password+"&dataEncrypt=true";
}
catch (error){
console.log(error);
}
above I have directly used new RSA() instance(in cryptico library it will be different. Internaly library is using the same) and set the publickey to the instance. We have to use hex string value is '10001'. Form the query string with encrypted data which we send to server. Form data holds the encrypted data well as well as 'dataEncrypt' key value. I used to check whether data is encrypted or not.
Finally on the server side you will get the request params and below is the code for decrypt.
Boolean isDataEncrypted = false
String decryptedPassword = null
isDataEncrypted = params.containsKey("dataEncrypt")
if(params.containsKey("password")){
if(isDataEncrypted) {
String keystorePath = helperService.fetchKeystoreFilePath()
decryptedPassword = encryptDecryptService.decryptData(params.password, keystorePath)
// update decrypted data into request params
params.password = decryptedPassword
}
}
println("Data decrypted => " + decryptedPassword)

Categories