text: # =============================================================================
  # Copyright (c) 2008 Christophe Oosterlynck <christophe.oosterlynck_AT_gmail.com>
  #                    & NXP ( Philippe Teuwen <philippe.teuwen_AT_nxp.com> )
  #
  # Permission is hereby granted, free of charge, to any person obtaining a copy
  # of this software and associated documentation files (the "Software"), to deal
  # in the Software without restriction, including without limitation the rights
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  # copies of the Software, and to permit persons to whom the Software is
  # furnished to do so, subject to the following conditions:
  #
  # The above copyright notice and this permission notice shall be included in
  # all copies or substantial portions of the Software.
  #
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  # THE SOFTWARE.
  # =============================================================================
  
  """Module for padding functions
  
  padding info here: http://en.wikipedia.org/wiki/Padding_(cryptography)
  """
      
  import random
  
  PAD = 0
  UNPAD = 1
  
  def bitPadding (padData, direction, length=None):
          """Pad a string using bitPadding
  
              padData = raw string to pad/unpad
              direction = PAD or UNPAD
              length = amount of bytes the padded string should be a multiple of
                       (length variable is not used when unpadding)
              
              returns: (un)padded raw string
              
              A new block full of padding will be added when padding data that is
              already a multiple of the length.
              
              Example:
              =========
              >>> from CryptoPlus.Util import padding
  
              >>> padding.bitPadding(b'test', padding.PAD, 8)
              b'test\\x80\\x00\\x00\\x00'
              >>> padding.bitPadding(_,padding.UNPAD)
              b'test'"""
          if direction == PAD:
              if length == None:
                  raise ValueError("Supply a valid length")
              return __bitPadding(padData, length)
          elif direction == UNPAD:
              return __bitPadding_unpad(padData)
          else:
              raise ValueError("Supply a valid direction")
  
  def __bitPadding (toPad,length):
      padded = toPad + b'\x80' + b'\x00'*(length - len(toPad)%length -1)
      return padded
  
  def __bitPadding_unpad (padded):
      if padded.rstrip(b'\x00')[-1:] == b'\x80':
          return padded.rstrip(b'\x00')[:-1]
      else:
          return padded
  
  def zerosPadding (padData, direction, length=None):
          """Pad a string using zerosPadding
  
              padData = raw string to pad/unpad
              direction = PAD or UNPAD
                          beware: padding and unpadding a string ending in 0's
                                  will remove those 0's too
              length = amount of bytes the padded string should be a multiple of
                       (length variable is not used when unpadding)
              
              returns: (un)padded raw string
              
              No padding will be added when padding data that is already a
              multiple of the given length.
              
              Example:
              =========
              >>> from CryptoPlus.Util import padding
  
              >>> padding.zerosPadding(b'12345678',padding.PAD,16)
              b'12345678\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'
              >>> padding.zerosPadding(_,padding.UNPAD)
              b'12345678'"""
          if direction == PAD:
              if length == None:
                  raise ValueError("Supply a valid length")
              return __zerosPadding(padData, length)
          elif direction == UNPAD:
              return __zerosPadding_unpad(padData)
          else:
              raise ValueError("Supply a valid direction")
  
  def __zerosPadding (toPad, length):
      padLength = (length - len(toPad))%length
      return toPad + b'\x00'*padLength
  
  def __zerosPadding_unpad (padded ):
      return padded.rstrip(b'\x00')
  
  def PKCS7(padData, direction, length=None):
          """Pad a string using PKCS7
  
              padData = raw string to pad/unpad
              direction = PAD or UNPAD
              length = amount of bytes the padded string should be a multiple of
                       (length variable is not used when unpadding)
              
              returns: (un)padded raw string
              
              A new block full of padding will be added when padding data that is
              already a multiple of the given length.
              
              Example:
              =========
              >>> from CryptoPlus.Util import padding
  
              >>> padding.PKCS7(b'12345678',padding.PAD,16)
              b'12345678\\x08\\x08\\x08\\x08\\x08\\x08\\x08\\x08'
              >>> padding.PKCS7(_,padding.UNPAD)
              b'12345678'"""
          if direction == PAD:
              if length == None:
                  raise ValueError("Supply a valid length")
              return __PKCS7(padData, length)
          elif direction == UNPAD:
              return __PKCS7_unpad(padData)
          else:
              raise ValueError("Supply a valid direction")
  
  
  def __PKCS7 (toPad, length):
      amount = length - len(toPad)%length
      pattern = bytearray([amount])
      pad = pattern*amount
      return bytes(toPad + pad)
  
  def __PKCS7_unpad (padded):
      pattern = padded[-1:]
      length = bytearray(pattern)[0]
      #check if the bytes to be removed are all the same pattern
      if padded.endswith(pattern*length):
          return padded[:-length]
      else:
          print('error: padding pattern not recognized')
          return padded
  
  def ANSI_X923 (padData, direction, length=None):
          """Pad a string using ANSI_X923
  
              padData = raw string to pad/unpad
              direction = PAD or UNPAD
              length = amount of bytes the padded string should be a multiple of
                       (length variable is not used when unpadding)
              
              returns: (un)padded raw string
              
              A new block full of padding will be added when padding data that is
              already a multiple of the given length.
              
              Example:
              =========
              >>> from CryptoPlus.Util import padding
              
              >>> padding.ANSI_X923(b'12345678',padding.PAD,16)
              b'12345678\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x08'
              >>> padding.ANSI_X923(_,padding.UNPAD)
              b'12345678'"""
          if direction == PAD:
              if length == None:
                  raise ValueError("Supply a valid length")
              return __ANSI_X923(padData, length)
          elif direction == UNPAD:
              return __ANSI_X923_unpad(padData)
          else:
              raise ValueError("Supply a valid direction")
  
  def __ANSI_X923 (toPad, length):
      bytesToPad = length - len(toPad)%length
      trail = bytes(bytearray([bytesToPad]))
      pattern = b'\x00'*(bytesToPad -1) + trail
      return toPad + pattern
  
  def __ANSI_X923_unpad (padded):
      length = bytearray(padded)[-1]
      #check if the bytes to be removed are all zero
      if padded.count(b'\x00',-length,-1) == length - 1:
          return padded[:-length]
      else:
          print('error: padding pattern not recognized %s' % padded.count('\x00',-length,-1))
          return padded
  
  def ISO_10126 (padData, direction, length=None):
          """Pad a string using ISO_10126
  
              padData = raw string to pad/unpad
              direction = PAD or UNPAD
              length = amount of bytes the padded string should be a multiple of
                       (length variable is not used when unpadding)
              
              returns: (un)padded raw string
              
              A new block full of padding will be added when padding data that is
              already a multiple of the given length.
              
              Example:
              =========
              >>> from CryptoPlus.Util import padding
  
              >>> padded = padding.ISO_10126(b'12345678',padding.PAD,16)
              >>> padding.ISO_10126(padded,padding.UNPAD)
              b'12345678'"""
          if direction == PAD:
              if length == None:
                  raise ValueError("Supply a valid length")
              return __ISO_10126(padData, length)
          elif direction == UNPAD:
              return __ISO_10126_unpad(padData)
          else:
              raise ValueError("Supply a valid direction")
  
  def __ISO_10126 (toPad, length):
      bytesToPad = length - len(toPad)%length
      randomPattern = bytearray(random.randint(0,255) for x in range(0,bytesToPad-1))
      return bytes(toPad + randomPattern + bytearray([bytesToPad]))
  
  def __ISO_10126_unpad (padded):
     return padded[0:len(padded)-bytearray(padded)[-1]]
  
  def _test():
      import doctest
      doctest.testmod()
  
  if __name__ == "__main__":
      _test()
  