Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dffa394

Browse files
committed
Issue #27744: Add AF_ALG (Linux Kernel crypto) to socket module.
1 parent 92a6c17 commit dffa394

7 files changed

Lines changed: 646 additions & 72 deletions

File tree

Doc/library/socket.rst

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,22 @@ created. Socket addresses are represented as follows:
131131
string format. (ex. ``b'12:23:34:45:56:67'``) This protocol is not
132132
supported under FreeBSD.
133133

134+
- :const:`AF_ALG` is a Linux-only socket based interface to Kernel
135+
cryptography. An algorithm socket is configured with a tuple of two to four
136+
elements ``(type, name [, feat [, mask]])``, where:
137+
138+
- *type* is the algorithm type as string, e.g. ``aead``, ``hash``,
139+
``skcipher`` or ``rng``.
140+
141+
- *name* is the algorithm name and operation mode as string, e.g.
142+
``sha256``, ``hmac(sha256)``, ``cbc(aes)`` or ``drbg_nopr_ctr_aes256``.
143+
144+
- *feat* and *mask* are unsigned 32bit integers.
145+
146+
Availability Linux 2.6.38, some algorithm types require more recent Kernels.
147+
148+
.. versionadded:: 3.6
149+
134150
- Certain other address families (:const:`AF_PACKET`, :const:`AF_CAN`)
135151
support specific representations.
136152

@@ -350,6 +366,16 @@ Constants
350366
TIPC related constants, matching the ones exported by the C socket API. See
351367
the TIPC documentation for more information.
352368

369+
.. data:: AF_ALG
370+
SOL_ALG
371+
ALG_*
372+
373+
Constants for Linux Kernel cryptography.
374+
375+
Availability: Linux >= 2.6.38.
376+
377+
.. versionadded:: 3.6
378+
353379
.. data:: AF_LINK
354380

355381
Availability: BSD, OSX.
@@ -1294,6 +1320,15 @@ to sockets.
12941320
an exception, the method now retries the system call instead of raising
12951321
an :exc:`InterruptedError` exception (see :pep:`475` for the rationale).
12961322

1323+
.. method:: socket.sendmsg_afalg([msg], *, op[, iv[, assoclen[, flags]]])
1324+
1325+
Specialized version of :meth:`~socket.sendmsg` for :const:`AF_ALG` socket.
1326+
Set mode, IV, AEAD associated data length and flags for :const:`AF_ALG` socket.
1327+
1328+
Availability: Linux >= 2.6.38
1329+
1330+
.. versionadded:: 3.6
1331+
12971332
.. method:: socket.sendfile(file, offset=0, count=None)
12981333

12991334
Send a file until EOF is reached by using high-performance
@@ -1342,21 +1377,29 @@ to sockets.
13421377
For further information, please consult the :ref:`notes on socket timeouts <socket-timeouts>`.
13431378

13441379

1345-
.. method:: socket.setsockopt(level, optname, value)
1380+
.. method:: socket.setsockopt(level, optname, value: int)
1381+
.. method:: socket.setsockopt(level, optname, value: buffer)
1382+
.. method:: socket.setsockopt(level, optname, None, optlen: int)
13461383

13471384
.. index:: module: struct
13481385

13491386
Set the value of the given socket option (see the Unix manual page
13501387
:manpage:`setsockopt(2)`). The needed symbolic constants are defined in the
1351-
:mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer or
1352-
a :term:`bytes-like object` representing a buffer. In the latter case it is
1353-
up to the caller to
1354-
ensure that the bytestring contains the proper bits (see the optional built-in
1355-
module :mod:`struct` for a way to encode C structures as bytestrings).
1388+
:mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer,
1389+
None or a :term:`bytes-like object` representing a buffer. In the later
1390+
case it is up to the caller to ensure that the bytestring contains the
1391+
proper bits (see the optional built-in module :mod:`struct` for a way to
1392+
encode C structures as bytestrings). When value is set to None,
1393+
optlen argument is required. It's equivalent to call setsockopt C
1394+
function with optval=NULL and optlen=optlen.
1395+
13561396

13571397
.. versionchanged:: 3.5
13581398
Writable :term:`bytes-like object` is now accepted.
13591399

1400+
.. versionchanged:: 3.6
1401+
setsockopt(level, optname, None, optlen: int) form added.
1402+
13601403

13611404
.. method:: socket.shutdown(how)
13621405

