@@ -16,7 +16,15 @@ public record EncryptedFlowData(
1616 [ property: JsonPropertyName ( "initial_vector" ) ] string IV ) ;
1717
1818/// <summary>Parsed flow data containing decrypted JSON and AES key/IV.</summary>
19- public record FlowData ( JsonElement Data , byte [ ] Key , byte [ ] IV ) ;
19+ public record FlowData < TData > ( TData Data , byte [ ] Key , byte [ ] IV ) ;
20+
21+ /// <summary>Represents flow data with decrypted JSON content, AES key, and IV.</summary>
22+ public record FlowData ( JsonElement Data , byte [ ] Key , byte [ ] IV ) : FlowData < JsonElement > ( Data , Key , IV )
23+ {
24+ /// <summary>Creates a new instance of <see cref="FlowData{TData}"/> with the specified data.</summary>
25+ public FlowData < TData > With < TData > ( TData data ) =>
26+ new ( data , Key , IV ) ;
27+ }
2028
2129/// <summary>Implements the flow message encryption and decryption for the WhatsApp Business API.</summary>
2230public class FlowCryptography : IDisposable
@@ -46,6 +54,43 @@ public FlowCryptography(string privatePem, string passphrase)
4654 rsa . ImportFromEncryptedPem ( privatePem , passphrase ) ;
4755 }
4856
57+ /// <summary>Decrypts the provided encrypted flow data into a <see cref="FlowData"/> object.</summary>
58+ public FlowData Decrypt ( EncryptedFlowData data )
59+ {
60+ // Inline decode & decrypt pipeline (Base64 -> RSA -> AES-GCM -> JSON)
61+ var aesKey = rsa . Decrypt ( Convert . FromBase64String ( data . Key ) , RSAEncryptionPadding . OaepSHA256 ) ;
62+ var iv = Convert . FromBase64String ( data . IV ) ;
63+ var cipher = Convert . FromBase64String ( data . Data ) ;
64+ var plaintext = AesGcmDecrypt ( aesKey , iv , cipher ) ;
65+ var json = JsonSerializer . Deserialize < JsonElement > ( Encoding . UTF8 . GetString ( plaintext ) ) ;
66+ return new FlowData ( json , aesKey , iv ) ;
67+ }
68+
69+ /// <summary>Decrypts the provided encrypted flow data into a <see cref="FlowData"/> object, returning false on failure.</summary>
70+ public bool TryDecrypt ( EncryptedFlowData data , out FlowData ? result )
71+ {
72+ try
73+ {
74+ result = Decrypt ( data ) ;
75+ return true ;
76+ }
77+ catch ( CryptographicException )
78+ {
79+ result = null ;
80+ return false ;
81+ }
82+ }
83+
84+ /// <summary>Encrypts the provided flow data into a Base64-encoded string.</summary>
85+ public string Encrypt < TData > ( FlowData < TData > data )
86+ {
87+ // Derive nonce via bit-flip (encapsulated) and serialize JSON directly to UTF-8 bytes.
88+ var flippedIv = FlipIvBits ( data . IV ) ;
89+ var payload = JsonSerializer . SerializeToUtf8Bytes ( data . Data ) ;
90+ var cipherWithTag = AesGcmEncrypt ( data . Key , flippedIv , payload ) ;
91+ return Convert . ToBase64String ( cipherWithTag ) ;
92+ }
93+
4994 /// <summary>Disposes the inner RSA key.</summary>
5095 public void Dispose ( ) => rsa . Dispose ( ) ;
5196
@@ -102,26 +147,4 @@ static byte[] FlipIvBits(byte[] iv)
102147 flipped [ i ] = ( byte ) ~ iv [ i ] ;
103148 return flipped ;
104149 }
105-
106- /// <summary>Decrypts the provided encrypted flow data into a <see cref="FlowData"/> object.</summary>
107- public FlowData Decrypt ( EncryptedFlowData data )
108- {
109- // Inline decode & decrypt pipeline (Base64 -> RSA -> AES-GCM -> JSON)
110- var aesKey = rsa . Decrypt ( Convert . FromBase64String ( data . Key ) , RSAEncryptionPadding . OaepSHA256 ) ;
111- var iv = Convert . FromBase64String ( data . IV ) ;
112- var cipher = Convert . FromBase64String ( data . Data ) ;
113- var plaintext = AesGcmDecrypt ( aesKey , iv , cipher ) ;
114- var json = JsonSerializer . Deserialize < JsonElement > ( Encoding . UTF8 . GetString ( plaintext ) ) ;
115- return new FlowData ( json , aesKey , iv ) ;
116- }
117-
118- /// <summary>Encrypts the provided flow data into a Base64-encoded string.</summary>
119- public string Encrypt ( FlowData data )
120- {
121- // Derive nonce via bit-flip (encapsulated) and serialize JSON directly to UTF-8 bytes.
122- var flippedIv = FlipIvBits ( data . IV ) ;
123- var payload = JsonSerializer . SerializeToUtf8Bytes ( data . Data ) ;
124- var cipherWithTag = AesGcmEncrypt ( data . Key , flippedIv , payload ) ;
125- return Convert . ToBase64String ( cipherWithTag ) ;
126- }
127150}
0 commit comments