Created
August 10, 2024 03:09
-
-
Save phuonglazy/5eb82055447407f6f5028f415efb7d22 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class EncryptPasswordKeyFetch | |
{ | |
static string public_key; | |
static byte key_id; | |
public static void GetPwdKeyFetch() | |
{ | |
Leaf.xNet.HttpRequest request = new Leaf.xNet.HttpRequest(); | |
Leaf.xNet.RequestParams requestParams = new Leaf.xNet.RequestParams(); | |
requestParams["version"] = "2"; | |
requestParams["flow"] = "CONTROLLER_INITIALIZATION"; | |
requestParams["locale"] = "en_US"; | |
requestParams["client_country_code"] = "US"; | |
requestParams["method"] = "GET"; | |
requestParams["fb_api_req_friendly_name"] = "pwdKeyFetch"; | |
requestParams["fb_api_caller_class"] = "Fb4aAuthHandler"; | |
requestParams["access_token"] = "350685531728|62f8ce9f74b12f84c123cc23437a4a32"; | |
string text = request.Post("https://b-graph.facebook.com//pwd_key_fetch", requestParams).ToString(); | |
dynamic jsonSSL = JsonConvert.DeserializeObject<dynamic>(text); | |
public_key = (string)jsonSSL["public_key"]; | |
key_id = Convert.ToByte(jsonSSL["key_id"]); | |
Console.WriteLine($"public_key: {public_key}"); | |
Console.WriteLine($"key_id: {jsonSSL["key_id"]}"); | |
} | |
public static string Encrypt(string password) | |
{ | |
byte[] encryptionKey = GenerateSaltNewInstance(32); | |
byte[] encryptionIV = GenerateSaltNewInstance(12); | |
string current_time = DateTimeHelper.ToUnixTime().ToString(); | |
byte[] current_time_byte = Encoding.UTF8.GetBytes(current_time); | |
RSACryptoServiceProvider rsa = ImportPublicKeyRSA(public_key); | |
byte[] encrypted_rand_key = rsa.Encrypt(encryptionKey, RSAEncryptionPadding.Pkcs1); | |
//================================================================================= | |
int tagLenth = 16; | |
var plaintextBytes = Encoding.UTF8.GetBytes(password); | |
var bcCiphertext = new byte[plaintextBytes.Length + tagLenth]; | |
var cipher = new GcmBlockCipher(new AesEngine()); | |
var parameters = new AeadParameters(new KeyParameter(encryptionKey), tagLenth * 8, encryptionIV); | |
cipher.Init(true, parameters); | |
cipher.ProcessAadBytes(current_time_byte, 0, current_time_byte.Length); | |
var offset = cipher.ProcessBytes(plaintextBytes, 0, plaintextBytes.Length, bcCiphertext, 0); | |
cipher.DoFinal(bcCiphertext, offset); | |
// Bouncy Castle includes the authentication tag in the ciphertext | |
var ciphertext = new byte[plaintextBytes.Length]; | |
var auth_tag = new byte[tagLenth]; | |
Buffer.BlockCopy(bcCiphertext, 0, ciphertext, 0, plaintextBytes.Length); | |
Buffer.BlockCopy(bcCiphertext, plaintextBytes.Length, auth_tag, 0, tagLenth); | |
//================================================================================= | |
var combinedStream = new MemoryStream(); | |
using (var binaryWriter = new BinaryWriter(combinedStream)) | |
{ | |
binaryWriter.Write(new byte[] { 1, key_id }); | |
binaryWriter.Write(encryptionIV); | |
binaryWriter.Write(new Packer().Pack("<h", 0, encrypted_rand_key.Length)); | |
binaryWriter.Write(encrypted_rand_key); | |
binaryWriter.Write(auth_tag); | |
binaryWriter.Write(ciphertext); | |
} | |
string encode = Convert.ToBase64String(combinedStream.ToArray()); | |
//return $"#PWD_MSGR:1:{current_time}:{encode}"; | |
return $"#PWD_FB4A:2:{current_time}:{encode}"; | |
} | |
private static void WriteListByte(byte[] input) | |
{ | |
string str = ""; | |
for (int i = 0; i < input.Length; i++) | |
{ | |
str += input[i] + ","; | |
} | |
Console.WriteLine(str.Substring(0, str.Length - 1)); | |
} | |
public static byte[] StringToByteArray(string hex) | |
{ | |
return Enumerable.Range(0, hex.Length) | |
.Where(x => x % 2 == 0) | |
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) | |
.ToArray(); | |
} | |
private static byte[] GenerateSaltNewInstance(int size) | |
{ | |
using (var generator = RandomNumberGenerator.Create()) | |
{ | |
var salt = new byte[size]; | |
generator.GetBytes(salt); | |
return salt; | |
} | |
} | |
private static RSACryptoServiceProvider ImportPublicKeyRSA(string public_key) | |
{ | |
return DecodeX509PublicKey(Convert.FromBase64String(public_key.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", ""))); | |
} | |
private static bool CompareBytearrays(byte[] a, byte[] b) | |
{ | |
if (a.Length != b.Length) | |
return false; | |
int i = 0; | |
foreach (byte c in a) | |
{ | |
if (c != b[i]) | |
return false; | |
i++; | |
} | |
return true; | |
} | |
private static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key) | |
{ | |
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" | |
byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; | |
byte[] seq = new byte[15]; | |
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ | |
MemoryStream mem = new MemoryStream(x509key); | |
BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading | |
byte bt = 0; | |
ushort twobytes = 0; | |
try | |
{ | |
twobytes = binr.ReadUInt16(); | |
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
binr.ReadByte(); //advance 1 byte | |
else if (twobytes == 0x8230) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
seq = binr.ReadBytes(15); //read the Sequence OID | |
if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct | |
return null; | |
twobytes = binr.ReadUInt16(); | |
if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) | |
binr.ReadByte(); //advance 1 byte | |
else if (twobytes == 0x8203) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
bt = binr.ReadByte(); | |
if (bt != 0x00) //expect null byte next | |
return null; | |
twobytes = binr.ReadUInt16(); | |
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
binr.ReadByte(); //advance 1 byte | |
else if (twobytes == 0x8230) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
twobytes = binr.ReadUInt16(); | |
byte lowbyte = 0x00; | |
byte highbyte = 0x00; | |
if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) | |
lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus | |
else if (twobytes == 0x8202) | |
{ | |
highbyte = binr.ReadByte(); //advance 2 bytes | |
lowbyte = binr.ReadByte(); | |
} | |
else | |
return null; | |
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order | |
int modsize = BitConverter.ToInt32(modint, 0); | |
byte firstbyte = binr.ReadByte(); | |
binr.BaseStream.Seek(-1, SeekOrigin.Current); | |
if (firstbyte == 0x00) | |
{ //if first byte (highest order) of modulus is zero, don't include it | |
binr.ReadByte(); //skip this null byte | |
modsize -= 1; //reduce modulus buffer size by 1 | |
} | |
byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes | |
if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data | |
return null; | |
int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values) | |
byte[] exponent = binr.ReadBytes(expbytes); | |
// ------- create RSACryptoServiceProvider instance and initialize with public key ----- | |
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); | |
RSAParameters RSAKeyInfo = new RSAParameters(); | |
RSAKeyInfo.Modulus = modulus; | |
RSAKeyInfo.Exponent = exponent; | |
RSA.ImportParameters(RSAKeyInfo); | |
return RSA; | |
} | |
catch (Exception) | |
{ | |
return null; | |
} | |
finally { binr.Close(); } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment