We want to use Cipher encryption/decryption in windows phone 7. We have done for android using java. But when we try to develop in c# we struggling.
Our Java code:
public AES()
{
try
{
Security.addProvider(new BouncyCastleProvider());
cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public String doDecrypt(String key, String cipherText)
{
try
{
byte[] raw = key.getBytes(Charset.forName("UTF-8"));
SecretKeySpec skey = new SecretKeySpec(raw, "AES");
cipher.init(Cipher.DECRYPT_MODE, skey );
return new String(cipher.doFinal(Base64.decode(cipherText,Base64.DEFAULT)), Charset.forName("UTF-8"));
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
public String doEncrypt(String key, String plainText)
{
try
{
byte[] raw = key.getBytes(Charset.forName("UTF-8"));
SecretKeySpec skey = new SecretKeySpec(raw, "AES");
cipher.init(Cipher.ENCRYPT_MODE, skey );
return Base64.encodeToString(cipher.doFinal(plainText.getBytes(Charset.forName("UTF-8"))),Base64.DEFAULT);
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
}
Here we can encrypt and decryption.
Our C# code is:
public static byte[] EncryptWithAES(string dataToEncrypt, String Key)
{
byte[] encryptedData;
byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(Key);
using (AesManaged aesEnc = new AesManaged())
{
aesEnc.Key = keyBytes;
aesEnc.IV = new byte[16];
//Create encryptor for converting
ICryptoTransform encryptor = aesEnc.CreateEncryptor(aesEnc.Key, aesEnc.IV);
using (MemoryStream memStream = new MemoryStream())
{
using (CryptoStream crypStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter srmWriter = new StreamWriter(crypStream))
{
srmWriter.Write(dataToEncrypt);
}
encryptedData = memStream.ToArray();
}
}
}
return encryptedData;
}
But here we receive different output.
Java OP:-
OYbW6pI8mgqU5xOcfG8N92e28T9GUObtcea4XWqU0yQyJRULSLV/yjAzDh8gq9Hgj5K5OubZfdm/
/ts66eQMJYH4TBX0/hN5zPwQbdTWmfVU3dDyU2SyQek5zYcWW+OgnppL9jcMcJZg4pv2+q6x8w==
C# OP:-
OYbW6pI8mgqU5xOcfG8N9wXs2/gWMc6dcUSEoLXm3L5v9Ih9eN63xO31mXmEDLprIzusXaOS1rNNtBPi5I8FG3IukVgicagrkLul1vfa142z+XDULJXFmg5rxPa6iJzXqeZ6x3wxbfI3T/ZqGwxqbg==
We can not get the exact encrypted data like java. Please suggest or provide any links for Cipher encryption/decryption in windows phone 7.
It works for me using LINQPad:
Console.Write(String.Join(" ", EncryptWithAES("hello", "AAECAwQFBgcICQoLDA0ODw==")));
yields:
91 209 208 157 151 41 81 76 99 8 248 231 34 62 204 1
Perhaps it's something specific for Window Phone 7 that is causing it not to work?
Key from https://stackoverflow.com/a/2919565/1185053
Finally I got solution from stackoverflow. I found the solution from here.. It is working fine..
The Solution is:-
Crypt Class:-
public class BCEngine
{
private Encoding _encoding;
private IBlockCipher _blockCipher;
private PaddedBufferedBlockCipher _cipher;
private IBlockCipherPadding _padding;
Pkcs7Padding pkcs = new Pkcs7Padding();
public BCEngine(IBlockCipher blockCipher, Encoding encoding)
{
_blockCipher = blockCipher;
_encoding = encoding;
}
public string Encrypt(string plain, string key)
{
byte[] result = BouncyCastleCrypto(true, _encoding.GetBytes(plain), key);
return Convert.ToBase64String(result);
}
public string Decrypt(string cipher, string key)
{
byte[] result = BouncyCastleCrypto(false, Convert.FromBase64String(cipher), key);
return _encoding.GetString(result, 0, result.Length);
}
private byte[] BouncyCastleCrypto(bool forEncrypt, byte[] input, string key)
{
try
{
_cipher = _padding == null ? new PaddedBufferedBlockCipher(_blockCipher) : new PaddedBufferedBlockCipher(_blockCipher, _padding);
byte[] keyByte = _encoding.GetBytes(key);
_cipher.Init(forEncrypt, new KeyParameter(keyByte));
return _cipher.DoFinal(input);
}
catch (Org.BouncyCastle.Crypto.CryptoException ex)
{
throw new CryptoException(ex.Message);
}
}
public string AESEncryption(string plain, string key)
{
return Encrypt(plain, key);
}
public string AESDecryption(string cipher, string key)
{
return Decrypt(cipher, key);
}
public BCEngine()
{
_blockCipher = new AesEngine();
_encoding = Encoding.UTF8;
pkcs = new Pkcs7Padding();
_padding = pkcs;
}
}
Now I can Call from anywhere to encrypt/decrypt the text.
Example:-
public partial class AesExample : PhoneApplicationPage
{
public AesExample()
{
InitializeComponent();
string key = "b09f72a0lkb1lktb";
string plainText = "Text To Encrypt";
BCEngine bcEngine = new BCEngine();
string encryptedString= bcEngine.Encrypt(plainText, key);
Console.WriteLine("\n\nEncrypted String==> " + encryptedString);
BCEngine bcEnginenew = new BCEngine();
string decryptedString = bcEnginenew.Decrypt(encryptedString, key);
Console.WriteLine("\n\nDecrypted String==> " + decryptedString);
}
}
Related
We are trying to implement PGP encryption into one of our .net apps for the first time at the request of a vendor that we work with. Most of the examples I have found reference using Bouncy Castle so I have attempted to implement that. Everything seems to work fine and I end up with a .pgp file that looks correct. When I send it to the vendor, they say that it appears to be double-encrypted. They said they had to decrypt it twice to read it. Anyone have any ideas what may be going on here? I'll include the sample code that I am using below.
public class Pgp
{
public static void DecryptFile(
string inputFileName,
string keyFileName,
char[] passwd,
string defaultFileName)
{
using (Stream input = File.OpenRead(inputFileName),
keyIn = File.OpenRead(keyFileName))
{
DecryptFile(input, keyIn, passwd, defaultFileName);
}
}
/**
* decrypt the passed in message stream
*/
private static void DecryptFile(
Stream inputStream,
Stream keyIn,
char[] passwd,
string defaultFileName)
{
inputStream = PgpUtilities.GetDecoderStream(inputStream);
try
{
PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
PgpEncryptedDataList enc;
PgpObject o = pgpF.NextPgpObject();
//
// the first object might be a PGP marker packet.
//
if (o is PgpEncryptedDataList)
{
enc = (PgpEncryptedDataList)o;
}
else
{
enc = (PgpEncryptedDataList)pgpF.NextPgpObject();
}
//
// find the secret key
//
PgpPrivateKey sKey = null;
PgpPublicKeyEncryptedData pbe = null;
PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(
PgpUtilities.GetDecoderStream(keyIn));
foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
{
sKey = PgpExampleUtilities.FindSecretKey(pgpSec, pked.KeyId, passwd);
if (sKey != null)
{
pbe = pked;
break;
}
}
if (sKey == null)
{
throw new ArgumentException("secret key for message not found.");
}
Stream clear = pbe.GetDataStream(sKey);
PgpObjectFactory plainFact = new PgpObjectFactory(clear);
PgpObject message = plainFact.NextPgpObject();
if (message is PgpCompressedData)
{
PgpCompressedData cData = (PgpCompressedData)message;
PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream());
message = pgpFact.NextPgpObject();
}
if (message is PgpLiteralData)
{
PgpLiteralData ld = (PgpLiteralData)message;
string outFileName = ld.FileName;
if (outFileName.Length == 0)
{
outFileName = defaultFileName;
}
Stream fOut = File.Create(outFileName);
Stream unc = ld.GetInputStream();
Streams.PipeAll(unc, fOut);
fOut.Close();
}
else if (message is PgpOnePassSignatureList)
{
throw new PgpException("encrypted message contains a signed message - not literal data.");
}
else
{
throw new PgpException("message is not a simple encrypted file - type unknown.");
}
if (pbe.IsIntegrityProtected())
{
if (!pbe.Verify())
{
Console.Error.WriteLine("message failed integrity check");
}
else
{
Console.Error.WriteLine("message integrity check passed");
}
}
else
{
Console.Error.WriteLine("no message integrity check");
}
}
catch (PgpException e)
{
Console.Error.WriteLine(e);
Exception underlyingException = e.InnerException;
if (underlyingException != null)
{
Console.Error.WriteLine(underlyingException.Message);
Console.Error.WriteLine(underlyingException.StackTrace);
}
}
}
public static void EncryptFile(
string outputFileName,
string inputFileName,
string encKeyFileName,
bool armor,
bool withIntegrityCheck)
{
PgpPublicKey encKey = PgpExampleUtilities.ReadPublicKey(encKeyFileName);
using (Stream output = File.Create(outputFileName))
{
EncryptFile(output, inputFileName, encKey, armor, withIntegrityCheck);
}
}
private static void EncryptFile(
Stream outputStream,
string fileName,
PgpPublicKey encKey,
bool armor,
bool withIntegrityCheck)
{
if (armor)
{
outputStream = new ArmoredOutputStream(outputStream);
}
try
{
byte[] bytes = PgpExampleUtilities.CompressFile(fileName, CompressionAlgorithmTag.Zip);
PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(
SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
encGen.AddMethod(encKey);
Stream cOut = encGen.Open(outputStream, bytes.Length);
cOut.Write(bytes, 0, bytes.Length);
cOut.Close();
if (armor)
{
outputStream.Close();
}
}
catch (PgpException e)
{
Console.Error.WriteLine(e);
Exception underlyingException = e.InnerException;
if (underlyingException != null)
{
Console.Error.WriteLine(underlyingException.Message);
Console.Error.WriteLine(underlyingException.StackTrace);
}
}
}
}
public class PgpExampleUtilities
{
/**
* Search a secret key ring collection for a secret key corresponding to keyID if it
* exists.
*
* #param pgpSec a secret key ring collection.
* #param keyID keyID we want.
* #param pass passphrase to decrypt secret key with.
* #return
* #throws PGPException
* #throws NoSuchProviderException
*/
internal static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyID, char[] pass)
{
PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyID);
if (pgpSecKey == null)
{
return null;
}
return pgpSecKey.ExtractPrivateKey(pass);
}
internal static PgpPublicKey ReadPublicKey(string fileName)
{
using (Stream keyIn = File.OpenRead(fileName))
{
return ReadPublicKey(keyIn);
}
}
internal static PgpPublicKey ReadPublicKey(Stream input)
{
PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(
PgpUtilities.GetDecoderStream(input));
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
foreach (PgpPublicKeyRing keyRing in pgpPub.GetKeyRings())
{
foreach (PgpPublicKey key in keyRing.GetPublicKeys())
{
if (key.IsEncryptionKey)
{
return key;
}
}
}
throw new ArgumentException("Can't find encryption key in key ring.");
}
internal static byte[] CompressFile(string fileName, CompressionAlgorithmTag algorithm)
{
MemoryStream bOut = new MemoryStream();
PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(algorithm);
PgpUtilities.WriteFileToLiteralData(comData.Open(bOut), PgpLiteralData.Binary,
new FileInfo(fileName));
comData.Close();
return bOut.ToArray();
}
}
public class Streams
{
private const int BufferSize = 512;
public static void PipeAll(Stream inStr, Stream outStr)
{
byte[] bs = new byte[BufferSize];
int numRead;
while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0)
{
outStr.Write(bs, 0, numRead);
}
}
}
}
I then call the EncryptFile Method as below:
public void EncryptMyFile()
{
Pgp.EncryptFile(#"C:\ ... Output.pgp", #"C:\ ... Input.txt", #"C:\ ... pubkey.txt", false, false);
}
Used code above and it properly generated a file, but the vendor says that it is "double encrypted".
I want encrypt in C# and decrypt in c++ but I have some Encoding problem :
example variables :
Key : gOtIPaLver—vS5UAnJbPqsDZSf,yJ1
IVString : gOtIPaLver—vS5
my c# code :
public static string EncryptString(string message, string KeyString, string IVString)
{
byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString.Substring(0,32));
byte[] IV = UTF8Encoding.UTF8.GetBytes(IVString);
string encrypted = null;
RijndaelManaged rj = new RijndaelManaged();
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
rj.Padding = PaddingMode.PKCS7;
try
{
MemoryStream ms = new MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(message);
sw.Close();
}
cs.Close();
}
byte[] encoded = ms.ToArray();
encrypted = Convert.ToBase64String(encoded);
ms.Close();
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
return null;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
rj.Clear();
}
return encrypted;
}
When I try encrypt and my Key have some not ASCII char - count of bytes is more than lenght of string .
How Encoding I shound use ? In C++ I use EVP (default padding is PKCS7) .
static string decryptEX(string KS, string ctext)
{
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
string IV = KS.substr(0, 16);
int rc = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (byte*)&KS[0], (byte*)&IV[0]);
std::string rtext;
rtext.resize(ctext.size());
int out_len1 = (int)rtext.size();
rc = EVP_DecryptUpdate(ctx, (byte*)&rtext[0], &out_len1, (const byte*)&ctext[0], (int)ctext.size());
int out_len2 = (int)rtext.size() - out_len1;
rc = EVP_DecryptFinal_ex(ctx, (byte*)&rtext[0] + out_len1, &out_len2);
try
{
rtext.resize(out_len1 + out_len2);
}
catch (exception e)
{
}
return rtext;
}
Your call to
byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString.Substring(0,32));
fails because there are not 32 characters in that string. Yes, there would be 32 bytes if the string is encoded as UTF8. But Substring takes a count of characters.
Changing that line to
byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString);
gives a 32-byte long key.
Since you can't count on getting proper input for the KeyString, you could validate after this point that your key length is long enough.
byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString);
if (Key.Length < 32)
throw new KeyLengthException("some useful info as to why this was thrown"); // or some other appropriate Exception type you create or resuse.
If I'm correct in assuming which key, IV, and block sizes you require, this should do what you need:
public static string EncryptString(string message, string KeyString, string IVString)
{
byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString).Take(32).ToArray();
if (Key.Length < 32)
throw new Exception("KeyString not at least 32 bytes.");
byte[] IV = UTF8Encoding.UTF8.GetBytes(IVString).Take(16).ToArray();
if (Key.Length < 32)
throw new Exception("IVString not at least 16 bytes.");
string encrypted = null;
RijndaelManaged rj = new RijndaelManaged();
rj.KeySize = 128;
rj.BlockSize = 128;
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
rj.Padding = PaddingMode.PKCS7;
try
{
MemoryStream ms = new MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(message);
sw.Close();
}
cs.Close();
}
byte[] encoded = ms.ToArray();
encrypted = Convert.ToBase64String(encoded);
ms.Close();
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
return null;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
rj.Clear();
}
return encrypted;
}
I'm going to encrypt my data transferring between my multi platform apps. My question is that which algorithm can be used that work for all these platforms?
That should have these parameters:
Dynamic key and iv.
Supported in C#, Android, Swift, PHP.
Be secure enough.
It will be welcome if anybody give me some samples or links for each platform.
UPDATE:
I tried these classes:
Android:
public class Cryptor {
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
public Cryptor(byte[] key_par,byte[] iv_par)
{
keyspec = new SecretKeySpec(key_par, "AES");
ivspec = new IvParameterSpec(iv_par);
try {
cipher = Cipher.getInstance("AES/CBC/ZeroPadding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
}
public byte[] encrypt(byte[] input) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty input");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(input);
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] data)
{
if (data==null)
{
return null;
}
int len = data.length;
String str = "";
for (int i=0; i<len; i++) {
if ((data[i]&0xFF)<16)
str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
else
str = str + java.lang.Integer.toHexString(data[i]&0xFF);
}
return str;
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
}
PHP:
class MCrypt
{
protected $in_iv;
protected $in_key;
function __construct($in_key , $in_iv)
{
$this->key = $in_key;
$this->iv = $in_iv;
}
function encrypt($str) {
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return bin2hex($encrypted);
}
function decrypt($code) {
$code = $this->hex2bin($code);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return utf8_encode(trim($decrypted));
}
protected function hex2bin($hexdata) {
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
C#:
class Cryptor
{
private byte[] iv;
private byte[] key;
public Cypher(byte[] key, byte[] iv)
{
this.key = key;
this.iv = iv;
}
public byte[] EncryptRJ128(byte[] input)
{
var encoding = new UTF8Encoding();
byte[] encrypted;
using (var rj = new RijndaelManaged())
{
try
{
rj.Padding = PaddingMode.Zeros;
rj.Mode = CipherMode.CBC;
rj.KeySize = 128;
rj.BlockSize = 128;
rj.Key = key;
rj.IV = iv;
var ms = new MemoryStream();
var cs = new CryptoStream(ms, rj.CreateEncryptor(key, iv), CryptoStreamMode.Write);
var sr = new StreamWriter(cs);
sr.Write(input);
sr.Flush();
cs.FlushFinalBlock();
encrypted = ms.ToArray();
}
finally
{
rj.Clear();
}
}
return encrypted;
}
public String DecryptRJ128(byte[] input)
{
var sRet = "";
var encoding = new UTF8Encoding();
using (var rj = new RijndaelManaged())
{
try
{
rj.Padding = PaddingMode.Zeros;
rj.Mode = CipherMode.CBC;
rj.KeySize = 128;
rj.BlockSize = 128;
rj.Key = key;
rj.IV = iv;
var ms = new MemoryStream(input);
var cs = new CryptoStream(ms, rj.CreateDecryptor(key, iv), CryptoStreamMode.Read);
var sr = new StreamReader(cs);
sRet = sr.ReadLine();
}
finally
{
rj.Clear();
}
}
return sRet;
}
}
TEST:
This is some example that I used to test:
key ={ 106,104,103,97,103,94,115,106,102,96,115,53,53,52,55,53}
iv ={104,49,52,56,114,102,103,49,48,50,52,97,56,51,118,52}
input ={57,102,117,105,65,75,113,105,108,119,113,54,109,73,89,104}
Now trying to encrypt:
Android and PHP output:
170, 29, 170, 139, 14, 192, 81, 232, 41, 237, 25, 19, 130, 237, 15, 198
c# OUTPUT:
59 , 85 , 127 , 29 , 161 , 145 , 23 , 127 , 246 , 100 , 157 , 234 , 128 , 65
here are the whole story:
(1) I have string "123";
(2) Encrypt to "????g*Ox*??D#?\v" using EncryptFromBase64;
(3) Converted to hex string using ConvertStringToHex
Here is the C# code.
public string ConvertStringToHex(string asciiString)
{
string hex = "";
foreach (char c in asciiString)
{
int value = Convert.ToInt32(c);
// Convert the decimal value to a hexadecimal value in string form.
hex += String.Format("{0:X2}", value);
}
return hex;
}
public string ConvertHexToString(string HexValue)
{
string StrValue = "";
while (HexValue.Length > 0)
{
StrValue += System.Convert.ToChar(System.Convert.ToUInt32(HexValue.Substring(0, 2), 16)).ToString();
HexValue = HexValue.Substring(2, HexValue.Length - 2);
}
return StrValue;
}
public string Encrypt(byte[] encryptedData)
{
byte[] newClearData = rijndaelEncryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.ASCII.GetString(newClearData);
}
public string EncryptFromBase64(string encryptedBase64)
{
if (encryptedBase64.Length < 1) return "";
byte[] bytes = Encoding.ASCII.GetBytes(encryptedBase64);
return Encrypt(bytes);
}
(4)The hex string is then transported to Android request command to C# web service and converted back to string. using convertHexToString
(5) Decryt using decryptAsBase64. There is padding exception.
Here is the android code.
public String decryptAsBase64(String clearData) {
if(clearData.length() < 1) return "";
byte[] encryptedData = clearData.getBytes();
byte[] decryptedData = decryptAsBase64(encryptedData);
String str = Base64.encodeBytes(decryptedData);
str = str.replace("+", "%2B");
return str;
}
public byte[] decryptAsBase64(byte[] clearData) {
byte[] decryptedData =decrypt(clearData);
try {
return Base64.decode(decryptedData);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return decryptedData;
}
public byte[] decrypt(byte[] clearData) {
byte[] decryptedData;
try {
decryptedData = aesCipher_Decoder.doFinal(clearData);
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "Illegal block size", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "Bad padding", e);
return null;
}
return decryptedData;
}
public String convertHexToString(String hex){
StringBuilder sb = new StringBuilder();
//49204c6f7665204a617661 split into two characters 49, 20, 4c...
for( int i=0; i<hex.length()-1; i+=2 ){
//grab the hex in pairs
String output = hex.substring(i, (i + 2));
//convert hex to decimal
int decimal = Integer.parseInt(output, 16);
//convert the decimal to character
sb.append((char)decimal);
}
return sb.toString();
}
The string converted back "????g*Ox*??D#?" is incorrect.
Anything wrong with my code?
You're grabbing the hex characters in pairs in your convertHexToString() method, but your {0:X} format string doesn't necessarily output 2 hex digits per character. If you want to make sure each character is represented by 2 hex digits, then use this format string instead:
{0:X2}
The problem was resolved. The error is in the encryption and decryption codes. The following code
public string Encrypt(byte[] encryptedData)
{
byte[] newClearData = rijndaelEncryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.ASCII.GetString(newClearData);
}
should be
public string Encrypt(byte[] encryptedData)
{
byte[] newClearData = rijndaelEncryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
// return Encoding.ASCII.GetString(newClearData);
return Convert.ToBase64String(newClearData);
}
In the android decryption code. The code
public String decryptAsBase64(String clearData) {
if(clearData.length() < 1) return "";
byte[] encryptedData = clearData.getBytes();
byte[] decryptedData = decryptAsBase64(encryptedData);
String str = Base64.encodeBytes(decryptedData);
str = str.replace("+", "%2B");
return str;
}
should be
public String decryptAsBase64(String clearData) {
if(clearData.length() < 1) return "";
byte[] encryptedData = null;
try {
encryptedData = Base64.decode(clearData);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] decryptedData = decrypt(encryptedData);
String str = null;
try {
str = new String(decryptedData, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str;
}
i am implementing the application using asp.net.
I want to make the querysting unchangeable. if i do the changes in manually , some exception needs to thrown .
how do i implement ?
"Try encrypting the querystring and append the resulting string to the querystring. When reading out your querystring, first encrypt the normal parameters again and compare it to the string. Then when any parameters get changed, the hash will not match anymore and you can throw an exception.
Something like this. Search for a nice Querystring reader/writer class to make life easier.
private string GetSecureQsToken(string querystring)
{
Byte[] buffer = Encoding.UTF8.GetBytes(querystring);
SHA1CryptoServiceProvider cryptoTransformSha1 =
new SHA1CryptoServiceProvider();
string hash = BitConverter.ToString(
cryptoTransformSha1.ComputeHash(buffer)).Replace("-", "");
return hash;
}
private void GoToSecureQsPage()
{
string qsvalues = "id=1&page=4";
Response.Redirect(string.Format("Default.aspx?{0}&hash={1}", qsvalues, GetSecureQsToken(qsvalues)));
}
private void ReadSecureQs()
{
//here check the normal querystring parameters again against the hash parameter
if (GetSecureQsToken("id=1&page=4") != Request.QueryString["hash"])
{
throw new Exception("Error here");
}
}
I simply went for the Hash version as it was suggested in the comments, but yes, then it becomes changeable again by the client. SO you will need some encryption like this:
public class SecureQuerystring
{
public SecureQuerystring()
{
m_passPhrase = "#oqT6%hKg";
m_saltValue = "7651273512";
m_initVector = "#1B2c3D4e5F6g7H8";
m_hashAlgorithm = "SHA1";
m_passwordIterations = 5;
m_keySize = 128;
}
private string m_plaintext;
private string m_ciphertext;
private byte[] m_plaintextbytes;
private byte[] m_ciphertextbytes;
private string m_passPhrase;
private string m_saltValue;
private string m_hashAlgorithm;
private Int32 m_passwordIterations;
private string m_initVector;
private Int32 m_keySize;
public string plaintext
{
get { return m_plaintext; }
set { m_plaintext = value; }
}
public string ciphertext
{
get { return m_ciphertext; }
set { m_ciphertext = value; }
}
public byte[] plaintextbytes
{
get { return m_plaintextbytes; }
set { m_plaintextbytes = value; }
}
public byte[] ciphertextbytes
{
get { return m_ciphertextbytes; }
set { m_ciphertextbytes = value; }
}
public string passPhrase
{
get { return m_passPhrase; }
set { m_passPhrase = value; }
}
public string saltValue
{
get { return m_saltValue; }
set { m_saltValue = value; }
}
public string hashAlgorithm
{
get { return m_hashAlgorithm; }
set { m_hashAlgorithm = value; }
}
public Int32 passwordIterations
{
get { return m_passwordIterations; }
set { m_passwordIterations = value; }
}
public string initVector
{
get { return m_initVector; }
set { m_initVector = value; }
}
public Int32 keySize
{
get { return m_keySize; }
set { m_keySize = value; }
}
public string ASCIIEncrypt(string plaintext2)
{
try
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(m_initVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(m_saltValue);
byte[] plainTextBytes = Encoding.ASCII.GetBytes(plaintext2);
PasswordDeriveBytes password = new PasswordDeriveBytes(m_passPhrase, saltValueBytes, m_hashAlgorithm, m_passwordIterations);
byte[] keyBytes = password.GetBytes(m_keySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
m_ciphertext = Convert.ToBase64String(cipherTextBytes);
return "SUCCESS";
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
public string ASCIIDecrypt(string ciphertext2)
{
try
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(m_initVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(m_saltValue);
byte[] cipherTextBytes = Convert.FromBase64String(ciphertext2);
PasswordDeriveBytes password = new PasswordDeriveBytes(m_passPhrase, saltValueBytes, m_hashAlgorithm, m_passwordIterations);
byte[] keyBytes = password.GetBytes(keySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
m_plaintext = Encoding.ASCII.GetString(plainTextBytes);
return "SUCCESS";
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
}
So append to the qyerstring the ASCIIEncrypt("yourquerstring without encryption string") and when reading read the normal qs paramaters again and compare the hash in the qs to the result.