packages feed

argon2 1.2.0 → 1.3.0.0

raw patch · 25 files changed

+2470/−792 lines, 25 filesdep +deepseqdep +tasty-hunitdep +text-shortdep −textdep −transformersdep ~QuickCheckdep ~basedep ~bytestringnew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: deepseq, tasty-hunit, text-short

Dependencies removed: text, transformers

Dependency ranges changed: QuickCheck, base, bytestring, tasty, tasty-quickcheck

API changes (from Hackage documentation)

- Crypto.Argon2: Argon2Exception :: !Int32 -> Argon2Exception
- Crypto.Argon2: Argon2IterationCountOutOfRange :: !Word32 -> Argon2Exception
- Crypto.Argon2: Argon2MemoryUseOutOfRange :: !Word32 -> Argon2Exception
- Crypto.Argon2: Argon2ParallelismOutOfRange :: !Word32 -> Argon2Exception
- Crypto.Argon2: Argon2PasswordLengthOutOfRange :: !CSize -> Argon2Exception
- Crypto.Argon2: Argon2SaltLengthOutOfRange :: !CSize -> Argon2Exception
- Crypto.Argon2: data Argon2Exception
- Crypto.Argon2: instance GHC.Exception.Exception Crypto.Argon2.Argon2Exception
- Crypto.Argon2: instance GHC.Show.Show Crypto.Argon2.Argon2Exception
- Crypto.Argon2: verify :: Text -> ByteString -> Bool
- Crypto.Argon2.FFI: argon2d_hash_encoded :: (Word32) -> (Word32) -> (Word32) -> Ptr a -> CSize -> Ptr b -> CSize -> CSize -> CString -> CSize -> IO (Int32)
- Crypto.Argon2.FFI: argon2d_hash_raw :: (Word32) -> (Word32) -> (Word32) -> Ptr a -> CSize -> Ptr b -> CSize -> Ptr c -> CSize -> IO (Int32)
- Crypto.Argon2.FFI: argon2d_verify :: CString -> Ptr a -> CSize -> IO (Int32)
- Crypto.Argon2.FFI: argon2i_hash_encoded :: (Word32) -> (Word32) -> (Word32) -> Ptr a -> CSize -> Ptr b -> CSize -> CSize -> CString -> CSize -> IO (Int32)
- Crypto.Argon2.FFI: argon2i_hash_raw :: (Word32) -> (Word32) -> (Word32) -> Ptr a -> CSize -> Ptr b -> CSize -> Ptr c -> CSize -> IO (Int32)
- Crypto.Argon2.FFI: argon2i_verify :: CString -> Ptr a -> CSize -> IO (Int32)
+ Crypto.Argon2: Argon2AdPtrMismatch :: Argon2Status
+ Crypto.Argon2: Argon2AdTooLong :: Argon2Status
+ Crypto.Argon2: Argon2AdTooShort :: Argon2Status
+ Crypto.Argon2: Argon2AllocateMemoryCbkNull :: Argon2Status
+ Crypto.Argon2: Argon2DecodingFail :: Argon2Status
+ Crypto.Argon2: Argon2DecodingLengthFail :: Argon2Status
+ Crypto.Argon2: Argon2EncodingFail :: Argon2Status
+ Crypto.Argon2: Argon2FreeMemoryCbkNull :: Argon2Status
+ Crypto.Argon2: Argon2IncorrectParameter :: Argon2Status
+ Crypto.Argon2: Argon2IncorrectType :: Argon2Status
+ Crypto.Argon2: Argon2InternalError :: Argon2Status
+ Crypto.Argon2: Argon2LanesTooFew :: Argon2Status
+ Crypto.Argon2: Argon2LanesTooMany :: Argon2Status
+ Crypto.Argon2: Argon2MemoryAllocationError :: Argon2Status
+ Crypto.Argon2: Argon2MemoryTooLittle :: Argon2Status
+ Crypto.Argon2: Argon2MemoryTooMuch :: Argon2Status
+ Crypto.Argon2: Argon2MissingArgs :: Argon2Status
+ Crypto.Argon2: Argon2Ok :: Argon2Status
+ Crypto.Argon2: Argon2OutPtrMismatch :: Argon2Status
+ Crypto.Argon2: Argon2OutputPtrNull :: Argon2Status
+ Crypto.Argon2: Argon2OutputTooLong :: Argon2Status
+ Crypto.Argon2: Argon2OutputTooShort :: Argon2Status
+ Crypto.Argon2: Argon2PwdPtrMismatch :: Argon2Status
+ Crypto.Argon2: Argon2PwdTooLong :: Argon2Status
+ Crypto.Argon2: Argon2PwdTooShort :: Argon2Status
+ Crypto.Argon2: Argon2SaltPtrMismatch :: Argon2Status
+ Crypto.Argon2: Argon2SaltTooLong :: Argon2Status
+ Crypto.Argon2: Argon2SaltTooShort :: Argon2Status
+ Crypto.Argon2: Argon2SecretPtrMismatch :: Argon2Status
+ Crypto.Argon2: Argon2SecretTooLong :: Argon2Status
+ Crypto.Argon2: Argon2SecretTooShort :: Argon2Status
+ Crypto.Argon2: Argon2ThreadFail :: Argon2Status
+ Crypto.Argon2: Argon2ThreadsTooFew :: Argon2Status
+ Crypto.Argon2: Argon2ThreadsTooMany :: Argon2Status
+ Crypto.Argon2: Argon2TimeTooLarge :: Argon2Status
+ Crypto.Argon2: Argon2TimeTooSmall :: Argon2Status
+ Crypto.Argon2: Argon2VerifyMismatch :: Argon2Status
+ Crypto.Argon2: Argon2Version10 :: Argon2Version
+ Crypto.Argon2: Argon2Version13 :: Argon2Version
+ Crypto.Argon2: Argon2id :: Argon2Variant
+ Crypto.Argon2: [hashLength] :: HashOptions -> !Word32
+ Crypto.Argon2: [hashVersion] :: HashOptions -> !Argon2Version
+ Crypto.Argon2: data Argon2Status
+ Crypto.Argon2: data Argon2Version
+ Crypto.Argon2: instance Control.DeepSeq.NFData Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance Control.DeepSeq.NFData Crypto.Argon2.Argon2Variant
+ Crypto.Argon2: instance Control.DeepSeq.NFData Crypto.Argon2.Argon2Version
+ Crypto.Argon2: instance Control.DeepSeq.NFData Crypto.Argon2.HashOptions
+ Crypto.Argon2: instance GHC.Classes.Eq Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance GHC.Classes.Eq Crypto.Argon2.Argon2Version
+ Crypto.Argon2: instance GHC.Classes.Ord Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance GHC.Classes.Ord Crypto.Argon2.Argon2Version
+ Crypto.Argon2: instance GHC.Enum.Bounded Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance GHC.Enum.Bounded Crypto.Argon2.Argon2Version
+ Crypto.Argon2: instance GHC.Enum.Enum Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance GHC.Enum.Enum Crypto.Argon2.Argon2Version
+ Crypto.Argon2: instance GHC.Exception.Exception Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance GHC.Generics.Generic Crypto.Argon2.Argon2Version
+ Crypto.Argon2: instance GHC.Read.Read Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance GHC.Read.Read Crypto.Argon2.Argon2Version
+ Crypto.Argon2: instance GHC.Show.Show Crypto.Argon2.Argon2Status
+ Crypto.Argon2: instance GHC.Show.Show Crypto.Argon2.Argon2Version
+ Crypto.Argon2: verifyEncoded :: ShortText -> ByteString -> Argon2Status
+ Crypto.Argon2.FFI: argon2_hash :: Word32 -> Word32 -> Word32 -> Ptr a -> CSize -> Ptr b -> CSize -> Ptr c -> CSize -> CString -> CSize -> Argon2_type -> Argon2_version -> IO CInt
+ Crypto.Argon2.FFI: argon2_verify :: CString -> Ptr a -> CSize -> Argon2_type -> IO CInt
+ Crypto.Argon2.FFI: type Argon2_type = (Word32)
+ Crypto.Argon2.FFI: type Argon2_version = Word32
- Crypto.Argon2: HashOptions :: !Word32 -> !Word32 -> !Word32 -> !Argon2Variant -> HashOptions
+ Crypto.Argon2: HashOptions :: !Word32 -> !Word32 -> !Word32 -> !Argon2Variant -> !Argon2Version -> !Word32 -> HashOptions
- Crypto.Argon2: hash :: HashOptions -> ByteString -> ByteString -> ByteString
+ Crypto.Argon2: hash :: HashOptions -> ByteString -> ByteString -> Either Argon2Status ByteString
- Crypto.Argon2: hashEncoded :: HashOptions -> ByteString -> ByteString -> Text
+ Crypto.Argon2: hashEncoded :: HashOptions -> ByteString -> ByteString -> Either Argon2Status ShortText
- Crypto.Argon2.FFI: argon2_encodedlen :: (Word32) -> (Word32) -> (Word32) -> (Word32) -> (Word32) -> IO CSize
+ Crypto.Argon2.FFI: argon2_encodedlen :: Word32 -> Word32 -> Word32 -> Word32 -> Word32 -> Argon2_type -> CSize

Files

