Been trying to venture out and learn some C# and powershell, giving myself little projects to try and learn. Recently I have been trying to convert some code from powershell to C# and I believe I got it working but am coming across some errors creating the IV for RijndaelManaged.
This is the powershell code that works fine, pulled from the internet
function Decrypt-String($Encrypted, $Passphrase, $salt, $init="Yet another key")
{
if($Encrypted -is [string]){
$Encrypted = [Convert]::FromBase64String($Encrypted)
}
$r = new-Object System.Security.Cryptography.RijndaelManaged
$pass = [System.Text.Encoding]::UTF8.GetBytes($Passphrase)
$salt = [System.Text.Encoding]::UTF8.GetBytes($salt)
$r.Key = (new-Object Security.Cryptography.PasswordDeriveBytes $pass, $salt, "SHA1", 5).GetBytes(32) #256/8
$r.IV = (new-Object Security.Cryptography.SHA1Managed).ComputeHash( [Text.Encoding]::UTF8.GetBytes($init) )[0..15]
$d = $r.CreateDecryptor()
$ms = new-Object IO.MemoryStream #(,$Encrypted)
$cs = new-Object Security.Cryptography.CryptoStream $ms,$d,"Read"
$sr = new-Object IO.StreamReader $cs
Write-Output $sr.ReadToEnd()
$sr.Close()
$cs.Close()
$ms.Close()
$r.Clear()
}
And this is the C# code i moved it over to
public static string Decrypt_String(string cipherText, string passPhrase, string Salt)
{
string hashAlgorithm = "SHA1";
int passwordIterations = 5;
initName = "Yet another key";
using (RijndaelManaged r = new RijndaelManaged())
{
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
byte[] PassPhraseBytes = Encoding.UTF8.GetBytes(passPhrase);
byte[] SaltBytes = Encoding.UTF8.GetBytes(Salt);
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initName);
PasswordDeriveBytes password = new PasswordDeriveBytes(PassPhraseBytes,SaltBytes,hashAlgorithm,passwordIterations);
byte[] keyBytes = password.GetBytes(32); //(256 / 32)
r.Key = keyBytes;
SHA1Managed cHash = new SHA1Managed();
r.IV = cHash.ComputeHash(Encoding.UTF8.GetBytes(initName),0,16);
ICryptoTransform decryptor = r.CreateDecryptor();
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream,
decryptor,
CryptoStreamMode.Read);
StreamReader streamReader = new StreamReader(cryptoStream);
string output = streamReader.ReadToEnd();
return output;
}
}
Currently the ComputeHash is spitting back an error telling me the value is invalid.
here are the values I am using from the working encrypt function
cipherText = "s6ZqNpJq05jsMh2+1BxZzJQDDiJGRQPqIYzBjYQHsgw="
saltValue = "}=[BJ8%)vjJDnQfmvC))))3Q"
passphrase = "S#lt3d"
Any ideas on why the IV wont set properly?
EDIT:
Sorry the exception is
Line 38: r.IV = cHash.ComputeHash(initVectorBytes, 0, 16);
Exception Details: System.ArgumentException: Value was invalid.
Kind of generic
#Nate is correct, you are using a different overload of the ComputeHash method, and you are not quite handling it properly:
Encoding.UTF8.GetBytes(initName)
This will return a byte array the same length as your string - 15. But by passing 0 and 16, you are asking ComputeHash to use the first 16 elements of the array.
cHash.ComputeHash(Encoding.UTF8.GetBytes(initName),0,16);
So this first fix is to either pass 0 and 15 (or maybe 0 and initName.Length), or better yet, go back to the overload you are using in your powershell script, which figures out the array length automatically:
cHash.ComputeHash(Encoding.UTF8.GetBytes(initName));
But you will need to shorten the resulting array (it comes back length 20, but you only want 16):
using System.Linq;
...
cHash.ComputeHash(Encoding.UTF8.GetBytes(initName)).Take(16).ToArray();
Related
I am trying to solve an encryption issue I am having between php and c#.
I have encrypted data using the following php and openssl operation.
$encrypt_method = "AES-256-CBC";
$secret_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$secret_iv = 'XXXXXXXXXXXXXXXX';
$key = hash ('sha256', $secret_key);
$iv = substr (hash ('sha256', $secret_iv), 0, 16);
$output = openssl_encrypt ($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode ($output);
I have tried a couple of methods in C# to decrypt but this is what I am trying now.
public string Encrypt_Decrypt(string action, string value) {
string secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string secretIV = "XXXXXXXXXXXXXXXX";
string key = Hash(secretKey);
string iv = Hash(secretIV).Substring(0,16);
string retValue = "";
if (action == "encrypt") {
retValue = EncryptString(value, key, iv);
}
else if (action == "decrypt") {
retValue = DecryptString(value, key, iv);
}
}
// Hash to match php hash function
public static string Hash(string unhashedString) {
return BitConverter.ToString(new SHA256CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(unhashedString))).Replace("-", String.Empty).ToLower();
}
public static string DecryptString(string cipherData, string keyString, string ivString) {
byte[] key = Encoding.UTF8.GetBytes(keyString);
Console.WriteLine(key.Length);
byte[] iv = Encoding.UTF8.GetBytes(ivString);
Console.WriteLine(iv.Length);
byte[] cipherCrypt = Convert.FromBase64String(cipherData);
for (int i = 0; i < cipherCrypt.Length; i++) {
Console.Write(cipherCrypt[i] + " ");
}
try {
RijndaelManaged crypto = new RijndaelManaged();
crypto.Key = key;
crypto.IV = iv;
crypto.Mode = CipherMode.CBC;
crypto.KeySize = 256;
crypto.BlockSize = 128;
crypto.Padding = PaddingMode.None;
ICryptoTransform decryptor = crypto.CreateDecryptor(crypto.Key, crypto.IV);
using (MemoryStream memStream = new MemoryStream(cipherCrypt)) {
using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) {
using (StreamReader streamReader = new StreamReader(cryptoStream)) {
return streamReader.ReadToEnd();
}
}
}
}
catch (CryptographicException e) {
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
I have tried a couple different encoding types when getting the byte[] for the operation.
I keep getting the following error:
Specified key is not a valid size for this algorithm.
Not sure what I am missing. Any help is appreciated.
Also, I already read through this and tried what the solution suggestion recommended. I got the same resulting error.
UPDATE - 01
I have updated the code here to reflect the code I have changed.
The key length is 32,
The iv length is 16,
The data coming in at "cipherData" is length 32,
When "cipherData" goes through "FromBase64String(cipherData)" it comes out as a 24 byte array. This is causing an issue for the decryptor which wants a 32 byte array.
There are obviously problems with the key size. The code between PHP and C# seem to match. The problem seems to be that the code is wrong in both cases.
Let's see how long the key actually is:
Start with a 32 byte key (non-encoded).
Hash the key with SHA-256: 32 bytes (non-encoded).
Encode to hex (integrated into PHP's hash() function by default): 64 bytes.
AES only supports the following key sizes: 16, 24 and 32 bytes. openssl_encrypt() will only use the first 32 bytes of the hex key silently. So, you need to use the first 32 bytes in C#.
Note that openssl_encrypt() takes an options argument which denotes that the output is Base64 when OPENSSL_RAW_DATA is not set. It means that the PHP output was encoded twice with Base64. So you need to decode it twice in C#.
<Original Code From Here>
I came across this thread while googling. However after trying it out and making adjustments, I've come across a hurdle, hopefully someone can help me out a bit.
The code above is fine but since the algorithm isn't really useful without making the IV change everytime, I tried using following code to generate iv but it kept saying "Specified key is not a valid size for this algorithm." in my C# debugger.
I also tried outputting IV from the C# code, after decoding base 64 string the string length varies from 30 31 2X ==> basically just fluctuates for some reason.
I also would like to change the KEY as well but couldn't due to similar reasons as the IV issue, so hopefully someone can help me out with that?
(I've tried the following from http://php.net/manual/en/function.mcrypt-encrypt.php, couldn't get it to work in harmony with C#, maybe once I fix the IV issue I'll be able to fix this as well?
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3"); )
PHP========================
<?php
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
//$iv = "45287112549354892144548565456541";
$key = "anjueolkdiwpoida";
$text = "This is my encrypted message";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
$crypttext = urlencode($crypttext);
$crypttext64=base64_encode($crypttext);
print($crypttext64) . "\n<br/>";
print(base64encode($iv)) . "\n<br/>";
?>
C#========================
string iv = Encoding.UTF8.GetString(Convert.FromBase64String("SOME IV STRING I COPY FROM BROSWER WITH ABOVE PHP LOADED"));
string kyy = "anjueolkdiwpoida";
//ciphertext is also SOME TXT STRING I COPIED FROM BROWSER WITH ABOVE PHP LOADED
string plainText = ValidationControls.DecryptRJ256(cipherText, kyy, iv);
public byte[] Decode(string str)
{
var decbuff = Convert.FromBase64String(str);
return decbuff;
}
static public String DecryptRJ256(byte[] cypher, string KeyString, string IVString)
{
var sRet = "";
var encoding = new UTF8Encoding();
var Key = encoding.GetBytes(KeyString);
var IV = encoding.GetBytes(IVString);
using (var rj = new RijndaelManaged())
{
try
{
rj.Padding = PaddingMode.PKCS7;
rj.Mode = CipherMode.CBC;
rj.KeySize = 256;
rj.BlockSize = 256;
rj.Key = Key;
rj.IV = IV;
var ms = new MemoryStream(cypher);
using (var cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Read))
{
using (var sr = new StreamReader(cs))
{
sRet = sr.ReadLine();
}
}
}
catch (Exception exc) { Console.WriteLine(exc.Message); App.Current.Shutdown(); }
finally
{
rj.Clear();
}
}
return sRet;
}
I realized that .NET decoding for Base 64 string is really weird. When I called DecryptRJ256() I was sending in the Key and IV that I received from the php code by a series of conversion base64_string -> byte -> utf8_string before sending both into the function. The solution to this is to just send in the byte array directly and let DecryptRJ256() deal with it directly.
After doing the above, the problem with automated Key and IV generation becomes apparent and no longer is a problem.
Code Modified From Question:
PHP
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
$text = "This is my encrypted message";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
$crypttext = base64_encode($crypttext);
$key= base64_encode($key);
$iv = base64_encode($iv);
C#
string plainText = ValidationControls.DecryptRJ256(Convert.FromBase64String("/*$CRYPTTEXT STRING FROM PHP*/"), Convert.FromBase64String("/*$KEY STRING FROM PHP*/"), Convert.FromBase64String("/*$ STRING FROM PHP*/"));
static public String DecryptRJ256(byte[] cypher, byte[] KeyString, byte[] IVString)
{
...
var Key = KeyString;
//var Key = encoding.GetBytes(KeyString);
var IV = IVString;
//var IV = encoding.GetBytes(IVString);
...
}
(preface: I'm a newbie with encryption and security, figured this would be a fun way to learn)
I'm building a program in C# that communicates with a server written in PHP using standard HTTP protocol. I want both programs to be able to send and receive encrypted data. However, there appear to be inconsistencies regarding how the encryption is being handled, despite them both using the same kind of functions.
Both programs use Rjindael 128 bit in CBC mode.
For demonstration / testing, I made two functions that are virtually identical, each taking the same string, encrypting it, and spitting out the result as a base64 string.
The PHP function:
public static function EncryptionTest () {
echo 'Testing Encryption to base64 string...<br/>';
$originalString = 'This is the original String! How cool is that?';
$key = "abcdefghijklmnopqrstuvwxyz012345";
$iv = "1234567890123456";
$encrypted = mcrypt_encrypt (MCRYPT_RIJNDAEL_128, $key, $originalString, MCRYPT_MODE_CBC, $iv);
echo base64_encode ($encrypted);
}
And it's C# counterpart:
public static void EncryptionTest ()
{
System.Console.WriteLine ("Testing Encryption to base64 string...");
string originalString = "This is the original String! How cool is that?";
byte [] encryptedData;
byte [] key = System.Text.ASCIIEncoding.UTF8.GetBytes ("abcdefghijklmnopqrstuvwxyz012345");
byte [] iv = System.Text.ASCIIEncoding.UTF8.GetBytes ("1234567890123456");
RijndaelManaged cryptor = new RijndaelManaged ();
cryptor.Key = key;
cryptor.IV = iv;
cryptor.BlockSize = 128;
cryptor.Mode = CipherMode.CBC;
ICryptoTransform encryptor = cryptor.CreateEncryptor (cryptor.Key, cryptor.IV);
using (MemoryStream msEncrypt = new MemoryStream ())
{
using (CryptoStream csEncrypt = new CryptoStream (msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter (csEncrypt) )
{
swEncrypt.Write (originalString);
}
encryptedData = msEncrypt.ToArray ();
}
}
System.Console.WriteLine (System.Convert.ToBase64String (encryptedData) );
}
Now, here is the PHP result:
Testing Encryption to base64 string...
yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv
And the C# result:
Testing Encryption to base64 string...
yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW+OQ68m6cpp
As you can see, the two results are clearly encrypted (good), are the same number of characters (good), but are different (could be bad).
I wrote decryption tests which take these strings and process them. Here is the PHP function:
public static function DecryptionTest () {
$phpBase64 = 'yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv';
$csBase64 = 'yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW+OQ68m6cpp';
$key = "abcdefghijklmnopqrstuvwxyz012345";
$iv = "1234567890123456";
$phpEncrypted = base64_decode ($phpBase64);
$phpDecrypted = mcrypt_decrypt (MCRYPT_RIJNDAEL_128, $key, $phpEncrypted, MCRYPT_MODE_CBC, $iv);
$csEncrypted = base64_decode ($csBase64);
$csDecrypted = mcrypt_decrypt (MCRYPT_RIJNDAEL_128, $key, $csEncrypted, MCRYPT_MODE_CBC, $iv);
echo 'Decrypted PHP string: "' . $phpDecrypted . '"<br/>' .
'Decrypted CS string: "' . $csDecrypted . '"';
}
And the C# version:
public static void DecryptionTest ()
{
System.Console.WriteLine ("Testing Decryption for PHP and CS generated base64 strings!");
string phpBase64 = "yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUOJdFykLjsaKfK4VfaBGRv";
string csBase64 = "yzwIdowhLj+cMOFPMuHSA80pWQ6R8yfFQlEsLx5kIzUg74mGEQf9iW+OQ68m6cpp";
byte [] phpEncrypted = System.Convert.FromBase64String (phpBase64);
byte [] csEncrypted = System.Convert.FromBase64String (csBase64);
string phpDecrypted;
string csDecrypted;
byte [] encryptedData;
byte [] key = System.Text.ASCIIEncoding.UTF8.GetBytes ("abcdefghijklmnopqrstuvwxyz012345");
byte [] iv = System.Text.ASCIIEncoding.UTF8.GetBytes ("1234567890123456");
RijndaelManaged cryptor = new RijndaelManaged ();
cryptor.Key = key;
cryptor.IV = iv;
cryptor.BlockSize = 128;
cryptor.Mode = CipherMode.CBC;
ICryptoTransform decryptor = cryptor.CreateDecryptor (cryptor.Key, cryptor.IV);
using (MemoryStream msDecrypt = new MemoryStream (csEncrypted))
{
using (CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader swDecrypt = new StreamReader (csDecrypt) )
{
csDecrypted = swDecrypt.ReadToEnd ();
}
}
}
System.Console.WriteLine ("Decrypted CS string: \"" + csDecrypted + "\"");
using (MemoryStream msDecrypt = new MemoryStream (phpEncrypted))
{
using (CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader swDecrypt = new StreamReader (csDecrypt) )
{
phpDecrypted = swDecrypt.ReadToEnd ();
}
}
}
System.Console.WriteLine ("Decrypted PHP string: \"" + phpDecrypted + "\"");
}
The PHP results:
Decrypted PHP string: "This is the original String! How cool is that?"
Decrypted CS string: "This is the original String! How cool is that?"
And the C# results:
Decrypted CS string: "This is the original String! How cool is that?"
CryptographicException: Bad PKCS7 padding. Invalid length 0.
at Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException (PaddingMode padding, Int32 length, Int32 position) [0x0005c] in > /Applications/buildAgent/work/84669f285f6a667f/mcs/class/corlib/Mono.Security.Cryptography/SymmetricTransform.cs:363
So, basically, the PHP code can successfully decrypt both base64 strings, but the C# code can only decrypt base64 strings that were created by its own decryptor.
A lot of this is code I found on the internet and modified to suit my needs. Like I said, I'm a newbie with cryptography, but I've gotten decently far here. I could theorize and test all day, but it's starting to eat into my schedule so I'm looking for insights from others as to why it isn't working. Thank you!
You need to use the PHPSecLib because the PHP implementation is not compatible with C++/C#. It has a different padding size (not a crypto expert here but this is what I found after days of testing). So use the native implementations in the phpseclib and it will work.
Bumped into this issue a while ago myself. But with C++ / CryptoAPI and PHP.
I am having difficulty encrypting something in C#.
I have 3 variables.
First one is a 16 digit hex,lets call it X value I.E 0072701351979990
Second one is also a 16 digit hex value, lets call it Y I.E 3008168011FFFFFF
These two values have to be XOR 'ed to get the key for the DES-ECB encryption.
Thus resulting in 307a66934068666f . Now thus is my keyblock for the encryption.
Then i have this as my datablock,which is 64 bits for encryption 0E329232EA6D0D73
Now i have the following code for encryption this.
The result of the encryption should be XOR'ed with the datablock again and
result in a 64bit result. This is not the case.
This is my code for the encryption
$ public static string DESEncrypt(string keyBlock,string dataBlock){
DES desEncrypt = new DESCryptoServiceProvider();
byte[] keyBlockBytes = BitConverter.GetBytes(Convert.ToInt64(keyBlock, 16));
byte[] dataBlockBytes = BitConverter.GetBytes(Convert.ToInt64(dataBlock, 16));
desEncrypt.Mode = CipherMode.ECB;
desEncrypt.Key = keyBlockBytes;
ICryptoTransform transForm = desEncrypt.CreateEncryptor();
MemoryStream enecryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(enecryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(dataBlockBytes, 0, dataBlockBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] encryptedData = new byte[enecryptedStream.Length];
enecryptedStream.Position = 0;
enecryptedStream.Read(encryptedData, 0, encryptedData.Length);
string enCryptedHex = BitConverter.ToString(encryptedData);
return enCryptedHex.Replace("-","");
}
What am i doing wrong?
UPDATED QUESTION
I have tested the above solution from CodeInChaos.
It does give me back a 64 bit result. But still there is something wrong.
Here is my updated code.
The keyblock value is abababababababab
and the data block value is 215135734068666F.
The resultant 64 bit result should be XOR'ed with the data block again.
The final answer is suppose to be 414945DD33C97C47 but I get
288a08c01a57ed3d.
Why does it not come out right?
Here is the specifications in suppliers documentation for the encryption.
Encryption is DEA in accordance with FIPS 46-3, single DES in ECB mode, using a single 64-
bit DES Key with odd parity.
$ public static string DESEncrypt(string keyBlock,string dataBlock){
DES desEncrypt = new DESCryptoServiceProvider();
byte[] keyBlockBytes = BitConverter.GetBytes(Convert.ToInt64(keyBlock, 16));
byte[] dataBlockBytes = BitConverter.GetBytes(Convert.ToInt64(dataBlock, 16));
desEncrypt.Mode = CipherMode.ECB;
desEncrypt.Key = keyBlockBytes;
desEncrypt.Padding = PaddingMode.None;
ICryptoTransform transForm = desEncrypt.CreateEncryptor();
MemoryStream enecryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(enecryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(dataBlockBytes, 0, dataBlockBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] encryptedData = enecryptedStream.ToArray();
string enCryptedHex = BitConverter.ToString(encryptedData);
enCryptedHex = enCryptedHex.Replace("-", "");
long iDeaEncrypt = Convert.ToInt64(enCryptedHex, 16);
long iDataBlock = Convert.ToInt64(dataBlock, 16);
long decoderKey = iDeaEncrypt ^ iDataBlock;
string decKeyHex = Convert.ToString(decoderKey, 16);
return decKeyHex;
}
I think you need to set the padding to PaddingMode.None:
desEncrypt.Padding = PaddingMode.None;
But you should really think hard, if DES and ECB is really what you want.
b.t.w.
byte[] encryptedData = new byte[enecryptedStream.Length];
encryptedStream.Position = 0;
encryptedStream.Read(encryptedData, 0, encryptedData.Length);
can be replaced by:
encryptedData = encryptedStream.ToArray();
Perhaps it is necessary to set DES Provider to use the FIPS 46-3 Standard so that the DEA uses the permutation tables etc. specified in FIPS 46-3. Unfortunately I’m also struggling with this same issue.
I have the following .Net code which takes two inputs. 1) A 128 bit base 64 encoded key and 2) the userid. It outputs the AES encrypted token.
I need the php equivalent of the same code, but dont know which corresponding php classes are to be used for RNGCryptoServiceProvider,RijndaelManaged,ICryptoTransform,MemoryStream and CryptoStream.
Im stuck so any help regarding this would be really appreciated.
using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
class AESToken
{
[STAThread]
static int Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Usage: AESToken key userId\n");
Console.WriteLine("key Specifies 128-bit AES key base64 encoded supplied by MediaNet to the partner");
Console.WriteLine("userId specifies the unique id");
return -1;
}
string key = args[0];
string userId = args[1];
StringBuilder sb = new StringBuilder();
// This example code uses the magic string “CAMB2B”. The implementer
// must use the appropriate magic string for the web services API.
sb.Append("CAMB2B");
sb.Append(args[1]); // userId
sb.Append('|'); // pipe char
sb.Append(System.DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ssUTC")); //timestamp
Byte[] payload = Encoding.ASCII.GetBytes(sb.ToString());
byte[] salt = new Byte[16]; // 16 bytes of random salt
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(salt); // the plaintext is 16 bytes of salt followed by the payload.
byte[] plaintext = new byte[salt.Length + payload.Length];
salt.CopyTo(plaintext, 0);
payload.CopyTo(plaintext, salt.Length);
// the AES cryptor: 128-bit key, 128-bit block size, CBC mode
RijndaelManaged cryptor = new RijndaelManaged();
cryptor.KeySize = 128;
cryptor.BlockSize = 128;
cryptor.Mode = CipherMode.CBC;
cryptor.GenerateIV();
cryptor.Key = Convert.FromBase64String(args[0]); // the key
byte[] iv = cryptor.IV; // the IV.
// do the encryption
ICryptoTransform encryptor = cryptor.CreateEncryptor(cryptor.Key, iv);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
cs.Write(plaintext, 0, plaintext.Length);
cs.FlushFinalBlock();
byte[] ciphertext = ms.ToArray();
ms.Close();
cs.Close();
// build the token
byte[] tokenBytes = new byte[iv.Length + ciphertext.Length];
iv.CopyTo(tokenBytes, 0);
ciphertext.CopyTo(tokenBytes, iv.Length);
string token = Convert.ToBase64String(tokenBytes);
Console.WriteLine(token);
return 0;
}
}
Please help.
Thank You.
We are also trying figure out the same C# in PHP. You can post your code without the key.
First approach:
// Open the cipher:
// Using Rijndael 128 in CBC mode.
$m = mcrypt_module_open('rijndael-128', '', 'cbc', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($m), MCRYPT_RAND);
// Initialize the encryption:
mcrypt_generic_init($m, (base64_decode($key_)), $iv);
// Encrypt the data:
$cryptext = mcrypt_generic($m, $plain_text);
//echo "IV SIZE ".mcrypt_enc_get_iv_size($m);
$tx2 = base64_encode($iv.$cipherText);
// Close the encryption handler:
mcrypt_generic_deinit($m);
// Close the cipher:
mcrypt_module_close($m);
Second approach for initialization:
$m = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$iv_size = mcrypt_enc_get_iv_size($m);
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($m), MCRYPT_RAND);
$key128 = base64_decode($key_);
// Encrypt the data:
$cryptext = mcrypt_generic($m, $plain_text);
$tx2 = base64_encode($iv.$cipherText);
// Close the encryption handler:
mcrypt_generic_deinit($m);
You would use the mcrypt library in PHP to implement the same functionality.
You can see the following code that works:
<?php
class UserData
{
public $email;
public $name;
public $expires;
}
class Application
{
private $api_key = "<private_key>";
private $app_key = "appkey";
public function run()
{
$user = new UserData();
$date = new DateTime(null, new DateTimeZone('UTC'));
$date->modify('+5 minute');
$user->expires = $date->format('c');
$user->email = "testing#domain.com";
$user->name = "PHP5 Example";
$encrypted_data = $this->encryptUserData($user);
// Example login URL
printf("http://<domain>/multipass?sso=%s", $encrypted_data);
}
private function encryptUserData($user_data)
{
$app_key = $this->app_key;
$api_key = $this->api_key;
$json = json_encode($user_data);
$salted = $api_key . $app_key;
$saltedHash = substr(sha1($salted, true), 0, 16);
$pad = 16 - (strlen($json) % 16);
$data = $json . (str_repeat(chr($pad), $pad));
if (!function_exists('mcrypt_encrypt'))
throw new Exception('Mcrypt extension is not installed for PHP.');
$aes = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $saltedHash, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16));
$b64token = base64_encode($aes);
$b64token = rtrim(str_replace(array('+', '/'), array('-', '_'), $b64token), '=');
return $b64token;
}
}
$app = new Application();
$app->run();
?>
I hope it will be helpful for you. Thanks.