Translate cipher process from java to nodejs (Blowfish) - java

We're migrating an old middleware written in java to our server and we want to write it down in nodejs, and we have no clue how to translate some of the functions:
With the first function we would need to find a solution in nodejs for the Cipher class, which we haven't found yet, is there any "simmetric" or similar package that we can use in node?
public static String encryptBlowFish(String cleartext, String key)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
{
String encBlowFish = "";
SecretKeySpec skeySpec = getGenerateKey(key);
Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init(1, skeySpec);
byte[] raw = cipher.doFinal(cleartext.getBytes("UTF8"));
encBlowFish = new Base64Encoder().encode(raw);
encBlowFish = URLEncoder.encode(encBlowFish, "UTF8");
encBlowFish = specialChars(encBlowFish);
return encBlowFish;
}
For the second method it is pretty much the same, we need a solution in node to emulate this behaviour:
private static SecretKeySpec getGenerateKey(String key)
throws NoSuchAlgorithmException
{
SecretKeySpec skeySpec = null;
Provider sunJce = new SunJCE();
Security.addProvider(sunJce);
KeyGenerator kgen = KeyGenerator.getInstance("Blowfish");
kgen.init(448);
byte[] raw = key.getBytes();
skeySpec = new SecretKeySpec(raw, "Blowfish");
return skeySpec;
}
Since we've been surfing around and haven't found anything relevant appart from the package "crypto" for node, which looks nice but we don't know which methods to use to emulate the expected result.
If there is anything else I can do to help you understand our issue, please let me know.
Thanks for your time.

Related

Using RSA with Java and C#

I'm currently working on a Project where I wanna use RSA for authentification. But as I'm using Java for my Server and C# for my Client I have alot of problems with creating or better initilize the PublicKey class from java.security in Java. I've already used mutlipe solutions for both languages and most of them are working themself.
So thats my basic C# RSA Client:
public static void NewKeyPair()
{
var csp = new RSACryptoServiceProvider(1024);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
_ = privKey.Modulus;
_ = pubKey.Modulus;
}
public void Encrypt(string text, string publicKey)
{
RSAParameters para = new RSAParameters();
para.Modulus = Convert.FromBase64String(publicKey);
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(para);
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(text);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);
}
public static void Decrypt(string encryptedText, RSAParameters para)
{
var bytesCypherText = Convert.FromBase64String(encryptedText);
//we want to decrypt, therefore we need a csp and load our private key
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(para);
//decrypt and strip pkcs#1.5 padding
var bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
//get our original plainText back...
var plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
So this is basically from a Microsoft doc if I remmeber right.
Meanwhile that's my Java code:
public static KeyPair gen() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
return keyGen.generateKeyPair();
}
public static String encrypt(String message, PublicKey pk) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pk);
return Base64.getEncoder().encodeToString(cipher.doFinal(message.getBytes()));
}
public static String decrypt(String encryptedText, PrivateKey pk) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pk);
return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedText)));
}
So for connecting those I'm exporting the Key first in C# with
Convert.ToBase64String(csp.ExportSubjectPublicKeyInfo()
After writing this to Console I paste it into this code snip in Java:
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(""));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
// Encrypting
String encrypted = encrypt("Hello", pubKey);
Afterwards I'm checking everythink by decrypting it again in C# ( Mostly failing before at keyFactory.generatePublic(keySpec); )
Also though aleady that's maybe caused by the byte system as c# using unsigned and java signed, but don't really have an idea how to fix that.
Someone has an idea how to solve this problem? c:

AES Encryption in JAVA and InputStream