Changelog.md view
@@ -1,3 +1,29 @@+# 1.3.0.0++- This represents a major rewrite/refactoring of this package.++- Add support for generating version 1.0 hashes.++- Add support for controlling length of generated hash.++- Add support for hybrid `Argon2id` variant.++- Add `NFData` instances.++- Defaults in `defaultHashOptions` changed to the current ones from the upstream `argon2` executable.++- Replace `Argon2Exception` by more direct `Argon2Status` enumeration; report failures purely via `Either` rather than by throwing as exceptions.++- Rename `verify` to `verifyEncoded` and return more informative `Argon2Status` result instead of `Bool`.++- Embedded `phc-winner-argon2` version updated to release `20171227`.++- Mangle names of global symbols from `phc-winner-argon2` to reduce risk of symbol clashes at the C ABI level.++- Add support for `libargon2`'s optimised C routines on x86_64 (can be disabled via new `non-optimised-c` cabal flag).++- Fix potential memory leak.+ # 1.2.0  - Updated embedded phc-winner-argon2, so that hashes are generated
LICENSE view
@@ -1,4 +1,5 @@ Copyright (c) 2016, Ollie Charles+              2018, Herbert Valerio Riedel  All rights reserved. 
− Tests.hs
@@ -1,84 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--import Crypto.Argon2-import Test.QuickCheck-import Test.Tasty-import Data.Ix-import Test.Tasty.QuickCheck-import qualified Crypto.Argon2.FFI as FFI-import qualified Data.ByteString as BS-import qualified Data.Text.Encoding as T-import Data.Bits (shiftL)--arbitraryVariant :: Gen Argon2Variant-arbitraryVariant = arbitraryBoundedEnum---- The hard-coded constants correspond to `decode_string`, but see--- https://github.com/P-H-C/phc-winner-argon2/issues/77-arbitraryHashOptions :: Gen HashOptions-arbitraryHashOptions =-  do p <--       arbitraryWithin (max (max FFI.ARGON2_MIN_LANES FFI.ARGON2_MIN_THREADS) 1)-                       (min (min FFI.ARGON2_MAX_LANES FFI.ARGON2_MAX_THREADS) 254)-     HashOptions <$>-       arbitraryWithin FFI.ARGON2_MIN_TIME-                       (min FFI.ARGON2_MAX_TIME (2 ^ 32 - 1)) <*>-       arbitraryWithin-         (max (max FFI.ARGON2_MIN_MEMORY (8 * p))-              (shiftL p 3))-         FFI.ARGON2_MAX_MEMORY <*>-       pure p <*>-       arbitraryVariant--arbitraryWithin lower upper = arbitrary `suchThat` (inRange (lower,upper))--arbitraryBytes :: Gen BS.ByteString-arbitraryBytes = fmap BS.pack arbitrary--arbitraryPassword :: Gen BS.ByteString-arbitraryPassword = arbitraryBytes `suchThat`-                             (\pwd ->-                                (FFI.ARGON2_MIN_PWD_LENGTH-                                ,FFI.ARGON2_MAX_PWD_LENGTH) `inRange`-                                BS.length pwd)--arbitrarySalt =-  arbitraryBytes `suchThat`-  (\salt ->-     (FFI.ARGON2_MIN_SALT_LENGTH,FFI.ARGON2_MAX_SALT_LENGTH) `inRange`-     BS.length salt)--main :: IO ()-main =-  defaultMain-    (testGroup "Properties"-               [testProperty-                  "Round trip"-                  (forAll arbitraryHashOptions $-                   \hashOptions ->-                     forAll arbitraryPassword $-                     \password ->-                       forAll arbitrarySalt $-                       \salt ->-                         verify (hashEncoded hashOptions password salt) password)-               ,testProperty-                  "Unencoded hashing"-                  (forAll arbitraryHashOptions $-                   \hashOptions ->-                     forAll arbitraryPassword $-                     \password ->-                       forAll arbitrarySalt $-                       \salt -> hash hashOptions password salt /= password)-               ,testProperty-                  "defaultHashOptions"-                  (forAll arbitraryVariant $-                   \variant ->-                     (forAll arbitraryPassword $-                      \password ->-                        forAll arbitrarySalt $-                        \salt ->-                          verify (hashEncoded-                                    (defaultHashOptions {hashVariant = variant})-                                    password-                                    salt)-                                 password))])
argon2.cabal view
@@ -1,49 +1,108 @@+cabal-version:       1.22 name:                argon2-version:             1.2.0-synopsis:            Haskell bindings to libargon2 - the reference implementation of the Argon2 password-hashing function--- description:         -homepage:            https://github.com/ocharles/argon2.git+version:             1.3.0.0++synopsis:            Memory-hard password hash and proof-of-work function+description:+    Argon2 is the key derivation function (KDF) selected as the winner of the [Password Hashing Competition](https://en.wikipedia.org/wiki/Password_Hashing_Competition). The API exposed by this bindings provide access to the 3 specified variants+    .+    * @Argon2d@ (maximize resistance to GPU cracking attacks),+    * @Argon2i@ (optimized to resist side-channel attacks), and+    * @Argon2id@ (hybrid version combining @Argon2d@ and @Argon2i@)+    .+    and allows to control various parameters (time cost, memory cost, parallelism) of the Argon2 function. Moreover, it is also supported to generate and verify the deprecated version 1.0 hashes, as well as the current version 1.3 hashes.+    .+    The Haskell API supports both raw binary hashes as well as the ASCII-based [PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md).+    .+    This version provides bindings to the \"@20171227@\" release of the [Argon2 reference implementation (libargon2)](https://github.com/P-H-C/phc-winner-argon2) of the Argon2 password-hashing function.+    .+    Please refer to the [Argon2 specification](https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf) for more information.++ license:             BSD3-license-file:        LICENSE-author:              Ollie Charles-maintainer:          ollie@ocharles.org.uk--- copyright:           --- category:            +license-files:       LICENSE+                     phc-winner-argon2/LICENSE++author:              Ollie Charles, Herbert Valerio Riedel+maintainer:          Herbert Valerio Riedel <hvr@gnu.org>+bug-reports:         https://github.com/hvr/argon2/issues+category:            Cryptography build-type:          Simple extra-source-files:  Changelog.md-cabal-version:       >=1.10-extra-source-files: phc-winner-argon2/src/blake2/blake2.h-                    phc-winner-argon2/src/blake2/blake2-impl.h-                    phc-winner-argon2/src/blake2/blamka-round-ref.h-                    phc-winner-argon2/include/argon2.h +                     phc-winner-argon2/include/argon2.h+                     phc-winner-argon2/include/hs_argon2_mangling.h+                     phc-winner-argon2/src/blake2/blake2-impl.h+                     phc-winner-argon2/src/blake2/blake2.h+                     phc-winner-argon2/src/blake2/blamka-round-ref.h+                     phc-winner-argon2/src/blake2/blamka-round-opt.h+                     phc-winner-argon2/src/core.h+                     phc-winner-argon2/src/encoding.h+                     phc-winner-argon2/src/thread.h++source-repository head+  type:     git+  location: https://github.com/hvr/argon2.git+ flag use-system-library-  description: Link against system libargon2 library rather than embedded copy+  description: Link against system @libargon2@ library (discovery via @pkg-config(1)@) rather than using embedded copy of @libargon2@   default: False+  manual: True +flag non-optimised-c+  description: Force use of non-optimised C routines on @x86_64@. Ineffective when @use-system-library@ flag is active.+  default: False+  manual: True+ library+  default-language:    Haskell2010   exposed-modules:     Crypto.Argon2.FFI                        Crypto.Argon2-  build-depends:       base >=4.8 && <4.10, bytestring, text, transformers++  build-depends:       base         >= 4.8   && < 4.12+                     , bytestring   == 0.10.*+                     , deepseq      == 1.4.*+                     , text-short   >= 0.1.2 && < 0.2+   hs-source-dirs:      src-  default-language:    Haskell2010++  ghc-options: -Wall+  if impl(ghc >= 8.0)+    ghc-options: -Wno-missing-pattern-synonym-signatures+   if flag(use-system-library)-    extra-libraries: argon2+    cpp-options: -DUSE_SYSTEM_ARGON2=1+    pkgconfig-depends: argon2   else+    cpp-options: -DUSE_SYSTEM_ARGON2=0     c-sources: phc-winner-argon2/src/argon2.c                phc-winner-argon2/src/core.c                phc-winner-argon2/src/blake2/blake2b.c                phc-winner-argon2/src/thread.c-               phc-winner-argon2/src/ref.c                phc-winner-argon2/src/encoding.c-               phc-winner-argon2/src/encoding.h-               phc-winner-argon2/src/core.h-               phc-winner-argon2/src/thread.h-               phc-winner-argon2/src/ref.h++    if arch(x86_64) && !flag(non-optimised-c)+      c-sources: phc-winner-argon2/src/opt.c+    else+      c-sources: phc-winner-argon2/src/ref.c+     include-dirs: phc-winner-argon2/src                   phc-winner-argon2/include +    cc-options: -O3+ test-suite tests+  default-language: Haskell2010   type: exitcode-stdio-1.0+  hs-source-dirs: src-tests   main-is: Tests.hs-  build-depends: argon2, base >= 4.8 && <4.9, QuickCheck >= 2.0, tasty-quickcheck, tasty, bytestring, text+  build-depends: argon2+               , base+               , bytestring++               , QuickCheck       == 2.11.*+               , tasty-quickcheck == 0.10.*+               , tasty-hunit      == 0.10.*+               , tasty            == 1.0.*++  ghc-options: -threaded
+ phc-winner-argon2/LICENSE view
@@ -0,0 +1,314 @@+Argon2 reference source code package - reference C implementations++Copyright 2015+Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves++You may use this work under the terms of a Creative Commons CC0 1.0 +License/Waiver or the Apache Public License 2.0, at your option. The terms of+these licenses can be found at:++- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+- Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0++The terms of the licenses are reproduced below.++--------------------------------------------------------------------------------++Creative Commons Legal Code++CC0 1.0 Universal++    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED+    HEREUNDER.++Statement of Purpose++The laws of most jurisdictions throughout the world automatically confer+exclusive Copyright and Related Rights (defined below) upon the creator+and subsequent owner(s) (each and all, an "owner") of an original work of+authorship and/or a database (each, a "Work").++Certain owners wish to permanently relinquish those rights to a Work for+the purpose of contributing to a commons of creative, cultural and+scientific works ("Commons") that the public can reliably and without fear+of later claims of infringement build upon, modify, incorporate in other+works, reuse and redistribute as freely as possible in any form whatsoever+and for any purposes, including without limitation commercial purposes.+These owners may contribute to the Commons to promote the ideal of a free+culture and the further production of creative, cultural and scientific+works, or to gain reputation or greater distribution for their Work in+part through the use and efforts of others.++For these and/or other purposes and motivations, and without any+expectation of additional consideration or compensation, the person+associating CC0 with a Work (the "Affirmer"), to the extent that he or she+is an owner of Copyright and Related Rights in the Work, voluntarily+elects to apply CC0 to the Work and publicly distribute the Work under its+terms, with knowledge of his or her Copyright and Related Rights in the+Work and the meaning and intended legal effect of CC0 on those rights.++1. Copyright and Related Rights. A Work made available under CC0 may be+protected by copyright and related or neighboring rights ("Copyright and+Related Rights"). Copyright and Related Rights include, but are not+limited to, the following:++  i. the right to reproduce, adapt, distribute, perform, display,+     communicate, and translate a Work;+ ii. moral rights retained by the original author(s) and/or performer(s);+iii. publicity and privacy rights pertaining to a person's image or+     likeness depicted in a Work;+ iv. rights protecting against unfair competition in regards to a Work,+     subject to the limitations in paragraph 4(a), below;+  v. rights protecting the extraction, dissemination, use and reuse of data+     in a Work;+ vi. database rights (such as those arising under Directive 96/9/EC of the+     European Parliament and of the Council of 11 March 1996 on the legal+     protection of databases, and under any national implementation+     thereof, including any amended or successor version of such+     directive); and+vii. other similar, equivalent or corresponding rights throughout the+     world based on applicable law or treaty, and any national+     implementations thereof.++2. Waiver. To the greatest extent permitted by, but not in contravention+of, applicable law, Affirmer hereby overtly, fully, permanently,+irrevocably and unconditionally waives, abandons, and surrenders all of+Affirmer's Copyright and Related Rights and associated claims and causes+of action, whether now known or unknown (including existing as well as+future claims and causes of action), in the Work (i) in all territories+worldwide, (ii) for the maximum duration provided by applicable law or+treaty (including future time extensions), (iii) in any current or future+medium and for any number of copies, and (iv) for any purpose whatsoever,+including without limitation commercial, advertising or promotional+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each+member of the public at large and to the detriment of Affirmer's heirs and+successors, fully intending that such Waiver shall not be subject to+revocation, rescission, cancellation, termination, or any other legal or+equitable action to disrupt the quiet enjoyment of the Work by the public+as contemplated by Affirmer's express Statement of Purpose.++3. Public License Fallback. Should any part of the Waiver for any reason+be judged legally invalid or ineffective under applicable law, then the+Waiver shall be preserved to the maximum extent permitted taking into+account Affirmer's express Statement of Purpose. In addition, to the+extent the Waiver is so judged Affirmer hereby grants to each affected+person a royalty-free, non transferable, non sublicensable, non exclusive,+irrevocable and unconditional license to exercise Affirmer's Copyright and+Related Rights in the Work (i) in all territories worldwide, (ii) for the+maximum duration provided by applicable law or treaty (including future+time extensions), (iii) in any current or future medium and for any number+of copies, and (iv) for any purpose whatsoever, including without+limitation commercial, advertising or promotional purposes (the+"License"). The License shall be deemed effective as of the date CC0 was+applied by Affirmer to the Work. Should any part of the License for any+reason be judged legally invalid or ineffective under applicable law, such+partial invalidity or ineffectiveness shall not invalidate the remainder+of the License, and in such case Affirmer hereby affirms that he or she+will not (i) exercise any of his or her remaining Copyright and Related+Rights in the Work or (ii) assert any associated claims and causes of+action with respect to the Work, in either case contrary to Affirmer's+express Statement of Purpose.++4. Limitations and Disclaimers.++ a. No trademark or patent rights held by Affirmer are waived, abandoned,+    surrendered, licensed or otherwise affected by this document.+ b. Affirmer offers the Work as-is and makes no representations or+    warranties of any kind concerning the Work, express, implied,+    statutory or otherwise, including without limitation warranties of+    title, merchantability, fitness for a particular purpose, non+    infringement, or the absence of latent or other defects, accuracy, or+    the present or absence of errors, whether or not discoverable, all to+    the greatest extent permissible under applicable law.+ c. Affirmer disclaims responsibility for clearing rights of other persons+    that may apply to the Work or any use thereof, including without+    limitation any person's Copyright and Related Rights in the Work.+    Further, Affirmer disclaims responsibility for obtaining any necessary+    consents, permissions or other rights required for any use of the+    Work.+ d. Affirmer understands and acknowledges that Creative Commons is not a+    party to this document and has no duty or obligation with respect to+    this CC0 or use of the Work.++--------------------------------------------------------------------------------++                                 Apache License+                           Version 2.0, January 2004+                        http://www.apache.org/licenses/++   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++   1. Definitions.++      "License" shall mean the terms and conditions for use, reproduction,+      and distribution as defined by Sections 1 through 9 of this document.++      "Licensor" shall mean the copyright owner or entity authorized by+      the copyright owner that is granting the License.++      "Legal Entity" shall mean the union of the acting entity and all+      other entities that control, are controlled by, or are under common+      control with that entity. For the purposes of this definition,+      "control" means (i) the power, direct or indirect, to cause the+      direction or management of such entity, whether by contract or+      otherwise, or (ii) ownership of fifty percent (50%) or more of the+      outstanding shares, or (iii) beneficial ownership of such entity.++      "You" (or "Your") shall mean an individual or Legal Entity+      exercising permissions granted by this License.++      "Source" form shall mean the preferred form for making modifications,+      including but not limited to software source code, documentation+      source, and configuration files.++      "Object" form shall mean any form resulting from mechanical+      transformation or translation of a Source form, including but+      not limited to compiled object code, generated documentation,+      and conversions to other media types.++      "Work" shall mean the work of authorship, whether in Source or+      Object form, made available under the License, as indicated by a+      copyright notice that is included in or attached to the work+      (an example is provided in the Appendix below).++      "Derivative Works" shall mean any work, whether in Source or Object+      form, that is based on (or derived from) the Work and for which the+      editorial revisions, annotations, elaborations, or other modifications+      represent, as a whole, an original work of authorship. For the purposes+      of this License, Derivative Works shall not include works that remain+      separable from, or merely link (or bind by name) to the interfaces of,+      the Work and Derivative Works thereof.++      "Contribution" shall mean any work of authorship, including+      the original version of the Work and any modifications or additions+      to that Work or Derivative Works thereof, that is intentionally+      submitted to Licensor for inclusion in the Work by the copyright owner+      or by an individual or Legal Entity authorized to submit on behalf of+      the copyright owner. For the purposes of this definition, "submitted"+      means any form of electronic, verbal, or written communication sent+      to the Licensor or its representatives, including but not limited to+      communication on electronic mailing lists, source code control systems,+      and issue tracking systems that are managed by, or on behalf of, the+      Licensor for the purpose of discussing and improving the Work, but+      excluding communication that is conspicuously marked or otherwise+      designated in writing by the copyright owner as "Not a Contribution."++      "Contributor" shall mean Licensor and any individual or Legal Entity+      on behalf of whom a Contribution has been received by Licensor and+      subsequently incorporated within the Work.++   2. Grant of Copyright License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      copyright license to reproduce, prepare Derivative Works of,+      publicly display, publicly perform, sublicense, and distribute the+      Work and such Derivative Works in Source or Object form.++   3. Grant of Patent License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      (except as stated in this section) patent license to make, have made,+      use, offer to sell, sell, import, and otherwise transfer the Work,+      where such license applies only to those patent claims licensable+      by such Contributor that are necessarily infringed by their+      Contribution(s) alone or by combination of their Contribution(s)+      with the Work to which such Contribution(s) was submitted. If You+      institute patent litigation against any entity (including a+      cross-claim or counterclaim in a lawsuit) alleging that the Work+      or a Contribution incorporated within the Work constitutes direct+      or contributory patent infringement, then any patent licenses+      granted to You under this License for that Work shall terminate+      as of the date such litigation is filed.++   4. Redistribution. You may reproduce and distribute copies of the+      Work or Derivative Works thereof in any medium, with or without+      modifications, and in Source or Object form, provided that You+      meet the following conditions:++      (a) You must give any other recipients of the Work or+          Derivative Works a copy of this License; and++      (b) You must cause any modified files to carry prominent notices+          stating that You changed the files; and++      (c) You must retain, in the Source form of any Derivative Works+          that You distribute, all copyright, patent, trademark, and+          attribution notices from the Source form of the Work,+          excluding those notices that do not pertain to any part of+          the Derivative Works; and++      (d) If the Work includes a "NOTICE" text file as part of its+          distribution, then any Derivative Works that You distribute must+          include a readable copy of the attribution notices contained+          within such NOTICE file, excluding those notices that do not+          pertain to any part of the Derivative Works, in at least one+          of the following places: within a NOTICE text file distributed+          as part of the Derivative Works; within the Source form or+          documentation, if provided along with the Derivative Works; or,+          within a display generated by the Derivative Works, if and+          wherever such third-party notices normally appear. The contents+          of the NOTICE file are for informational purposes only and+          do not modify the License. You may add Your own attribution+          notices within Derivative Works that You distribute, alongside+          or as an addendum to the NOTICE text from the Work, provided+          that such additional attribution notices cannot be construed+          as modifying the License.++      You may add Your own copyright statement to Your modifications and+      may provide additional or different license terms and conditions+      for use, reproduction, or distribution of Your modifications, or+      for any such Derivative Works as a whole, provided Your use,+      reproduction, and distribution of the Work otherwise complies with+      the conditions stated in this License.++   5. Submission of Contributions. Unless You explicitly state otherwise,+      any Contribution intentionally submitted for inclusion in the Work+      by You to the Licensor shall be under the terms and conditions of+      this License, without any additional terms or conditions.+      Notwithstanding the above, nothing herein shall supersede or modify+      the terms of any separate license agreement you may have executed+      with Licensor regarding such Contributions.++   6. Trademarks. This License does not grant permission to use the trade+      names, trademarks, service marks, or product names of the Licensor,+      except as required for reasonable and customary use in describing the+      origin of the Work and reproducing the content of the NOTICE file.++   7. Disclaimer of Warranty. Unless required by applicable law or+      agreed to in writing, Licensor provides the Work (and each+      Contributor provides its Contributions) on an "AS IS" BASIS,+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+      implied, including, without limitation, any warranties or conditions+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+      PARTICULAR PURPOSE. You are solely responsible for determining the+      appropriateness of using or redistributing the Work and assume any+      risks associated with Your exercise of permissions under this License.++   8. Limitation of Liability. In no event and under no legal theory,+      whether in tort (including negligence), contract, or otherwise,+      unless required by applicable law (such as deliberate and grossly+      negligent acts) or agreed to in writing, shall any Contributor be+      liable to You for damages, including any direct, indirect, special,+      incidental, or consequential damages of any character arising as a+      result of this License or out of the use or inability to use the+      Work (including but not limited to damages for loss of goodwill,+      work stoppage, computer failure or malfunction, or any and all+      other commercial damages or losses), even if such Contributor+      has been advised of the possibility of such damages.++   9. Accepting Warranty or Additional Liability. While redistributing+      the Work or Derivative Works thereof, You may choose to offer,+      and charge a fee for, acceptance of support, warranty, indemnity,+      or other liability obligations and/or rights consistent with this+      License. However, in accepting such obligations, You may act only+      on Your own behalf and on Your sole responsibility, not on behalf+      of any other Contributor, and only if You agree to indemnify,+      defend, and hold each Contributor harmless for any liability+      incurred by, or claims asserted against, such Contributor by reason+      of your accepting any such warranty or additional liability.
phc-winner-argon2/include/argon2.h view
@@ -1,13 +1,18 @@ /*- * Argon2 source code package+ * Argon2 reference source code package - reference C implementations  *- * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves  *- * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:  *- * You should have received a copy of the CC0 Public Domain Dedication- * along with this software. If not, see- * <http://creativecommons.org/publicdomain/zero/1.0/>.+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.  */  #ifndef ARGON2_H@@ -16,6 +21,7 @@ #include <stdint.h> #include <stddef.h> #include <limits.h>+#include "hs_argon2_mangling.h"  #if defined(__cplusplus) extern "C" {@@ -24,10 +30,13 @@ /* Symbols visibility control */ #ifdef A2_VISCTL #define ARGON2_PUBLIC __attribute__((visibility("default")))+#define ARGON2_LOCAL __attribute__ ((visibility ("hidden"))) #elif _MSC_VER #define ARGON2_PUBLIC __declspec(dllexport)+#define ARGON2_LOCAL #else #define ARGON2_PUBLIC+#define ARGON2_LOCAL #endif  /*@@ -79,11 +88,15 @@ #define ARGON2_MIN_SECRET UINT32_C(0) #define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) +/* Flags to determine which fields are securely wiped (default = no wipe). */+#define ARGON2_DEFAULT_FLAGS UINT32_C(0) #define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) #define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)-#define ARGON2_FLAG_CLEAR_MEMORY (UINT32_C(1) << 2)-#define ARGON2_DEFAULT_FLAGS (ARGON2_FLAG_CLEAR_MEMORY) +/* Global flag to determine if we are wiping internal memory buffers. This flag+ * is defined in core.c and deafults to 1 (wipe internal memory). */+extern int FLAG_clear_internal_memory;+ /* Error codes */ typedef enum Argon2_ErrorCodes {     ARGON2_OK = 0,@@ -206,7 +219,11 @@ } argon2_context;  /* Argon2 primitive type */-typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type;+typedef enum Argon2_type {+  Argon2_d = 0,+  Argon2_i = 1,+  Argon2_id = 2+} argon2_type;  /* Version of the algorithm */ typedef enum Argon2_version {@@ -216,6 +233,14 @@ } argon2_version;  /*+ * Function that gives the string representation of an argon2_type.+ * @param type The argon2_type that we want the string for+ * @param uppercase Whether the string should have the first letter uppercase+ * @return NULL if invalid type, otherwise the string representation.+ */+ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase);++/*  * Function that performs memory-hard hashing with certain degree of parallelism  * @param  context  Pointer to the Argon2 internal structure  * @return Error code if smth is wrong, ARGON2_OK otherwise@@ -246,8 +271,7 @@                                        const size_t encodedlen);  /**- * Hashes a password with Argon2i, producing a raw hash by allocating memory at- * @hash+ * Hashes a password with Argon2i, producing a raw hash at @hash  * @param t_cost Number of iterations  * @param m_cost Sets memory usage to m_cost kibibytes  * @param parallelism Number of threads and compute lanes@@ -280,6 +304,21 @@                                    const size_t saltlen, void *hash,                                    const size_t hashlen); +ARGON2_PUBLIC int argon2id_hash_encoded(const uint32_t t_cost,+                                        const uint32_t m_cost,+                                        const uint32_t parallelism,+                                        const void *pwd, const size_t pwdlen,+                                        const void *salt, const size_t saltlen,+                                        const size_t hashlen, char *encoded,+                                        const size_t encodedlen);++ARGON2_PUBLIC int argon2id_hash_raw(const uint32_t t_cost,+                                    const uint32_t m_cost,+                                    const uint32_t parallelism, const void *pwd,+                                    const size_t pwdlen, const void *salt,+                                    const size_t saltlen, void *hash,+                                    const size_t hashlen);+ /* generic function underlying the above ones */ ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,                               const uint32_t parallelism, const void *pwd,@@ -302,6 +341,9 @@ ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd,                                  const size_t pwdlen); +ARGON2_PUBLIC int argon2id_verify(const char *encoded, const void *pwd,+                                  const size_t pwdlen);+ /* generic function underlying the above ones */ ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd,                                 const size_t pwdlen, argon2_type type);@@ -327,6 +369,17 @@ ARGON2_PUBLIC int argon2i_ctx(argon2_context *context);  /**+ * Argon2id: Version of Argon2 where the first half-pass over memory is+ * password-independent, the rest are password-dependent (on the password and+ * salt). OK against side channels (they reduce to 1/2-pass Argon2i), and+ * better with w.r.t. tradeoff attacks (similar to Argon2d).+ *****+ * @param  context  Pointer to current Argon2 context+ * @return  Zero if successful, a non zero error code otherwise+ */+ARGON2_PUBLIC int argon2id_ctx(argon2_context *context);++/**  * Verify if a given password is correct for Argon2d hashing  * @param  context  Pointer to current Argon2 context  * @param  hash  The password hash to verify. The length of the hash is@@ -344,6 +397,16 @@  */ ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash); +/**+ * Verify if a given password is correct for Argon2id hashing+ * @param  context  Pointer to current Argon2 context+ * @param  hash  The password hash to verify. The length of the hash is+ * specified by the context outlen member+ * @return  Zero if successful, a non zero error code otherwise+ */+ARGON2_PUBLIC int argon2id_verify_ctx(argon2_context *context,+                                      const char *hash);+ /* generic function underlying the above ones */ ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash,                                     argon2_type type);@@ -361,11 +424,12 @@  * @param parallelism  Number of threads; used to compute lanes  * @param saltlen  Salt size in bytes  * @param hashlen  Hash size in bytes+ * @param type The argon2_type that we want the encoded length for  * @return  The encoded hash length in bytes  */ ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost,                                        uint32_t parallelism, uint32_t saltlen,-                                       uint32_t hashlen);+                                       uint32_t hashlen, argon2_type type);  #if defined(__cplusplus) }
+ phc-winner-argon2/include/hs_argon2_mangling.h view
@@ -0,0 +1,58 @@+#if !defined(HS_ARGON2_MANGLING_H)+#define HS_ARGON2_MANGLING_H++/* local symbol mangling */+#define blake2b              hs_argon2__blake2b+#define blake2b_final        hs_argon2__blake2b_final+#define blake2b_init         hs_argon2__blake2b_init+#define blake2b_init_key     hs_argon2__blake2b_init_key+#define blake2b_init_param   hs_argon2__blake2b_init_param+#define blake2b_long         hs_argon2__blake2b_long+#define blake2b_update       hs_argon2__blake2b_update++#define allocate_memory       hs_argon2__allocate_memory+#define argon2_ctx            hs_argon2__argon2_ctx+#define argon2_encodedlen     hs_argon2__argon2_encodedlen+#define argon2_error_message  hs_argon2__argon2_error_message+#define argon2_hash           hs_argon2__argon2_hash+#define argon2_thread_create  hs_argon2__argon2_thread_create+#define argon2_thread_exit    hs_argon2__argon2_thread_exit+#define argon2_thread_join    hs_argon2__argon2_thread_join+#define argon2_type2string    hs_argon2__argon2_type2string+#define argon2_verify         hs_argon2__argon2_verify+#define argon2_verify_ctx     hs_argon2__argon2_verify_ctx+#define argon2d_ctx           hs_argon2__argon2d_ctx+#define argon2d_hash_encoded  hs_argon2__argon2d_hash_encoded+#define argon2d_hash_raw      hs_argon2__argon2d_hash_raw+#define argon2d_verify        hs_argon2__argon2d_verify+#define argon2d_verify_ctx    hs_argon2__argon2d_verify_ctx+#define argon2i_ctx           hs_argon2__argon2i_ctx+#define argon2i_hash_encoded  hs_argon2__argon2i_hash_encoded+#define argon2i_hash_raw      hs_argon2__argon2i_hash_raw+#define argon2i_verify        hs_argon2__argon2i_verify+#define argon2i_verify_ctx    hs_argon2__argon2i_verify_ctx+#define argon2id_ctx          hs_argon2__argon2id_ctx+#define argon2id_hash_encoded hs_argon2__argon2id_hash_encoded+#define argon2id_hash_raw     hs_argon2__argon2id_hash_raw+#define argon2id_verify       hs_argon2__argon2id_verify+#define argon2id_verify_ctx   hs_argon2__argon2id_verify_ctx+#define b64len                hs_argon2__b64len+#define clear_internal_memory hs_argon2__clear_internal_memory+#define copy_block            hs_argon2__copy_block+#define decode_string         hs_argon2__decode_string+#define encode_string         hs_argon2__encode_string+#define fill_first_blocks     hs_argon2__fill_first_blocks+#define fill_memory_blocks    hs_argon2__fill_memory_blocks+#define fill_segment          hs_argon2__fill_segment+#define finalize              hs_argon2__finalize+#define free_memory           hs_argon2__free_memory+#define index_alpha           hs_argon2__index_alpha+#define init_block_value      hs_argon2__init_block_value+#define initial_hash          hs_argon2__initial_hash+#define initialize            hs_argon2__initialize+#define numlen                hs_argon2__numlen+#define secure_wipe_memory    hs_argon2__secure_wipe_memory+#define validate_inputs       hs_argon2__validate_inputs+#define xor_block             hs_argon2__xor_block+  +#endif
phc-winner-argon2/src/argon2.c view
@@ -1,14 +1,18 @@ /*- * Argon2 source code package+ * Argon2 reference source code package - reference C implementations  *- * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves  *- * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:  *- * You should have received a copy of the CC0 Public Domain Dedication along- * with- * this software. If not, see- * <http://creativecommons.org/publicdomain/zero/1.0/>.+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.  */  #include <string.h>@@ -19,7 +23,19 @@ #include "encoding.h" #include "core.h" +const char *argon2_type2string(argon2_type type, int uppercase) {+    switch (type) {+        case Argon2_d:+            return uppercase ? "Argon2d" : "argon2d";+        case Argon2_i:+            return uppercase ? "Argon2i" : "argon2i";+        case Argon2_id:+            return uppercase ? "Argon2id" : "argon2id";+    } +    return NULL;+}+ int argon2_ctx(argon2_context *context, argon2_type type) {     /* 1. Validate all inputs */     int result = validate_inputs(context);@@ -30,7 +46,7 @@         return result;     } -    if (Argon2_d != type && Argon2_i != type) {+    if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {         return ARGON2_INCORRECT_TYPE;     } @@ -56,6 +72,10 @@     instance.threads = context->threads;     instance.type = type; +    if (instance.threads > instance.lanes) {+        instance.threads = instance.lanes;+    }+     /* 3. Initialization: Hashing inputs, allocating memory, filling first      * blocks      */@@ -81,13 +101,21 @@                 const uint32_t parallelism, const void *pwd,                 const size_t pwdlen, const void *salt, const size_t saltlen,                 void *hash, const size_t hashlen, char *encoded,-                const size_t encodedlen, argon2_type type, +                const size_t encodedlen, argon2_type type,                 const uint32_t version){      argon2_context context;     int result;     uint8_t *out; +    if (pwdlen > ARGON2_MAX_PWD_LENGTH) {+        return ARGON2_PWD_TOO_LONG;+    }++    if (saltlen > ARGON2_MAX_SALT_LENGTH) {+        return ARGON2_SALT_TOO_LONG;+    }+     if (hashlen > ARGON2_MAX_OUTLEN) {         return ARGON2_OUTPUT_TOO_LONG;     }@@ -123,7 +151,7 @@     result = argon2_ctx(&context, type);      if (result != ARGON2_OK) {-        secure_wipe_memory(out, hashlen);+        clear_internal_memory(out, hashlen);         free(out);         return result;     }@@ -136,13 +164,13 @@     /* if encoding requested, write it */     if (encoded && encodedlen) {         if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) {-            secure_wipe_memory(out, hashlen); /* wipe buffers if error */-            secure_wipe_memory(encoded, encodedlen);+            clear_internal_memory(out, hashlen); /* wipe buffers if error */+            clear_internal_memory(encoded, encodedlen);             free(out);             return ARGON2_ENCODING_FAIL;         }     }-    secure_wipe_memory(out, hashlen);+    clear_internal_memory(out, hashlen);     free(out);      return ARGON2_OK;@@ -188,6 +216,26 @@                        hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER); } +int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,+                          const uint32_t parallelism, const void *pwd,+                          const size_t pwdlen, const void *salt,+                          const size_t saltlen, const size_t hashlen,+                          char *encoded, const size_t encodedlen) {++    return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,+                       NULL, hashlen, encoded, encodedlen, Argon2_id,+                       ARGON2_VERSION_NUMBER);+}++int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost,+                      const uint32_t parallelism, const void *pwd,+                      const size_t pwdlen, const void *salt,+                      const size_t saltlen, void *hash, const size_t hashlen) {+    return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,+                       hash, hashlen, NULL, 0, Argon2_id,+                       ARGON2_VERSION_NUMBER);+}+ static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) {     size_t i;     uint8_t d = 0U;@@ -202,69 +250,64 @@                   argon2_type type) {      argon2_context ctx;-    uint8_t *out;-    int ret;-    int decode_result;-    uint32_t encoded_len;-    size_t encoded_len_tmp;+    uint8_t *desired_result = NULL; -    if(encoded == NULL) {+    int ret = ARGON2_OK;++    size_t encoded_len;+    uint32_t max_field_len;++    if (pwdlen > ARGON2_MAX_PWD_LENGTH) {+        return ARGON2_PWD_TOO_LONG;+    }++    if (encoded == NULL) {         return ARGON2_DECODING_FAIL;     } -    encoded_len_tmp = strlen(encoded);-    /* max values, to be updated in decode_string */-    if (UINT32_MAX < encoded_len_tmp) {+    encoded_len = strlen(encoded);+    if (encoded_len > UINT32_MAX) {         return ARGON2_DECODING_FAIL;     } -    encoded_len = (uint32_t)encoded_len_tmp;-    ctx.adlen = encoded_len;-    ctx.saltlen = encoded_len;-    ctx.outlen = encoded_len;-    ctx.allocate_cbk = NULL;-    ctx.free_cbk = NULL;-    ctx.secret = NULL;-    ctx.secretlen = 0;-    ctx.pwdlen = 0;-    ctx.pwd = NULL;-    ctx.ad = malloc(ctx.adlen);+    /* No field can be longer than the encoded length */+    max_field_len = (uint32_t)encoded_len;++    ctx.saltlen = max_field_len;+    ctx.outlen = max_field_len;+     ctx.salt = malloc(ctx.saltlen);     ctx.out = malloc(ctx.outlen);-    if (!ctx.out || !ctx.salt || !ctx.ad) {-        free(ctx.ad);-        free(ctx.salt);-        free(ctx.out);-        return ARGON2_MEMORY_ALLOCATION_ERROR;+    if (!ctx.salt || !ctx.out) {+        ret = ARGON2_MEMORY_ALLOCATION_ERROR;+        goto fail;     }-    out = malloc(ctx.outlen);-    if (!out) {-        free(ctx.ad);-        free(ctx.salt);-        free(ctx.out);-        return ARGON2_MEMORY_ALLOCATION_ERROR;++    ctx.pwd = (uint8_t *)pwd;+    ctx.pwdlen = (uint32_t)pwdlen;++    ret = decode_string(&ctx, encoded, type);+    if (ret != ARGON2_OK) {+        goto fail;     }-    decode_result = decode_string(&ctx, encoded, type);-    if (decode_result != ARGON2_OK) {-        free(ctx.ad);-        free(ctx.salt);-        free(ctx.out);-        free(out);-        return decode_result;++    /* Set aside the desired result, and get a new buffer. */+    desired_result = ctx.out;+    ctx.out = malloc(ctx.outlen);+    if (!ctx.out) {+        ret = ARGON2_MEMORY_ALLOCATION_ERROR;+        goto fail;     } -    ret = argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen,-                      ctx.salt, ctx.saltlen, out, ctx.outlen, NULL, 0, type,-                      ctx.version);+    ret = argon2_verify_ctx(&ctx, (char *)desired_result, type);+    if (ret != ARGON2_OK) {+        goto fail;+    } -    free(ctx.ad);+fail:     free(ctx.salt);--    if (ret == ARGON2_OK && argon2_compare(out, ctx.out, ctx.outlen)) {-        ret = ARGON2_VERIFY_MISMATCH;-    }-    free(out);     free(ctx.out);+    free(desired_result);      return ret; }@@ -279,6 +322,11 @@     return argon2_verify(encoded, pwd, pwdlen, Argon2_d); } +int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) {++    return argon2_verify(encoded, pwd, pwdlen, Argon2_id);+}+ int argon2d_ctx(argon2_context *context) {     return argon2_ctx(context, Argon2_d); }@@ -287,20 +335,22 @@     return argon2_ctx(context, Argon2_i); } +int argon2id_ctx(argon2_context *context) {+    return argon2_ctx(context, Argon2_id);+}+ int argon2_verify_ctx(argon2_context *context, const char *hash,                       argon2_type type) {-    int result;-    if (0 == context->outlen || NULL == hash) {-        return ARGON2_OUT_PTR_MISMATCH;+    int ret = argon2_ctx(context, type);+    if (ret != ARGON2_OK) {+        return ret;     } -    result = argon2_ctx(context, type);--    if (ARGON2_OK != result) {-        return result;+    if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) {+        return ARGON2_VERIFY_MISMATCH;     } -    return 0 == memcmp(hash, context->out, context->outlen);+    return ARGON2_OK; }  int argon2d_verify_ctx(argon2_context *context, const char *hash) {@@ -311,6 +361,10 @@     return argon2_verify_ctx(context, hash, Argon2_i); } +int argon2id_verify_ctx(argon2_context *context, const char *hash) {+    return argon2_verify_ctx(context, hash, Argon2_id);+}+ const char *argon2_error_message(int error_code) {     switch (error_code) {     case ARGON2_OK:@@ -391,8 +445,8 @@ }  size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism,-                         uint32_t saltlen, uint32_t hashlen) {-    return strlen("$argon2x$v=$m=,t=,p=$$") + numlen(t_cost) + numlen(m_cost)-        + numlen(parallelism) + b64len(saltlen) + b64len(hashlen)-        + numlen(ARGON2_VERSION_NUMBER) + 1;+                         uint32_t saltlen, uint32_t hashlen, argon2_type type) {+  return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) ++         numlen(t_cost) + numlen(m_cost) + numlen(parallelism) ++         b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1; }
phc-winner-argon2/src/blake2/blake2-impl.h view
@@ -1,3 +1,20 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */+ #ifndef PORTABLE_BLAKE2_IMPL_H #define PORTABLE_BLAKE2_IMPL_H @@ -134,6 +151,6 @@     return (w >> c) | (w << (64 - c)); } -void secure_wipe_memory(void *v, size_t n);+void clear_internal_memory(void *v, size_t n);  #endif
phc-winner-argon2/src/blake2/blake2.h view
@@ -1,9 +1,24 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */+ #ifndef PORTABLE_BLAKE2_H #define PORTABLE_BLAKE2_H -#include <stddef.h>-#include <stdint.h>-#include <limits.h>+#include <argon2.h>  #if defined(__cplusplus) extern "C" {@@ -52,19 +67,19 @@ };  /* Streaming API */-int blake2b_init(blake2b_state *S, size_t outlen);-int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,+ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen);+ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,                      size_t keylen);-int blake2b_init_param(blake2b_state *S, const blake2b_param *P);-int blake2b_update(blake2b_state *S, const void *in, size_t inlen);-int blake2b_final(blake2b_state *S, void *out, size_t outlen);+ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);+ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen);+ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen);  /* Simple API */-int blake2b(void *out, size_t outlen, const void *in, size_t inlen,-            const void *key, size_t keylen);+ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen,+                         const void *key, size_t keylen);  /* Argon2 Team - Begin Code */-int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);+ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); /* Argon2 Team - End Code */  #if defined(__cplusplus)
phc-winner-argon2/src/blake2/blake2b.c view
@@ -1,3 +1,20 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */+ #include <stdint.h> #include <string.h> #include <stdio.h>@@ -44,7 +61,7 @@ }  static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {-    secure_wipe_memory(S, sizeof(*S));      /* wipe */+    clear_internal_memory(S, sizeof(*S));      /* wipe */     blake2b_set_lastblock(S); /* invalidate for further use */ } @@ -140,7 +157,8 @@         memset(block, 0, BLAKE2B_BLOCKBYTES);         memcpy(block, key, keylen);         blake2b_update(S, block, BLAKE2B_BLOCKBYTES);-        secure_wipe_memory(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */+        /* Burn the key from stack */+        clear_internal_memory(block, BLAKE2B_BLOCKBYTES);     }     return 0; }@@ -267,9 +285,9 @@     }      memcpy(out, buffer, S->outlen);-    secure_wipe_memory(buffer, sizeof(buffer));-    secure_wipe_memory(S->buf, sizeof(S->buf));-    secure_wipe_memory(S->h, sizeof(S->h));+    clear_internal_memory(buffer, sizeof(buffer));+    clear_internal_memory(S->buf, sizeof(S->buf));+    clear_internal_memory(S->h, sizeof(S->h));     return 0; } @@ -307,7 +325,7 @@     ret = blake2b_final(&S, out, outlen);  fail:-    secure_wipe_memory(&S, sizeof(S));+    clear_internal_memory(&S, sizeof(S));     return ret; } @@ -365,7 +383,7 @@         memcpy(out, out_buffer, toproduce);     } fail:-    secure_wipe_memory(&blake_state, sizeof(blake_state));+    clear_internal_memory(&blake_state, sizeof(blake_state));     return ret; #undef TRY }
+ phc-winner-argon2/src/blake2/blamka-round-opt.h view
@@ -0,0 +1,471 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */++#ifndef BLAKE_ROUND_MKA_OPT_H+#define BLAKE_ROUND_MKA_OPT_H++#include "blake2-impl.h"++#include <emmintrin.h>+#if defined(__SSSE3__)+#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */+#endif++#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__))+#include <x86intrin.h>+#endif++#if !defined(__AVX512F__)+#if !defined(__AVX2__)+#if !defined(__XOP__)+#if defined(__SSSE3__)+#define r16                                                                    \+    (_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))+#define r24                                                                    \+    (_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))+#define _mm_roti_epi64(x, c)                                                   \+    (-(c) == 32)                                                               \+        ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1))                      \+        : (-(c) == 24)                                                         \+              ? _mm_shuffle_epi8((x), r24)                                     \+              : (-(c) == 16)                                                   \+                    ? _mm_shuffle_epi8((x), r16)                               \+                    : (-(c) == 63)                                             \+                          ? _mm_xor_si128(_mm_srli_epi64((x), -(c)),           \+                                          _mm_add_epi64((x), (x)))             \+                          : _mm_xor_si128(_mm_srli_epi64((x), -(c)),           \+                                          _mm_slli_epi64((x), 64 - (-(c))))+#else /* defined(__SSE2__) */+#define _mm_roti_epi64(r, c)                                                   \+    _mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c))))+#endif+#else+#endif++static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) {+    const __m128i z = _mm_mul_epu32(x, y);+    return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));+}++#define G1(A0, B0, C0, D0, A1, B1, C1, D1)                                     \+    do {                                                                       \+        A0 = fBlaMka(A0, B0);                                                  \+        A1 = fBlaMka(A1, B1);                                                  \+                                                                               \+        D0 = _mm_xor_si128(D0, A0);                                            \+        D1 = _mm_xor_si128(D1, A1);                                            \+                                                                               \+        D0 = _mm_roti_epi64(D0, -32);                                          \+        D1 = _mm_roti_epi64(D1, -32);                                          \+                                                                               \+        C0 = fBlaMka(C0, D0);                                                  \+        C1 = fBlaMka(C1, D1);                                                  \+                                                                               \+        B0 = _mm_xor_si128(B0, C0);                                            \+        B1 = _mm_xor_si128(B1, C1);                                            \+                                                                               \+        B0 = _mm_roti_epi64(B0, -24);                                          \+        B1 = _mm_roti_epi64(B1, -24);                                          \+    } while ((void)0, 0)++#define G2(A0, B0, C0, D0, A1, B1, C1, D1)                                     \+    do {                                                                       \+        A0 = fBlaMka(A0, B0);                                                  \+        A1 = fBlaMka(A1, B1);                                                  \+                                                                               \+        D0 = _mm_xor_si128(D0, A0);                                            \+        D1 = _mm_xor_si128(D1, A1);                                            \+                                                                               \+        D0 = _mm_roti_epi64(D0, -16);                                          \+        D1 = _mm_roti_epi64(D1, -16);                                          \+                                                                               \+        C0 = fBlaMka(C0, D0);                                                  \+        C1 = fBlaMka(C1, D1);                                                  \+                                                                               \+        B0 = _mm_xor_si128(B0, C0);                                            \+        B1 = _mm_xor_si128(B1, C1);                                            \+                                                                               \+        B0 = _mm_roti_epi64(B0, -63);                                          \+        B1 = _mm_roti_epi64(B1, -63);                                          \+    } while ((void)0, 0)++#if defined(__SSSE3__)+#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                            \+    do {                                                                       \+        __m128i t0 = _mm_alignr_epi8(B1, B0, 8);                               \+        __m128i t1 = _mm_alignr_epi8(B0, B1, 8);                               \+        B0 = t0;                                                               \+        B1 = t1;                                                               \+                                                                               \+        t0 = C0;                                                               \+        C0 = C1;                                                               \+        C1 = t0;                                                               \+                                                                               \+        t0 = _mm_alignr_epi8(D1, D0, 8);                                       \+        t1 = _mm_alignr_epi8(D0, D1, 8);                                       \+        D0 = t1;                                                               \+        D1 = t0;                                                               \+    } while ((void)0, 0)++#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                          \+    do {                                                                       \+        __m128i t0 = _mm_alignr_epi8(B0, B1, 8);                               \+        __m128i t1 = _mm_alignr_epi8(B1, B0, 8);                               \+        B0 = t0;                                                               \+        B1 = t1;                                                               \+                                                                               \+        t0 = C0;                                                               \+        C0 = C1;                                                               \+        C1 = t0;                                                               \+                                                                               \+        t0 = _mm_alignr_epi8(D0, D1, 8);                                       \+        t1 = _mm_alignr_epi8(D1, D0, 8);                                       \+        D0 = t1;                                                               \+        D1 = t0;                                                               \+    } while ((void)0, 0)+#else /* SSE2 */+#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                            \+    do {                                                                       \+        __m128i t0 = D0;                                                       \+        __m128i t1 = B0;                                                       \+        D0 = C0;                                                               \+        C0 = C1;                                                               \+        C1 = D0;                                                               \+        D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0));               \+        D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1));               \+        B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1));               \+        B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1));               \+    } while ((void)0, 0)++#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                          \+    do {                                                                       \+        __m128i t0, t1;                                                        \+        t0 = C0;                                                               \+        C0 = C1;                                                               \+        C1 = t0;                                                               \+        t0 = B0;                                                               \+        t1 = D0;                                                               \+        B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0));               \+        B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1));               \+        D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1));               \+        D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1));               \+    } while ((void)0, 0)+#endif++#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1)                           \+    do {                                                                       \+        G1(A0, B0, C0, D0, A1, B1, C1, D1);                                    \+        G2(A0, B0, C0, D0, A1, B1, C1, D1);                                    \+                                                                               \+        DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1);                           \+                                                                               \+        G1(A0, B0, C0, D0, A1, B1, C1, D1);                                    \+        G2(A0, B0, C0, D0, A1, B1, C1, D1);                                    \+                                                                               \+        UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1);                         \+    } while ((void)0, 0)+#else /* __AVX2__ */++#include <immintrin.h>++#define rotr32(x)   _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1))+#define rotr24(x)   _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))+#define rotr16(x)   _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))+#define rotr63(x)   _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x)))++#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+    do { \+        __m256i ml = _mm256_mul_epu32(A0, B0); \+        ml = _mm256_add_epi64(ml, ml); \+        A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \+        D0 = _mm256_xor_si256(D0, A0); \+        D0 = rotr32(D0); \+        \+        ml = _mm256_mul_epu32(C0, D0); \+        ml = _mm256_add_epi64(ml, ml); \+        C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \+        \+        B0 = _mm256_xor_si256(B0, C0); \+        B0 = rotr24(B0); \+        \+        ml = _mm256_mul_epu32(A1, B1); \+        ml = _mm256_add_epi64(ml, ml); \+        A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \+        D1 = _mm256_xor_si256(D1, A1); \+        D1 = rotr32(D1); \+        \+        ml = _mm256_mul_epu32(C1, D1); \+        ml = _mm256_add_epi64(ml, ml); \+        C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \+        \+        B1 = _mm256_xor_si256(B1, C1); \+        B1 = rotr24(B1); \+    } while((void)0, 0);++#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+    do { \+        __m256i ml = _mm256_mul_epu32(A0, B0); \+        ml = _mm256_add_epi64(ml, ml); \+        A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \+        D0 = _mm256_xor_si256(D0, A0); \+        D0 = rotr16(D0); \+        \+        ml = _mm256_mul_epu32(C0, D0); \+        ml = _mm256_add_epi64(ml, ml); \+        C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \+        B0 = _mm256_xor_si256(B0, C0); \+        B0 = rotr63(B0); \+        \+        ml = _mm256_mul_epu32(A1, B1); \+        ml = _mm256_add_epi64(ml, ml); \+        A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \+        D1 = _mm256_xor_si256(D1, A1); \+        D1 = rotr16(D1); \+        \+        ml = _mm256_mul_epu32(C1, D1); \+        ml = _mm256_add_epi64(ml, ml); \+        C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \+        B1 = _mm256_xor_si256(B1, C1); \+        B1 = rotr63(B1); \+    } while((void)0, 0);++#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \+    do { \+        B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \+        C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \+        D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \+        \+        B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \+        C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \+        D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \+    } while((void)0, 0);++#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \+    do { \+        __m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \+        __m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \+        B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \+        B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \+        \+        tmp1 = C0; \+        C0 = C1; \+        C1 = tmp1; \+        \+        tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \+        tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \+        D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \+        D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \+    } while(0);++#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \+    do { \+        B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \+        C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \+        D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \+        \+        B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \+        C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \+        D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \+    } while((void)0, 0);++#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \+    do { \+        __m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \+        __m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \+        B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \+        B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \+        \+        tmp1 = C0; \+        C0 = C1; \+        C1 = tmp1; \+        \+        tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \+        tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \+        D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \+        D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \+    } while((void)0, 0);++#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \+    do{ \+        G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        \+        DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \+        \+        G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        \+        UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \+    } while((void)0, 0);++#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \+    do{ \+        G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        \+        DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \+        \+        G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \+        \+        UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \+    } while((void)0, 0);++#endif /* __AVX2__ */++#else /* __AVX512F__ */++#include <immintrin.h>++#define ror64(x, n) _mm512_ror_epi64((x), (n))++static __m512i muladd(__m512i x, __m512i y)+{+    __m512i z = _mm512_mul_epu32(x, y);+    return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z));+}++#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \+    do { \+        A0 = muladd(A0, B0); \+        A1 = muladd(A1, B1); \+\+        D0 = _mm512_xor_si512(D0, A0); \+        D1 = _mm512_xor_si512(D1, A1); \+\+        D0 = ror64(D0, 32); \+        D1 = ror64(D1, 32); \+\+        C0 = muladd(C0, D0); \+        C1 = muladd(C1, D1); \+\+        B0 = _mm512_xor_si512(B0, C0); \+        B1 = _mm512_xor_si512(B1, C1); \+\+        B0 = ror64(B0, 24); \+        B1 = ror64(B1, 24); \+    } while ((void)0, 0)++#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \+    do { \+        A0 = muladd(A0, B0); \+        A1 = muladd(A1, B1); \+\+        D0 = _mm512_xor_si512(D0, A0); \+        D1 = _mm512_xor_si512(D1, A1); \+\+        D0 = ror64(D0, 16); \+        D1 = ror64(D1, 16); \+\+        C0 = muladd(C0, D0); \+        C1 = muladd(C1, D1); \+\+        B0 = _mm512_xor_si512(B0, C0); \+        B1 = _mm512_xor_si512(B1, C1); \+\+        B0 = ror64(B0, 63); \+        B1 = ror64(B1, 63); \+    } while ((void)0, 0)++#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \+    do { \+        B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \+        B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \+\+        C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \+        C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \+\+        D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \+        D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \+    } while ((void)0, 0)++#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \+    do { \+        B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \+        B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \+\+        C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \+        C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \+\+        D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \+        D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \+    } while ((void)0, 0)++#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \+    do { \+        G1(A0, B0, C0, D0, A1, B1, C1, D1); \+        G2(A0, B0, C0, D0, A1, B1, C1, D1); \+\+        DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \+\+        G1(A0, B0, C0, D0, A1, B1, C1, D1); \+        G2(A0, B0, C0, D0, A1, B1, C1, D1); \+\+        UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \+    } while ((void)0, 0)++#define SWAP_HALVES(A0, A1) \+    do { \+        __m512i t0, t1; \+        t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \+        t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \+        A0 = t0; \+        A1 = t1; \+    } while((void)0, 0)++#define SWAP_QUARTERS(A0, A1) \+    do { \+        SWAP_HALVES(A0, A1); \+        A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \+        A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \+    } while((void)0, 0)++#define UNSWAP_QUARTERS(A0, A1) \+    do { \+        A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \+        A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \+        SWAP_HALVES(A0, A1); \+    } while((void)0, 0)++#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \+    do { \+        SWAP_HALVES(A0, B0); \+        SWAP_HALVES(C0, D0); \+        SWAP_HALVES(A1, B1); \+        SWAP_HALVES(C1, D1); \+        BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \+        SWAP_HALVES(A0, B0); \+        SWAP_HALVES(C0, D0); \+        SWAP_HALVES(A1, B1); \+        SWAP_HALVES(C1, D1); \+    } while ((void)0, 0)++#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \+    do { \+        SWAP_QUARTERS(A0, A1); \+        SWAP_QUARTERS(B0, B1); \+        SWAP_QUARTERS(C0, C1); \+        SWAP_QUARTERS(D0, D1); \+        BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \+        UNSWAP_QUARTERS(A0, A1); \+        UNSWAP_QUARTERS(B0, B1); \+        UNSWAP_QUARTERS(C0, C1); \+        UNSWAP_QUARTERS(D0, D1); \+    } while ((void)0, 0)++#endif /* __AVX512F__ */+#endif /* BLAKE_ROUND_MKA_OPT_H */
phc-winner-argon2/src/blake2/blamka-round-ref.h view
@@ -1,10 +1,27 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */+ #ifndef BLAKE_ROUND_MKA_H #define BLAKE_ROUND_MKA_H  #include "blake2.h" #include "blake2-impl.h" -/*designed by the Lyra PHC team */+/* designed by the Lyra PHC team */ static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) {     const uint64_t m = UINT64_C(0xFFFFFFFF);     const uint64_t xy = (x & m) * (y & m);
phc-winner-argon2/src/core.c view
@@ -1,14 +1,18 @@ /*- * Argon2 source code package+ * Argon2 reference source code package - reference C implementations  *- * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves  *- * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:  *- * You should have received a copy of the CC0 Public Domain Dedication along- * with- * this software. If not, see- * <http://creativecommons.org/publicdomain/zero/1.0/>.+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.  */  /*For memory wiping*/@@ -21,7 +25,6 @@ #endif #define VC_GE_2005(version) (version >= 1400) -#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h>@@ -78,27 +81,45 @@     } } -/***************Memory allocators*****************/-int allocate_memory(block **memory, uint32_t m_cost) {-    if (memory != NULL) {-        size_t memory_size = sizeof(block) * m_cost;-        if (m_cost != 0 &&-            memory_size / m_cost !=-                sizeof(block)) { /*1. Check for multiplication overflow*/-            return ARGON2_MEMORY_ALLOCATION_ERROR;-        }+/***************Memory functions*****************/ -        *memory = (block *)malloc(memory_size); /*2. Try to allocate*/+int allocate_memory(const argon2_context *context, uint8_t **memory,+                    size_t num, size_t size) {+    size_t memory_size = num*size;+    if (memory == NULL) {+        return ARGON2_MEMORY_ALLOCATION_ERROR;+    } -        if (!*memory) {-            return ARGON2_MEMORY_ALLOCATION_ERROR;-        }-        return ARGON2_OK;+    /* 1. Check for multiplication overflow */+    if (size != 0 && memory_size / size != num) {+        return ARGON2_MEMORY_ALLOCATION_ERROR;+    }++    /* 2. Try to allocate with appropriate allocator */+    if (context->allocate_cbk) {+        (context->allocate_cbk)(memory, memory_size);     } else {+        *memory = malloc(memory_size);+    }++    if (*memory == NULL) {         return ARGON2_MEMORY_ALLOCATION_ERROR;     }++    return ARGON2_OK; } +void free_memory(const argon2_context *context, uint8_t *memory,+                 size_t num, size_t size) {+    size_t memory_size = num*size;+    clear_internal_memory(memory, memory_size);+    if (context->free_cbk) {+        (context->free_cbk)(memory, memory_size);+    } else {+        free(memory);+    }+}+ void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) { #if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)     SecureZeroMemory(v, n);@@ -112,17 +133,14 @@ #endif } -/*********Memory functions*/--void clear_memory(argon2_instance_t *instance, int clear) {-    if (instance->memory != NULL && clear) {-        secure_wipe_memory(instance->memory,-                           sizeof(block) * instance->memory_blocks);-    }+/* Memory clear flag defaults to true. */+int FLAG_clear_internal_memory = 1;+void clear_internal_memory(void *v, size_t n) {+  if (FLAG_clear_internal_memory && v) {+    secure_wipe_memory(v, n);+  } } -void free_memory(block *memory) { free(memory); }- void finalize(const argon2_context *context, argon2_instance_t *instance) {     if (context != NULL && instance != NULL) {         block blockhash;@@ -143,26 +161,17 @@             store_block(blockhash_bytes, &blockhash);             blake2b_long(context->out, context->outlen, blockhash_bytes,                          ARGON2_BLOCK_SIZE);-            secure_wipe_memory(blockhash.v,-                               ARGON2_BLOCK_SIZE); /* clear blockhash */-            secure_wipe_memory(blockhash_bytes,-                               ARGON2_BLOCK_SIZE); /* clear blockhash_bytes */+            /* clear blockhash and blockhash_bytes */+            clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE);+            clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);         }  #ifdef GENKAT         print_tag(context->out, context->outlen); #endif -        /* Clear memory */-        clear_memory(instance, context->flags & ARGON2_FLAG_CLEAR_PASSWORD);--        /* Deallocate the memory */-        if (NULL != context->free_cbk) {-            context->free_cbk((uint8_t *)instance->memory,-                              instance->memory_blocks * sizeof(block));-        } else {-            free_memory(instance->memory);-        }+        free_memory(context, (uint8_t *)instance->memory,+                    instance->memory_blocks, sizeof(block));     } } @@ -236,42 +245,60 @@     return absolute_position; } +/* Single-threaded version for p=1 case */+static int fill_memory_blocks_st(argon2_instance_t *instance) {+    uint32_t r, s, l;++    for (r = 0; r < instance->passes; ++r) {+        for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {+            for (l = 0; l < instance->lanes; ++l) {+                argon2_position_t position = {r, l, (uint8_t)s, 0};+                fill_segment(instance, position);+            }+        }+#ifdef GENKAT+        internal_kat(instance, r); /* Print all memory blocks */+#endif+    }+    return ARGON2_OK;+}++#if !defined(ARGON2_NO_THREADS)+ #ifdef _WIN32 static unsigned __stdcall fill_segment_thr(void *thread_data) #else static void *fill_segment_thr(void *thread_data) #endif {-    argon2_thread_data *my_data = (argon2_thread_data *)thread_data;+    argon2_thread_data *my_data = thread_data;     fill_segment(my_data->instance_ptr, my_data->pos);     argon2_thread_exit();     return 0; } -int fill_memory_blocks(argon2_instance_t *instance) {+/* Multi-threaded version for p > 1 case */+static int fill_memory_blocks_mt(argon2_instance_t *instance) {     uint32_t r, s;     argon2_thread_handle_t *thread = NULL;     argon2_thread_data *thr_data = NULL;--    if (instance == NULL || instance->lanes == 0) {-        return ARGON2_THREAD_FAIL;-    }+    int rc = ARGON2_OK;      /* 1. Allocating space for threads */     thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t));     if (thread == NULL) {-        return ARGON2_MEMORY_ALLOCATION_ERROR;+        rc = ARGON2_MEMORY_ALLOCATION_ERROR;+        goto fail;     }      thr_data = calloc(instance->lanes, sizeof(argon2_thread_data));     if (thr_data == NULL) {-        free(thread);-        return ARGON2_MEMORY_ALLOCATION_ERROR;+        rc = ARGON2_MEMORY_ALLOCATION_ERROR;+        goto fail;     }      for (r = 0; r < instance->passes; ++r) {         for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {-            int rc;             uint32_t l;              /* 2. Calling threads */@@ -280,11 +307,9 @@                  /* 2.1 Join a thread if limit is exceeded */                 if (l >= instance->threads) {-                    rc = argon2_thread_join(thread[l - instance->threads]);-                    if (rc) {-                        free(thr_data);-                        free(thread);-                        return ARGON2_THREAD_FAIL;+                    if (argon2_thread_join(thread[l - instance->threads])) {+                        rc = ARGON2_THREAD_FAIL;+                        goto fail;                     }                 } @@ -297,12 +322,10 @@                     instance; /* preparing the thread input */                 memcpy(&(thr_data[l].pos), &position,                        sizeof(argon2_position_t));-                rc = argon2_thread_create(&thread[l], &fill_segment_thr,-                                          (void *)&thr_data[l]);-                if (rc) {-                    free(thr_data);-                    free(thread);-                    return ARGON2_THREAD_FAIL;+                if (argon2_thread_create(&thread[l], &fill_segment_thr,+                                         (void *)&thr_data[l])) {+                    rc = ARGON2_THREAD_FAIL;+                    goto fail;                 }                  /* fill_segment(instance, position); */@@ -312,9 +335,9 @@             /* 3. Joining remaining threads */             for (l = instance->lanes - instance->threads; l < instance->lanes;                  ++l) {-                rc = argon2_thread_join(thread[l]);-                if (rc) {-                    return ARGON2_THREAD_FAIL;+                if (argon2_thread_join(thread[l])) {+                    rc = ARGON2_THREAD_FAIL;+                    goto fail;                 }             }         }@@ -324,15 +347,30 @@ #endif     } +fail:     if (thread != NULL) {         free(thread);     }     if (thr_data != NULL) {         free(thr_data);     }-    return ARGON2_OK;+    return rc; } +#endif /* ARGON2_NO_THREADS */++int fill_memory_blocks(argon2_instance_t *instance) {+	if (instance == NULL || instance->lanes == 0) {+	    return ARGON2_INCORRECT_PARAMETER;+    }+#if defined(ARGON2_NO_THREADS)+    return fill_memory_blocks_st(instance);+#else+    return instance->threads == 1 ?+			fill_memory_blocks_st(instance) : fill_memory_blocks_mt(instance);+#endif+}+ int validate_inputs(const argon2_context *context) {     if (NULL == context) {         return ARGON2_INCORRECT_PARAMETER;@@ -351,37 +389,37 @@         return ARGON2_OUTPUT_TOO_LONG;     } -    /* Validate password length */+    /* Validate password (required param) */     if (NULL == context->pwd) {         if (0 != context->pwdlen) {             return ARGON2_PWD_PTR_MISMATCH;         }-    } else {-        if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {-            return ARGON2_PWD_TOO_SHORT;-        }+    } -        if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {-            return ARGON2_PWD_TOO_LONG;-        }+    if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {+      return ARGON2_PWD_TOO_SHORT;     } -    /* Validate salt length */+    if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {+        return ARGON2_PWD_TOO_LONG;+    }++    /* Validate salt (required param) */     if (NULL == context->salt) {         if (0 != context->saltlen) {             return ARGON2_SALT_PTR_MISMATCH;         }-    } else {-        if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {-            return ARGON2_SALT_TOO_SHORT;-        }+    } -        if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {-            return ARGON2_SALT_TOO_LONG;-        }+    if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {+        return ARGON2_SALT_TOO_SHORT;     } -    /* Validate secret length */+    if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {+        return ARGON2_SALT_TOO_LONG;+    }++    /* Validate secret (optional param) */     if (NULL == context->secret) {         if (0 != context->secretlen) {             return ARGON2_SECRET_PTR_MISMATCH;@@ -390,13 +428,12 @@         if (ARGON2_MIN_SECRET > context->secretlen) {             return ARGON2_SECRET_TOO_SHORT;         }-         if (ARGON2_MAX_SECRET < context->secretlen) {             return ARGON2_SECRET_TOO_LONG;         }     } -    /* Validate associated data */+    /* Validate associated data (optional param) */     if (NULL == context->ad) {         if (0 != context->adlen) {             return ARGON2_AD_PTR_MISMATCH;@@ -405,7 +442,6 @@         if (ARGON2_MIN_AD_LENGTH > context->adlen) {             return ARGON2_AD_TOO_SHORT;         }-         if (ARGON2_MAX_AD_LENGTH < context->adlen) {             return ARGON2_AD_TOO_LONG;         }@@ -464,8 +500,8 @@  void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) {     uint32_t l;-    /* Make the first and second block in each lane as G(H0||i||0) or-       G(H0||i||1) */+    /* Make the first and second block in each lane as G(H0||0||i) or+       G(H0||1||i) */     uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];     for (l = 0; l < instance->lanes; ++l) { @@ -482,7 +518,7 @@         load_block(&instance->memory[l * instance->lane_length + 1],                    blockhash_bytes);     }-    secure_wipe_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);+    clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); }  void initial_hash(uint8_t *blockhash, argon2_context *context,@@ -565,22 +601,13 @@      if (instance == NULL || context == NULL)         return ARGON2_INCORRECT_PARAMETER;+    instance->context_ptr = context;      /* 1. Memory allocation */--    if (NULL != context->allocate_cbk) {-        uint8_t *p;-        result = context->allocate_cbk(&p, instance->memory_blocks *-                                               ARGON2_BLOCK_SIZE);-        if (ARGON2_OK != result) {-            return result;-        }-        instance->memory = (block *)p;-    } else {-        result = allocate_memory(&(instance->memory), instance->memory_blocks);-        if (ARGON2_OK != result) {-            return result;-        }+    result = allocate_memory(context, (uint8_t **)&(instance->memory),+                             instance->memory_blocks, sizeof(block));+    if (result != ARGON2_OK) {+        return result;     }      /* 2. Initial hashing */@@ -589,9 +616,9 @@     /* Hashing all inputs */     initial_hash(blockhash, context, instance->type);     /* Zeroing 8 extra bytes */-    secure_wipe_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,-                       ARGON2_PREHASH_SEED_LENGTH --                           ARGON2_PREHASH_DIGEST_LENGTH);+    clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,+                          ARGON2_PREHASH_SEED_LENGTH -+                              ARGON2_PREHASH_DIGEST_LENGTH);  #ifdef GENKAT     initial_kat(blockhash, context, instance->type);@@ -601,7 +628,7 @@      */     fill_first_blocks(blockhash, instance);     /* Clearing the hash */-    secure_wipe_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);+    clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);      return ARGON2_OK; }
phc-winner-argon2/src/core.h view
@@ -1,14 +1,18 @@ /*- * Argon2 source code package+ * Argon2 reference source code package - reference C implementations  *- * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves  *- * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:  *- * You should have received a copy of the CC0 Public Domain Dedication along- * with- * this software. If not, see- * <http://creativecommons.org/publicdomain/zero/1.0/>.+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.  */  #ifndef ARGON2_CORE_H@@ -16,24 +20,17 @@  #include "argon2.h" -#if defined(_MSC_VER)-#define ALIGN(n) __declspec(align(16))-#elif defined(__GNUC__) || defined(__clang)-#define ALIGN(x) __attribute__((__aligned__(x)))-#else-#define ALIGN(x)-#endif- #define CONST_CAST(x) (x)(uintptr_t) -/*************************Argon2 internal- * constants**************************************************/+/**********************Argon2 internal constants*******************************/  enum argon2_core_constants {     /* Memory block size in bytes */     ARGON2_BLOCK_SIZE = 1024,     ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,     ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,+    ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,+    ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,      /* Number of pseudo-random values generated by one call to Blake in Argon2i        to@@ -45,8 +42,7 @@     ARGON2_PREHASH_SEED_LENGTH = 72 }; -/*************************Argon2 internal data- * types**************************************************/+/*************************Argon2 internal data types***********************/  /*  * Structure for the (1KB) memory block implemented as 128 64-bit words.@@ -83,6 +79,7 @@     uint32_t threads;     argon2_type type;     int print_internals; /* whether to print the memory blocks */+    argon2_context *context_ptr; /* points back to original context */ } argon2_instance_t;  /*@@ -102,32 +99,43 @@     argon2_position_t pos; } argon2_thread_data; -/*************************Argon2 core- * functions**************************************************/+/*************************Argon2 core functions********************************/ -/* Allocates memory to the given pointer+/* Allocates memory to the given pointer, uses the appropriate allocator as+ * specified in the context. Total allocated memory is num*size.+ * @param context argon2_context which specifies the allocator  * @param memory pointer to the pointer to the memory- * @param m_cost number of blocks to allocate in the memory+ * @param size the size in bytes for each element to be allocated+ * @param num the number of elements to be allocated  * @return ARGON2_OK if @memory is a valid pointer and memory is allocated  */-int allocate_memory(block **memory, uint32_t m_cost);+int allocate_memory(const argon2_context *context, uint8_t **memory,+                    size_t num, size_t size); -/* Function that securely cleans the memory+/*+ * Frees memory at the given pointer, uses the appropriate deallocator as+ * specified in the context. Also cleans the memory using clear_internal_memory.+ * @param context argon2_context which specifies the deallocator+ * @param memory pointer to buffer to be freed+ * @param size the size in bytes for each element to be deallocated+ * @param num the number of elements to be deallocated+ */+void free_memory(const argon2_context *context, uint8_t *memory,+                 size_t num, size_t size);++/* Function that securely cleans the memory. This ignores any flags set+ * regarding clearing memory. Usually one just calls clear_internal_memory.  * @param mem Pointer to the memory  * @param s Memory size in bytes  */ void secure_wipe_memory(void *v, size_t n); -/* Clears memory- * @param instance pointer to the current instance- * @param clear_memory indicates if we clear the memory with zeros.- */-void clear_memory(argon2_instance_t *instance, int clear);--/* Deallocates memory- * @param memory pointer to the blocks+/* Function that securely clears the memory if FLAG_clear_internal_memory is+ * set. If the flag isn't set, this function does nothing.+ * @param mem Pointer to the memory+ * @param s Memory size in bytes  */-void free_memory(block *memory);+void clear_internal_memory(void *v, size_t n);  /*  * Computes absolute position of reference block in the lane following a skewed@@ -201,6 +209,7 @@ /*  * Function that fills the segment using previous segments also from other  * threads+ * @param context current context  * @param instance Pointer to the current instance  * @param position Current position  * @pre all block pointers must be valid
phc-winner-argon2/src/encoding.c view
@@ -1,3 +1,20 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */+ #include <stdio.h> #include <stdlib.h> #include <string.h>@@ -22,11 +39,6 @@  *   the parameters, salts and outputs. It does not compute the hash  *   itself.  *- *   -- The third section is test code, with a main() function. With- *   this section, the whole file compiles as a stand-alone program- *   that exercises the encoding and decoding functions with some- *   test vectors.- *  * The code was originally written by Thomas Pornin <pornin@bolet.org>,  * to whom comments and remarks may be sent. It is released under what  * should amount to Public Domain or its closest equivalent; the@@ -229,19 +241,18 @@  *  * The code below applies the following format:  *- *  $argon2<T>[$v=<num>]$m=<num>,t=<num>,p=<num>[,keyid=<bin>][,data=<bin>][$<bin>[$<bin>]]+ *  $argon2<T>[$v=<num>]$m=<num>,t=<num>,p=<num>$<bin>$<bin>  *- * where <T> is either 'd' or 'i', <num> is a decimal integer (positive, fits in- * an 'unsigned long'), and <bin> is Base64-encoded data (no '=' padding+ * where <T> is either 'd', 'id', or 'i', <num> is a decimal integer (positive,+ * fits in an 'unsigned long'), and <bin> is Base64-encoded data (no '=' padding  * characters, no newline or whitespace).- * The "keyid" is a binary identifier for a key (up to 8 bytes);- * "data" is associated data (up to 32 bytes). When the 'keyid'- * (resp. the 'data') is empty, then it is ommitted from the output.  *  * The last two binary chunks (encoded in Base64) are, in that order,- * the salt and the output. Both are optional, but you cannot have an- * output without a salt. The binary salt length is between 8 and 48 bytes.- * The output length is always exactly 32 bytes.+ * the salt and the output. Both are required. The binary salt length and the+ * output length must be in the allowed ranges defined in argon2.h.+ *+ * The ctx struct must contain buffers large enough to hold the salt and pwd+ * when it is fed into decode_string.  */  int decode_string(argon2_context *ctx, const char *str, argon2_type type) {@@ -256,7 +267,7 @@         str += cc_len;                                                         \     } while ((void)0, 0) -/* prefix checking with supplied code */+/* optional prefix checking with supplied code */ #define CC_opt(prefix, code)                                                   \     do {                                                                       \         size_t cc_len = strlen(prefix);                                        \@@ -266,7 +277,7 @@         }                                                                      \     } while ((void)0, 0) -/* Decoding  prefix into decimal */+/* Decoding prefix into decimal */ #define DECIMAL(x)                                                             \     do {                                                                       \         unsigned long dec_x;                                                   \@@ -277,6 +288,20 @@         (x) = dec_x;                                                           \     } while ((void)0, 0) ++/* Decoding prefix into uint32_t decimal */+#define DECIMAL_U32(x)                                                         \+    do {                                                                       \+        unsigned long dec_x;                                                   \+        str = decode_decimal(str, &dec_x);                                     \+        if (str == NULL || dec_x > UINT32_MAX) {                               \+            return ARGON2_DECODING_FAIL;                                       \+        }                                                                      \+        (x) = (uint32_t)dec_x;                                                 \+    } while ((void)0, 0)+++/* Decoding base64 into a binary buffer */ #define BIN(buf, max_len, len)                                                 \     do {                                                                       \         size_t bin_len = (max_len);                                            \@@ -287,48 +312,53 @@         (len) = (uint32_t)bin_len;                                             \     } while ((void)0, 0) -    size_t maxadlen = ctx->adlen;     size_t maxsaltlen = ctx->saltlen;     size_t maxoutlen = ctx->outlen;     int validation_result;--    ctx->adlen = 0;-    ctx->saltlen = 0;-    ctx->outlen = 0;-    ctx->pwdlen = 0;+    const char* type_string; -    if (type == Argon2_i)-        CC("$argon2i");-    else if (type == Argon2_d)-        CC("$argon2d");-    else+    /* We should start with the argon2_type we are using */+    type_string = argon2_type2string(type, 0);+    if (!type_string) {         return ARGON2_INCORRECT_TYPE;-    ctx->version = ARGON2_VERSION_10;+    }++    CC("$");+    CC(type_string);+     /* Reading the version number if the default is suppressed */-    CC_opt("$v=", DECIMAL(ctx->version));+    ctx->version = ARGON2_VERSION_10;+    CC_opt("$v=", DECIMAL_U32(ctx->version));+     CC("$m=");-    DECIMAL(ctx->m_cost);+    DECIMAL_U32(ctx->m_cost);     CC(",t=");-    DECIMAL(ctx->t_cost);+    DECIMAL_U32(ctx->t_cost);     CC(",p=");-    DECIMAL(ctx->lanes);+    DECIMAL_U32(ctx->lanes);     ctx->threads = ctx->lanes; -    CC_opt(",data=", BIN(ctx->ad, maxadlen, ctx->adlen));-    if (*str == 0) {-        return ARGON2_OK;-    }     CC("$");     BIN(ctx->salt, maxsaltlen, ctx->saltlen);-    if (*str == 0) {-        return ARGON2_OK;-    }     CC("$");     BIN(ctx->out, maxoutlen, ctx->outlen);++    /* The rest of the fields get the default values */+    ctx->secret = NULL;+    ctx->secretlen = 0;+    ctx->ad = NULL;+    ctx->adlen = 0;+    ctx->allocate_cbk = NULL;+    ctx->free_cbk = NULL;+    ctx->flags = ARGON2_DEFAULT_FLAGS;++    /* On return, must have valid context */     validation_result = validate_inputs(ctx);     if (validation_result != ARGON2_OK) {         return validation_result;     }++    /* Can't have any additional characters */     if (*str == 0) {         return ARGON2_OK;     } else {@@ -370,17 +400,24 @@         dst_len -= sb_len;                                                     \     } while ((void)0, 0) -    if (type == Argon2_i)-        SS("$argon2i$v=");-    else if (type == Argon2_d)-        SS("$argon2d$v=");-    else-        return ARGON2_ENCODING_FAIL;+    const char* type_string = argon2_type2string(type, 0);+    int validation_result = validate_inputs(ctx); -    if (validate_inputs(ctx) != ARGON2_OK) {-        return validate_inputs(ctx);+    if (!type_string) {+      return ARGON2_ENCODING_FAIL;     }++    if (validation_result != ARGON2_OK) {+      return validation_result;+    }+++    SS("$");+    SS(type_string);++    SS("$v=");     SX(ctx->version);+     SS("$m=");     SX(ctx->m_cost);     SS(",t=");@@ -388,19 +425,8 @@     SS(",p=");     SX(ctx->lanes); -    if (ctx->adlen > 0) {-        SS(",data=");-        SB(ctx->ad, ctx->adlen);-    }--    if (ctx->saltlen == 0)-        return ARGON2_OK;-     SS("$");     SB(ctx->salt, ctx->saltlen);--    if (ctx->outlen == 0)-        return ARGON2_OK;      SS("$");     SB(ctx->out, ctx->outlen);
phc-winner-argon2/src/encoding.h view
@@ -1,3 +1,20 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */+ #ifndef ENCODING_H #define ENCODING_H #include "argon2.h"@@ -12,21 +29,21 @@ * is less than the number of required characters (including the * terminating 0), then this function returns ARGON2_ENCODING_ERROR. *-* if ctx->outlen is 0, then the hash string will be a salt string-* (no output). if ctx->saltlen is also 0, then the string will be a-* parameter-only string (no salt and no output).-* * on success, ARGON2_OK is returned.-*-* No other parameters are checked */ int encode_string(char *dst, size_t dst_len, argon2_context *ctx,                   argon2_type type);  /* * Decodes an Argon2 hash string into the provided structure 'ctx'.-* The fields ctx.saltlen, ctx.adlen, ctx.outlen set the maximal salt, ad, out-* length values that are allowed; invalid input string causes an error.+* The only fields that must be set prior to this call are ctx.saltlen and+* ctx.outlen (which must be the maximal salt and out length values that are+* allowed), ctx.salt and ctx.out (which must be buffers of the specified+* length), and ctx.pwd and ctx.pwdlen which must hold a valid password.+*+* Invalid input string causes an error. On success, the ctx is valid and all+* fields have been initialized.+* * Returned value is ARGON2_OK on success, other ARGON2_ codes on error. */ int decode_string(argon2_context *ctx, const char *str, argon2_type type);
+ phc-winner-argon2/src/opt.c view
@@ -0,0 +1,283 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */++#include <stdint.h>+#include <string.h>+#include <stdlib.h>++#include "argon2.h"+#include "core.h"++#include "blake2/blake2.h"+#include "blake2/blamka-round-opt.h"++/*+ * Function fills a new memory block and optionally XORs the old block over the new one.+ * Memory must be initialized.+ * @param state Pointer to the just produced block. Content will be updated(!)+ * @param ref_block Pointer to the reference block+ * @param next_block Pointer to the block to be XORed over. May coincide with @ref_block+ * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)+ * @pre all block pointers must be valid+ */+#if defined(__AVX512F__)+static void fill_block(__m512i *state, const block *ref_block,+                       block *next_block, int with_xor) {+    __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];+    unsigned int i;++    if (with_xor) {+        for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {+            state[i] = _mm512_xor_si512(+                state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));+            block_XY[i] = _mm512_xor_si512(+                state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));+        }+    } else {+        for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {+            block_XY[i] = state[i] = _mm512_xor_si512(+                state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));+        }+    }++    for (i = 0; i < 2; ++i) {+        BLAKE2_ROUND_1(+            state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],+            state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);+    }++    for (i = 0; i < 2; ++i) {+        BLAKE2_ROUND_2(+            state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i],+            state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);+    }++    for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {+        state[i] = _mm512_xor_si512(state[i], block_XY[i]);+        _mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);+    }+}+#elif defined(__AVX2__)+static void fill_block(__m256i *state, const block *ref_block,+                       block *next_block, int with_xor) {+    __m256i block_XY[ARGON2_HWORDS_IN_BLOCK];+    unsigned int i;++    if (with_xor) {+        for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {+            state[i] = _mm256_xor_si256(+                state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));+            block_XY[i] = _mm256_xor_si256(+                state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));+        }+    } else {+        for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {+            block_XY[i] = state[i] = _mm256_xor_si256(+                state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));+        }+    }++    for (i = 0; i < 4; ++i) {+        BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],+                       state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);+    }++    for (i = 0; i < 4; ++i) {+        BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i],+                       state[16 + i], state[20 + i], state[24 + i], state[28 + i]);+    }++    for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {+        state[i] = _mm256_xor_si256(state[i], block_XY[i]);+        _mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);+    }+}+#else+static void fill_block(__m128i *state, const block *ref_block,+                       block *next_block, int with_xor) {+    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];+    unsigned int i;++    if (with_xor) {+        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {+            state[i] = _mm_xor_si128(+                state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));+            block_XY[i] = _mm_xor_si128(+                state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));+        }+    } else {+        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {+            block_XY[i] = state[i] = _mm_xor_si128(+                state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));+        }+    }++    for (i = 0; i < 8; ++i) {+        BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2],+            state[8 * i + 3], state[8 * i + 4], state[8 * i + 5],+            state[8 * i + 6], state[8 * i + 7]);+    }++    for (i = 0; i < 8; ++i) {+        BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i],+            state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i],+            state[8 * 6 + i], state[8 * 7 + i]);+    }++    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {+        state[i] = _mm_xor_si128(state[i], block_XY[i]);+        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);+    }+}+#endif++static void next_addresses(block *address_block, block *input_block) {+    /*Temporary zero-initialized blocks*/+#if defined(__AVX512F__)+    __m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK];+    __m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK];+#elif defined(__AVX2__)+    __m256i zero_block[ARGON2_HWORDS_IN_BLOCK];+    __m256i zero2_block[ARGON2_HWORDS_IN_BLOCK];+#else+    __m128i zero_block[ARGON2_OWORDS_IN_BLOCK];+    __m128i zero2_block[ARGON2_OWORDS_IN_BLOCK];+#endif++    memset(zero_block, 0, sizeof(zero_block));+    memset(zero2_block, 0, sizeof(zero2_block));++    /*Increasing index counter*/+    input_block->v[6]++;++    /*First iteration of G*/+    fill_block(zero_block, input_block, address_block, 0);++    /*Second iteration of G*/+    fill_block(zero2_block, address_block, address_block, 0);+}++void fill_segment(const argon2_instance_t *instance,+                  argon2_position_t position) {+    block *ref_block = NULL, *curr_block = NULL;+    block address_block, input_block;+    uint64_t pseudo_rand, ref_index, ref_lane;+    uint32_t prev_offset, curr_offset;+    uint32_t starting_index, i;+#if defined(__AVX512F__)+    __m512i state[ARGON2_512BIT_WORDS_IN_BLOCK];+#elif defined(__AVX2__)+    __m256i state[ARGON2_HWORDS_IN_BLOCK];+#else+    __m128i state[ARGON2_OWORDS_IN_BLOCK];+#endif+    int data_independent_addressing;++    if (instance == NULL) {+        return;+    }++    data_independent_addressing =+        (instance->type == Argon2_i) ||+        (instance->type == Argon2_id && (position.pass == 0) &&+         (position.slice < ARGON2_SYNC_POINTS / 2));++    if (data_independent_addressing) {+        init_block_value(&input_block, 0);++        input_block.v[0] = position.pass;+        input_block.v[1] = position.lane;+        input_block.v[2] = position.slice;+        input_block.v[3] = instance->memory_blocks;+        input_block.v[4] = instance->passes;+        input_block.v[5] = instance->type;+    }++    starting_index = 0;++    if ((0 == position.pass) && (0 == position.slice)) {+        starting_index = 2; /* we have already generated the first two blocks */++        /* Don't forget to generate the first block of addresses: */+        if (data_independent_addressing) {+            next_addresses(&address_block, &input_block);+        }+    }++    /* Offset of the current block */+    curr_offset = position.lane * instance->lane_length ++                  position.slice * instance->segment_length + starting_index;++    if (0 == curr_offset % instance->lane_length) {+        /* Last block in this lane */+        prev_offset = curr_offset + instance->lane_length - 1;+    } else {+        /* Previous block */+        prev_offset = curr_offset - 1;+    }++    memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);++    for (i = starting_index; i < instance->segment_length;+         ++i, ++curr_offset, ++prev_offset) {+        /*1.1 Rotating prev_offset if needed */+        if (curr_offset % instance->lane_length == 1) {+            prev_offset = curr_offset - 1;+        }++        /* 1.2 Computing the index of the reference block */+        /* 1.2.1 Taking pseudo-random value from the previous block */+        if (data_independent_addressing) {+            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {+                next_addresses(&address_block, &input_block);+            }+            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];+        } else {+            pseudo_rand = instance->memory[prev_offset].v[0];+        }++        /* 1.2.2 Computing the lane of the reference block */+        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;++        if ((position.pass == 0) && (position.slice == 0)) {+            /* Can not reference other lanes yet */+            ref_lane = position.lane;+        }++        /* 1.2.3 Computing the number of possible reference block within the+         * lane.+         */+        position.index = i;+        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,+                                ref_lane == position.lane);++        /* 2 Creating a new block */+        ref_block =+            instance->memory + instance->lane_length * ref_lane + ref_index;+        curr_block = instance->memory + curr_offset;+        if (ARGON2_VERSION_10 == instance->version) {+            /* version 1.2.1 and earlier: overwrite, not XOR */+            fill_block(state, ref_block, curr_block, 0);+        } else {+            if(0 == position.pass) {+                fill_block(state, ref_block, curr_block, 0);+            } else {+                fill_block(state, ref_block, curr_block, 1);+            }+        }+    }+}
phc-winner-argon2/src/ref.c view
@@ -1,14 +1,18 @@ /*- * Argon2 source code package+ * Argon2 reference source code package - reference C implementations  *- * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves  *- * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:  *- * You should have received a copy of the CC0 Public Domain Dedication along- * with- * this software. If not, see- * <http://creativecommons.org/publicdomain/zero/1.0/>.+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.  */  #include <stdint.h>@@ -16,61 +20,38 @@ #include <stdlib.h>  #include "argon2.h"-#include "ref.h"+#include "core.h"  #include "blake2/blamka-round-ref.h" #include "blake2/blake2-impl.h" #include "blake2/blake2.h"  -void fill_block(const block *prev_block, const block *ref_block,-    block *next_block) {+/*+ * Function fills a new memory block and optionally XORs the old block over the new one.+ * @next_block must be initialized.+ * @param prev_block Pointer to the previous block+ * @param ref_block Pointer to the reference block+ * @param next_block Pointer to the block to be constructed+ * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)+ * @pre all block pointers must be valid+ */+static void fill_block(const block *prev_block, const block *ref_block,+                       block *next_block, int with_xor) {     block blockR, block_tmp;     unsigned i;      copy_block(&blockR, ref_block);     xor_block(&blockR, prev_block);     copy_block(&block_tmp, &blockR);-            /*Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block */-                /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then-                (16,17,..31)... finally (112,113,...127) */-    for (i = 0; i < 8; ++i) {-        BLAKE2_ROUND_NOMSG(-            blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],-            blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],-            blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],-            blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],-            blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],-            blockR.v[16 * i + 15]);-    }--    /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then-    (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */-    for (i = 0; i < 8; i++) {-        BLAKE2_ROUND_NOMSG(-            blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],-            blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],-            blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],-            blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],-            blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],-            blockR.v[2 * i + 113]);+    /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */+    if (with_xor) {+        /* Saving the next block contents for XOR over: */+        xor_block(&block_tmp, next_block);+        /* Now blockR = ref_block + prev_block and+           block_tmp = ref_block + prev_block + next_block */     } -    copy_block(next_block, &block_tmp);-    xor_block(next_block, &blockR);-}---void fill_block_with_xor(const block *prev_block, const block *ref_block,-                block *next_block) {-    block blockR, block_tmp;-    unsigned i;--    copy_block(&blockR, ref_block);-    xor_block(&blockR, prev_block);-    copy_block(&block_tmp, &blockR);-    xor_block(&block_tmp, next_block); /*Saving the next block contents for XOR over*/-    /*Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + next_block*/     /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then        (16,17,..31)... finally (112,113,...127) */     for (i = 0; i < 8; ++i) {@@ -99,69 +80,53 @@     xor_block(next_block, &blockR); } -void generate_addresses(const argon2_instance_t *instance,-                        const argon2_position_t *position,-                        uint64_t *pseudo_rands) {-    block zero_block, input_block, address_block,tmp_block;-    uint32_t i;--    init_block_value(&zero_block, 0);-    init_block_value(&input_block, 0);--    if (instance != NULL && position != NULL) {-        input_block.v[0] = position->pass;-        input_block.v[1] = position->lane;-        input_block.v[2] = position->slice;-        input_block.v[3] = instance->memory_blocks;-        input_block.v[4] = instance->passes;-        input_block.v[5] = instance->type;--        for (i = 0; i < instance->segment_length; ++i) {-            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {-                input_block.v[6]++;-                init_block_value(&tmp_block, 0);-                init_block_value(&address_block, 0);-                fill_block_with_xor(&zero_block, &input_block, &tmp_block);-                fill_block_with_xor(&zero_block, &tmp_block, &address_block);-            }--            pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];-        }-    }+static void next_addresses(block *address_block, block *input_block,+                           const block *zero_block) {+    input_block->v[6]++;+    fill_block(zero_block, input_block, address_block, 0);+    fill_block(zero_block, address_block, address_block, 0); }  void fill_segment(const argon2_instance_t *instance,                   argon2_position_t position) {     block *ref_block = NULL, *curr_block = NULL;+    block address_block, input_block, zero_block;     uint64_t pseudo_rand, ref_index, ref_lane;     uint32_t prev_offset, curr_offset;     uint32_t starting_index;     uint32_t i;     int data_independent_addressing;-    /* Pseudo-random values that determine the reference block position */-    uint64_t *pseudo_rands = NULL;      if (instance == NULL) {         return;     } -    data_independent_addressing = (instance->type == Argon2_i);--    pseudo_rands =-        (uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length));--    if (pseudo_rands == NULL) {-        return;-    }+    data_independent_addressing =+        (instance->type == Argon2_i) ||+        (instance->type == Argon2_id && (position.pass == 0) &&+         (position.slice < ARGON2_SYNC_POINTS / 2));      if (data_independent_addressing) {-        generate_addresses(instance, &position, pseudo_rands);+        init_block_value(&zero_block, 0);+        init_block_value(&input_block, 0);++        input_block.v[0] = position.pass;+        input_block.v[1] = position.lane;+        input_block.v[2] = position.slice;+        input_block.v[3] = instance->memory_blocks;+        input_block.v[4] = instance->passes;+        input_block.v[5] = instance->type;     }      starting_index = 0;      if ((0 == position.pass) && (0 == position.slice)) {         starting_index = 2; /* we have already generated the first two blocks */++        /* Don't forget to generate the first block of addresses: */+        if (data_independent_addressing) {+            next_addresses(&address_block, &input_block, &zero_block);+        }     }      /* Offset of the current block */@@ -186,7 +151,10 @@         /* 1.2 Computing the index of the reference block */         /* 1.2.1 Taking pseudo-random value from the previous block */         if (data_independent_addressing) {-            pseudo_rand = pseudo_rands[i];+            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {+                next_addresses(&address_block, &input_block, &zero_block);+            }+            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];         } else {             pseudo_rand = instance->memory[prev_offset].v[0];         }@@ -212,17 +180,15 @@         curr_block = instance->memory + curr_offset;         if (ARGON2_VERSION_10 == instance->version) {             /* version 1.2.1 and earlier: overwrite, not XOR */-            fill_block(instance->memory + prev_offset, ref_block, curr_block);+            fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);         } else {             if(0 == position.pass) {                 fill_block(instance->memory + prev_offset, ref_block,-                           curr_block);+                           curr_block, 0);             } else {-                fill_block_with_xor(instance->memory + prev_offset, ref_block,-                                    curr_block);+                fill_block(instance->memory + prev_offset, ref_block,+                           curr_block, 1);             }         }     }--    free(pseudo_rands); }
− phc-winner-argon2/src/ref.h
@@ -1,51 +0,0 @@-/*- * Argon2 source code package- *- * Written by Daniel Dinu and Dmitry Khovratovich, 2015- *- * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.- *- * You should have received a copy of the CC0 Public Domain Dedication along- * with- * this software. If not, see- * <http://creativecommons.org/publicdomain/zero/1.0/>.- */--#ifndef ARGON2_REF_H-#define ARGON2_REF_H--#include "core.h"--/*- * Function fills a new memory block by XORing over @next_block. @next_block must be initialized- * @param prev_block Pointer to the previous block- * @param ref_block Pointer to the reference block- * @param next_block Pointer to the block to be constructed- * @pre all block pointers must be valid- */-void fill_block_with_xor(const block *prev_block, const block *ref_block,-                block *next_block);--/* LEGACY CODE: version 1.2.1 and earlier-* Function fills a new memory block by overwriting @next_block. -* @param prev_block Pointer to the previous block-* @param ref_block Pointer to the reference block-* @param next_block Pointer to the block to be constructed-* @pre all block pointers must be valid-*/-void fill_block(const block *prev_block, const block *ref_block,-    block *next_block);--/*- * Generate pseudo-random values to reference blocks in the segment and puts- * them into the array- * @param instance Pointer to the current instance- * @param position Pointer to the current position- * @param pseudo_rands Pointer to the array of 64-bit values- * @pre pseudo_rands must point to @a instance->segment_length allocated values- */-void generate_addresses(const argon2_instance_t *instance,-                        const argon2_position_t *position,-                        uint64_t *pseudo_rands);--#endif /* ARGON2_REF_H */
phc-winner-argon2/src/thread.c view
@@ -1,3 +1,22 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */++#if !defined(ARGON2_NO_THREADS)+ #include "thread.h" #if defined(_WIN32) #include <windows.h>@@ -34,3 +53,5 @@     pthread_exit(NULL); #endif }++#endif /* ARGON2_NO_THREADS */
phc-winner-argon2/src/thread.h view
@@ -1,5 +1,27 @@+/*+ * Argon2 reference source code package - reference C implementations+ *+ * Copyright 2015+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves+ *+ * You may use this work under the terms of a Creative Commons CC0 1.0+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of+ * these licenses can be found at:+ *+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0+ *+ * You should have received a copy of both of these licenses along with this+ * software. If not, they may be obtained at the above URLs.+ */+ #ifndef ARGON2_THREAD_H #define ARGON2_THREAD_H++#include "hs_argon2_mangling.h"++#if !defined(ARGON2_NO_THREADS)+ /*         Here we implement an abstraction layer for the simpĺe requirements         of the Argon2 code. We only require 3 primitives---thread creation,@@ -26,7 +48,7 @@  * @param func A function pointer for the thread's entry point. Must not be  * NULL.  * @param args Pointer that is passed as an argument to @func. May be NULL.- * @return 0 if @handle and @func are valid pointers and a thread is successfuly+ * @return 0 if @handle and @func are valid pointers and a thread is successfully  * created.  */ int argon2_thread_create(argon2_thread_handle_t *handle,@@ -43,4 +65,5 @@ */ void argon2_thread_exit(void); +#endif /* ARGON2_NO_THREADS */ #endif
+ src-tests/Tests.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE OverloadedStrings #-}++import           Crypto.Argon2+import qualified Crypto.Argon2.FFI     as FFI+import           Data.Bits             (shiftL)+import qualified Data.ByteString       as BS+import           Data.Ix+import           Test.QuickCheck+import           Test.Tasty+import           Test.Tasty.HUnit+import           Test.Tasty.QuickCheck++arbitraryVariant :: Gen Argon2Variant+arbitraryVariant = arbitraryBoundedEnum++arbitraryVersion :: Gen Argon2Version+arbitraryVersion = arbitraryBoundedEnum++arbitraryHashOptions :: Gen HashOptions+arbitraryHashOptions =+  do p <- arbitraryWithin 1 4+     HashOptions <$> arbitraryWithin FFI.ARGON2_MIN_TIME (min FFI.ARGON2_MAX_TIME 65536)+                 <*> arbitraryWithin (FFI.ARGON2_MIN_MEMORY*p) (FFI.ARGON2_MIN_MEMORY*p*4)  -- arbitraryWithin (max (max FFI.ARGON2_MIN_MEMORY (8 * p)) (shiftL p 3)) (min FFI.ARGON2_MAX_MEMORY 512)+                 <*> pure p+                 <*> arbitraryVariant+                 <*> arbitraryVersion+                 <*> arbitraryWithin FFI.ARGON2_MIN_OUTLEN (min FFI.ARGON2_MAX_OUTLEN 65536)++arbitraryWithin lower upper = arbitrary `suchThat` (inRange (lower,upper))++arbitraryBytes :: Gen BS.ByteString+arbitraryBytes = BS.pack <$> arbitrary++arbitraryPassword :: Gen BS.ByteString+arbitraryPassword = arbitraryBytes `suchThat`+                    (\pwd -> (FFI.ARGON2_MIN_PWD_LENGTH,FFI.ARGON2_MAX_PWD_LENGTH) `inRange` BS.length pwd)++arbitrarySalt = arbitraryBytes `suchThat`+                (\salt -> (FFI.ARGON2_MIN_SALT_LENGTH,FFI.ARGON2_MAX_SALT_LENGTH) `inRange` BS.length salt)++main :: IO ()+main = defaultMain $ testGroup "Tests" [unitTests,props]+  where+    props = testGroup "Properties"+       [ testProperty "Round trip"+                  (forAll arbitraryHashOptions $ \hashOptions ->+                   forAll arbitraryPassword $ \password ->+                   forAll arbitrarySalt $ \salt ->+                         verifyEncoded (either undefined id $ hashEncoded hashOptions password salt) password == Argon2Ok)++       , testProperty "Unencoded hashing"+                  (forAll arbitraryHashOptions $ \hashOptions ->+                   forAll arbitraryPassword $ \password ->+                   forAll arbitrarySalt $ \salt ->+                          either undefined id (hash hashOptions password salt) /= password)++       , testProperty "defaultHashOptions"+                  (forAll arbitraryVariant $ \variant ->+                  (forAll arbitraryPassword $ \password ->+                   forAll arbitrarySalt $ \salt ->+                          verifyEncoded (either undefined id $+                                         hashEncoded (defaultHashOptions {hashVariant = variant})+                                         password+                                         salt)+                                        password == Argon2Ok))+       ]+++    unitTests = testGroup "KATs"+       [ testGroup "argon2 README" $+         let opts = defaultHashOptions { hashVariant     = Argon2i+                                       , hashMemory      = 2^16+                                       , hashIterations  = 2+                                       , hashParallelism = 4+                                       , hashLength      = 24+                                       , hashVersion     = Argon2Version13+                                       }+         in [ testCase "hashEncoded" $+              hashEncoded opts "password" "somesalt" @?= Right "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG"+            , testCase "verifyEncoded" $+              verifyEncoded "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG" "password" @?= Argon2Ok+            , testCase "verifyEncoded 2" $+              verifyEncoded "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG" "passvord" @?= Argon2VerifyMismatch+            , testCase "verifyEncoded 3" $+              verifyEncoded "$argon2d$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG" "password" @?= Argon2VerifyMismatch+            , testCase "verifyEncoded 4" $+              verifyEncoded "$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG" "password" @?= Argon2VerifyMismatch+            , testCase "verifyEncoded 5" $+              verifyEncoded "$argon2id$v=19$m=1,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG" "password" @?= Argon2MemoryTooLittle+            , testCase "verifyEncoded 6" $+              verifyEncoded "$argon2x$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG" "password" @?= Argon2DecodingFail+            , testCase "verifyEncoded 7" $+              verifyEncoded "$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJ" "password" @?= Argon2DecodingFail+            , testCase "hash" $+              hash opts "password" "somesalt" @?= Right "\x45\xD7\xAC\x72\xE7\x6F\x24\x2B\x20\xB7\x7B\x9B\xF9\xBF\x9D\x59\x15\x89\x4E\x66\x9A\x24\xE6\xC6"+            ]+       ]
src/Crypto/Argon2.hs view
@@ -1,14 +1,21 @@+{-# LANGUAGE BangPatterns       #-} {-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveGeneric      #-}+{-# LANGUAGE LambdaCase         #-}+{-# LANGUAGE OverloadedStrings  #-}+{-# LANGUAGE RecordWildCards    #-}+{-# LANGUAGE Trustworthy        #-}  {-| +Module      : Crypto.Argon2+License     : BSD3+Maintainer  : hvr@gnu.org+ "Crypto.Argon2" provides bindings to the <https://github.com/P-H-C/phc-winner-argon2 reference implementation> of Argon2, the password-hashing function that won the-<https://password-hashing.net/ Password Hashing Competition (PHC)>. +<https://password-hashing.net/ Password Hashing Competition (PHC)>.  The main entry points to this module are 'hashEncoded', which produces a crypt-like ASCII output; and 'hash' which produces a 'BS.ByteString' (a stream@@ -17,31 +24,38 @@ a good starting point. See 'HashOptions' for more documentation on the particular parameters that can be adjusted. -For access directly to the C interface, see "Crypto.Argon2.FFI".+For (unsafe) access directly to the C interface, see "Crypto.Argon2.FFI". +@since 1.3.0.0 -} module Crypto.Argon2-       ( -- * Computing hashes-         hashEncoded, hash,-         -- * Verification-         verify,-         -- * Configuring hashing-         HashOptions(..), Argon2Variant(..), defaultHashOptions,-         -- * Exceptions-         Argon2Exception(..))-       where+    ( -- * Hash computation & verification+      -- ** Binary hash representation+      hash+      -- ** ASCII-encoded representation+      --+      -- | These operations use the [PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md), a [crypt(3)](https://en.wikipedia.org/wiki/Crypt_\(C\))-like serialization format for password hashes.+    , hashEncoded+    , verifyEncoded+      -- * Configuring hashing+    , HashOptions(..)+    , Argon2Variant(..)+    , Argon2Version(..)+    , defaultHashOptions+      -- * Status codes+    , Argon2Status(..)+    ) where -import GHC.Generics (Generic)-import Control.Exception-import Data.Typeable-import Foreign-import Foreign.C-import Numeric.Natural-import System.IO.Unsafe (unsafePerformIO)+import           Control.DeepSeq   (NFData (rnf))+import           Control.Exception import qualified Crypto.Argon2.FFI as FFI-import qualified Data.ByteString as BS-import qualified Data.Text as T-import qualified Data.Text.Encoding as T+import qualified Data.ByteString   as BS+import qualified Data.Text.Short   as TS+import           Data.Typeable+import           Foreign+import           Foreign.C+import           GHC.Generics      (Generic)+import           System.IO.Unsafe  (unsafePerformIO)  -- | Which variant of Argon2 to use. You should choose the variant that is most -- applicable to your intention to hash inputs.@@ -50,199 +64,293 @@              -- for password hashing and password-based key derivation. Argon2i              -- is slower as it makes more passes over the memory to protect from              -- tradeoff attacks.-  | Argon2d -- ^ Argon2d is faster and uses data-depending memory access, which-            -- makes it suitable for cryptocurrencies and applications with no-            -- threats from side-channel timing attacks.+  | Argon2d  -- ^ Argon2d is faster and uses data-depending memory access, which+             -- makes it suitable for cryptocurrencies and applications with no+             -- threats from side-channel timing attacks.+  | Argon2id -- ^ Argon2id works as Argon2i for the first half of the first iteration+             -- over the memory, and as Argon2d for the rest, thus providing both+             -- side-channel attack protection and brute-force cost savings due to+             -- time-memory tradeoffs.   deriving (Eq,Ord,Read,Show,Bounded,Generic,Typeable,Enum) +instance NFData Argon2Variant where rnf !_ = ()++toArgon2Type :: Argon2Variant -> FFI.Argon2_type+toArgon2Type Argon2i  = FFI.Argon2_i+toArgon2Type Argon2d  = FFI.Argon2_d+toArgon2Type Argon2id = FFI.Argon2_id++-- | Version of the Argon2 algorithm.+data Argon2Version+  = Argon2Version10 -- ^ Version 1.0 (deprecated)+  | Argon2Version13 -- ^ Version 1.3 (See [this announcment](https://www.ietf.org/mail-archive/web/cfrg/current/msg07948.html) for more details)+  deriving (Eq,Ord,Read,Show,Bounded,Generic,Typeable,Enum)++instance NFData Argon2Version where rnf !_ = ()++toArgon2Ver :: Argon2Version -> FFI.Argon2_version+toArgon2Ver Argon2Version10 = FFI.ARGON2_VERSION_10+toArgon2Ver Argon2Version13 = FFI.ARGON2_VERSION_13+ -- | Parameters that can be adjusted to change the runtime performance of the--- hashing.+-- hashing. See also 'defaultHashOptions'. data HashOptions =-  HashOptions {hashIterations :: !Word32 -- ^ The time cost, which defines the amount of computation realized and therefore the execution time, given in number of iterations.+  HashOptions { hashIterations  :: !Word32 -- ^ The time cost, which defines the amount of computation realized and therefore the execution time, given in number of iterations.                                          --                                          -- 'FFI.ARGON2_MIN_TIME' <= 'hashIterations' <= 'FFI.ARGON2_MAX_TIME'-              ,hashMemory :: !Word32 -- ^ The memory cost, which defines the memory usage, given in kibibytes.++              , hashMemory      :: !Word32 -- ^ The memory cost, which defines the memory usage, given in [kibibytes](https://en.wikipedia.org/wiki/Kibibyte).                                      --                                      -- max 'FFI.ARGON2_MIN_MEMORY' (8 * 'hashParallelism') <= 'hashMemory' <= 'FFI.ARGON2_MAX_MEMORY'-              ,hashParallelism :: !Word32 -- ^ A parallelism degree, which defines the number of parallel threads.++              , hashParallelism :: !Word32 -- ^ A parallelism degree, which defines the number of parallel threads.                                           --                                           -- 'FFI.ARGON2_MIN_LANES' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_LANES' && 'FFI.ARGON_MIN_THREADS' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_THREADS'-              ,hashVariant :: !Argon2Variant -- ^ Which version of Argon2 to use.++              , hashVariant     :: !Argon2Variant -- ^ Which variant of Argon2 to use.++              , hashVersion     :: !Argon2Version -- ^ Which version of Argon2 to use for generating hashes.++              , hashLength      :: !Word32        -- ^ Desired length of hash expressed in octets.               }   deriving (Eq,Ord,Read,Show,Bounded,Generic,Typeable) +instance NFData HashOptions where rnf !_ = ()+ -- | A set of default 'HashOptions', taken from the @argon2@ executable. -- -- @ -- 'defaultHashOptions' :: 'HashOptions' -- 'defaultHashOptions' =---   'HashOptions' {'hashIterations' = 1---               ,'hashMemory' = 2 ^ 17---               ,'hashParallelism' = 4---               ,'hashVariant' = 'Argon2i'}+--   'HashOptions' { 'hashIterations'  = 3+--               , 'hashMemory'      = 2 ^ 12 -- 4 MiB+--               , 'hashParallelism' = 1+--               , 'hashVariant'     = 'Argon2i'+--               , 'hashVersion'     = 'Argon2Version13'+--               , 'hashLength'      = 2 ^ 5 -- 32 bytes+--               } -- @+--+-- For more information on how to select these parameters for your application, see section 6.4 of the [Argon2 specification](https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf).+-- defaultHashOptions :: HashOptions-defaultHashOptions =-  HashOptions {hashIterations = 1-              ,hashMemory = 2 ^ 17-              ,hashParallelism = 4-              ,hashVariant = Argon2i}+defaultHashOptions = HashOptions+    { hashIterations  = 3+    , hashMemory      = 2 ^ (12 :: Int) -- 4 MiB+    , hashParallelism = 1+    , hashVariant     = Argon2i+    , hashVersion     = Argon2Version13+    , hashLength      = 32+    } +-- | Encode a password with a given salt and 'HashOptions' and produce a binary stream+-- of bytes (of size 'hashLength').+hash :: HashOptions -- ^ Options pertaining to how expensive the hash is to calculate.+     -> BS.ByteString -- ^ The password to hash. Must be less than 4294967295 bytes.+     -> BS.ByteString -- ^ The salt to use when hashing. Must be less than 4294967295 bytes.+     -> Either Argon2Status BS.ByteString -- ^ The un-encoded password hash (or error code in case of failure).+hash options password salt = unsafePerformIO $ try $ hash' options password salt+ -- | Encode a password with a given salt and 'HashOptions' and produce a textual--- encoding of the result.-hashEncoded :: HashOptions -- ^ Options pertaining to how expensive the hash is to calculate.+-- encoding according to the [PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md) of the result.+--+-- Use 'verifyEncoded' to verify.+hashEncoded :: HashOptions   -- ^ Options pertaining to how expensive the hash is to calculate.             -> BS.ByteString -- ^ The password to hash. Must be less than 4294967295 bytes.             -> BS.ByteString -- ^ The salt to use when hashing. Must be less than 4294967295 bytes.-            -> T.Text -- ^ The encoded password hash.-hashEncoded options password salt =-  unsafePerformIO-    (hashEncoded' options password salt FFI.argon2i_hash_encoded FFI.argon2d_hash_encoded)+            -> Either Argon2Status TS.ShortText  -- ^ The encoded password hash (or error code in case of failure).+hashEncoded options password salt = unsafePerformIO $ try $ hashEncoded' options password salt --- | Encode a password with a given salt and 'HashOptions' and produce a stream--- of bytes.-hash :: HashOptions -- ^ Options pertaining to how expensive the hash is to calculate.-     -> BS.ByteString -- ^ The password to hash. Must be less than 4294967295 bytes.-     -> BS.ByteString -- ^ The salt to use when hashing. Must be less than 4294967295 bytes.-     -> BS.ByteString -- ^ The un-encoded password hash.-hash options password salt =-  unsafePerformIO (hash' options password salt FFI.argon2i_hash_raw FFI.argon2d_hash_raw)+-- | Verify that a given password could result in a given hash output.+-- Automatically determines the correct 'HashOptions' based on the+-- encoded hash (using the [PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md) as produced by 'hashEncoded').+--+-- Returns 'Argon2Ok' on successful verification. If decoding is+-- successful but the password mismatches, 'Argon2VerifyMismatch' is+-- returned; if decoding fails, the respective 'Argon2Status' code is+-- returned.+verifyEncoded :: TS.ShortText -> BS.ByteString -> Argon2Status+verifyEncoded encoded password+  -- c.f. https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md+  | "$argon2id$" `TS.isPrefixOf` encoded = unsafePerformIO $ go FFI.Argon2_id+  | "$argon2i$"  `TS.isPrefixOf` encoded = unsafePerformIO $ go FFI.Argon2_i+  | "$argon2d$"  `TS.isPrefixOf` encoded = unsafePerformIO $ go FFI.Argon2_d+  | otherwise                            = Argon2DecodingFail+  where+    go v = BS.useAsCString password $ \pwd ->+             BS.useAsCString (TS.toByteString encoded) $ \enc ->+               toArgon2Status <$> FFI.argon2_verify enc pwd (fromIntegral (BS.length password)) v -variant :: a -> a -> Argon2Variant -> a-variant a _ Argon2i = a-variant _ b Argon2d = b-{-# INLINE variant #-} --- | Not all 'HashOptions' can necessarily be used to compute hashes. If you--- supply invalid 'HashOptions' (or hashing otherwise fails) a 'Argon2Exception'--- will be throw.-data Argon2Exception-  = -- | The length of the supplied password is outside the range supported by @libargon2@.-    Argon2PasswordLengthOutOfRange !CSize -- ^ The erroneous length.-  | -- | The length of the supplied salt is outside the range supported by @libargon2@.-    Argon2SaltLengthOutOfRange !CSize -- ^ The erroneous length.-  | -- | Either too much or too little memory was requested via 'hashMemory'.-    Argon2MemoryUseOutOfRange !Word32 -- ^ The erroneous 'hashMemory' value.-  | -- | Either too few or too many iterations were requested via 'hashIterations'.-    Argon2IterationCountOutOfRange !Word32 -- ^ The erroneous 'hashIterations' value.-  | -- | Either too much or too little parallelism was requested via 'hasParallelism'.-    Argon2ParallelismOutOfRange !Word32 -- ^ The erroneous 'hashParallelism' value.-  | -- | An unexpected exception was throw. Please <https://github.com/ocharles/argon2/issues report this as a bug>!-    Argon2Exception !Int32 -- ^ The =libargon2= error code.-  deriving (Typeable, Show)+-- | Returned status code for Argon2 functions.+--+-- Not all 'HashOptions' can necessarily be used to compute hashes. If+-- you supply unsupported or invalid 'HashOptions' (or hashing+-- otherwise fails) an 'Argon2Status' value will be returned to+-- describe the failure.+--+-- Note that this enumeration contains some status codes which are not+-- expected to be returned by the operation provided by the Haskell+-- API.+data Argon2Status+    = Argon2Ok                            -- ^ OK (operation succeeded)+    | Argon2OutputPtrNull                 -- ^ Output pointer is @NULL@+    | Argon2OutputTooShort                -- ^ Output is too short+    | Argon2OutputTooLong                 -- ^ Output is too long+    | Argon2PwdTooShort                   -- ^ Password is too short+    | Argon2PwdTooLong                    -- ^ Password is too long+    | Argon2SaltTooShort                  -- ^ Salt is too short+    | Argon2SaltTooLong                   -- ^ Salt is too long+    | Argon2AdTooShort                    -- ^ Associated data is too short+    | Argon2AdTooLong                     -- ^ Associated data is too long+    | Argon2SecretTooShort                -- ^ Secret is too short+    | Argon2SecretTooLong                 -- ^ Secret is too long+    | Argon2TimeTooSmall                  -- ^ Time cost is too small+    | Argon2TimeTooLarge                  -- ^ Time cost is too large+    | Argon2MemoryTooLittle               -- ^ Memory cost is too small+    | Argon2MemoryTooMuch                 -- ^ Memory cost is too large+    | Argon2LanesTooFew                   -- ^ Too few lanes+    | Argon2LanesTooMany                  -- ^ Too many lanes+    | Argon2PwdPtrMismatch                -- ^ Password pointer is @NULL@, but password length is not 0+    | Argon2SaltPtrMismatch               -- ^ Salt pointer is @NULL@, but salt length is not 0+    | Argon2SecretPtrMismatch             -- ^ Secret pointer is @NULL@, but secret length is not 0+    | Argon2AdPtrMismatch                 -- ^ Associated data pointer is @NULL@, but ad length is not 0+    | Argon2MemoryAllocationError         -- ^ Memory allocation error+    | Argon2FreeMemoryCbkNull             -- ^ The free memory callback is @NULL@+    | Argon2AllocateMemoryCbkNull         -- ^ The allocate memory callback is @NULL@+    | Argon2IncorrectParameter            -- ^ @Argon2_Context@ context is @NULL@+    | Argon2IncorrectType                 -- ^ There is no such version of Argon2+    | Argon2OutPtrMismatch                -- ^ Output pointer mismatch+    | Argon2ThreadsTooFew                 -- ^ Not enough threads+    | Argon2ThreadsTooMany                -- ^ Too many threads+    | Argon2MissingArgs                   -- ^ Missing arguments+    | Argon2EncodingFail                  -- ^ Encoding failed+    | Argon2DecodingFail                  -- ^ Decoding failed+    | Argon2ThreadFail                    -- ^ Threading failure+    | Argon2DecodingLengthFail            -- ^ Some of encoded parameters are too long or too short+    | Argon2VerifyMismatch                -- ^ The password does not match the supplied hash -instance Exception Argon2Exception+    | Argon2InternalError                 -- ^ Internal error or unrecognized status code+    deriving (Typeable,Eq,Ord,Read,Show,Enum,Bounded) -type Argon2Encoded = Word32 -> Word32 -> Word32 -> CString -> CSize -> CString -> CSize -> CSize -> CString -> CSize -> IO Int32+instance NFData Argon2Status where rnf !_ = () +instance Exception Argon2Status++toArgon2Status :: CInt -> Argon2Status+toArgon2Status = \case+    FFI.ARGON2_OK                         -> Argon2Ok+    FFI.ARGON2_OUTPUT_PTR_NULL            -> Argon2OutputPtrNull+    FFI.ARGON2_OUTPUT_TOO_SHORT           -> Argon2OutputTooShort+    FFI.ARGON2_OUTPUT_TOO_LONG            -> Argon2OutputTooLong+    FFI.ARGON2_PWD_TOO_SHORT              -> Argon2PwdTooShort+    FFI.ARGON2_PWD_TOO_LONG               -> Argon2PwdTooLong+    FFI.ARGON2_SALT_TOO_SHORT             -> Argon2SaltTooShort+    FFI.ARGON2_SALT_TOO_LONG              -> Argon2SaltTooLong+    FFI.ARGON2_AD_TOO_SHORT               -> Argon2AdTooShort+    FFI.ARGON2_AD_TOO_LONG                -> Argon2AdTooLong+    FFI.ARGON2_SECRET_TOO_SHORT           -> Argon2SecretTooShort+    FFI.ARGON2_SECRET_TOO_LONG            -> Argon2SecretTooLong+    FFI.ARGON2_TIME_TOO_SMALL             -> Argon2TimeTooSmall+    FFI.ARGON2_TIME_TOO_LARGE             -> Argon2TimeTooLarge+    FFI.ARGON2_MEMORY_TOO_LITTLE          -> Argon2MemoryTooLittle+    FFI.ARGON2_MEMORY_TOO_MUCH            -> Argon2MemoryTooMuch+    FFI.ARGON2_LANES_TOO_FEW              -> Argon2LanesTooFew+    FFI.ARGON2_LANES_TOO_MANY             -> Argon2LanesTooMany+    FFI.ARGON2_PWD_PTR_MISMATCH           -> Argon2PwdPtrMismatch+    FFI.ARGON2_SALT_PTR_MISMATCH          -> Argon2SaltPtrMismatch+    FFI.ARGON2_SECRET_PTR_MISMATCH        -> Argon2SecretPtrMismatch+    FFI.ARGON2_AD_PTR_MISMATCH            -> Argon2AdPtrMismatch+    FFI.ARGON2_MEMORY_ALLOCATION_ERROR    -> Argon2MemoryAllocationError+    FFI.ARGON2_FREE_MEMORY_CBK_NULL       -> Argon2FreeMemoryCbkNull+    FFI.ARGON2_ALLOCATE_MEMORY_CBK_NULL   -> Argon2AllocateMemoryCbkNull+    FFI.ARGON2_INCORRECT_PARAMETER        -> Argon2IncorrectParameter+    FFI.ARGON2_INCORRECT_TYPE             -> Argon2IncorrectType+    FFI.ARGON2_OUT_PTR_MISMATCH           -> Argon2OutPtrMismatch+    FFI.ARGON2_THREADS_TOO_FEW            -> Argon2ThreadsTooFew+    FFI.ARGON2_THREADS_TOO_MANY           -> Argon2ThreadsTooMany+    FFI.ARGON2_MISSING_ARGS               -> Argon2MissingArgs+    FFI.ARGON2_ENCODING_FAIL              -> Argon2EncodingFail+    FFI.ARGON2_DECODING_FAIL              -> Argon2DecodingFail+    FFI.ARGON2_THREAD_FAIL                -> Argon2ThreadFail+    FFI.ARGON2_DECODING_LENGTH_FAIL       -> Argon2DecodingLengthFail+    FFI.ARGON2_VERIFY_MISMATCH            -> Argon2VerifyMismatch+    _                                     -> Argon2InternalError -- should never happen++ hashEncoded' :: HashOptions              -> BS.ByteString              -> BS.ByteString-             -> Argon2Encoded-             -> Argon2Encoded-             -> IO T.Text-hashEncoded' options@HashOptions{..} password salt argon2i argon2d =-  do let saltLen = fromIntegral (BS.length salt)-         passwordLen = fromIntegral (BS.length password)-     outLen <- fmap fromIntegral $ FFI.argon2_encodedlen-                                              hashIterations-                                              hashMemory-                                              hashParallelism-                                              saltLen-                                              hashlen-     out <- mallocBytes outLen-     res <--       BS.useAsCString password $-       \password' ->-         BS.useAsCString salt $-         \salt' ->-           argon2 hashIterations-                  hashMemory-                  hashParallelism-                  password'-                  passwordLen-                  salt'-                  (fromIntegral saltLen)-                  (fromIntegral hashlen)-                  out-                  (fromIntegral outLen)-     handleSuccessCode res options password salt-     fmap T.decodeUtf8 (BS.packCString out)-  where argon2 = variant argon2i argon2d hashVariant-        hashlen = 64+             -> IO TS.ShortText+hashEncoded' HashOptions{..} password salt =+    allocaBytes (fromIntegral outLen) $ \out -> do+        res <- BS.useAsCString password $ \password' ->+               BS.useAsCString salt $ \salt' ->+               FFI.argon2_hash+                   hashIterations+                   hashMemory+                   hashParallelism+                   password'+                   passwordLen+                   salt'+                   (fromIntegral saltLen)+                   nullPtr+                   (fromIntegral hashLength)+                   out+                   outLen+                   (toArgon2Type hashVariant)+                   (toArgon2Ver hashVersion) -type Argon2Unencoded = Word32 -> Word32 -> Word32 -> CString -> CSize -> CString -> CSize -> CString -> CSize -> IO Int32+        handleSuccessCode res+        res' <- TS.fromByteString <$> BS.packCString out+        case res' of+          Nothing -> throwIO Argon2InternalError+          Just t  -> evaluate t +  where+    !outLen = FFI.argon2_encodedlen+                    hashIterations+                    hashMemory+                    hashParallelism+                    saltLen+                    hashLength+                    (toArgon2Type hashVariant)++    saltLen     = fromIntegral (BS.length salt)+    passwordLen = fromIntegral (BS.length password)++ hash' :: HashOptions       -> BS.ByteString       -> BS.ByteString-      -> Argon2Unencoded-      -> Argon2Unencoded       -> IO BS.ByteString-hash' options@HashOptions{..} password salt argon2i argon2d =-  do let saltLen = fromIntegral (BS.length salt)-         passwordLen = fromIntegral (BS.length password)-         outLen = 512-     out <- mallocBytes outLen-     res <--       BS.useAsCString password $-       \password' ->-         BS.useAsCString salt $-         \salt' ->-           argon2 hashIterations-                  hashMemory-                  hashParallelism-                  password'-                  passwordLen-                  salt'-                  saltLen-                  out-                  (fromIntegral outLen)-     handleSuccessCode res options password salt-     BS.packCStringLen (out, outLen)-  where argon2 = variant argon2i argon2d hashVariant+hash' HashOptions{..} password salt =+    allocaBytes (fromIntegral hashLength) $ \out -> do+        res <- BS.useAsCString password $ \password' ->+               BS.useAsCString salt $ \salt' ->+               FFI.argon2_hash+                   hashIterations+                   hashMemory+                   hashParallelism+                   password'+                   passwordLen+                   salt'+                   saltLen+                   out+                   (fromIntegral hashLength)+                   nullPtr+                   0+                   (toArgon2Type hashVariant)+                   (toArgon2Ver hashVersion) -handleSuccessCode :: Int32-                  -> HashOptions-                  -> BS.ByteString-                  -> BS.ByteString-                  -> IO ()-handleSuccessCode res HashOptions{..} password salt =-  let saltLen = fromIntegral (BS.length salt)-      passwordLen = fromIntegral (BS.length password)-  in case res of-       a-         | a `elem` [FFI.ARGON2_OK] -> return ()-         | a `elem` [FFI.ARGON2_SALT_TOO_SHORT,FFI.ARGON2_SALT_TOO_LONG] ->-           throwIO (Argon2SaltLengthOutOfRange saltLen)-         | a `elem` [FFI.ARGON2_PWD_TOO_SHORT,FFI.ARGON2_PWD_TOO_LONG] ->-           throwIO (Argon2PasswordLengthOutOfRange passwordLen)-         | a `elem` [FFI.ARGON2_TIME_TOO_SMALL,FFI.ARGON2_TIME_TOO_LARGE] ->-           throwIO (Argon2IterationCountOutOfRange hashIterations)-         | a `elem` [FFI.ARGON2_MEMORY_TOO_LITTLE,FFI.ARGON2_MEMORY_TOO_MUCH] ->-           throwIO (Argon2MemoryUseOutOfRange hashMemory)-         | a `elem`-             [FFI.ARGON2_LANES_TOO_FEW-             ,FFI.ARGON2_LANES_TOO_MANY-             ,FFI.ARGON2_THREADS_TOO_FEW-             ,FFI.ARGON2_THREADS_TOO_MANY] ->-           throwIO (Argon2ParallelismOutOfRange hashParallelism)-         | otherwise -> throwIO (Argon2Exception a)+        handleSuccessCode res+        evaluate =<< BS.packCStringLen (out, fromIntegral hashLength)+  where+    saltLen     = fromIntegral (BS.length salt)+    passwordLen = fromIntegral (BS.length password) --- | Verify that a given password could result in a given hash output.--- Automatically determines the correct 'HashOptions' based on the--- encoded hash (as produced by 'hashEncoded').-verify-  :: T.Text -> BS.ByteString -> Bool-verify encoded password =-  unsafePerformIO-    (BS.useAsCString password $-     \pwd ->-       BS.useAsCString (T.encodeUtf8 encoded) $-       \enc ->-         do res <--              (variant FFI.argon2i_verify FFI.argon2d_verify v) enc-                                                                pwd-                                                                (fromIntegral (BS.length password))-            return (res == FFI.ARGON2_OK))-    where v | T.pack "$argon2i" `T.isPrefixOf` encoded = Argon2i-            | otherwise = Argon2d+handleSuccessCode :: CInt -> IO ()+handleSuccessCode res = case toArgon2Status res of+                          Argon2Ok -> return ()+                          nok      -> throwIO nok+
src/Crypto/Argon2/FFI.hsc view
@@ -1,6 +1,14 @@-{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE Unsafe #-} +-- |+-- Module      : Crypto.Argon2.FFI+-- License     : BSD3+-- Maintainer  : hvr@gnu.org+--+-- This module provides low-level access to parts of the C API+--+-- Prefer the "Crypto.Argon2" API when possible. module Crypto.Argon2.FFI where  #include <argon2.h>@@ -9,54 +17,160 @@ import Foreign import Foreign.C -foreign import ccall unsafe "argon2.h argon2i_hash_encoded" argon2i_hash_encoded :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> CSize -> Ptr b -> CSize -> CSize -> CString -> CSize -> IO (#type int) -foreign import ccall unsafe "argon2.h argon2i_hash_raw" argon2i_hash_raw :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> CSize -> Ptr b -> CSize -> Ptr c -> CSize -> IO (#type int)+#if !defined(USE_SYSTEM_ARGON2)+# error USE_SYSTEM_ARGON2 undefined+#endif -foreign import ccall unsafe "argon2.h argon2d_hash_encoded" argon2d_hash_encoded :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> CSize -> Ptr b -> CSize -> CSize -> CString -> CSize -> IO (#type int)+-- * @libargon2@ functions -foreign import ccall unsafe "argon2.h argon2d_hash_raw" argon2d_hash_raw :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> CSize -> Ptr b -> CSize -> Ptr c -> CSize -> IO (#type int)+-- | Compute Argon2 hash+--+-- > int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,+-- >                 const uint32_t parallelism, const void *pwd,+-- >                 const size_t pwdlen, const void *salt,+-- >                 const size_t saltlen, void *hash,+-- >                 const size_t hashlen, char *encoded,+-- >                 const size_t encodedlen, argon2_type type,+-- >                 const uint32_t version);+--+-- === __Parameters__+--+--  [t_cost] Number of iterations+--  [m_cost] Sets memory usage to m_cost kibibytes+--  [parallelism] Number of threads and compute lanes+--  [pwd] Pointer to password+--  [pwdlen] Password size in bytes+--  [salt] Pointer to salt+--  [saltlen] Salt size in bytes+--  [hash] Buffer where to write the raw hash+--  [hashlen] Desired length of the hash in bytes+--  [encoded] Buffer where to write the encoded hash+--  [encodedlen] Size of the buffer (thus max size of the encoded hash)+--  [type] Variant of Argon2 hash+--  [version] Version of Argon2 specification+--+foreign import ccall safe+#if USE_SYSTEM_ARGON2+    "argon2.h argon2_hash"+#else+    "argon2.h hs_argon2__argon2_hash"+#endif+    argon2_hash+    :: Word32 {- t_cost -}+    -> Word32 {- m_cost -}+    -> Word32 {- parallelism -}+    -> Ptr a -> CSize {- pwd  + pwdlen -}+    -> Ptr b -> CSize {- salt + saltlen -}+    -> Ptr c -> CSize {- hash + hashlen -}+    -> CString -> CSize {- encoded + encodedlen -}+    -> Argon2_type+    -> Argon2_version+    -> IO CInt -foreign import ccall unsafe "argon2.h argon2i_verify" argon2i_verify :: CString -> Ptr a -> CSize -> IO (#type int)+-- | Verify encoded hash+--+-- > int argon2_verify(const char *encoded, const void *pwd,+-- >                   const size_t pwdlen, argon2_type type);+--+-- === __Parameters__+--+--  [encoded] Pointer to zero-terminated encoded hash+--  [pwd] Pointer to password+--  [pwdlen] Password size in bytes+--  [type] Variant of Argon2 hash+--+foreign import ccall safe+#if USE_SYSTEM_ARGON2+    "argon2.h argon2_verify"+#else+    "argon2.h hs_argon2__argon2_verify"+#endif+    argon2_verify+    :: CString -> Ptr a -> CSize -> Argon2_type -> IO CInt -foreign import ccall unsafe "argon2.h argon2d_verify" argon2d_verify :: CString -> Ptr a -> CSize -> IO (#type int)+-- | Compute size of encoded hash+--+-- > size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism,+-- >                          uint32_t saltlen, uint32_t hashlen, argon2_type type);+--+-- === __Parameters__+--+--  [t_cost] Number of iterations+--  [m_cost] Sets memory usage to m_cost kibibytes+--  [parallelism] Number of threads and compute lanes+--  [salt] Pointer to salt+--  [saltlen] Salt size in bytes+--  [hashlen] Desired length of the hash in bytes+--  [type] Variant of Argon2 hash+--+foreign import ccall unsafe+#if USE_SYSTEM_ARGON2+    "argon2.h argon2_encodedlen"+#else+    "argon2.h hs_argon2__argon2_encodedlen"+#endif+    argon2_encodedlen+    :: Word32 -> Word32 -> Word32 -> Word32 -> Word32 -> Argon2_type -> CSize -foreign import ccall unsafe "argon2.h argon2_encodedlen" argon2_encodedlen :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> IO CSize+-- * @libargon2@ API typedefs -pattern ARGON2_OK = (#const ARGON2_OK)-pattern ARGON2_OUTPUT_PTR_NULL = (#const ARGON2_OUTPUT_PTR_NULL)-pattern ARGON2_OUTPUT_TOO_SHORT = (#const ARGON2_OUTPUT_TOO_SHORT)-pattern ARGON2_OUTPUT_TOO_LONG = (#const ARGON2_OUTPUT_TOO_LONG)-pattern ARGON2_PWD_TOO_SHORT = (#const ARGON2_PWD_TOO_SHORT)-pattern ARGON2_PWD_TOO_LONG = (#const ARGON2_PWD_TOO_LONG)-pattern ARGON2_SALT_TOO_SHORT = (#const ARGON2_SALT_TOO_SHORT)-pattern ARGON2_SALT_TOO_LONG = (#const ARGON2_SALT_TOO_LONG)-pattern ARGON2_AD_TOO_SHORT = (#const ARGON2_AD_TOO_SHORT)-pattern ARGON2_AD_TOO_LONG = (#const ARGON2_AD_TOO_LONG)-pattern ARGON2_SECRET_TOO_SHORT = (#const ARGON2_SECRET_TOO_SHORT)-pattern ARGON2_SECRET_TOO_LONG = (#const ARGON2_SECRET_TOO_LONG)-pattern ARGON2_TIME_TOO_SMALL = (#const ARGON2_TIME_TOO_SMALL)-pattern ARGON2_TIME_TOO_LARGE = (#const ARGON2_TIME_TOO_LARGE)-pattern ARGON2_MEMORY_TOO_LITTLE = (#const ARGON2_MEMORY_TOO_LITTLE)-pattern ARGON2_MEMORY_TOO_MUCH = (#const ARGON2_MEMORY_TOO_MUCH)-pattern ARGON2_LANES_TOO_FEW = (#const ARGON2_LANES_TOO_FEW)-pattern ARGON2_LANES_TOO_MANY = (#const ARGON2_LANES_TOO_MANY)-pattern ARGON2_PWD_PTR_MISMATCH = (#const ARGON2_PWD_PTR_MISMATCH)-pattern ARGON2_SALT_PTR_MISMATCH = (#const ARGON2_SALT_PTR_MISMATCH)-pattern ARGON2_SECRET_PTR_MISMATCH = (#const ARGON2_SECRET_PTR_MISMATCH)-pattern ARGON2_AD_PTR_MISMATCH = (#const ARGON2_AD_PTR_MISMATCH)-pattern ARGON2_MEMORY_ALLOCATION_ERROR = (#const ARGON2_MEMORY_ALLOCATION_ERROR)-pattern ARGON2_FREE_MEMORY_CBK_NULL = (#const ARGON2_FREE_MEMORY_CBK_NULL)+-- ** @argon2_type@++type Argon2_type = (#type argon2_type)+pattern Argon2_d  = (#const Argon2_d)+pattern Argon2_i  = (#const Argon2_i)+pattern Argon2_id = (#const Argon2_id)++-- ** @argon2_version@++type Argon2_version = Word32 -- NB, not (#type argon2_version)+pattern ARGON2_VERSION_10 = (#const ARGON2_VERSION_10)+pattern ARGON2_VERSION_13 = (#const ARGON2_VERSION_13)+pattern ARGON2_VERSION_NUMBER = (#const ARGON2_VERSION_NUMBER)++-- ** @argon2_error_codes@++-- argon2_error_codes+pattern ARGON2_OK                       = (#const ARGON2_OK)+pattern ARGON2_OUTPUT_PTR_NULL          = (#const ARGON2_OUTPUT_PTR_NULL)+pattern ARGON2_OUTPUT_TOO_SHORT         = (#const ARGON2_OUTPUT_TOO_SHORT)+pattern ARGON2_OUTPUT_TOO_LONG          = (#const ARGON2_OUTPUT_TOO_LONG)+pattern ARGON2_PWD_TOO_SHORT            = (#const ARGON2_PWD_TOO_SHORT)+pattern ARGON2_PWD_TOO_LONG             = (#const ARGON2_PWD_TOO_LONG)+pattern ARGON2_SALT_TOO_SHORT           = (#const ARGON2_SALT_TOO_SHORT)+pattern ARGON2_SALT_TOO_LONG            = (#const ARGON2_SALT_TOO_LONG)+pattern ARGON2_AD_TOO_SHORT             = (#const ARGON2_AD_TOO_SHORT)+pattern ARGON2_AD_TOO_LONG              = (#const ARGON2_AD_TOO_LONG)+pattern ARGON2_SECRET_TOO_SHORT         = (#const ARGON2_SECRET_TOO_SHORT)+pattern ARGON2_SECRET_TOO_LONG          = (#const ARGON2_SECRET_TOO_LONG)+pattern ARGON2_TIME_TOO_SMALL           = (#const ARGON2_TIME_TOO_SMALL)+pattern ARGON2_TIME_TOO_LARGE           = (#const ARGON2_TIME_TOO_LARGE)+pattern ARGON2_MEMORY_TOO_LITTLE        = (#const ARGON2_MEMORY_TOO_LITTLE)+pattern ARGON2_MEMORY_TOO_MUCH          = (#const ARGON2_MEMORY_TOO_MUCH)+pattern ARGON2_LANES_TOO_FEW            = (#const ARGON2_LANES_TOO_FEW)+pattern ARGON2_LANES_TOO_MANY           = (#const ARGON2_LANES_TOO_MANY)+pattern ARGON2_PWD_PTR_MISMATCH         = (#const ARGON2_PWD_PTR_MISMATCH)+pattern ARGON2_SALT_PTR_MISMATCH        = (#const ARGON2_SALT_PTR_MISMATCH)+pattern ARGON2_SECRET_PTR_MISMATCH      = (#const ARGON2_SECRET_PTR_MISMATCH)+pattern ARGON2_AD_PTR_MISMATCH          = (#const ARGON2_AD_PTR_MISMATCH)+pattern ARGON2_MEMORY_ALLOCATION_ERROR  = (#const ARGON2_MEMORY_ALLOCATION_ERROR)+pattern ARGON2_FREE_MEMORY_CBK_NULL     = (#const ARGON2_FREE_MEMORY_CBK_NULL) pattern ARGON2_ALLOCATE_MEMORY_CBK_NULL = (#const ARGON2_ALLOCATE_MEMORY_CBK_NULL)-pattern ARGON2_INCORRECT_PARAMETER = (#const ARGON2_INCORRECT_PARAMETER)-pattern ARGON2_INCORRECT_TYPE = (#const ARGON2_INCORRECT_TYPE)-pattern ARGON2_OUT_PTR_MISMATCH = (#const ARGON2_OUT_PTR_MISMATCH)-pattern ARGON2_THREADS_TOO_FEW = (#const ARGON2_THREADS_TOO_FEW)-pattern ARGON2_THREADS_TOO_MANY = (#const ARGON2_THREADS_TOO_MANY)-pattern ARGON2_MISSING_ARGS = (#const ARGON2_MISSING_ARGS)-pattern ARGON2_ENCODING_FAIL = (#const ARGON2_ENCODING_FAIL)-pattern ARGON2_DECODING_FAIL = (#const ARGON2_DECODING_FAIL)+pattern ARGON2_INCORRECT_PARAMETER      = (#const ARGON2_INCORRECT_PARAMETER)+pattern ARGON2_INCORRECT_TYPE           = (#const ARGON2_INCORRECT_TYPE)+pattern ARGON2_OUT_PTR_MISMATCH         = (#const ARGON2_OUT_PTR_MISMATCH)+pattern ARGON2_THREADS_TOO_FEW          = (#const ARGON2_THREADS_TOO_FEW)+pattern ARGON2_THREADS_TOO_MANY         = (#const ARGON2_THREADS_TOO_MANY)+pattern ARGON2_MISSING_ARGS             = (#const ARGON2_MISSING_ARGS)+pattern ARGON2_ENCODING_FAIL            = (#const ARGON2_ENCODING_FAIL)+pattern ARGON2_DECODING_FAIL            = (#const ARGON2_DECODING_FAIL)+pattern ARGON2_THREAD_FAIL              = (#const ARGON2_THREAD_FAIL)+pattern ARGON2_DECODING_LENGTH_FAIL     = (#const ARGON2_DECODING_LENGTH_FAIL)+pattern ARGON2_VERIFY_MISMATCH          = (#const ARGON2_VERIFY_MISMATCH) +-- * @libargon2@ limits & constants+ pattern ARGON2_MIN_LANES = (#const ARGON2_MIN_LANES) pattern ARGON2_MAX_LANES = (#const ARGON2_MAX_LANES) @@ -88,7 +202,15 @@ pattern ARGON2_MIN_SECRET = (#const ARGON2_MIN_SECRET) pattern ARGON2_MAX_SECRET = (#const ARGON2_MAX_SECRET) +{-++/* Global flag to determine if we are wiping internal memory buffers. This flag+ * is defined in core.c and deafults to 1 (wipe internal memory). */+extern int FLAG_clear_internal_memory;+ pattern ARGON2_FLAG_CLEAR_PASSWORD = (#const ARGON2_FLAG_CLEAR_PASSWORD)-pattern ARGON2_FLAG_CLEAR_SECRET = (#const ARGON2_FLAG_CLEAR_SECRET)-pattern ARGON2_FLAG_CLEAR_MEMORY = (#const ARGON2_FLAG_CLEAR_MEMORY)-pattern ARGON2_DEFAULT_FLAGS = (#const ARGON2_DEFAULT_FLAGS)+pattern ARGON2_FLAG_CLEAR_SECRET   = (#const ARGON2_FLAG_CLEAR_SECRET)+pattern ARGON2_DEFAULT_FLAGS       = (#const ARGON2_DEFAULT_FLAGS)++-}+