|
20 | 20 | */ |
21 | 21 |
|
22 | 22 | using System; |
| 23 | +using System.Collections.Generic; |
| 24 | +#if !WindowsCE |
23 | 25 | using System.Collections.Concurrent; |
| 26 | +#endif |
24 | 27 | using System.Runtime.InteropServices; |
25 | 28 | using System.Security.Cryptography; |
26 | 29 | using System.Text; |
@@ -3289,9 +3292,53 @@ private struct HpkeContextState |
3289 | 3292 | public IntPtr rng; |
3290 | 3293 | public HpkeKem kem; |
3291 | 3294 | } |
| 3295 | + |
| 3296 | +#if WindowsCE |
| 3297 | + /* .NET Compact Framework / Windows CE does not provide |
| 3298 | + * System.Collections.Concurrent, so fall back to a plain Dictionary |
| 3299 | + * guarded by an explicit lock. */ |
| 3300 | + private static readonly Dictionary<IntPtr, HpkeContextState> hpkeContexts = |
| 3301 | + new Dictionary<IntPtr, HpkeContextState>(); |
| 3302 | + private static readonly object hpkeContextsLock = new object(); |
| 3303 | + |
| 3304 | + private static void HpkeContextStore(IntPtr hpke, HpkeContextState state) |
| 3305 | + { |
| 3306 | + lock (hpkeContextsLock) { hpkeContexts[hpke] = state; } |
| 3307 | + } |
| 3308 | + private static bool HpkeContextTryGet(IntPtr hpke, out HpkeContextState state) |
| 3309 | + { |
| 3310 | + lock (hpkeContextsLock) { return hpkeContexts.TryGetValue(hpke, out state); } |
| 3311 | + } |
| 3312 | + private static bool HpkeContextTryRemove(IntPtr hpke, out HpkeContextState state) |
| 3313 | + { |
| 3314 | + lock (hpkeContextsLock) |
| 3315 | + { |
| 3316 | + if (hpkeContexts.TryGetValue(hpke, out state)) |
| 3317 | + { |
| 3318 | + hpkeContexts.Remove(hpke); |
| 3319 | + return true; |
| 3320 | + } |
| 3321 | + return false; |
| 3322 | + } |
| 3323 | + } |
| 3324 | +#else |
3292 | 3325 | private static readonly ConcurrentDictionary<IntPtr, HpkeContextState> hpkeContexts = |
3293 | 3326 | new ConcurrentDictionary<IntPtr, HpkeContextState>(); |
3294 | 3327 |
|
| 3328 | + private static void HpkeContextStore(IntPtr hpke, HpkeContextState state) |
| 3329 | + { |
| 3330 | + hpkeContexts[hpke] = state; |
| 3331 | + } |
| 3332 | + private static bool HpkeContextTryGet(IntPtr hpke, out HpkeContextState state) |
| 3333 | + { |
| 3334 | + return hpkeContexts.TryGetValue(hpke, out state); |
| 3335 | + } |
| 3336 | + private static bool HpkeContextTryRemove(IntPtr hpke, out HpkeContextState state) |
| 3337 | + { |
| 3338 | + return hpkeContexts.TryRemove(hpke, out state); |
| 3339 | + } |
| 3340 | +#endif |
| 3341 | + |
3295 | 3342 | /// <summary> |
3296 | 3343 | /// Get the enc (encapsulated key) length for a given KEM |
3297 | 3344 | /// </summary> |
@@ -3355,7 +3402,7 @@ public static IntPtr HpkeInit(HpkeKem kem, HpkeKdf kdf, HpkeAead aead) |
3355 | 3402 | return IntPtr.Zero; |
3356 | 3403 | } |
3357 | 3404 |
|
3358 | | - hpkeContexts[hpke] = new HpkeContextState { rng = rng, kem = kem }; |
| 3405 | + HpkeContextStore(hpke, new HpkeContextState { rng = rng, kem = kem }); |
3359 | 3406 | } |
3360 | 3407 | catch (Exception e) |
3361 | 3408 | { |
@@ -3392,7 +3439,7 @@ public static IntPtr HpkeGenerateKeyPair(IntPtr hpke) |
3392 | 3439 | } |
3393 | 3440 |
|
3394 | 3441 | HpkeContextState state; |
3395 | | - if (!hpkeContexts.TryGetValue(hpke, out state) || state.rng == IntPtr.Zero) |
| 3442 | + if (!HpkeContextTryGet(hpke, out state) || state.rng == IntPtr.Zero) |
3396 | 3443 | { |
3397 | 3444 | log(ERROR_LOG, "HPKE generate keypair: no RNG associated with context"); |
3398 | 3445 | return IntPtr.Zero; |
@@ -3527,7 +3574,7 @@ public static void HpkeFree(IntPtr hpke) |
3527 | 3574 | if (hpke != IntPtr.Zero) |
3528 | 3575 | { |
3529 | 3576 | HpkeContextState state; |
3530 | | - if (hpkeContexts.TryRemove(hpke, out state) && state.rng != IntPtr.Zero) |
| 3577 | + if (HpkeContextTryRemove(hpke, out state) && state.rng != IntPtr.Zero) |
3531 | 3578 | { |
3532 | 3579 | RandomFree(state.rng); |
3533 | 3580 | } |
@@ -3558,7 +3605,9 @@ public static byte[] HpkeSealBase(IntPtr hpke, IntPtr ephemeralKey, IntPtr recei |
3558 | 3605 | log(ERROR_LOG, "HPKE seal base: invalid parameter"); |
3559 | 3606 | return null; |
3560 | 3607 | } |
3561 | | - if (plaintext == null || plaintext.Length == 0) |
| 3608 | + /* Native wc_HpkeSealBase only requires plaintext to be non-NULL; |
| 3609 | + * ptSz == 0 is valid (output is just the AEAD tag). */ |
| 3610 | + if (plaintext == null) |
3562 | 3611 | { |
3563 | 3612 | log(ERROR_LOG, "HPKE seal base: invalid plaintext"); |
3564 | 3613 | return null; |
|
0 commit comments