Sorry, JAVA beginner here. I was trying out some encryption decryption examples. My methods were supposed to be returning an InputStream and were also supposed to take in an Inputstream as a parameter.
The signature of the method looked like this,
public static InputStream encriptFile(InputStream inputFile).
I researched a bit, and wrote some code confidently, but i don't think the code is properly encrypting a sample file because when I decrypt it and convert into string, it still shows me gibberish. I really don't know what's going wrong with encrypting and decrypting the InputStreams. The Java class looks like this,
private static final String key = "aesEncryptionKey";
private static final String initVector = "encryptionIntVec";
/*
* Getting a 128 bit key and iv for encryption
*/
public static InputStream encriptFile(InputStream inputFile) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
byte[] nonEncryptedByteArray = IOUtils.toByteArray(inputFile);
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec secretkey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); //Cipher instance using AES encryption algorithm
cipher.init(Cipher.ENCRYPT_MODE, secretkey, iv);
byte[] encryptedByteArray = cipher.doFinal(nonEncryptedByteArray);
/*
* Used the cipher library to encrypt the stream to a byte array
*/
InputStream encryptedInputStream = new ByteArrayInputStream(encryptedByteArray);
/*
* Back to streams, but this time encrypted
*/
return encryptedInputStream;
}
public static InputStream decriptFile(InputStream inputFile) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] encrytToDecryptByteArray = IOUtils.toByteArray(inputFile);
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec secretkey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretkey, iv);
byte[] decryptedByteArray = cipher.doFinal(encrytToDecryptByteArray);
/*
* dencrypted the encrypted data
*/
InputStream decryptedInputStream = new ByteArrayInputStream(decryptedByteArray);
return decryptedInputStream;
}
The main method looks like this,
File file = new File("test.txt");
InputStream is = new FileInputStream(file);
InputStream eis = encriptFile(is);
StringWriter writer = new StringWriter();
IOUtils.copy(eis, writer, "UTF-8");
String theString = writer.toString();
System.out.print(theString);
The contents of the text file are "Hello, file to be encrypted. Let's see if this works.".
The output which should have printed out an encrypted output looks like this.
��T��� ���N�?]�7!2. When I go ahead and decrypt it, it still shows me gibberish. Sorry for the really long question, any help is appreciated.
You should not return input streams at all. And the way you are using the streams, you're not actually streaming. If you have to use a stream, use CipherInputStream. Personally I'd always use CipherOutputStream for encryption and CipherInputStream for decryption (you are not likely to do anything with the encrypted data, after all, other than exporting it from your application).
A cipher furthermore returns binary data. That's not the same as UTF-8, and no encoding should be necessary for files either, as they accept binary data directly. This is likely the current problem. Just use FileOutputStream / FileInputStream instead of writers or readers.
I tested your code and I think you are printing the encrypted value (so, gibberish) and not the decrypted.
If you update the main to:
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream(new File("test.txt"));
InputStream eis = encriptFile(is);
InputStream result = decriptFile(eis); // <-- Decryption here
StringWriter writer = new StringWriter();
IOUtils.copy(result, writer, "UTF-8");
String theString = writer.toString();
System.out.print(theString);
}
You should be fine.
I tested just by changing the decryptFile() method to:
public static InputStream decriptFile(InputStream inputFile) throws Exception {
byte[] encrytToDecryptByteArray = new byte[inputFile.available()];
inputFile.read(encrytToDecryptByteArray);
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8));
SecretKeySpec secretkey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES);
Cipher cipher = Cipher.getInstance(AES_CBC_PKCS_5_PADDING);
cipher.init(Cipher.DECRYPT_MODE, secretkey, iv);
byte[] decryptedByteArray = cipher.doFinal(encrytToDecryptByteArray);
System.out.println(new String(decryptedByteArray));
return new ByteArrayInputStream(decryptedByteArray);
}
And calling it with the result from the encriptFile() and it worked properly.

well formed String as output of decryption using wrong key, AES

I'm searching a known encryption algorithm that would let me encrypt data with a key and if the data is decrypted with another key would give me data that is different from the first one. It's string data. I tried AES but the problem is that the result of decryption using a wrong key gives a lot of invalid symbols so the resulting String is differentiable from a result given with a good key.
Is there a work around to this?
I did this so far:
private static final String truc = "f41a3ff27aab7d5c";
public static String encryptPass(String pass,String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes("UTF-8"));
byte[] digest = md.digest();
BCrypt bcrypt = new BCrypt();
SecretKey keyL = new SecretKeySpec(digest, "AES");
Cipher AesCipher = Cipher.getInstance("AES/CTR/NoPadding");
AesCipher.init(Cipher.ENCRYPT_MODE, keyL, new IvParameterSpec(truc.getBytes()));
byte[] encVal = AesCipher.doFinal(pass.getBytes());
pass = Base64.encodeToString(encVal, Base64.DEFAULT);
Log.i("ADA", "encoded pass: " + pass);
return pass;
}
public static String decryptPass(String encPass , String key) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes("UTF-8"));
byte[] digest = md.digest();
SecretKey keyL = new SecretKeySpec(digest, "AES");
Cipher AesCipher = Cipher.getInstance("AES/CTR/NoPadding");
AesCipher.init(Cipher.DECRYPT_MODE, keyL, new IvParameterSpec(truc.getBytes()));
byte[] decodedValue = Base64.decode(encPass, Base64.DEFAULT);
byte[] decValue = AesCipher.doFinal(decodedValue);
String decryptedValue = new String(decValue);
Log.i("ADA", "decrpyted pass: " + decryptedValue);
return decryptedValue;
}
After reading the answer of MaybeWeCouldStartAVar, last paragraph I used "AES/CTR/NoPadding".
When I'm saying a well formed String I'm expecting mostly ASCII chars 32 to 125.
Is there something out there that would respond to my needs, or should I just roll my own encryption algorithm (I heard it's not advised but if it's my only option well..)?
I'm not trying to restrict access to any data. Data is fully visible by anyone who would use the app but unless they have the right key they should see erroneous data (that don't obviously look erroneous).
The idea is to restrain brute force.

What encryption scheme is supported by Java on most platforms out of the box?

I've googled and I've experimented, and I'm having no luck.
I'm writing a program that talks between android, windows/linux java and a raspberry pi and I want to encrypt something on one side and decrypt on the other, in all directions, as in, I want it to work in each possible platform case.
Blowfish, and DES eventually give me the dreaded "Given final block not properly padded"
on one platform or another and AES goes so slow on the raspberry as to be useless.
I've tried various secretkeyfactorys and keygenerators, and everything my master-cut-and-paste skills allowed for, and nothing works.
Very frustrating, I'm considering using ROT13. At least I know that works.
I know somebody's going to ask for a code sample so here it is... it's the same exact code everybody else shows examples of.
public static SecretKey generatedessecretkey(String password) throws InvalidKeyException, UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException
{
DESKeySpec keySpec = new DESKeySpec(password.getBytes("UTF8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(keySpec);
return key;
}
public static void encrypt(IOLogger log, byte[] datablock, String grouppw, ArrayList<byte[]> resp)
{
try
{
SecretKey ks = generatedessecretkey(grouppw);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, ks);
byte[] b = cipher.doFinal(datablock);
resp.clear();
resp.add(b);
return;
}
catch (Exception e)
{
}
}
edit: here's the decrypt, it's the same thing backwards
public static void desdecrypt(IOLogger log, byte[] datablock, String grouppw, ArrayList<byte[]> resp)
{
try
{
SecretKey ks = generatedessecretkey(grouppw);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, ks);
byte[] b = cipher.doFinal(datablock);
resp.clear();
resp.add(b);
return;
}
catch (Exception e)
{
}
}
the question I really want to ask is what encryption scheme is supported on most platforms out of the box
That question is answered in full by the JCA Specification and the list of standard algorithms given here.
It seems to me that you just haven't specified the chaining and padding modes correctly, or at all.

I block-padded and still get "data not block size aligned"

I have a problem when encrypting that causes the error:
javax.crypto.IllegalBlockSizeException: data not block size aligned
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2086)
at com.lcp.sso.logic.SsoCipher.encode(SsoCipher.java:89)
The constructor for the object:
public MyCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException {
Security.addProvider(new BouncyCastleProvider());
KeyGenerator keyGen = KeyGenerator.getInstance("DESede", "BC");
keyGen.init(new SecureRandom());
SecretKey keySpec = keyGen.generateKey();
this.sharedKey = keySpec.getEncoded().toString();
this.encrypter = Cipher.getInstance("DESede/ECB/Nopadding", "BC");
this.encrypter.init(Cipher.ENCRYPT_MODE, keySpec);
this.decrypter = Cipher.getInstance("DESede/ECB/Nopadding", "BC");
this.decrypter.init(Cipher.DECRYPT_MODE, keySpec);
}
The method in which the error occurs:
public String encode(String arg_text) throws IllegalBlockSizeException, BadPaddingException {
byte[] encrypt = arg_text.getBytes();
if(encrypt.length % 8 != 0){ //not a multiple of 8
//create a new array with a size which is a multiple of 8
byte[] padded = new byte[encrypt.length + 8 - (encrypt.length % 8)];
//copy the old array into it
System.arraycopy(encrypt, 0, padded, 0, encrypt.length);
encrypt = padded;
}
byte[] b = Base64.encodeBase64URLSafe(encrypt);
return Base64.encodeBase64String(encrypter.doFinal(b));
}
The error happens when calling that last method there. I'd swear that I'm making it the right block size, there, by null-padding the byte array to make sure it's a multiple of 8. I just don't know what went wrong!
I'm using:
Eclipse Version: Juno Service Release 1
Server: Tomcat v7.0 Server at Localhost ( specifically 7.0.32 )
--- EDIT ---
Program isn't working yet, (EDIT: YES IT IS! Muahahahaha!) but this problem is solved.
The constructor for the object:
public MyCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, InvalidParameterSpecException, InvalidAlgorithmParameterException {
Security.addProvider(new BouncyCastleProvider());
KeyGenerator keyGen = KeyGenerator.getInstance("DES", "BC");
keyGen.init(new SecureRandom());
SecretKey keySpec = keyGen.generateKey();
this.sharedKey = new String( Base64.encodeBase64URLSafe( keySpec.getEncoded() ) );
this.encrypter = Cipher.getInstance("DES/CBC/PKCS5Padding", "BC");
this.encrypter.init(Cipher.ENCRYPT_MODE, keySpec);
AlgorithmParameters params = this.encrypter.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
IvParameterSpec ivSpec = new IvParameterSpec(iv);
this.sharedIV = new String( Base64.encodeBase64URLSafe( iv ) );
this.decrypter = Cipher.getInstance("DES/CBC/PKCS5Padding", "BC");
this.decrypter.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
}
And the encrypting method is:
public String encode(String arg_text) throws IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
byte[] encrypt = arg_text.getBytes();
return new String( Base64.encodeBase64URLSafe(encrypter.doFinal(encrypt)), "US-ASCII");
}
It's now working to encrypt and decrypt just fine. Thank you VERY much.
Strange code in some aspects. Begining by why your code doesn't work, you are making sure that the size of encrypt is a multiple of 8, but you are trying to cipher byte[] b = Base64.encodeBase64URLSafe(encrypt); which may not be a multiple of 8. The following code should work:
public String encode(String arg_text) throws IllegalBlockSizeException, BadPaddingException {
byte[] encrypt = arg_text.getBytes();
if(encrypt.length % 8 != 0){ //not a multiple of 8
//create a new array with a size which is a multiple of 8
byte[] padded = new byte[encrypt.length + 8 - (encrypt.length % 8)];
//copy the old array into it
System.arraycopy(encrypt, 0, padded, 0, encrypt.length);
encrypt = padded;
}
return new String(Base64.encodeBase64URLSafe(encrypter.doFinal(b)), "US-ASCII");
}
Now, where there is this.encrypter = Cipher.getInstance("DESede/ECB/Nopadding", "BC"); do you notice the "Nopadding" part of the string? Well, the code does what you ask it to do... but the library can do the padding work for you, you just have to tell it. Try this.encrypter = Cipher.getInstance("DESede/ECB/PKCS5Padding", "BC"); instead and see if it works.
But really, why would you want to use 3DES in ECB mode? Unless the reason is legacy (which is unlikely from what I see here), it makes no sense. I believe you need to read a bit more about cryptography.

Categories

Resources