1# -*- coding: ascii -*-
2#
3# Util/Counter.py : Fast counter for use with CTR-mode ciphers
4#
5# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
6#
7# ===================================================================
8# The contents of this file are dedicated to the public domain. To
9# the extent that dedication to the public domain is not available,
10# everyone is granted a worldwide, perpetual, royalty-free,
11# non-exclusive license to exercise all rights associated with the
12# contents of this file for any purpose whatsoever.
13# No rights are reserved.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22# SOFTWARE.
23# ===================================================================
24"""Fast counter functions for CTR cipher modes.
25
26CTR is a chaining mode for symmetric block encryption or decryption.
27Messages are divideded into blocks, and the cipher operation takes
28place on each block using the secret key and a unique *counter block*.
29
30The most straightforward way to fulfil the uniqueness property is
31to start with an initial, random *counter block* value, and increment it as
32the next block is processed.
33
34The block ciphers from `Crypto.Cipher` (when configured in *MODE_CTR* mode)
35invoke a callable object (the *counter* parameter) to get the next *counter block*.
36Unfortunately, the Python calling protocol leads to major performance degradations.
37
38The counter functions instantiated by this module will be invoked directly
39by the ciphers in `Crypto.Cipher`. The fact that the Python layer is bypassed
40lead to more efficient (and faster) execution of CTR cipher modes.
41
42An example of usage is the following:
43
44 >>> from Crypto.Cipher import AES
45 >>> from Crypto.Util import Counter
46 >>> from Crypto import Random
47 >>>
48 >>> nonce = Random.get_random_bytes(8)
49 >>> ctr = Counter.new(64, nonce)
50 >>> key = b'AES-128 symm key'
51 >>> plaintext = b'X'*1000000
52 >>> cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
53 >>> ciphertext = cipher.encrypt(plaintext)
54
55:undocumented: __package__
56"""
57import sys
58if sys.version_info[0] == 2 and sys.version_info[1] == 1:
59 from Crypto.Util.py21compat import *
60from Crypto.Util.py3compat import *
61
62from Crypto.pct_warnings import DisableShortcut_DeprecationWarning
63from Crypto.Util import _counter
64import struct
65import warnings
66
67
68# Factory function
69_deprecated = "deprecated"
70def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_endian=False, allow_wraparound=False, disable_shortcut=_deprecated):
71 """Create a stateful counter block function suitable for CTR encryption modes.
72
73 Each call to the function returns the next counter block.
74 Each counter block is made up by three parts::
75
76 prefix || counter value || postfix
77
78 The counter value is incremented by 1 at each call.
79
80 :Parameters:
81 nbits : integer
82 Length of the desired counter, in bits. It must be a multiple of 8.
83 prefix : byte string
84 The constant prefix of the counter block. By default, no prefix is
85 used.
86 suffix : byte string
87 The constant postfix of the counter block. By default, no suffix is
88 used.
89 initial_value : integer
90 The initial value of the counter. Default value is 1.
91 overflow : integer
92 This value is currently ignored.
93 little_endian : boolean
94 If *True*, the counter number will be encoded in little endian format.
95 If *False* (default), in big endian format.
96 allow_wraparound : boolean
97 If *True*, the counter will automatically restart from zero after
98 reaching the maximum value (``2**nbits-1``).
99 If *False* (default), the object will raise an *OverflowError*.
100 disable_shortcut : deprecated
101 This option is a no-op for backward compatibility. It will be removed
102 in a future version. Don't use it.
103 :Returns:
104 The counter block function.
105 """
106
107 # Sanity-check the message size
108 (nbytes, remainder) = divmod(nbits, 8)
109 if remainder != 0:
110 # In the future, we might support arbitrary bit lengths, but for now we don't.
111 raise ValueError("nbits must be a multiple of 8; got %d" % (nbits,))
112 if nbytes < 1:
113 raise ValueError("nbits too small")
114 elif nbytes > 0xffff:
115 raise ValueError("nbits too large")
116
117 initval = _encode(initial_value, nbytes, little_endian)
118
119 if disable_shortcut is not _deprecated: # exact object comparison
120 warnings.warn("disable_shortcut has no effect and is deprecated", DisableShortcut_DeprecationWarning)
121
122 if little_endian:
123 return _counter._newLE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound)
124 else:
125 return _counter._newBE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound)
126
127def _encode(n, nbytes, little_endian=False):
128 retval = []
129 n = int(n)
130 for i in range(nbytes):
131 if little_endian:
132 retval.append(bchr(n & 0xff))
133 else:
134 retval.insert(0, bchr(n & 0xff))
135 n >>= 8
136 return b("").join(retval)
137
138# vim:set ts=4 sw=4 sts=4 expandtab: