Data encryption between a file created in php and a kotlin application - php

I am creating a JSON file in PHP and I need to transfer it to the kotlin app
The requirements are that the information in the file be locked so that it cannot be modified
I used encryption and decryption in PHP and kotlin using SSL
But I could not combine them
Where should I put PHP keys in kotlin?
These IS the codes I work with:
php
$cipher = "aes-128-ctr";
$iv = base64_decode("bVQzNFNhRkQ1Njc4UUFaWA==");
$plaintext = "Encryption information";
$ciphertext = openssl_encrypt($plaintext, $cipher, $kay, $options=0, $iv);
echo $ciphertext; // 19t56L06a5m934HbeJKoVDxGErTBgg==
Kotlin
import android.util.Base64
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
object AESEncyption {
const val secretKey = "tK5UTui+DPh8lIlBxya5XVsmeDCoUl6vHhdIESMB6sQ="
const val salt = "QWlGNHNhMTJTQWZ2bGhpV3U="
const val iv = "bVQzNFNhRkQ1Njc4UUFaWA=="
fun decrypt(strToDecrypt: String) : String? {
try {
val ivParameterSpec = IvParameterSpec(Base64.decode(iv, Base64.DEFAULT))
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
val spec = PBEKeySpec(secretKey.toCharArray(), Base64.decode(salt, Base64.DEFAULT), 10000, 256)
val tmp = factory.generateSecret(spec);
val secretKey = SecretKeySpec(tmp.encoded, "AES")
val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
return String(cipher.doFinal(Base64.decode(strToDecrypt, Base64.DEFAULT)))
}
catch (e: Exception) {
println("Error while decrypting: $e");
}
return null
}
}
I deleted the unnecessary code
I do not know what is the secretKey and the salt in Kotlin code
And where do I put the $cipher from PHP in the kotlin code
I switched to aes-128-gcm so I would not have to tag

There are several issues within your codes and my answer can just argue on how you present the encryption key (you called it "kay") to the encryption function.
As the encryption key looks like a Base64 encoded string the following steps base on that.
A) I'm decoding the key-string with this command:
$kay = base64_decode("tK5UTui+DPh8lIlBxya5XVsmeDCoUl6vHhdIESMB6sQ=");
and receive a key length of 32 bytes - that is important for the next step.
B) As your AES algorithm is set to AES-CTR-128 OpenSSL will strip of all bytes longer than 16 bytes. That said, how does your key looks like in hex encoding:
echo 'original key: ' . bin2hex(($kay)) . PHP_EOL;
original key: b4ae544ee8be0cf87c948941c726b95d5b267830a8525eaf1e1748112301eac4
used key: b4ae544ee8be0cf87c948941c726b95d
used key Base64 tK5UTui+DPh8lIlBxya5XQ==
C) you can test that yourself with both keys - both will result in the ciphertext (Base64 encoded) of
OM3XUymvpRm0bJdEVC+TiRc/VKy/lA==
and not, as you said in your question, 19t56L06a5m934HbeJKoVDxGErTBgg==.
D) now put all data together and switch to Kotlin (I'm using Java, but that should be no problem for you):
The simple program will return the original plaintext:
original plaintext: Encryption information
Security warning: The following code uses static secret keys and IV's, has no exception handling and is for educational purpose only:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class SoAnswer {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
String ciphertextBase64 = "OM3XUymvpRm0bJdEVC+TiRc/VKy/lA==";
byte[] ciphertext = Base64.getDecoder().decode(ciphertextBase64);
byte[] key = Base64.getDecoder().decode("tK5UTui+DPh8lIlBxya5XQ==");
byte[] iv = Base64.getDecoder().decode("bVQzNFNhRkQ1Njc4UUFaWA==");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decryptedtext = cipher.doFinal(ciphertext);
System.out.println("original plaintext: " + new String(decryptedtext));
}
}

Related

Why does decipherIv.final() fail in node.js when decrypting a value encrypted using PHP?