Lib/test/test_socket.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5325,6 +5325,170 @@ class SendfileUsingSendfileTest(SendfileUsingSendTest):
53255325
def meth_from_sock(self, sock):
53265326
return getattr(sock, "_sendfile_use_sendfile")
53275327

5328+
@unittest.skipUnless(hasattr(socket, "AF_ALG"), 'AF_ALG required')
5329+
class LinuxKernelCryptoAPI(unittest.TestCase):
5330+
# tests for AF_ALG
5331+
def create_alg(self, typ, name):
5332+
sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
5333+
sock.bind((typ, name))
5334+
return sock
5335+
5336+
def test_sha256(self):
5337+
expected = bytes.fromhex("ba7816bf8f01cfea414140de5dae2223b00361a396"
5338+
"177a9cb410ff61f20015ad")
5339+
with self.create_alg('hash', 'sha256') as algo:
5340+
op, _ = algo.accept()
5341+
with op:
5342+
op.sendall(b"abc")
5343+
self.assertEqual(op.recv(512), expected)
5344+
5345+
op, _ = algo.accept()
5346+
with op:
5347+
op.send(b'a', socket.MSG_MORE)
5348+
op.send(b'b', socket.MSG_MORE)
5349+
op.send(b'c', socket.MSG_MORE)
5350+
op.send(b'')
5351+
self.assertEqual(op.recv(512), expected)
5352+
5353+
def test_hmac_sha1(self):
5354+
expected = bytes.fromhex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")
5355+
with self.create_alg('hash', 'hmac(sha1)') as algo:
5356+
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, b"Jefe")
5357+
op, _ = algo.accept()
5358+
with op:
5359+
op.sendall(b"what do ya want for nothing?")
5360+
self.assertEqual(op.recv(512), expected)
5361+
5362+
def test_aes_cbc(self):
5363+
key = bytes.fromhex('06a9214036b8a15b512e03d534120006')
5364+
iv = bytes.fromhex('3dafba429d9eb430b422da802c9fac41')
5365+
msg = b"Single block msg"
5366+
ciphertext = bytes.fromhex('e353779c1079aeb82708942dbe77181a')
5367+
msglen = len(msg)
5368+
with self.create_alg('skcipher', 'cbc(aes)') as algo:
5369+
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
5370+
op, _ = algo.accept()
5371+
with op:
5372+
op.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, iv=iv,
5373+
flags=socket.MSG_MORE)
5374+
op.sendall(msg)
5375+
self.assertEqual(op.recv(msglen), ciphertext)
5376+
5377+
op, _ = algo.accept()
5378+
with op:
5379+
op.sendmsg_afalg([ciphertext],
5380+
op=socket.ALG_OP_DECRYPT, iv=iv)
5381+
self.assertEqual(op.recv(msglen), msg)
5382+
5383+
# long message
5384+
multiplier = 1024
5385+
longmsg = [msg] * multiplier
5386+
op, _ = algo.accept()
5387+
with op:
5388+
op.sendmsg_afalg(longmsg,
5389+
op=socket.ALG_OP_ENCRYPT, iv=iv)
5390+
enc = op.recv(msglen * multiplier)
5391+
self.assertEqual(len(enc), msglen * multiplier)
5392+
self.assertTrue(enc[:msglen], ciphertext)
5393+
5394+
op, _ = algo.accept()
5395+
with op:
5396+
op.sendmsg_afalg([enc],
5397+
op=socket.ALG_OP_DECRYPT, iv=iv)
5398+
dec = op.recv(msglen * multiplier)
5399+
self.assertEqual(len(dec), msglen * multiplier)
5400+
self.assertEqual(dec, msg * multiplier)
5401+
5402+
@support.requires_linux_version(3, 19)
5403+
def test_aead_aes_gcm(self):
5404+
key = bytes.fromhex('c939cc13397c1d37de6ae0e1cb7c423c')
5405+
iv = bytes.fromhex('b3d8cc017cbb89b39e0f67e2')
5406+
plain = bytes.fromhex('c3b3c41f113a31b73d9a5cd432103069')
5407+
assoc = bytes.fromhex('24825602bd12a984e0092d3e448eda5f')
5408+
expected_ct = bytes.fromhex('93fe7d9e9bfd10348a5606e5cafa7354')
5409+
expected_tag = bytes.fromhex('0032a1dc85f1c9786925a2e71d8272dd')
5410+
5411+
taglen = len(expected_tag)
5412+
assoclen = len(assoc)
5413+
5414+
with self.create_alg('aead', 'gcm(aes)') as algo:
5415+
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
5416+
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_AEAD_AUTHSIZE,
5417+
None, taglen)
5418+
5419+
# send assoc, plain and tag buffer in separate steps
5420+
op, _ = algo.accept()
5421+
with op:
5422+
op.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, iv=iv,
5423+
assoclen=assoclen, flags=socket.MSG_MORE)
5424+
op.sendall(assoc, socket.MSG_MORE)
5425+
op.sendall(plain, socket.MSG_MORE)
5426+
op.sendall(b'\x00' * taglen)
5427+
res = op.recv(assoclen + len(plain) + taglen)
5428+
self.assertEqual(expected_ct, res[assoclen:-taglen])
5429+
self.assertEqual(expected_tag, res[-taglen:])
5430+
5431+
# now with msg
5432+
op, _ = algo.accept()
5433+
with op:
5434+
msg = assoc + plain + b'\x00' * taglen
5435+
op.sendmsg_afalg([msg], op=socket.ALG_OP_ENCRYPT, iv=iv,
5436+
assoclen=assoclen)
5437+
res = op.recv(assoclen + len(plain) + taglen)
5438+
self.assertEqual(expected_ct, res[assoclen:-taglen])
5439+
self.assertEqual(expected_tag, res[-taglen:])
5440+
5441+
# create anc data manually
5442+
pack_uint32 = struct.Struct('I').pack
5443+
op, _ = algo.accept()
5444+
with op:
5445+
msg = assoc + plain + b'\x00' * taglen
5446+
op.sendmsg(
5447+
[msg],
5448+
([socket.SOL_ALG, socket.ALG_SET_OP, pack_uint32(socket.ALG_OP_ENCRYPT)],
5449+
[socket.SOL_ALG, socket.ALG_SET_IV, pack_uint32(len(iv)) + iv],
5450+
[socket.SOL_ALG, socket.ALG_SET_AEAD_ASSOCLEN, pack_uint32(assoclen)],
5451+
)
5452+
)
5453+
res = op.recv(len(msg))
5454+
self.assertEqual(expected_ct, res[assoclen:-taglen])
5455+
self.assertEqual(expected_tag, res[-taglen:])
5456+
5457+
# decrypt and verify
5458+
op, _ = algo.accept()
5459+
with op:
5460+
msg = assoc + expected_ct + expected_tag
5461+
op.sendmsg_afalg([msg], op=socket.ALG_OP_DECRYPT, iv=iv,
5462+
assoclen=assoclen)
5463+
res = op.recv(len(msg))
5464+
self.assertEqual(plain, res[assoclen:-taglen])
5465+
5466+
def test_drbg_pr_sha256(self):
5467+
# deterministic random bit generator, prediction resistance, sha256
5468+
with self.create_alg('rng', 'drbg_pr_sha256') as algo:
5469+
extra_seed = os.urandom(32)
5470+
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, extra_seed)
5471+
op, _ = algo.accept()
5472+
with op:
5473+
rn = op.recv(32)
5474+
self.assertEqual(len(rn), 32)
5475+
5476+
def test_sendmsg_afalg_args(self):
5477+
sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
5478+
with self.assertRaises(TypeError):
5479+
sock.sendmsg_afalg()
5480+
5481+
with self.assertRaises(TypeError):
5482+
sock.sendmsg_afalg(op=None)
5483+
5484+
with self.assertRaises(TypeError):
5485+
sock.sendmsg_afalg(1)
5486+
5487+
with self.assertRaises(TypeError):
5488+
sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=None)
5489+
5490+
with self.assertRaises(TypeError):
5491+
sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=-1)
53285492

53295493
def test_main():
53305494
tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest,
@@ -5352,6 +5516,7 @@ def test_main():
53525516
tests.extend([TIPCTest, TIPCThreadableTest])
53535517
tests.extend([BasicCANTest, CANTest])
53545518
tests.extend([BasicRDSTest, RDSTest])
5519+
tests.append(LinuxKernelCryptoAPI)
53555520
tests.extend([
53565521
CmsgMacroTests,
53575522
SendmsgUDPTest,

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ Core and Builtins
7777
Library
7878
-------
7979

80+
- Issue #27744: Add AF_ALG (Linux Kernel crypto) to socket module.
81+
8082
- Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0.
8183

8284
- Issue #11620: Fix support for SND_MEMORY in winsound.PlaySound. Based on a

0 commit comments

Comments
 (0)