@@ -3259,8 +3259,10 @@ public enum HpkeAead : ushort {
32593259 /* HPKE Nt (GCM tag length) */
32603260 private static readonly int HPKE_Nt = 16 ;
32613261
3262- /* Hpke struct is ~80 bytes on 64-bit (see hpke.h). Over-allocate to
3263- * accommodate future growth and platform alignment differences. */
3262+ /* Hpke struct is ~80 bytes on 64-bit (see hpke.h). Allocate 512 bytes
3263+ * (6x headroom) to accommodate platform alignment and future growth.
3264+ * If the native struct ever exceeds this, wc_HpkeInit will write OOB —
3265+ * keep in sync with hpke.h if the struct grows significantly. */
32643266 private static readonly int HPKE_STRUCT_SZ = 512 ;
32653267
32663268 /// <summary>
@@ -3605,13 +3607,26 @@ public static byte[] HpkeOpenBase(IntPtr hpke, IntPtr receiverKey,
36053607
36063608 /* encCiphertext = enc || ciphertext || GCM tag
36073609 * where ciphertext is ptLen bytes, tag is Nt bytes */
3610+ if ( ptLen < 0 || ptLen > int . MaxValue - HPKE_Nt )
3611+ {
3612+ log ( ERROR_LOG , "HPKE open base: invalid ptLen" ) ;
3613+ return null ;
3614+ }
3615+
36083616 int sealLen = ptLen + HPKE_Nt ;
3609- if ( ptLen < 0 || encCiphertext . Length < sealLen )
3617+ if ( encCiphertext . Length < sealLen )
36103618 {
36113619 log ( ERROR_LOG , "HPKE open base: encCiphertext too short for given ptLen" ) ;
36123620 return null ;
36133621 }
3614- ushort pubKeySz = ( ushort ) ( encCiphertext . Length - sealLen ) ;
3622+
3623+ int pubKeySzInt = encCiphertext . Length - sealLen ;
3624+ if ( pubKeySzInt < 0 || pubKeySzInt > ushort . MaxValue )
3625+ {
3626+ log ( ERROR_LOG , "HPKE open base: invalid encapsulated public key size" ) ;
3627+ return null ;
3628+ }
3629+ ushort pubKeySz = ( ushort ) pubKeySzInt ;
36153630
36163631 /* Split enc and sealed data (ciphertext || tag) */
36173632 byte [ ] pubKey = new byte [ pubKeySz ] ;
@@ -3625,7 +3640,7 @@ public static byte[] HpkeOpenBase(IntPtr hpke, IntPtr receiverKey,
36253640 byte [ ] plaintext = new byte [ ptLen ] ;
36263641
36273642 /* ctSz is just the ciphertext length (without tag);
3628- * wc_HpkeContextOpenBase reads the tag from ct + ctSz */
3643+ * wc_HpkeOpenBase reads the tag from ct + ctSz */
36293644 int ret = wc_HpkeOpenBase ( hpke , receiverKey , pubKey , pubKeySz ,
36303645 info , infoSz , aad , aadSz , ct , ( uint ) ptLen , plaintext ) ;
36313646 if ( ret != 0 )
@@ -3642,6 +3657,36 @@ public static byte[] HpkeOpenBase(IntPtr hpke, IntPtr receiverKey,
36423657 return null ;
36433658 }
36443659 }
3660+
3661+ /// <summary>
3662+ /// Convenience SingleShot open (decrypt) using HPKE Base mode.
3663+ /// Derives the plaintext length from the KEM enc length, so the caller
3664+ /// does not need to know ptLen.
3665+ /// </summary>
3666+ /// <param name="hpke">HPKE context from HpkeInit()</param>
3667+ /// <param name="receiverKey">Receiver private keypair</param>
3668+ /// <param name="encCiphertext">enc||ciphertext blob from HpkeSealBase()</param>
3669+ /// <param name="info">Info context bytes (can be null)</param>
3670+ /// <param name="aad">Additional authenticated data (can be null)</param>
3671+ /// <param name="kem">KEM used (to derive enc length)</param>
3672+ /// <returns>Decrypted plaintext byte array or null on failure</returns>
3673+ public static byte [ ] HpkeOpenBase ( IntPtr hpke , IntPtr receiverKey ,
3674+ byte [ ] encCiphertext , byte [ ] info , byte [ ] aad , HpkeKem kem )
3675+ {
3676+ ushort encLen = HpkeEncLen ( kem ) ;
3677+ if ( encLen == 0 )
3678+ {
3679+ log ( ERROR_LOG , "HPKE open base: unsupported KEM" ) ;
3680+ return null ;
3681+ }
3682+ if ( encCiphertext == null || encCiphertext . Length < encLen + HPKE_Nt )
3683+ {
3684+ log ( ERROR_LOG , "HPKE open base: encCiphertext too short" ) ;
3685+ return null ;
3686+ }
3687+ int ptLen = encCiphertext . Length - encLen - HPKE_Nt ;
3688+ return HpkeOpenBase ( hpke , receiverKey , encCiphertext , info , aad , ptLen ) ;
3689+ }
36453690 /* END HPKE */
36463691
36473692
0 commit comments