PHP version: 5.6.39
Node.js version: 10.9.0
Objective: Encrypt using PHP and decrypt using Node.js
Stuck Point: I'm currently assuming that both the PHP and Node.js bindings to OpenSSL make use of PKCS7 padding. Do PHP and Node.js use incompatible bindings to OpenSSL?
Example PHP encryption/decryption code:
class SymmetricEncryption {
public static function simpleEncrypt($key, $plaintext) {
$iv = openssl_random_pseudo_bytes(16);
$ciphertext = openssl_encrypt($plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv)
return base64_encode($iv) . "." . base64_encode($ciphertext);
}
public static function simpleDecrypt($key, $token) {
list($iv, $ciphertext) = explode(".", $token);
return openssl_decrypt(
base64_decode($ciphertext),
"aes-256-cbc",
$key,
OPENSSL_RAW_DATA,
base64_decode($iv)
);
}
}
Example Node.js encryption/decryption code:
class SymmetricEncryption {
static simpleEncrypt(key: Buffer, plaintext: string): string {
const iv = randomBytes(16)
const cipher = createCipheriv('aes-256-cbc', key, iv)
const encrypted = cipher.update(plaintext)
const token = Buffer.concat([encrypted, cipher.final()])
return iv.toString('base64') + "." + token.toString('base64')
}
static simpleDecrypt(key: Buffer, token: string): string {
const [iv, ciphertext] = token.split(".").map(piece => Buffer.from(piece, 'base64'))
const decipher = createDecipheriv('aes-256-cbc', key, iv)
const output = decipher.update(ciphertext)
return Buffer.concat([output, decipher.final()]).toString('utf8')
}
}
I've tested each implementation independently of one another successfully, but when encrypting in PHP and decrypting in node.js I get the following error:
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
The stack trace points me to the offending line, which is decipher.final() in the simpleDecrypt method.
I'm using the following (failing) unit test to verify my implementation
it('should be able to decrypt values from php', () => {
const testAesKey = Buffer.from('9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8', 'hex')
const phpToken = 'oMhL/oIPAGQdMvphMyWdJw==.bELyRSIwy+nQGIyLj+aN8A=='
const decrypted = SymmetricEncryption.simpleDecrypt(testAesKey, phpToken)
expect(decrypted).toBe('hello world')
})
The phpToken variable I'm using here was created using the following code:
$testAesKey = "9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8";
echo SymmetricEncryption::simpleEncrypt($testAesKey, "hello world");
I suspect your issue is caused by how you pass your key in PHP. The documentation for openssl_encrypt doesn't specify anywhere that it interprets the key as hex. It does, however, truncate keys that are too long.
What is likely happening here is PHP is truncating your 64 character hex string down to 32 bytes, and using those for the key. Try using hex2bin on your PHP key before using it - this should fix your issue!
$testAesKey = hex2bin("9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8");

PHP encrypts a password with RSA decryption and Android sees some junk data plus the true data after decryption

