Skip to content

Commit eb9fee3

Browse files
committed
Merge branch 'release-0.4' into develop
2 parents 0d7b611 + 6a409c0 commit eb9fee3

File tree

7 files changed

+169
-36
lines changed

7 files changed

+169
-36
lines changed

README.rst

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ Building `python-mbedtls` requires Cython::
5353

5454
then,
5555

56+
::
57+
58+
python3 -m pip install python-mbedtls
59+
60+
or
61+
5662
::
5763

5864
git clone https://github.com/Synss/python-mbedtls.git python-mbedtls.git
@@ -68,16 +74,70 @@ The unit tests further require `nose` and `pyCrypto`::
6874
Hashing module (`md.h`)
6975
-----------------------
7076

71-
The hashing module is wrapped, which provides message, file, and HMAC
72-
with the following algorithms: MD5, SHA-1, SHA-2, and RIPEMD-160.
77+
Message digest algorithms
78+
~~~~~~~~~~~~~~~~~~~~~~~~~
79+
80+
The `mbedtls.hash` module provides MD5, SHA-1, SHA-2, and RIPEMD-160 secure
81+
hashes and message digests. The API follows the recommendations from PEP 452
82+
so that it can be used as a drop-in replacement to e.g. `hashlib` or
83+
`PyCrypto`.
84+
85+
Here are the examples from `hashlib` executed with `python-mbedtls`::
86+
87+
>>> from mbedtls import hash as hashlib
88+
>>> m = hashlib.md5()
89+
>>> m.update(b"Nobody inspects")
90+
>>> m.update(b" the spammish repetition")
91+
>>> m.digest()
92+
b'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
93+
>>> m.digest_size
94+
16
95+
>>> m.block_size
96+
64
97+
98+
More condensed::
99+
100+
>>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
101+
'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
102+
103+
Using `new()`::
104+
105+
>>> h = hashlib.new('ripemd160')
106+
>>> h.update(b"Nobody inspects the spammish repetition")
107+
>>> h.hexdigest()
108+
'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc'
109+
73110

74-
The API follows the recommendations from PEP 452.
111+
HMAC algorithm
112+
~~~~~~~~~~~~~~
113+
114+
The `mbedtls.hmac` module computes HMAC. The API follows the recommendations
115+
from PEP 452 as well.
116+
117+
Example::
118+
119+
>>> from mbedtls import hmac
120+
>>> m = hmac.new(b"This is my secret key", digestmod="md5")
121+
>>> m.update(b"Nobody inspects")
122+
>>> m.update(b" the spammish repetition")
123+
>>> m.digest()
124+
b'\x9d-/rj\\\x98\x80\xb1rG\x87\x0f\xe9\xe4\xeb'
125+
126+
.. warning::
127+
128+
The message is cleared after calculation of the digest. Only call
129+
:meth:`mbedtls.hmac.Hmac.digest` or :meth:`mbedtls.hmac.Hmac.hexdigest` once
130+
per message.
75131

76132

77133
Symmetric cipher module (`cipher.h`)
78134
------------------------------------
79135

80-
The symmetric cipher module is wrapped, which provides:
136+
The `mbedtls.cipher` module provides symmetric encryption. The API follows the
137+
recommendations from PEP 272 so that it can be used as a drop-in replacement to
138+
e.g. `PyCrypto`.
139+
140+
mbedtls provides the following algorithms:
81141

82142
- Aes encryption/decryption (128, 192, and 256 bits) in ECB, CBC, CFB128,
83143
CTR, GCM, or CCM mode;
@@ -87,27 +147,60 @@ The symmetric cipher module is wrapped, which provides:
87147
CFB128, CTR, GCM, or CCM mode;
88148
- DES encryption/decryption in ECB, or CBC mode;
89149

90-
The API follows the recommendations from PEP 272.
91-
92150
Notes:
93151
- Tagging and padding are not wrapped.
94152
- The counter in CTR mode cannot be explicitly provided.
95153

154+
Example::
155+
156+
>>> from mbedtls import cipher
157+
>>> c = cipher.AES.new(b"My 16-bytes key.", cipher.MODE_CBC, b"CBC needs an IV.")
158+
>>> enc = c.encrypt(b"This is a super-secret message!")
159+
>>> enc
160+
b'*`k6\x98\x97=[\xdf\x7f\x88\x96\xf5\t\x19J7\x93\xb5\xe0~\t\x9e\x968m\xcd\x
161+
>>> c.decrypt(enc)
162+
b'This is a super-secret message!'
163+
96164

