1# -*- coding: utf-8 -*- 
    2# 
    3#  Cipher/mode_ecb.py : ECB mode 
    4# 
    5# =================================================================== 
    6# The contents of this file are dedicated to the public domain.  To 
    7# the extent that dedication to the public domain is not available, 
    8# everyone is granted a worldwide, perpetual, royalty-free, 
    9# non-exclusive license to exercise all rights associated with the 
    10# contents of this file for any purpose whatsoever. 
    11# No rights are reserved. 
    12# 
    13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    14# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
    15# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    16# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
    17# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
    18# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
    19# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
    20# SOFTWARE. 
    21# =================================================================== 
    22 
    23""" 
    24Electronic Code Book (ECB) mode. 
    25""" 
    26 
    27__all__ = [ 'EcbMode' ] 
    28 
    29from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, 
    30                                  VoidPointer, create_string_buffer, 
    31                                  get_raw_buffer, SmartPointer, 
    32                                  c_size_t, c_uint8_ptr, 
    33                                  is_writeable_buffer) 
    34 
    35raw_ecb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ecb", """ 
    36                    int ECB_start_operation(void *cipher, 
    37                                            void **pResult); 
    38                    int ECB_encrypt(void *ecbState, 
    39                                    const uint8_t *in, 
    40                                    uint8_t *out, 
    41                                    size_t data_len); 
    42                    int ECB_decrypt(void *ecbState, 
    43                                    const uint8_t *in, 
    44                                    uint8_t *out, 
    45                                    size_t data_len); 
    46                    int ECB_stop_operation(void *state); 
    47                    """ 
    48                                        ) 
    49 
    50 
    51class EcbMode(object): 
    52    """*Electronic Code Book (ECB)*. 
    53 
    54    This is the simplest encryption mode. Each of the plaintext blocks 
    55    is directly encrypted into a ciphertext block, independently of 
    56    any other block. 
    57 
    58    This mode is dangerous because it exposes frequency of symbols 
    59    in your plaintext. Other modes (e.g. *CBC*) should be used instead. 
    60 
    61    See `NIST SP800-38A`_ , Section 6.1. 
    62 
    63    .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf 
    64 
    65    :undocumented: __init__ 
    66    """ 
    67 
    68    def __init__(self, block_cipher): 
    69        """Create a new block cipher, configured in ECB mode. 
    70 
    71        :Parameters: 
    72          block_cipher : C pointer 
    73            A smart pointer to the low-level block cipher instance. 
    74        """ 
    75        self.block_size = block_cipher.block_size 
    76 
    77        self._state = VoidPointer() 
    78        result = raw_ecb_lib.ECB_start_operation(block_cipher.get(), 
    79                                                 self._state.address_of()) 
    80        if result: 
    81            raise ValueError("Error %d while instantiating the ECB mode" 
    82                             % result) 
    83 
    84        # Ensure that object disposal of this Python object will (eventually) 
    85        # free the memory allocated by the raw library for the cipher 
    86        # mode 
    87        self._state = SmartPointer(self._state.get(), 
    88                                   raw_ecb_lib.ECB_stop_operation) 
    89 
    90        # Memory allocated for the underlying block cipher is now owned 
    91        # by the cipher mode 
    92        block_cipher.release() 
    93 
    94    def encrypt(self, plaintext, output=None): 
    95        """Encrypt data with the key set at initialization. 
    96 
    97        The data to encrypt can be broken up in two or 
    98        more pieces and `encrypt` can be called multiple times. 
    99 
    100        That is, the statement: 
    101 
    102            >>> c.encrypt(a) + c.encrypt(b) 
    103 
    104        is equivalent to: 
    105 
    106             >>> c.encrypt(a+b) 
    107 
    108        This function does not add any padding to the plaintext. 
    109 
    110        :Parameters: 
    111          plaintext : bytes/bytearray/memoryview 
    112            The piece of data to encrypt. 
    113            The length must be multiple of the cipher block length. 
    114        :Keywords: 
    115          output : bytearray/memoryview 
    116            The location where the ciphertext must be written to. 
    117            If ``None``, the ciphertext is returned. 
    118        :Return: 
    119          If ``output`` is ``None``, the ciphertext is returned as ``bytes``. 
    120          Otherwise, ``None``. 
    121        """ 
    122 
    123        if output is None: 
    124            ciphertext = create_string_buffer(len(plaintext)) 
    125        else: 
    126            ciphertext = output 
    127 
    128            if not is_writeable_buffer(output): 
    129                raise TypeError("output must be a bytearray or a writeable memoryview") 
    130 
    131            if len(plaintext) != len(output): 
    132                raise ValueError("output must have the same length as the input" 
    133                                 "  (%d bytes)" % len(plaintext)) 
    134 
    135        result = raw_ecb_lib.ECB_encrypt(self._state.get(), 
    136                                         c_uint8_ptr(plaintext), 
    137                                         c_uint8_ptr(ciphertext), 
    138                                         c_size_t(len(plaintext))) 
    139        if result: 
    140            if result == 3: 
    141                raise ValueError("Data must be aligned to block boundary in ECB mode") 
    142            raise ValueError("Error %d while encrypting in ECB mode" % result) 
    143 
    144        if output is None: 
    145            return get_raw_buffer(ciphertext) 
    146        else: 
    147            return None 
    148 
    149    def decrypt(self, ciphertext, output=None): 
    150        """Decrypt data with the key set at initialization. 
    151 
    152        The data to decrypt can be broken up in two or 
    153        more pieces and `decrypt` can be called multiple times. 
    154 
    155        That is, the statement: 
    156 
    157            >>> c.decrypt(a) + c.decrypt(b) 
    158 
    159        is equivalent to: 
    160 
    161             >>> c.decrypt(a+b) 
    162 
    163        This function does not remove any padding from the plaintext. 
    164 
    165        :Parameters: 
    166          ciphertext : bytes/bytearray/memoryview 
    167            The piece of data to decrypt. 
    168            The length must be multiple of the cipher block length. 
    169        :Keywords: 
    170          output : bytearray/memoryview 
    171            The location where the plaintext must be written to. 
    172            If ``None``, the plaintext is returned. 
    173        :Return: 
    174          If ``output`` is ``None``, the plaintext is returned as ``bytes``. 
    175          Otherwise, ``None``. 
    176        """ 
    177 
    178        if output is None: 
    179            plaintext = create_string_buffer(len(ciphertext)) 
    180        else: 
    181            plaintext = output 
    182 
    183            if not is_writeable_buffer(output): 
    184                raise TypeError("output must be a bytearray or a writeable memoryview") 
    185 
    186            if len(ciphertext) != len(output): 
    187                raise ValueError("output must have the same length as the input" 
    188                                 "  (%d bytes)" % len(plaintext)) 
    189 
    190        result = raw_ecb_lib.ECB_decrypt(self._state.get(), 
    191                                         c_uint8_ptr(ciphertext), 
    192                                         c_uint8_ptr(plaintext), 
    193                                         c_size_t(len(ciphertext))) 
    194        if result: 
    195            if result == 3: 
    196                raise ValueError("Data must be aligned to block boundary in ECB mode") 
    197            raise ValueError("Error %d while decrypting in ECB mode" % result) 
    198 
    199        if output is None: 
    200            return get_raw_buffer(plaintext) 
    201        else: 
    202            return None 
    203 
    204 
    205def _create_ecb_cipher(factory, **kwargs): 
    206    """Instantiate a cipher object that performs ECB encryption/decryption. 
    207 
    208    :Parameters: 
    209      factory : module 
    210        The underlying block cipher, a module from ``Crypto.Cipher``. 
    211 
    212    All keywords are passed to the underlying block cipher. 
    213    See the relevant documentation for details (at least ``key`` will need 
    214    to be present""" 
    215 
    216    cipher_state = factory._create_base_cipher(kwargs) 
    217    cipher_state.block_size = factory.block_size 
    218    if kwargs: 
    219        raise TypeError("Unknown parameters for ECB: %s" % str(kwargs)) 
    220    return EcbMode(cipher_state)