I'm using RSA and AES encryption/Decryption
I create RSA public key and private key in Android
I send public key to PHP server
Utilizing AES encryption, PHP encrypts some large data with a password and utilizing RSA encyption and the received public key, it encodes the password and then returns back the encrypted large data with the password and the encoded encrypted password where the encode function is as following:
base64_encode(the encrypted password)
In Android, I first decode the encoded encrypted password where the decode instruction is as following:Base64.decode(the encoded encrypted password, Base64.DEFAULT)
PHP code is as following:
openssl_public_encrypt($password, $encrypted, $public_key);
$mystr= base64_encode($encrypted);
echo "mystrStart=$mystr mystrEnd\n"; //mystr will be retrieved in Android
Android code is as following:
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encryptedBytes,decryptedBytes;
encryptedBytes = Base64.decode(mystr, Base64.DEFAULT);
decryptedBytes = cipher.doFinal(encryptedBytes);
String DecryptedPassword = new String(decryptedBytes);
The problem is I see the password at the end of DecryptedPassword but some other junk data before the password is yet seen:
The password in PHP is "Hellooooo"
mystr (the encoded encrypted password) received in Android is as following:
sNfmwifoIEqXQzzge0zOFmBTFPlDqQZkAWqOPtGe3jNuI/zdV4SsCTxzcNZvww5RaaMOZ4ubQWrGXLuyuimKeQ==
The final result (DecryptedPassword) is as following:
����/
+�*#7JY��,��7��$C�-|8�[��p��Ĭ���,9v��}��Hellooooo
edit:
The code is as following:
KeyPairGenerator kpg;
KeyPair kp;
PublicKey publicKey;
final PrivateKey privateKey;
try {
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
byte[] pKbytes = Base64.encode(publicKey.getEncoded(), 0);
String pK = new String(pKbytes);
String pubKey = "-----BEGIN PUBLIC KEY-----\n" + pK + "-----END PUBLIC KEY-----\n";
Log.e(TAG, "pubKey:"+pubKey);
And then this pubKey is saved to a file named U.txt and then sent to the server
SendJSONToServerTest someTask = new SendJSONToServerTest(getApplicationContext(), "FileName"+".txt", PHP_address, getApplicationContext().getFilesDir().getPath() + "/" + "U.txt", new SendJSONToServerTest.OnEventListener<String>() {
#Override
public void onSuccess(String result) {
Log.e(TAG, "log1 = "+result);
String mstr = getBetweenStrings(result,"mystrStart=","mystrEnd");
Log.e(TAG, "log2 = "+mstr);
try {
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encryptedBytes, decryptedBytes;
encryptedBytes = Base64.decode(mstr, Base64.DEFAULT);
decryptedBytes = cipher.doFinal(encryptedBytes);
String DecryptedPassword = new String(decryptedBytes);
Log.e(TAG, "log3= "+DecryptedPassword);
} catch(GeneralSecurityException e) {
System.out.println(e);
}
Log.e(TAG, "Endddddddddddddd");
}
#Override
public void onFailure(String f) {
Log.e(TAG, "errR.......");
}
});
someTask.execute();
PHP code related to file content:
$fileContentStr = file_get_contents($_FILES["uploaded_file"]["tmp_name"]);
echo "\nfileContentStr = {$fileContentStr}\n";
$public_key = $fileContentStr;
echo "\npublic_key = {$public_key}\n";
I have the same problem and went searching and found the answer here.
Basically, the message is padded and the byte just before your original method is the 0x00 byte (NUL character).
The following code was extracted from the link which removes the padding and returns the original message.
def pkcs1_unpad(text):
if len(text) > 0 and text[0] == '\x02':
# Find end of padding marked by nul
pos = text.find('\x00')
if pos > 0:
return text[pos+1:]
return None
I am decoding the encrypted message in python but it is easy to port it to PHP.
I hope this help you, too.

Decrypting a Base64 encrypted image in Android

Im trying to decrypt a text sent from the server to an android application.
On PHP, I have the following:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$key = "-----BEGIN PUBLIC KEY-----\n" . ($PublicKey)
. '-----END PUBLIC KEY-----';
$rsa->loadKey($key);
$base64 = 'data:image/' . $type . ';base64,' . base64_encode($data);
$imageEncrypt = base64_encode($rsa->encrypt($base64));
The encoding and the encryption work well.
When I send the encrypted text to android, i cannot decrypt. I used the code:
public static String decryptString(String alias,String cipherText) {
try {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
// RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), output);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte)nextByte);
}
byte[] bytes = new byte[values.size()];
for(int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i).byteValue();
}
String finalText = new String(bytes, 0, bytes.length, "UTF-8");
return finalText;
//decryptedText.setText(finalText);
} catch (Exception e) {
Toast.makeText(context, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e("DecryptStringTAG", Log.getStackTraceString(e));
}
return "EMPTY";
}
The error is:
java.io.IOException: Error while finalizing cipher
Caused by: javax.crypto.IllegalBlockSizeException
The odd thing is that when i try to send from PHP a message like "Hello", android decrypts it successfully. But when i send the encrypted image, I get the stated error.
I've been struggling to find the error.
Any help?
Thanks
RSA asymmetric key encryption which is what public key encryption uses, that is RSA is essentially public key encryption. If you must use public/private key pair encryption the answer is hybrid encryption, similar to what SSL does.
Create a random symmetric key use it to encrypt the data with AES. Then encrypt the symmetric key with the RSA public key.
On decryption first decrypt the symmetric key with the RSA private key and use that to decrypt the data with the symmetric AES.
If you are looking for secure encryption you really need to get someone who is a domain expert to at least design and vett the implementation. Security is very hard to get right, if it isn't right is provides no security.

