Skip to content
This repository has been archived by the owner on Sep 20, 2023. It is now read-only.

Add AES Key Wrap algorithm (RFC 3394) #59

Open
frasertweedale opened this issue Jan 5, 2016 · 4 comments
Open

Add AES Key Wrap algorithm (RFC 3394) #59

frasertweedale opened this issue Jan 5, 2016 · 4 comments

Comments

@frasertweedale
Copy link
Contributor

I implemented the AES Key Wrap algorithm (RFC 3394) using
cryptonite primitives and am wondering if upstream is receptive to
adopting the algorithm in cryptonite itself?

Current API:

aesKeyWrap
  :: (ByteArrayAccess m, ByteArray c, BlockCipher128 cipher)
  => cipher -> m -> c

aesKeyUnwrap
  :: (ByteArrayAccess c, ByteArray m, BlockCipher128 cipher)
  => cipher -> c -> Maybe m

It is defined for all BlockCipher128 because despite the name,
the algorithm only requires a 128-bit block size. It does not use
any feature of BlockCipher128 though - only ECB.

@tekul
Copy link
Member

tekul commented Jan 5, 2016

I also have some code which does this.

It seems to me it would be a good fit for cryptonite to avoid duplication in other projects.

@vincenthz
Copy link
Member

yes, please add, we would'nt live to the crypto kitchen sink otherwise ;-)

The BlockCipher128 constraint/class is slightly unfortunate but needed to make the algorithm block-size=128 bits only.

@frasertweedale
Copy link
Contributor Author

Ok, would you mind reviewing my implementation[1] and suggesting where you
would like it to live within cryptonite?

Implementation notes:

  • Single allocation of output ByteArray
  • (6 * N) allocations of temporary 16-byte ByteArray for input to ECB function, where N is number of 64-bit chunks in plaintext. No doubt there is an allocation for the ECB output at each step as well. Would be nice to avoid these.
  • Is it safe to use unsafePerformIO to make it a "pure" computation, as I have done? It looks OK to me but I want a second (more experienced) opinion.
  • I clobbered together a QC prop[2] for testing.

[1] https://github.com/frasertweedale/hs-jose/blob/jwe/src/Crypto/JOSE/AESKW.hs
[2] https://github.com/frasertweedale/hs-jose/blob/jwe/test/AESKW.hs#L35-L54

@tekul
Copy link
Member

tekul commented Feb 7, 2016

Sorry it's taken me a long time to get round to looking at this. I'm also rather nervous about using impure ptr-based code in Haskell and don't consider myself an expert at all (see #57). Vincent can probably comment on what's safe to use. I did wonder whether it makes much difference in terms of performance, especially in a case like this when the plaintext will always be so small. I put together a benchmark for the two approaches:

https://gist.github.com/tekul/d8875bcde7c32bc3d04d

The times are pretty much the same, but bizarrely, the pure code is consistently about 12% faster. I have no idea why that might be. Maybe because of the use of StateT and mapM_ ?

$ ghc -O --make keywrap.hs
$ ./keywrap
benchmarking keywrap/ptr-based
time                 8.422 μs   (8.387 μs .. 8.467 μs)
                     1.000 R²   (0.999 R² .. 1.000 R²)
mean                 8.501 μs   (8.437 μs .. 8.605 μs)
std dev              282.7 ns   (194.5 ns .. 385.0 ns)
variance introduced by outliers: 40% (moderately inflated)

benchmarking keywrap/pure
time                 7.635 μs   (7.592 μs .. 7.686 μs)
                     1.000 R²   (0.999 R² .. 1.000 R²)
mean                 7.686 μs   (7.623 μs .. 7.795 μs)
std dev              274.7 ns   (155.6 ns .. 416.3 ns)
variance introduced by outliers: 44% (moderately inflated)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants