The problem is to convert non-ASCII characters into binary and vice versa
string of bits to string of char
string result = "";
while (value.Length > 0)
{ var first8 = value.Substring(0, 8);
value = value.Substring(8);
var number = Convert.ToInt64(first8, 2);
result += (char)number;
and
string of char to string of bits
string S = "";
byte[] asciiBytes = Encoding.ASCII.GetBytes(value);
for (int i = 0; i < asciiBytes.Length; i++)
for (int j = 0; j < 8; j++)
{
S += (asciiBytes[i] & 0x80) > 0 ? "1" : "0";
asciiBytes[i] <<= 1;
}
return S;
Can you correct my code if it is the best?
You could split the string into 8 character string, convert it to a byte using Convert.ToByte and then use Encoding.ASCII.GetString to convert the byte array to string.
var str = "0011111110110101001111110110111100111111110110110011111101101111";
var byteArray = Enumerable.Range(0, str.Length / 8)
.Select(x => Convert.ToByte(str.Substring(x * 8, 8), 2)).ToArray();
var convertedString = Encoding.ASCII.GetString(byteArray);
For 8-Bit
Encoding enc = Encoding.GetEncoding(1252);
var convertedString = enc.GetString(byteArray);
Output
?µ?o?Û?o
I'd like to convert this function:
function DoHashPassword($username, $clear_password)
{
return strtoupper(bin2hex(strrev(hex2bin(strtoupper(hash("sha256",strtoupper(hash("sha256", strtoupper($username)).":".strtoupper($clear_password))))))));
}
to C# language.
How can I do that?
At the moment I'm at this point:
Remaining (in PHP)
strtoupper(bin2hex(strrev(hex2bin($password))));
What I've done (in C#)
public static string DoShaHashPassword256(string _email, string _password)
{
byte[] emailbyte = Encoding.ASCII.GetBytes(_email.ToUpper());
var sha_email = SHA256.Create();
byte[] bytehashemail = sha_email.ComputeHash(emailbyte);
_email = HexStringFromBytes(bytehashemail);
//now with password
byte[] passbyte = Encoding.ASCII.GetBytes(_email.ToUpper() + ":" + _password.ToUpper());
var sha_pass = SHA256.Create();
byte[] bytehashpass = sha_pass.ComputeHash(passbyte);
_password = HexStringFromBytes(bytehashpass).ToUpper();
return /* hashed password */
}
private static string HexStringFromBytes(byte[] bytes)
{
var sb = new StringBuilder();
foreach (byte b in bytes)
{
var hex = b.ToString("x2");
sb.Append(hex);
}
return sb.ToString();
}
I don't know how to go on now.
This is the answer to the question. Thanks for your bad votes to my question (you should help, not give bad vote and no answer.).
public static string DoShaHashPassword256(string _email, string _password)
{
byte[] emailbyte = Encoding.ASCII.GetBytes(_email.ToUpper());
var sha_email = SHA256.Create();
byte[] bytehashemail = sha_email.ComputeHash(emailbyte);
_email = HexStringFromBytes(bytehashemail);
//now with password
byte[] passbyte = Encoding.ASCII.GetBytes(_email.ToUpper() + ":" + _password.ToUpper());
var sha_pass = SHA256.Create();
byte[] bytehashpass = sha_pass.ComputeHash(passbyte);
_password = HexStringFromBytes(bytehashpass).ToUpper();
//hex2bin
var bindata = hex2bin(_password);
//strrev
char[] chararray = bindata.ToCharArray();
Array.Reverse(chararray);
var reversedstring = new string(chararray);
//bin2hex
byte[] bytes = Encoding.GetEncoding(1252).GetBytes(reversedstring);
string hexString = HexStringFromBytes(bytes);
return hexString.ToUpper();
}
private static string HexStringFromBytes(byte[] bytes)
{
var sb = new StringBuilder();
foreach (byte b in bytes)
{
var hex = b.ToString("x2");
sb.Append(hex);
}
return sb.ToString();
}
private static string hex2bin(string hexdata)
{
if (hexdata == null)
throw new ArgumentNullException("hexdata");
if (hexdata.Length % 2 != 0)
throw new ArgumentException("hexdata should have even length");
byte[] bytes = new byte[hexdata.Length / 2];
for (int i = 0; i < hexdata.Length; i += 2)
bytes[i / 2] = (byte)(HexValue(hexdata[i]) * 0x10
+ HexValue(hexdata[i + 1]));
return Encoding.GetEncoding(1252).GetString(bytes);
}
private static int HexValue(char c)
{
int ch = (int)c;
if (ch >= (int)'0' && ch <= (int)'9')
return ch - (int)'0';
if (ch >= (int)'a' && ch <= (int)'f')
return ch - (int)'a' + 10;
if (ch >= (int)'A' && ch <= (int)'F')
return ch - (int)'A' + 10;
throw new ArgumentException("Not a hexadecimal digit.");
}
How do we convert UTF-8 HEX: EE 94 93 into equivalent Emoji representation: 1f1e8, 1f1f3
taken from here: http://www.iemoji.com/view/emoji/175/places/regional-indicator-symbol-letters-cn
public static string ConvertEmoji2UnicodeHex(string emoji)
{
if (string.IsNullOrWhiteSpace(emoji))
return emoji;
byte[] bytes = Encoding.UTF8.GetBytes(emoji);
string firstItem = Convert.ToString(bytes[0], 2);
int iv;
if (bytes.Length == 1)
{
iv = Convert.ToInt32(firstItem, 2);
}
else
{
StringBuilder sbBinary = new StringBuilder();
sbBinary.Append(firstItem.Substring(bytes.Length + 1).TrimStart('0'));
for (int i = 1; i < bytes.Length; i++)
{
string item = Convert.ToString(bytes[i], 2);
item = item.Substring(2);
sbBinary.Append(item);
}
iv = Convert.ToInt32(sbBinary.ToString(), 2);
}
return Convert.ToString(iv, 16).PadLeft(4, '0');
}
I have an aes encryption code, i want to make it only return alphanumerical characters like {0123456789ABCDEFGHIJKLMNOPQRSTWUVYZ}
But however i could not figure out how to do that. I have almost no idea about encryption, could not figure out where to fix. I would really apreciate your feedback. Regards...
public class clsCrypto
{
private string _KEY = string.Empty;
protected internal string KEY
{
get
{
return _KEY;
}
set
{
if (!string.IsNullOrEmpty(value))
{
_KEY = value;
}
}
}
private string _IV = string.Empty;
protected internal string IV
{
get
{
return _IV;
}
set
{
if (!string.IsNullOrEmpty(value))
{
_IV = value;
}
}
}
private string CalcMD5(string strInput)
{
string strOutput = string.Empty;
if (!string.IsNullOrEmpty(strInput))
{
try
{
StringBuilder strHex = new StringBuilder();
using (MD5 md5 = MD5.Create())
{
byte[] bytArText = Encoding.Default.GetBytes(strInput);
byte[] bytArHash = md5.ComputeHash(bytArText);
for (int i = 0; i < bytArHash.Length; i++)
{
strHex.Append(bytArHash[i].ToString("X2"));
}
strOutput = strHex.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
return strOutput;
}
private byte[] GetBytesFromHexString(string strInput)
{
byte[] bytArOutput = new byte[] { };
if ((!string.IsNullOrEmpty(strInput)) && strInput.Length % 2 == 0)
{
SoapHexBinary hexBinary = null;
try
{
hexBinary = SoapHexBinary.Parse(strInput);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
bytArOutput = hexBinary.Value;
}
return bytArOutput;
}
private byte[] GenerateIV()
{
byte[] bytArOutput = new byte[] { };
try
{
string strIV = CalcMD5(IV);
bytArOutput = GetBytesFromHexString(strIV);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return bytArOutput;
}
private byte[] GenerateKey()
{
byte[] bytArOutput = new byte[] { };
try
{
string strKey = CalcMD5(KEY);
bytArOutput = GetBytesFromHexString(strKey);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return bytArOutput;
}
protected internal string Encrypt(string strInput, CipherMode cipherMode)
{
string strOutput = string.Empty;
if (!string.IsNullOrEmpty(strInput))
{
try
{
byte[] bytePlainText = Encoding.Default.GetBytes(strInput);
using (RijndaelManaged rijManaged = new RijndaelManaged())
{
rijManaged.Mode = cipherMode;
rijManaged.BlockSize = 128;
rijManaged.KeySize = 128;
rijManaged.IV = GenerateIV();
rijManaged.Key = GenerateKey();
rijManaged.Padding = PaddingMode.Zeros;
ICryptoTransform icpoTransform = rijManaged.CreateEncryptor(rijManaged.Key, rijManaged.IV);
using (MemoryStream memStream = new MemoryStream())
{
using (CryptoStream cpoStream = new CryptoStream(memStream, icpoTransform, CryptoStreamMode.Write))
{
cpoStream.Write(bytePlainText, 0, bytePlainText.Length);
cpoStream.FlushFinalBlock();
}
strOutput = Encoding.Default.GetString(memStream.ToArray());
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
return strOutput;
}
protected internal string Decrypt(string strInput, CipherMode cipherMode)
{
string strOutput = string.Empty;
if (!string.IsNullOrEmpty(strInput))
{
try
{
byte[] byteCipherText = Encoding.Default.GetBytes(strInput);
byte[] byteBuffer = new byte[strInput.Length];
using (RijndaelManaged rijManaged = new RijndaelManaged())
{
rijManaged.Mode = cipherMode;
rijManaged.BlockSize = 128;
rijManaged.KeySize = 128;
rijManaged.IV = GenerateIV();
rijManaged.Key = GenerateKey();
rijManaged.Padding = PaddingMode.Zeros;
ICryptoTransform icpoTransform = rijManaged.CreateDecryptor(rijManaged.Key, rijManaged.IV);
using (MemoryStream memStream = new MemoryStream(byteCipherText))
{
using (CryptoStream cpoStream = new CryptoStream(memStream, icpoTransform, CryptoStreamMode.Read))
{
cpoStream.Read(byteBuffer, 0, byteBuffer.Length);
}
strOutput = Encoding.Default.GetString(byteBuffer);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
return strOutput;
}
}
Encryption and decryption functions use byte arrays as parameters.
So, you must convert these arrays to base 36 string.
You can use the following class (Base36) to make these conversions:
All you have to do, is calling these two functions:
byte[] byteArray;
//To convert byte array to String
string byteArrayInBase36 = Base36.ByteArrayToBase36String(byteArray);
//To convert String to byte Array
byte[] byteArray2 = Base36.Base36StringToByteArray(byteArrayInBase36);
and, this is the class:
using System;
using System.Collections.Generic;
class Base36
{
#region public methods
public static string ByteArrayToBase36String(byte[] bytes)
{
string result = string.Empty;
result = Encode36((ulong)bytes.Length).PadLeft(BASE36_LENGTH_BLOC_SIZE_36, '0');
if (bytes.Length > 0)
{
List<byte[]> byteslist = SplitBytes(bytes, 8);
if (byteslist[byteslist.Count - 1].Length < 8)
{
byte[] newLastArray = new byte[8];
byteslist[byteslist.Count - 1].CopyTo(newLastArray, 0);
byteslist[byteslist.Count - 1] = newLastArray;
}
foreach (byte[] byteArray in byteslist)
{
ulong value = 0;
//for (int i = 0; i < byteArray.Length; i++) value = value * 256 + byteArray[i];
value = BitConverter.ToUInt64(byteArray, 0);
result = result + Encode36(value).PadLeft(BASE36_BLOC_SIZE_36, '0');
}
}
return result;
}
public static byte[] Base36StringToByteArray(string input)
{
byte[] result = new byte[0];
if (input.Length >= BASE36_LENGTH_BLOC_SIZE_36)
{
int arrayLength = (int)Decode36(input.Substring(0, BASE36_LENGTH_BLOC_SIZE_36));
string data = input.Remove(0, BASE36_LENGTH_BLOC_SIZE_36);
List<byte[]> bytesList = new List<byte[]>();
foreach (string value36 in new List<string>(SplitStringByLength(data, BASE36_BLOC_SIZE_36)))
{
byte[] byteArray = BitConverter.GetBytes(Decode36(value36));
bytesList.Add(byteArray);
}
result = JoinBytes(bytesList);
Array.Resize(ref result, arrayLength);
}
return result;
}
#endregion
#region Const
private const int BASE36_LENGTH_BLOC_SIZE_36 = 6;
private const int BASE36_BLOC_SIZE_36 = 13; //Encode36(ulong.MaxValue).Length;
#endregion
#region private methods
static string _CharList36 = string.Empty;
static private string CharList36
{
get
{
if (_CharList36.Length < 36)
{
char[] array = new char[36];
for (int i = 0; i < 10; i++) array[i] = (char)(i + 48);
for (int i = 0; i < 26; i++) array[i + 10] = (char)(i + 97);
_CharList36 = new string(array);
}
return _CharList36;
}
}
private static List<string> SplitStringByLength(string str, int chunkSize)
{
List<string> list = new List<string>();
int i;
for (i = 0; i < str.Length / chunkSize; i++)
{
list.Add(str.Substring(i * chunkSize, chunkSize));
}
i = i * chunkSize;
if (i < str.Length - 1)
list.Add(str.Substring(i, str.Length - i));
return list;
}
private static String Encode36(ulong input)
{
if (input < 0) throw new ArgumentOutOfRangeException("input", input, "input cannot be negative");
char[] clistarr = CharList36.ToCharArray();
var result = new Stack<char>();
while (input != 0)
{
result.Push(clistarr[input % 36]);
input /= 36;
}
return new string(result.ToArray()).ToUpper();
}
private static ulong Decode36(string input)
{
var reversed = ReverseString(input.ToLower());
ulong result = 0;
int pos = 0;
foreach (char c in reversed)
{
result += (ulong)CharList36.IndexOf(c) * (ulong)Math.Pow(36, pos);
pos++;
}
return result;
}
private static string ReverseString(string text)
{
char[] cArray = text.ToCharArray();
string reverse = String.Empty;
for (int i = 0; i < cArray.Length / 2; i++)
{
char c = cArray[i];
cArray[i] = cArray[cArray.Length - 1 - i];
cArray[cArray.Length - 1 - i] = c;
}
return new string(cArray);
}
private static byte[] StringToBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
private static List<byte[]> SplitBytes(byte[] bytes, int length)
{
List<byte[]> result = new List<byte[]>();
int position = 0;
while (bytes.Length - position > length)
{
byte[] temp = new byte[length];
for (int i = 0; i < temp.Length; i++) temp[i] = bytes[i + position];
position += length;
result.Add(temp);
}
if (position < bytes.Length)
{
byte[] temp = new byte[bytes.Length - position];
for (int i = 0; i + position < bytes.Length; i++) temp[i] = bytes[i + position];
result.Add(temp);
}
return result;
}
private static string BytesToString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
private static byte[] JoinBytes(List<byte[]> listBytes)
{
int totalLength = 0;
foreach (byte[] bytes in listBytes) totalLength += bytes.Length;
byte[] result = new byte[totalLength];
int position = 0;
foreach (byte[] bytes in listBytes)
for (int i = 0; i < bytes.Length; i++)
{
result[position] = bytes[i];
position++;
}
return result;
}
#endregion
}
You can encode the resulting bytes using Base36 or another such binary-to-text encoding.
For some time I've been a bit desperately trying to implement a TLS 1.1 in my application. The reason behind this is the usage of SocketType.Raw sockets, so no SslStream or other higher-level classes are available to me.
So far I'm stuck at Finished message in TLS handshake protocol - keep on receiving bad_record_mac(20) in server response. Cipher suite is 0x0005 - TLS_RSA_WITH_RC4_128_SHA.
Here's some sample code on what's happening:
byte[] client_random, server_random = new byte[28];
byte[] pre_master_secret, master_secret;
byte[] client_write_MAC_secret, server_write_MAC_secret, client_write_key, server_write_key;
byte[] handshake_messages, verify_data;
RSACryptoServiceProvider rsa;
List<X509Certificate2> certificates = new List<X509Certificate2>();
//certificates are added
rsa = (RSACryptoServiceProvider)certificates.First().PublicKey.Key;
private byte[] ClientKeyExchange()
{
pre_master_secret = new byte[48];
(new Random()).NextBytes(pre_master_secret);
//version 0302 for TLS 1.1
pre_master_secret[0] = 3;
pre_master_secret[1] = 2;
byte[] cryptedData = rsa.Encrypt(pre_master_secret, false);
//"1603020086"
string tmp_string = "100000820080" + Utils.BitConverter.ToString(cryptedData).Replace("-", "");
AddHandShakeData(Utils.BitConverter.StringToByteArray(tmp_string));
tmp_string =
"1603020086"
+ tmp_string
+ "140302000101" //Cipher Change Spec
+ "";
return Utils.BitConverter.StringToByteArray(tmp_string);
}
private void ComputeMasterSecret()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("master secret", Encoding.ASCII));
byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);
master_secret = PRF(pre_master_secret, label, seed, 48);
}
private void ComputeKeys()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("key expansion", Encoding.ASCII));
byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);
byte[] key_material = PRF(master_secret, label, seed, 72);
client_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 0, client_write_MAC_secret, 0, 20);
server_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 20, server_write_MAC_secret, 0, 20);
client_write_key = new byte[16];
Buffer.BlockCopy(key_material, 40, client_write_key, 0, 16);
server_write_key = new byte[16];
Buffer.BlockCopy(key_material, 56, server_write_key, 0, 16);
}
private void ComputeVerifyData()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("client finished", Encoding.ASCII));
SHA1 sha1 = SHA1.Create();
MD5 md5 = MD5.Create();
md5.ComputeHash(handshake_messages);
sha1.ComputeHash(handshake_messages);
byte[] seed = new byte[md5.HashSize / 8 + sha1.HashSize / 8];
Buffer.BlockCopy(md5.Hash, 0, seed, 0, md5.HashSize / 8);
Buffer.BlockCopy(sha1.Hash, 0, seed, md5.HashSize / 8, sha1.HashSize / 8);
verify_data = PRF(master_secret, label, seed, 12);
}
private byte[] PRF(byte[] secret, byte[] label, byte[] seed, int output_size)
{
int md5_iterations = (int)Math.Ceiling((double)output_size / 16),
sha1_iterations = (int)Math.Ceiling((double)output_size / 20);
byte[] md5_data = new byte[output_size],
sha1_data = new byte[output_size];
//особое колдунство для нечетного числа
byte[] secret_1 = new byte[(int)Math.Ceiling((double)secret.Length / 2)],
secret_2 = new byte[(int)Math.Ceiling((double)secret.Length / 2)];
Buffer.BlockCopy(secret, 0, secret_1, 0, secret_1.Length);
Buffer.BlockCopy(secret, secret.Length / 2, secret_2, 0, secret_2.Length);
byte[] A = new byte[label.Length + seed.Length];
Buffer.BlockCopy(label, 0, A, 0, label.Length);
Buffer.BlockCopy(seed, 0, A, label.Length, seed.Length);
byte[] tmp = new byte[md5_iterations * 16];
//A(1) ?
//A = P_MD5(secret_1, A);
for (int i = 0; i < md5_iterations; i++)
{
A = P_MD5(secret_1, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, md5_data, 0, md5_data.Length); //output_size = md5_data.Length
tmp = new byte[sha1_iterations * 20];
//does it have to start with A(1) ?
//A = P_SHA1(secret_2, A);
for (int i = 0; i < sha1_iterations; i++)
{
A = P_SHA1(secret_2, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, sha1_data, 0, sha1_data.Length); //output_size = sha1_data.Length
for (int i = 0; i < output_size; i++)
md5_data[i] = (byte)(md5_data[i] ^ sha1_data[i]);
return md5_data;
}
private byte[] P_MD5(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACMD5 HMD5 = new HMACMD5(secret);
HMD5.ComputeHash(seed);
return HMD5.Hash;
}
private byte[] P_SHA1(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACSHA1 HSHA1 = new HMACSHA1(secret);
HSHA1.ComputeHash(seed);
return HSHA1.Hash;
}
private byte[] MAC(byte[] secret, byte[] data)
{
byte[] secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);
for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)54);
byte[] xor_output_data = new byte[64 + data.Length];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(data, 0, xor_output_data, 64, data.Length);
SHA1 sha1 = SHA1.Create();
sha1.ComputeHash(xor_output_data);
secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);
for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)92);
xor_output_data = new byte[64 + sha1.HashSize / 8];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(sha1.Hash, 0, xor_output_data, 64, sha1.HashSize / 8);
sha1.ComputeHash(xor_output_data);
return sha1.Hash;
}
public void RC4(ref Byte[] bytes, Byte[] key)
{
Byte[] s = new Byte[128];
Byte[] k = new Byte[128];
Byte temp;
int i, j;
for (i = 0; i < 128; i++)
{
s[i] = (Byte)i;
k[i] = key[i % key.GetLength(0)];
}
j = 0;
for (i = 0; i < 128; i++)
{
j = (j + s[i] + k[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
i = j = 0;
for (int x = 0; x < bytes.GetLength(0); x++)
{
i = (i + 1) % 128;
j = (j + s[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
int t = (s[i] + s[j]) % 128;
bytes[x] ^= s[t];
}
}
Obviously, reading such a bunch of code ain't being the best way to spend your time, so I'd like to add some questions that, hopefully, can help a lot:
HMAC_MD5 and HMAC_SHA1 - in .Net implementation they take key and they take input byte[] to compute hash from. According to RFC4346:
First, we define a data expansion function, P_hash(secret, data)
which uses a single hash function to expand a secret and seed into an
arbitrary quantity of output:
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
Where + indicates concatenation.
A() is defined as:
A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))
What is seed? Is it data we compute hash from? Secret = key, so far I understand. Also, do we start P_hash with A(1)?
Thanks in advance!
Seed is Client_random + Server_random. You need to preserve them from preceding steps of the handshake, the client_hello and server_hello.
A(0) = seed
A(i) = HMAC_hash(secret,A(i-1)) for i>0
The output of the A() function consists of A(1), A(2), A(3)...