@@ -880,6 +880,202 @@ private static void hash_test(uint hashType)
880880 }
881881 } /* END hash_test */
882882
883+ private static void hpke_test ( wolfcrypt . HpkeKem kem ,
884+ wolfcrypt . HpkeKdf kdf , wolfcrypt . HpkeAead aead )
885+ {
886+ IntPtr hpke = IntPtr . Zero ;
887+ IntPtr receiverKey = IntPtr . Zero ;
888+ IntPtr deserializedKey = IntPtr . Zero ;
889+ IntPtr ephemeralKey = IntPtr . Zero ;
890+
891+ try
892+ {
893+ Console . WriteLine ( "\n Starting HPKE Base mode test..." ) ;
894+
895+ /* Initialize HPKE context */
896+ Console . WriteLine ( "Initializing HPKE context..." ) ;
897+ hpke = wolfcrypt . HpkeInit ( kem , kdf , aead ) ;
898+ if ( hpke == IntPtr . Zero )
899+ {
900+ throw new Exception ( "HpkeInit failed" ) ;
901+ }
902+ Console . WriteLine ( "HPKE context initialization passed." ) ;
903+
904+ /* Generate receiver keypair */
905+ Console . WriteLine ( "Generating receiver keypair..." ) ;
906+ receiverKey = wolfcrypt . HpkeGenerateKeyPair ( hpke ) ;
907+ if ( receiverKey == IntPtr . Zero )
908+ {
909+ throw new Exception ( "HpkeGenerateKeyPair (receiver) failed" ) ;
910+ }
911+ Console . WriteLine ( "Receiver keypair generation passed." ) ;
912+
913+ /* Serialize and deserialize public key (round-trip) */
914+ Console . WriteLine ( "Testing public key serialize/deserialize round-trip..." ) ;
915+ byte [ ] pubKeyBytes = wolfcrypt . HpkeSerializePublicKey ( hpke , receiverKey ) ;
916+ if ( pubKeyBytes == null )
917+ {
918+ throw new Exception ( "HpkeSerializePublicKey failed" ) ;
919+ }
920+ Console . WriteLine ( $ "Serialized public key length: { pubKeyBytes . Length } ") ;
921+
922+ deserializedKey = wolfcrypt . HpkeDeserializePublicKey ( hpke , pubKeyBytes ) ;
923+ if ( deserializedKey == IntPtr . Zero )
924+ {
925+ throw new Exception ( "HpkeDeserializePublicKey failed" ) ;
926+ }
927+
928+ /* Verify round-trip by re-serializing */
929+ byte [ ] pubKeyBytes2 = wolfcrypt . HpkeSerializePublicKey ( hpke , deserializedKey ) ;
930+ if ( pubKeyBytes2 == null || ! wolfcrypt . ByteArrayVerify ( pubKeyBytes , pubKeyBytes2 ) )
931+ {
932+ throw new Exception ( "Public key round-trip verification failed" ) ;
933+ }
934+ Console . WriteLine ( "Public key round-trip test passed." ) ;
935+
936+ /* Generate ephemeral keypair for sender */
937+ Console . WriteLine ( "Generating ephemeral keypair..." ) ;
938+ ephemeralKey = wolfcrypt . HpkeGenerateKeyPair ( hpke ) ;
939+ if ( ephemeralKey == IntPtr . Zero )
940+ {
941+ throw new Exception ( "HpkeGenerateKeyPair (ephemeral) failed" ) ;
942+ }
943+ Console . WriteLine ( "Ephemeral keypair generation passed." ) ;
944+
945+ /* Define test data */
946+ byte [ ] info = Encoding . UTF8 . GetBytes ( "HPKE .NET Test" ) ;
947+ byte [ ] aad = Encoding . UTF8 . GetBytes ( "additional data" ) ;
948+ byte [ ] plaintext = Encoding . UTF8 . GetBytes ( "Hello HPKE from wolfCrypt .NET!" ) ;
949+
950+ /* Seal (encrypt) */
951+ Console . WriteLine ( "Testing HpkeSealBase..." ) ;
952+ byte [ ] encCiphertext = wolfcrypt . HpkeSealBase ( hpke , ephemeralKey ,
953+ receiverKey , info , aad , plaintext ) ;
954+ if ( encCiphertext == null )
955+ {
956+ throw new Exception ( "HpkeSealBase failed" ) ;
957+ }
958+ Console . WriteLine ( $ "HpkeSealBase passed. Output length: { encCiphertext . Length } ") ;
959+
960+ /* Open (decrypt) */
961+ Console . WriteLine ( "Testing HpkeOpenBase..." ) ;
962+ byte [ ] decrypted = wolfcrypt . HpkeOpenBase ( hpke , receiverKey ,
963+ encCiphertext , info , aad , plaintext . Length ) ;
964+ if ( decrypted == null )
965+ {
966+ throw new Exception ( "HpkeOpenBase failed" ) ;
967+ }
968+ Console . WriteLine ( "HpkeOpenBase passed." ) ;
969+
970+ /* Compare plaintext and decrypted */
971+ if ( ! wolfcrypt . ByteArrayVerify ( plaintext , decrypted ) )
972+ {
973+ throw new Exception ( "Decrypted text does not match original plaintext" ) ;
974+ }
975+ Console . WriteLine ( "HPKE Base mode test PASSED." ) ;
976+
977+ /* Test convenience overload (no ephemeral key) */
978+ Console . WriteLine ( "Testing HpkeSealBase convenience overload..." ) ;
979+ byte [ ] encCiphertext2 = wolfcrypt . HpkeSealBase ( hpke , receiverKey ,
980+ info , aad , plaintext , kem ) ;
981+ if ( encCiphertext2 == null )
982+ {
983+ throw new Exception ( "HpkeSealBase (convenience) failed" ) ;
984+ }
985+ Console . WriteLine ( $ "HpkeSealBase convenience passed. Output length: { encCiphertext2 . Length } ") ;
986+
987+ byte [ ] decrypted2 = wolfcrypt . HpkeOpenBase ( hpke , receiverKey ,
988+ encCiphertext2 , info , aad , kem ) ;
989+ if ( decrypted2 == null )
990+ {
991+ throw new Exception ( "HpkeOpenBase (convenience) failed" ) ;
992+ }
993+ if ( ! wolfcrypt . ByteArrayVerify ( plaintext , decrypted2 ) )
994+ {
995+ throw new Exception ( "Convenience seal/open: decrypted text does not match" ) ;
996+ }
997+ Console . WriteLine ( "HPKE convenience overload test PASSED." ) ;
998+
999+ /* Empty plaintext round-trip - native API accepts ptSz == 0 */
1000+ Console . WriteLine ( "Testing HpkeSealBase/OpenBase with empty plaintext..." ) ;
1001+ byte [ ] emptyPt = new byte [ 0 ] ;
1002+ byte [ ] encEmpty = wolfcrypt . HpkeSealBase ( hpke , receiverKey ,
1003+ info , aad , emptyPt , kem ) ;
1004+ if ( encEmpty == null )
1005+ {
1006+ throw new Exception ( "HpkeSealBase with empty plaintext failed" ) ;
1007+ }
1008+ byte [ ] decEmpty = wolfcrypt . HpkeOpenBase ( hpke , receiverKey ,
1009+ encEmpty , info , aad , kem ) ;
1010+ if ( decEmpty == null || decEmpty . Length != 0 )
1011+ {
1012+ throw new Exception ( "HpkeOpenBase with empty plaintext: round-trip failed" ) ;
1013+ }
1014+ Console . WriteLine ( "Empty plaintext round-trip test PASSED." ) ;
1015+
1016+ /* Negative test: tampered ciphertext should fail */
1017+ Console . WriteLine ( "Testing HpkeOpenBase with tampered ciphertext..." ) ;
1018+ byte [ ] tampered = ( byte [ ] ) encCiphertext . Clone ( ) ;
1019+ tampered [ tampered . Length - 1 ] ^= 0xFF ; /* flip last byte (in tag) */
1020+ byte [ ] badResult = wolfcrypt . HpkeOpenBase ( hpke , receiverKey ,
1021+ tampered , info , aad , plaintext . Length ) ;
1022+ if ( badResult != null )
1023+ {
1024+ throw new Exception ( "HpkeOpenBase should fail with tampered ciphertext" ) ;
1025+ }
1026+ Console . WriteLine ( "Tampered ciphertext test PASSED (correctly rejected)." ) ;
1027+
1028+ /* Negative test: mismatched AAD should fail */
1029+ Console . WriteLine ( "Testing HpkeOpenBase with mismatched AAD..." ) ;
1030+ byte [ ] wrongAad = Encoding . UTF8 . GetBytes ( "wrong aad" ) ;
1031+ badResult = wolfcrypt . HpkeOpenBase ( hpke , receiverKey ,
1032+ encCiphertext , info , wrongAad , plaintext . Length ) ;
1033+ if ( badResult != null )
1034+ {
1035+ throw new Exception ( "HpkeOpenBase should fail with mismatched AAD" ) ;
1036+ }
1037+ Console . WriteLine ( "Mismatched AAD test PASSED (correctly rejected)." ) ;
1038+
1039+ /* Null info/aad round-trip - exercises the null-marshaling path through P/Invoke */
1040+ Console . WriteLine ( "Testing HpkeSealBase/OpenBase with null info and aad..." ) ;
1041+ byte [ ] encNull = wolfcrypt . HpkeSealBase ( hpke , receiverKey ,
1042+ null , null , plaintext , kem ) ;
1043+ if ( encNull == null )
1044+ {
1045+ throw new Exception ( "HpkeSealBase with null info/aad failed" ) ;
1046+ }
1047+ byte [ ] decNull = wolfcrypt . HpkeOpenBase ( hpke , receiverKey ,
1048+ encNull , null , null , kem ) ;
1049+ if ( decNull == null || ! wolfcrypt . ByteArrayVerify ( plaintext , decNull ) )
1050+ {
1051+ throw new Exception ( "HpkeOpenBase with null info/aad: round-trip failed" ) ;
1052+ }
1053+ Console . WriteLine ( "Null info/aad round-trip test PASSED." ) ;
1054+
1055+ /* Negative test: invalid ptLen should fail */
1056+ Console . WriteLine ( "Testing HpkeOpenBase with invalid ptLen..." ) ;
1057+ badResult = wolfcrypt . HpkeOpenBase ( hpke , receiverKey ,
1058+ encCiphertext , info , aad , plaintext . Length + 1 ) ;
1059+ if ( badResult != null )
1060+ {
1061+ throw new Exception ( "HpkeOpenBase should fail with incorrect ptLen" ) ;
1062+ }
1063+ Console . WriteLine ( "Invalid ptLen test PASSED (correctly rejected)." ) ;
1064+ }
1065+ finally
1066+ {
1067+ /* Cleanup */
1068+ if ( ephemeralKey != IntPtr . Zero )
1069+ wolfcrypt . HpkeFreeKey ( hpke , ephemeralKey , kem ) ;
1070+ if ( deserializedKey != IntPtr . Zero )
1071+ wolfcrypt . HpkeFreeKey ( hpke , deserializedKey , kem ) ;
1072+ if ( receiverKey != IntPtr . Zero )
1073+ wolfcrypt . HpkeFreeKey ( hpke , receiverKey , kem ) ;
1074+ if ( hpke != IntPtr . Zero )
1075+ wolfcrypt . HpkeFree ( hpke ) ;
1076+ }
1077+ } /* END hpke_test */
1078+
8831079 public static void standard_log ( int lvl , StringBuilder msg )
8841080 {
8851081 Console . WriteLine ( msg ) ;
@@ -941,6 +1137,15 @@ public static void Main(string[] args)
9411137 hash_test ( ( uint ) wolfcrypt . hashType . WC_HASH_TYPE_SHA512 ) ; /* SHA-512 HASH test */
9421138 hash_test ( ( uint ) wolfcrypt . hashType . WC_HASH_TYPE_SHA3_256 ) ; /* SHA3_256 HASH test */
9431139
1140+ Console . WriteLine ( "\n Starting HPKE tests" ) ;
1141+
1142+ hpke_test ( wolfcrypt . HpkeKem . DHKEM_P256_HKDF_SHA256 ,
1143+ wolfcrypt . HpkeKdf . HKDF_SHA256 ,
1144+ wolfcrypt . HpkeAead . AES_128_GCM ) ;
1145+ hpke_test ( wolfcrypt . HpkeKem . DHKEM_X25519_HKDF_SHA256 ,
1146+ wolfcrypt . HpkeKdf . HKDF_SHA256 ,
1147+ wolfcrypt . HpkeAead . AES_128_GCM ) ;
1148+
9441149 wolfcrypt . Cleanup ( ) ;
9451150
9461151 Console . WriteLine ( "\n All tests completed successfully" ) ;
0 commit comments