Encryption PHP, Decryption Java

I have a web-service in php that generates a keypair to encrypt a message, and one application in java that retrives the privatekey and decrypt the message.
For php I'm using http://phpseclib.sourceforge.net/ and have this two files:
keypair.php
<?php
set_time_limit(0);
if( file_exists('private.key') )
{
echo file_get_contents('private.key');
}
else
{
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->createKey();
$res = $rsa->createKey();
$privateKey = $res['privatekey'];
$publicKey = $res['publickey'];
file_put_contents('public.key', $publicKey);
file_put_contents('private.key', $privateKey);
}
?>
encrypt.php
<?php
include('Crypt/RSA.php');
//header("Content-type: text/plain");
set_time_limit(0);
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$rsa->loadKey(file_get_contents('public.key')); // public key
$plaintext = 'Hello World!';
$ciphertext = $rsa->encrypt($plaintext);
echo base64_encode($ciphertext);
?>
and in java I have this code:
package com.example.app;
import java.io.DataInputStream;
import java.net.URL;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
public class MainClass {
/**
* #param args
*/
public static void main(String[] args)
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
try {
BASE64Decoder decoder = new BASE64Decoder();
String b64PrivateKey = getContents("http://localhost/api/keypair.php").trim();
String b64EncryptedStr = getContents("http://localhost/api/encrypt.php").trim();
System.out.println("PrivateKey (b64): " + b64PrivateKey);
System.out.println(" Encrypted (b64): " + b64EncryptedStr);
SecretKeySpec privateKey = new SecretKeySpec( decoder.decodeBuffer(b64PrivateKey) , "AES");
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plainText = decoder.decodeBuffer(b64EncryptedStr);
System.out.println(" Message: " + plainText);
}
catch( Exception e )
{
System.out.println(" Error: " + e.getMessage());
}
}
public static String getContents(String url)
{
try {
String result = "";
String line;
URL u = new URL(url);
DataInputStream theHTML = new DataInputStream(u.openStream());
while ((line = theHTML.readLine()) != null)
result = result + "\n" + line;
return result;
}
catch(Exception e){}
return "";
}
}
My questions are:
Why I'm having a exception saying "not an RSA key!"?
How can I improve this code? I have used base64 to avoid encoding and comunication errors between Java and PHP.
This concept is correct? I mean, I'm using it correctly?
With the help of above answer, I got that SecretKeySpec is used wrong, and I found that PEM file from OpenSSL isn't a 'standart format', so I need to use the PEMReader to convert it to PrivateKey class.
Here is my working class:
package com.example.app;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.StringReader;
import java.net.URL;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Security;
import javax.crypto.Cipher;
import org.bouncycastle.openssl.PEMReader;
import sun.misc.BASE64Decoder;
public class MainClass {
/**
* #param args
*/
public static void main(String[] args)
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
try {
BASE64Decoder decoder = new BASE64Decoder();
String b64PrivateKey = getContents("http://localhost/api/keypair.php").trim();
String b64EncryptedStr = getContents("http://localhost/api/encrypt.php").trim();
System.out.println("PrivateKey (b64): " + b64PrivateKey);
System.out.println(" Encrypted (b64): " + b64EncryptedStr);
byte[] decodedKey = decoder.decodeBuffer(b64PrivateKey);
byte[] decodedStr = decoder.decodeBuffer(b64EncryptedStr);
PrivateKey privateKey = strToPrivateKey(new String(decodedKey));
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plainText = cipher.doFinal(decodedStr);
System.out.println(" Message: " + new String(plainText));
}
catch( Exception e )
{
System.out.println(" Error: " + e.getMessage());
}
}
public static String getContents(String url)
{
try {
String result = "";
String line;
URL u = new URL(url);
DataInputStream theHTML = new DataInputStream(u.openStream());
while ((line = theHTML.readLine()) != null)
result = result + "\n" + line;
return result;
}
catch(Exception e){}
return "";
}
public static PrivateKey strToPrivateKey(String s)
{
try {
BufferedReader br = new BufferedReader( new StringReader(s) );
PEMReader pr = new PEMReader(br);
KeyPair kp = (KeyPair)pr.readObject();
pr.close();
return kp.getPrivate();
}
catch( Exception e )
{
}
return null;
}
}
Here is my keypair.php
<?php
set_time_limit(0);
if( file_exists('private.key') )
{
echo base64_encode(file_get_contents('private.key'));
}
else
{
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->setHash('sha1');
$rsa->setMGFHash('sha1');
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$res = $rsa->createKey(1024);
$privateKey = $res['privatekey'];
$publicKey = $res['publickey'];
file_put_contents('public.key', $publicKey);
file_put_contents('private.key', $privateKey);
echo base64_encode($privateKey);
}
?>
and my encrypt.php
<?php
include('Crypt/RSA.php');
set_time_limit(0);
$rsa = new Crypt_RSA();
$rsa->setHash('sha1');
$rsa->setMGFHash('sha1');
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$rsa->loadKey(file_get_contents('public.key')); // public key
$plaintext = 'Hello World!';
$ciphertext = $rsa->encrypt($plaintext);
$md5 = md5($ciphertext);
file_put_contents('md5.txt', $md5);
file_put_contents('encrypted.txt', base64_encode($ciphertext));
echo base64_encode($ciphertext);
?>
I hope it helps anyone and thanks.
A few thoughts.
Shouldn't you be echo'ing out $privatekey in the else as well?
Are you using the latest Git version of phpseclib? I ask because a while ago there was this commit:
https://github.com/phpseclib/phpseclib/commit/e4ccaef7bf74833891386232946d2168a9e2fce2#phpseclib/Crypt/RSA.php
The commit was inspired by https://stackoverflow.com/a/13908986/569976
Might be worthwhile if you change your tags up a bit to include bouncycastle and phpseclib. I'd add those tags but some tags will have to be removed since you're already at the limit of 5. I'll let you decide which ones to remove (if you even want to do that).
SecretKeySpec privateKey = new SecretKeySpec( decoder.decodeBuffer(b64PrivateKey) , "AES");
b64PrivateKey is supposed to contain the private key right? 'cause looking it up in the docs it looks like SecretKeySpec is only intended for symmetric algorithms (like AES) - not asymmetric ones like RSA.
I did some digging into the classes you're using and it seems like what you've posted has most of the default parameters matching your explicit parameters. However, this doesn't ensure that your configuration has those all set to match the current documentation if you're using older implementations.
Also, a tip from a senior Facebook security engineer who discussed a similar issue in a lecture recently; different libraries implementing the same security protocols will oftentimes be incompatible and even the same libraries in different environments or languages will oftentimes fail to work together. With that in mind, a few things to try given that working examples similar to your setup exist online:
Make sure you're using the latest versions of libraries. Also note that some javax functions and classes are deprecated and suggest using java.security now (didn't check if this applies to your case).
Force the key size to be consistent (1024 or 2048). The java implementation can do either and I didn't find consistent documentation for both libraries saying what your configuration default would be used (could be causing problem #2, though you might get a different exception for invalid key size).
Ensure that your privatekey matches expectation (length/reads the same between java and php).
Force default values to be explicitly defined (set CryptRSA hash to sha1, key lengths, anything else you can explicitly set).
Try encrypting the same message with both java and php to see if you can get the same outputs. Do this after ensuring your keys read the same and don't throw exceptions while being used in both applications. Encrypting a single character can tell you if the same padding scheme is actually being used (it appears from the source code that both use MGF1, but it never hurts to check outputs).
Finally try taking an example for php to java encryption which is said to already work and do one change at a time until you get back to your current encryption scheme. I saw a few examples googling quickly which used different parameters and settings with CryptRSA and java security that stated they were working together. Take a working example and try swapping the hash function and then the encryption, etc.