97165
Public key module (`pk.h`)
98166
--------------------------
99167

100-
The RSA cryptosystem is wrapped, which provides:
168+
The `mbedtls.pk` module provides the RSA cryptosystem. This includes:
101169

102170
- Public-private key generation and key import/export in PEM and DER
103171
formats;
104172
- Asymmetric encryption and decryption;
105173
- Message signature and verification.
106174

107-
108-
Contribution
109-
============
110-
111-
`python-mbedtls` is in an early stage of development and contributions
112-
in any form is welcome. Note, however, that bugs against mbed TLS
113-
should be reported upstream directly.
175+
Key generation, the default size is 2048 bits::
176+
177+
>>> from mbedtls import pk
178+
>>> rsa = pk.RSA()
179+
>>> rsa.has_private()
180+
False
181+
>>> rsa.generate()
182+
>>> rsa.key_size
183+
256
184+
>>> rsa.has_private() and rsa.has_public()
185+
True
186+
187+
Message encryption and decryption::
188+
189+
>>> enc = rsa.encrypt(b"secret message")
190+
>>> rsa.decrypt(enc)
191+
b"secret message"
192+
193+
Message signature and verification::
194+
195+
>>> sig = rsa.sign(b"Please sign here.")
196+
>>> rsa.verify(b"Please sign here.", sig)
197+
True
198+
>>> rsa.verify(b"Sorry, wrong message.", sig)
199+
False
200+
>>> prv, pub = rsa.export(format="DER")
201+
>>> other = pk.RSA()
202+
>>> other.import_(pub)
203+
>>> other.has_private()
204+
False
205+
>>> other.verify(b"Please sign here.", sig)
206+
True

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@
6767
# built documents.
6868
#
6969
# The short X.Y version.
70-
version = '0.3'
70+
version = '0.4'
7171
# The full version, including alpha/beta/rc tags.
72-
release = '0.3'
72+
release = version
7373

7474
# The language for content autogenerated by Sphinx. Refer to documentation
7575
# for a list of supported languages.

mbedtls/__init__.pyx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""python-mbedtls is a this wrapper to ARM's mbed TLS library."""
2+
3+
__author__ = "Mathias Laurin"
4+
__copyright__ = "Copyright 2015, Elaborated Networks GmbH"
5+
__license__ = "MIT License"
6+
7+
8+
import mbedtls.cipher as cipher
9+
import mbedtls.exceptions as exceptions
10+
import mbedtls.hash as hash
11+
import mbedtls.hmac as hmac
12+
import mbedtls.pk as pk
13+
import mbedtls.random as random
14+
15+
16+
__all__ = "cipher", "exceptions", "hash", "hmac", "pk", "random"

mbedtls/_md.pxd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ cdef extern from "mbedtls/md.h":
5656
int mbedtls_md_hmac_finish(
5757
mbedtls_md_context_t *ctx,
5858
unsigned char *output)
59-
# mbedtls_md_hmac_reset
59+
int mbedtls_md_hmac_reset(mbedtls_md_context_t *ctx)
6060
# mbedtls_md_hmac
6161

6262

mbedtls/hmac.pyx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ cdef class Hmac(_md.MDBase):
2727
key (bytes): The key to use.
2828
name (bytes): The MD name known to mbed TLS.
2929
30+
Warning:
31+
The message is cleared after calculation of the digest. Only
32+
call :meth:`digest` or :meth:`hexdigest` once per message.
33+
3034
Attributes:
3135
digest_size (int): The size of the message digest, in bytes.
3236
block_size (int): Not implemented.
@@ -46,7 +50,10 @@ cdef class Hmac(_md.MDBase):
4650

4751
cdef _finish(self, unsigned char *output):
4852
"""Return the HMAC of key and message."""
49-
return _md.mbedtls_md_hmac_finish(&self._ctx, output)
53+
ret = _md.mbedtls_md_hmac_finish(&self._ctx, output)
54+
if ret != 0:
55+
return ret
56+
return _md.mbedtls_md_hmac_reset(&self._ctx)
5057

