"Fossies" - the Fresh Open Source Software Archive

Member "revelation-0.5.4/src/bundle/PBKDFv2.py" (4 Oct 2020, 5143 Bytes) of package /linux/privat/revelation-0.5.4.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "PBKDFv2.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.5.3_vs_0.5.4.

    1 # -*- coding: iso-8859-1 -*-
    2 """
    3   - Implements the PKCS#5 v2.0: Password-Based Cryptography Standard
    4     from RSA Laboratories. RFC2898 http://www.rfc-editor.org/rfc/rfc2898.txt
    5 
    6 Modifications by John Lenz <lenz@cs.wisc.edu>, April 2006
    7   + Fix the PBKDFv2 algorithm so it is correct
    8   + Use Cipher.XOR instead of slow python xor
    9   + other performance improvements
   10 
   11 Original Code written by:
   12 
   13 Copyright (C) 2004 - Lars Strand <lars strand at gnist org>
   14 
   15 This program is free software; you can redistribute it and/or
   16 modify it under the terms of the GNU General Public License
   17 as published by the Free Software Foundation; either version 2
   18 of the License, or (at your option) any later version.
   19 
   20 This program is distributed in the hope that it will be useful,
   21 but WITHOUT ANY WARRANTY; without even the implied warranty of
   22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   23 GNU General Public License for more details.
   24 
   25 You should have received a copy of the GNU General Public License
   26 along with this program; if not, write to the Free Software
   27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   28 
   29 http://www.gnu.org/copyleft/gpl.html
   30 
   31 """
   32 
   33 import struct, string, math, hashlib, hmac # RFC2104
   34 
   35 ################ PBKDFv2
   36 class PBKDFv2:
   37     """Implements the PKCS#5 v2.0: Password-Based Cryptography Standard
   38     from RSA Laboratories. RFC2898
   39 
   40     http://www.rfc-editor.org/rfc/rfc2898.txt
   41     """
   42 
   43     ################ init
   44     def __init__(self):
   45 
   46         # length of pseudorandom function: 20 for SHA-1, 16 for MD5
   47         self.hLen = 20
   48 
   49     ################ makeKey
   50     def makeKey(self, P, S, c, dkLen, digesttype='sha1'):
   51         """
   52            Input:   P         password, an octet string
   53                     S         salt, an octet string
   54                     c         iteration count, a positive integer (>1000)
   55                     dkLen     intended length on octets of the derived key, a positive integer,
   56                               at most (2^32 - 1) * hLen
   57                     digesttype Digest used, passed to hmac module
   58 
   59            Output   DK    derived key, a dkLen-octet string
   60            """
   61 
   62         # do some sanity checks
   63         try:
   64             str(P); str(S); int(c); float(dkLen); int(c)
   65         except:
   66             print("P = %s, S = %s, c = %s, dkLen = %s:" % (P, S, c, dkLen))
   67             raise ValueError("ERROR! Input is not correct!")
   68 
   69         # Step 1: if dkLen is larger than maximum possible key - exit
   70         if dkLen > ((2^32 - 1) * self.hLen):
   71             maxlength = (2^32 - 1) * self.hLen
   72             raise ValueError("ERROR! Key is to large! Maxlength is " . str(maxlength))
   73 
   74         # Step 2:
   75         # Let l be the number of hLen-octet blocks in the derived key, rounding up
   76         # and let r be the number of octets in the last block
   77         l = math.ceil(dkLen / float(self.hLen))
   78         #if (dkLen % float(self.hLen)): l = int(l) + 1 # round up if necessary
   79         r = dkLen - (l - 1) * self.hLen
   80 
   81         # Step 3:
   82         # For each block of the derived key, apply the function F to the
   83         # password P, the salt S, the iteration count c, and the block index
   84         # to compute the block
   85         T = b""
   86         for blockindex in range(int(l)):
   87             T += self.F(P, S, c, blockindex, digesttype)
   88         # Step 4 - extract the first dkLen octet to produce a derived key DK
   89         DK = T[:dkLen]
   90 
   91         # Step 5 - return the derived key DK
   92         return DK
   93 
   94     ################ F
   95     def F(self, P, S, c, i, digest):
   96         """For each block of the derived key, apply this function.
   97 
   98         Notation:
   99         ||   = concatenation operator
  100         PRF  = Underlying pseudorandom function
  101 
  102         The function F is defined as the exclusive-or sum of the first c
  103         iterates if the underlying pseudorandom function PRF applied to
  104         the password P and the concatenation of the salt S and the block
  105         index i:
  106 
  107         F(P, S, c, i) = U1 XOR U2 XOR ... XOR Uc
  108 
  109         where
  110 
  111         U1 = PRF(P, S || INT(i)),
  112         U2 = PRF(P, U1)
  113         ...
  114         Uc = PRF(P, Uc-1)
  115         """
  116 
  117         # The pseudorandom function, PRF, used is HMAC-SHA1 (rfc2104)
  118         iteration = 1
  119 
  120         # the first iteration; P is the key, and a concatination of
  121         # S and blocknumber is the message
  122         istr = struct.pack(">I", i+1)
  123         PRFMaster = hmac.new(P,digestmod=getattr(hashlib, digest))
  124         PRF = PRFMaster.copy()
  125         PRF.update(S)
  126         PRF.update(istr)
  127         U = PRF.digest() # the first iteration
  128 
  129         Fbuf = U
  130 
  131         while iteration < c:                  # loop through all iterations
  132             PRF = PRFMaster.copy()
  133             PRF.update(U)
  134             U = PRF.digest()
  135             Fbuf = self._xor(U, Fbuf)    # XOR this new iteration with the old one
  136             iteration += 1
  137         return Fbuf
  138 
  139     ################ xor
  140     def _xor(self, a, b):
  141         """Performs XOR on two strings a and b"""
  142 
  143         if len(a) != len(b):
  144             raise ValueError("ERROR: Strings are of different size! %s %s" % (len(a), len(b)))
  145 
  146         return bytes([x ^ y for (x, y) in zip(a, b)])