encyrpt a key with setted RSA public key in java - java

i'm triying encrypt a password. firstly i will set a rsa public key, after encyrpt a password. but my results are not equals between java and javascript code. is there a way or sample. Could you help me? thanks.
here is my javascript code
var rsa = new RSAKey();
rsa.setPublic(rasn, rase);
var res = rsa.encrypt("myPassword");
return restotal;
here is my java code
RSA1 rsa = new RSA1(new BigInteger(rasn.getBytes()),new BigInteger(rase.getBytes()));
String text1 = "myPassword";
BigInteger plaintext = new BigInteger(text1.getBytes());
BigInteger ciphertext = rsa.encrypt(plaintext);
System.out.println(ciphertext);

Not sure what your RSA1 class exactly does, but you can check a nice sample here.
Your results will never be same, because before RSA encryption, your data will be appended with random bytes called padding.
If you want to test your encryption, decrypt the result back with your private key and see if it works. You can do this between javascript and java if you wish.

Related

Not able to encrypt with PBEWITHHMACSHA512ANDAES_256 on openSSL and java

I have use case where i need to encrypt my data in Openssl and decrypt it in the java application. i need to use this PBEWITHSHA256ANDAES_256 algorithm for it.
not able to use this algo in decryption. how can i do it ?
also i have tried this algo PBEWITHHMACSHA512ANDAES_256. i am not able to encrypt it in OpenSSL with this.
what can be possible solutions for the above scenario ?
String text = "123456ABC";
String algorithm = "PBEWITHSHA256ANDAES_256";
// PBEWITHHMACSHA512ANDAES_128
String password = "abc";
//When
String encryptedText = JasyptCryptographer.encryptText(text, algorithm, password);
String decryptedText = JasyptCryptographer.decryptText(encryptedText, algorithm, password);
//Then
Assertions.assertNotEquals(text, encryptedText);
Assertions.assertEquals(text, decryptedText);
I am facing below error for one issue of above.
org.jasypt.exceptions.EncryptionInitializationException: java.security.NoSuchAlgorithmException: PBEWITHSHA256ANDAES_256 SecretKeyFactory not available
at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:773)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.initialize(StandardPBEStringEncryptor.java:566)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.encrypt(StandardPBEStringEncryptor.java:644)

Decrypting value encrypted by crypto kit from Web Service - Symmetric Key? - UPDATED with full working code below

How do I decrypt my iOS CryptoKit encrypted value on the web service side?
Similar to this SO question:
CryptoKit in Java
Or this SO question
Can I create my own SymmetricKey that we both know the string of? How can my value be decrypted in Java PhP or .NET? (I understand all these languages and can translate, the app is currently in php)
Apple's code from their playground:
let key = SymmetricKey(size: .bits256) //<--- how to share with web service???
let themeSongPath = Bundle.main.path(forResource: "ThemeSong", ofType: "aif")!
let themeSong = FileManager.default.contents(atPath: themeSongPath)!
// below code is from Apple Playground
let encryptedContentAES = try! AES.GCM.seal(themeSong, using: key).combined
/*:
The client decrypts using the same key, assumed to have been obtained out-of-band.
*/
let sealedBoxAES = try! AES.GCM.SealedBox(combined: encryptedContentAES!)
//HOW DO I DO THIS ON WEB SERVICE SIDE??? either in java or php or .net
let decryptedThemeSongAES = try! AES.GCM.open(sealedBoxAES, using: key)
assert(decryptedThemeSongAES == themeSong)
/*:
You use a sealed box to hold the three outputs of the encryption operation: a nonce, the ciphertext, and a tag.
*/
// The nonce should be unique per encryption operation.
// Some protocols require specific values to be used, such as monotonically increasing counters.
// If none is passed during the during the encryption, CryptoKit randomly generates a safe value for you.
let nonceAES = sealedBoxAES.nonce
// The ciphertext is the encrypted plaintext, and is the same size as the original data.
let ciphertextAES = sealedBoxAES.ciphertext
// The tag provides authentication.
let tagAES = sealedBoxAES.tag
// The combined property holds the collected nonce, ciphertext and tag.
assert(sealedBoxAES.combined == nonceAES + ciphertextAES + tagAES)
Link to Playground
So I guess my real questions was how do I encrypt with cryptokit and decrypt with php (web app.
These 2 links helped me:
Swift CryptoKit and Browser
iOS CryptoKit in Java
SwiftCode:
func encryptAES_GCMCryptoKit()->String {
let newkeyString1 = "I9GiP/cK4YKko8CeNF5F8X6/E6jt0QnV" //has to be 32 bytes for a 256 bit encryption or you will get the error key wrong size
let newKey = SymmetricKey(data: newkeyString1.data(using: .utf8)!)
let mySealedBox = try AES.GCM.seal(userString, using: newKey, nonce: iv)
let iv = AES.GCM.Nonce()
do{
let mySealedBox = try AES.GCM.seal(userString, using: newKey, nonce: iv)
let dataToShare = mySealedBox.combined?.base64EncodedData()
// The combined property holds the collected nonce, ciphertext and tag.
assert(mySealedBox.combined == nonceAES + ciphertextAES + tagAES)
}catch {
print("error \(error)")
}
}
Php code:
function decryptStringAES_GCM($combinedInput='') //64 base encoded combine string
{
$key = "I9GiP/cK4YKko8CeNF5F8X6/E6jt0QnV"; // <- 256 bit key - same key is on the swift side
$combined = base64_decode($combinedInput); //<- $combinedInput will be different every time even for the same value
$tag = substr($combined, -16);
$nonce = substr($combined, 0, 12);
$length = strlen($combined)-16-12; //take out tag and nonce (iv) lengths
$cipherText = substr($combined, 12, $length);
$res_non = openssl_decrypt($cipherText, 'aes-256-gcm', $key, OPENSSL_RAW_DATA| OPENSSL_NO_PADDING, $nonce, $tag);
return $res_non //decrypted string
You can also pass the key back to the server in a separate call like the first link does.
After watching the WWDC video: WWDC Cryptokit 2019 video
At around 29 min 20 seconds they advise you to get the key data from the server initially. So you can just create the key by doing this:
This way the server and the app have the same key. Or if you have control of both sides, you can know what your server key is and create the key with data from a string that you both know.

(Java to Javascript) javax.crypto.Cipher equivalent code in Nodejs Crypto Javascript

I'm trying to convert below java code into nodejs.
private static String TRANS_MODE = "Blowfish";
private static String BLOWFISH_KEY = "BLOWFISH_KEY";
public static String encrypt(String password) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(BLOWFISH_KEY.getBytes("Windows-31J"),TRANS_MODE);
Cipher cipher;
cipher = Cipher.getInstance(TRANS_MODE);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] passByte;
passByte = cipher.doFinal(password.getBytes("Windows-31J"));
return new String(Hex.encodeHex(passByte));
}
Here is what I was able to figure out-
const crypto = require('crypto');
function encrypt(password)
var fcKey = "BLOWFISH_KEY";
var cipher = crypto.createCipher('BF-CBC', fcKey, "");
var encrypted = cipher.update(password,'ascii','hex');
encrypted += cipher.final('hex');
return encrypted;
I'm not able to get same output. For example if
password= "password01"
Java Code output - fe0facbf8d458adaa47c5fe430cbc0ad
Nodejs Code output - ae5e8238c929b5716566e97fa35efb9b
Can someone help me figure out the problem ??
Notice that crypto.createCipher(algorithm, password[, options]) is deprecated and should not be used.
Where the SecretKeySpec(..) in java takes a binary key as input, the createCipher(..) in js takes a "password" as input, and behind the scene tries to derive a binary key using MD5. So your actually key used in the two programs ends up being different. The js methode
also tries to derive an IV from the password, which is bad practice and different from your java code.
In js you need to use the crypto.createCipheriv() instead. And when you are at it, you also need to consider if an iv is needed - both in Java and in js.

How to replicate Java encryption in PHP?