5158
cpdef copy(self):
5259
"""Return a copy ("clone") of the HMAC object.
@@ -70,45 +77,45 @@ def new(key, buffer=None, digestmod=None):
7077

7178
def md2(key, buffer=None):
7279
"""MD2 message-digest algorithm."""
73-
return Hash(key, buffer, digestmod="md2")
80+
return Hmac(key, "md2", buffer)
7481

7582

7683
def md4(key, buffer=None):
7784
"""MD4 message-digest algorithm."""
78-
return Hash(key, buffer, digestmod="md4")
85+
return Hmac(key, "md4", buffer)
7986

8087

8188
def md5(key, buffer=None):
8289
"""MD5 message-digest algorithm."""
83-
return Hash(key, buffer, digestmod="md5")
90+
return Hmac(key, "md5", buffer)
8491

8592

8693
def sha1(key, buffer=None):
87-
"""Secure Hash Algorithm 1 (SHA-1)."""
88-
return Hash(key, buffer, digestmod="sha1")
94+
"""Secure Hmac Algorithm 1 (SHA-1)."""
95+
return Hmac(key, "sha1", buffer)
8996

9097

9198
def sha224(key, buffer=None):
92-
"""Secure Hash Algorithm 2 (SHA-2) with 224 bits hash value."""
93-
return Hash(key, buffer, digestmod="sha224")
99+
"""Secure Hmac Algorithm 2 (SHA-2) with 224 bits hash value."""
100+
return Hmac(key, "sha224", buffer)
94101

95102

96103
def sha256(key, buffer=None):
97-
"""Secure Hash Algorithm 2 (SHA-2) with 256 bits hash value."""
98-
return Hash(key, buffer, digestmod="sha256")
104+
"""Secure Hmac Algorithm 2 (SHA-2) with 256 bits hash value."""
105+
return Hmac(key, "sha256", buffer)
99106

100107

101108
def sha384(key, buffer=None):
102-
"""Secure Hash Algorithm 2 (SHA-2) with 384 bits hash value."""
103-
return Hash(key, buffer, digestmod="sha384")
109+
"""Secure Hmac Algorithm 2 (SHA-2) with 384 bits hash value."""
110+
return Hmac(key, "sha384", buffer)
104111

105112

106113
def sha512(key, buffer=None):
107-
"""Secure Hash Algorithm 2 (SHA-2) with 512 bits hash value."""
108-
return Hash(key, buffer, digestmod="sha512")
114+
"""Secure Hmac Algorithm 2 (SHA-2) with 512 bits hash value."""
115+
return Hmac(key, "sha512", buffer)
109116

110117

111118
def ripemd160(key, buffer=None):
112119
"""RACE Integrity Primitives Evaluation Message Digest (RIPEMD) with
113120
160 bits hash value."""
114-
return Hash(key, buffer, digestmod="ripemd160")
121+
return Hmac(key, "ripemd160", buffer)

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from Cython.Build import cythonize
33

44

5-
version = "0.3"
5+
version = "0.4"
66
download_url = "https://github.com/Synss/python-mbedtls/tarball/%s" % version
77

88

@@ -45,7 +45,7 @@
4545
ext_modules=cythonize(extensions),
4646
setup_requires=setup_requires,
4747
classifiers=[
48-
"Development Status :: 3 - Alpha",
48+
"Development Status :: 4 - Beta",
4949
"Programming Language :: Cython",
5050
"License :: OSI Approved :: MIT License",
5151
"Topic :: Security :: Cryptography",

tests/test_md.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def test_check_against_hmac_buf():
127127
yield test
128128

129129

130-
def test_instantiation():
130+
def test_hash_instantiation():
131131
import inspect
132132

133133
def check_instantiation(fun, name):
@@ -139,5 +139,22 @@ def check_instantiation(fun, name):
139139
for name, member in inspect.getmembers(md_hash):
140140
if name in md_hash.algorithms_available:
141141
test = partial(check_instantiation, member, name)
142-
test.description = "check_instantiation(%s)" % name
142+
test.description = "check_hash_instantiation(%s)" % name
143+
yield test
144+
145+
146+
def test_hmac_instantiation():
147+
import inspect
148+
149+
def check_instantiation(fun, name):
150+
key = _rnd(16)
151+
alg1 = fun(key)
152+
alg2 = md_hmac.new(key, digestmod=name)
153+
assert_equal(type(alg1), type(alg2))
154+
assert_equal(alg1.name, alg2.name)
155+
156+
for name, member in inspect.getmembers(md_hmac):
157+
if name in md_hmac.algorithms_available:
158+
test = partial(check_instantiation, member, name)
159+
test.description = "check_hmac_instantiation(%s)" % name
143160
yield test

0 commit comments

Comments
 (0)