Blowfish decryption / Action Script 3 (AS3Crypto)

I have tried using Blowfish (CBC) technique for encrypting / decrypting a text from PHP to Flash.
After hours of investigation and research, I got to know that AS3Crypto could be used for decryption of Blowfish (CBC Mode).
In a simple example, I'm using Mcrypt (A Library for PHP) to encrypt the text:
const CYPHER = 'blowfish';
const MODE = 'cbc';
const KEY = '12345';
public function encrypt($plaintext)
{
$td = mcrypt_module_open(self::CYPHER, '', self::MODE, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, self::KEY, $iv);
$crypttext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
return $iv.$crypttext;
}
Then, I can transfer the output by encoding it using Base64.
So for example, if we have the original text as (without quotations) "stackoverflow" and the key as "123456", the output will be (base64):
MUXl8mBS9OsvxTbLAiCrAMp851L8vVD0
Till now there is no problem.
Now when I shift this encoded text to flash, I can get it without any problem.
You can try going to http://crypto.hurlant.com/demo/CryptoDemo.swf and then select "Secret Key" tab, and choose encryption as "Blowfish", mode as "CBC", Padding as "none" and tick the "Prepend IV to cipher text" option. After that, you can successfully decrypt the text above, using the key, and get the "stackoverflow" text again.
So, till now I know that its possible to convert from Mcrypt to AS3Crypt, and then I tried to use AS3Crypto library in flash (You can get it from: http://code.google.com/p/as3crypto/).
I made a new actionscript file which has the following content to test whether or not the encryptions would be the same (I couldn't figure out how to decrypt it because of the main problem):
package
{
import com.hurlant.crypto.Crypto;
import com.hurlant.util.Hex;
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.IHash;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.crypto.hash.SHA224;
import com.hurlant.crypto.hash.SHA256;
import com.hurlant.crypto.prng.ARC4;
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.BlowFishKey;
import com.hurlant.crypto.symmetric.CBCMode;
import com.hurlant.crypto.symmetric.CFB8Mode;
import com.hurlant.crypto.symmetric.CFBMode;
import com.hurlant.crypto.symmetric.CTRMode;
import com.hurlant.crypto.symmetric.DESKey;
import com.hurlant.crypto.symmetric.ECBMode;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IMode;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ISymmetricKey;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.crypto.symmetric.NullPad;
import com.hurlant.crypto.symmetric.OFBMode;
import com.hurlant.crypto.symmetric.PKCS5;
import com.hurlant.crypto.symmetric.SimpleIVMode;
import com.hurlant.crypto.symmetric.TripleDESKey;
import com.hurlant.crypto.symmetric.XTeaKey;
import flash.utils.ByteArray;
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.util.Base64;
public class BlowFish
{
/**
* Encrypts a string.
* #param text The text string to encrypt.
* #param key A cipher key to encrypt the text with.
*/
/**
* Decrypts an encrypted string.
* #param text The text string to decrypt.
* #param key The key used while originally encrypting the text.
*/
static public function encrypt( s :String, k :String ) :String
{
var key :ByteArray = Hex.toArray(k);
var data :ByteArray = Hex.toArray(Hex.fromString(s));
var pad :IPad = new NullPad();
var cipher :ICipher = Crypto.getCipher("blowfish-cbc", key, pad);
pad.setBlockSize(cipher.getBlockSize());
cipher.encrypt(data);
var result :String = Hex.fromArray(data);
var ivmode :IVMode = cipher as IVMode;
var iv :String = Hex.fromArray(ivmode.IV);
return Base64.encodeByteArray(Hex.toArray(Hex.fromArray(ivmode.IV) + Hex.fromArray(data)));
}
}
}
And I've used the following code to get out the result:
import BlowFish;
var $key:String = "123456";
var $encryption:String = BlowFish.encrypt("stackoverflow", $key);
trace( $encryption );
The problem is that I couldn't match the following outputs together.
I don't have any idea about actionscript, so you will obviously find a lot of mistakes in it.
I will be really appreciated about any explanation and solution with an example to figure out how to successfully decrypt the encrypted text in flash using AS3Crypto.
Thank you.
hope this is helpful:
public static function encryptString(encString : String = "") : String
{
var kdata : ByteArray = Hex.toArray(Hex.fromString(k))
var _method : String = "simple-blowfish-ecb";
var pad : IPad = new NullPad;
var crypt : ICipher = Crypto.getCipher(_method, kdata, pad);
var data : ByteArray = Hex.toArray(Hex.fromString(encString));
pad.setBlockSize(crypt.getBlockSize());
crypt.encrypt(data);
encString = Base64.encodeByteArray(data);
return encString;
}

Categories