Some background of what I'm trying to accomplish.
Part 1.
PHP server communicates with a Java-based device. PHP uses OpenSSL to generate a public/private keypair, then sends the public key to the device which in turn gives back an encrypted macKey (generated using the public key), encoded in base64. PHP now needs to base64-decode and decrypt the macKey using the private key.
What is the equivalent of the below Java code snippet in PHP?
String base64EncodedMacKey = "LkvTT9LFj5lcxRRB8KrwwN906fSIDDcJvQK3E7a5PbR+Ox9WnslOs32jSCC9FkE8ouvr2MfWwtppuZmoPjaxwg3yAQI4UN3T1loISuF2VwKWfJ45fywbK9bNnD5Cw7336mjoGctv77Tg3JXPrsRwgMGIlBsNwdt1B0wgT4MMMAjl32TnBI3iwQ94VTMHffrK+QToddTahRHHoVsr3FVrETdiqKXdkiX1jES53im5lrXYIsY89UFkGzPo+3u4ijKIQWSLvYnA5wXI128gFHKxKYS82MbJDUn9i1RVFsGaP6T3nQRSX5SZNpSe5yGFWwMgYOx0KXMgET82FeaL2hfWuw==";
byte[] base64DecodedMacKey = DatatypeConverter.parseBase64Binary(base64EncodedMacKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, keypair.getPrivate());
byte[] macKey = cipher.doFinal(base64DecodedMacKey);
Here's what I attempted in PHP, however I'm confused about using byte array versus string when decrypting the macKey
$macKey = 'LkvTT9LFj5lcxRRB8KrwwN906fSIDDcJvQK3E7a5PbR+Ox9WnslOs32jSCC9FkE8ouvr2MfWwtppuZmoPjaxwg3yAQI4UN3T1loISuF2VwKWfJ45fywbK9bNnD5Cw7336mjoGctv77Tg3JXPrsRwgMGIlBsNwdt1B0wgT4MMMAjl32TnBI3iwQ94VTMHffrK+QToddTahRHHoVsr3FVrETdiqKXdkiX1jES53im5lrXYIsY89UFkGzPo+3u4ijKIQWSLvYnA5wXI128gFHKxKYS82MbJDUn9i1RVFsGaP6T3nQRSX5SZNpSe5yGFWwMgYOx0KXMgET82FeaL2hfWuw==';
$base64DecodedMacKey = base64_decode($macKey);
openssl_private_decrypt($base64DecodedMacKey, $decrypted, $privateKey);
The $decrypted above holds some binary data as it appears, so I'm unsure whether I need to convert it into a byte array or treat it as a string...
Part 2.
Each request has a counter. The macKey in Java code above is used to create a MAC value out of the counter.
What is the equivalent of the below Java code snippet in PHP?
int counter = 0;
String nextCounter = String.valueOf(++counter);
SecretKeySpec signingKey = new SecretKeySpec(macKey, "AES");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] counterMac = mac.doFinal(nextCounter.getBytes("UTF-8"));
String base64EncodedMac = DatatypeConverter.printBase64Binary(counterMac);
The base64EncodedMac above is finally sent to the device to validate communication.
I've tried googling different solutions, however I've not been successful in generating a valid base64EncodedMac string in PHP for the device to approve it.
Found the solution myself. For Part 1, I chose to use phpseclib to generate the public/private keys and to specify the encryption algorithm. Decrypting macKey:
$rsa = new Crypt_RSA();
$keys = $rsa->createKey(2048);
// [...]
$macKey = base64_decode($base64EncodedMacKey);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->loadKey($keys['privatekey']);
$decryptedMac = $rsa->decrypt($macKey);
Followed by Part 2:
$counter = 0;
$hmac = hash_hmac('sha256', ++$counter, $decryptedMac, true);
$counterMac = base64_encode($hmac);
The main confusing part was that in Java, HMAC was done out of byte array, while in PHP the hash_hmac function expects a String as its 2nd parameter, so using unpack() was not sufficient. However, it seems to have worked with passing the $counter directly. It was also important to use the 4th parameter as TRUE to return raw data.

Encryption in Java & Flex

I want tp encrypt and decrypt string, with defined salt. But the result must be same if the code run in java and adobe flex.
The main goal is: the app in adobe flex will be generate a string that can be decrypt in server using java.
I use this flex library
http://crypto.hurlant.com/demo/
Try to 'Secret Key' Tab. I want to use AES Encryption, 'CBC' or 'PKCS5'.
var k:String = "1234567890123456";
var kdata:ByteArray = Hex.toArray(k);
var txt:String = "hello";
var data:ByteArray = Hex.toArray(Hex.fromString(txt));;
var name:String = "simple-aes-cbc";
var pad:IPad =new PKCS5();
var mode:ICipher = Crypto.getCipher(name, kdata, pad);
pad.setBlockSize(mode.getBlockSize());
mode.encrypt(data);
encrypted.text=Hex.fromArray(data);
trace(Hex.fromArray(data));
And here is the code in java
String plaintext = "hello";
String key = "1234567890123456";
SecretKey keyspec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE,keyspec);
byte[] encrypted = cipher.doFinal(plaintext.getBytes());
BASE64Encoder base64 = new BASE64Encoder();
String encodedString = base64.encode(encrypted);
System.out.println(encodedString);
Why the result is not same?
Can you guys provide the sample with the same result both of java and flex (encrypt and decrypt)? And if I want to change the paramater, for example, from cbc to ebc, which line that need to be changed?
Thanks!
"Simple" encryption mode (simple-aes-cbc) uses random initialization vector which is different each time you use it even if your secret key is the same.
If you wish to guarantee the same results when using the same key you should use "aes-cbc". Additionally you have to manually set the IV on the Cipher:
var ivmode:IVMode = mode as IVMode;
ivmode.IV = "some string guaranteed to be constant"
The IV can be made dependent on something like userId, which makes encryption repeatable for the same user.
You should consider how this affects your security scheme.
Seems like I do not convert into hex first in java when pass the key. And so on when get result byteArray at adobe flex, I do not cast again in java.
That's what I got when I see Arcadio code. Thanks.

Categories