Skip to content
This repository was archived by the owner on Apr 20, 2025. It is now read-only.

Commit 28f89a0

Browse files
committed
Implementation of bitwise XOR function for bytes object
1 parent cf124d3 commit 28f89a0

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

rsa/_compat.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,33 @@ def byte(num):
105105
return pack("B", num)
106106

107107

108+
def xor_bytes(b1, b2):
109+
"""
110+
Returns the bitwise XOR result between two bytes objects, b1 ^ b2.
111+
112+
Bitwise XOR operation is commutative, so order of parameters doesn't
113+
generate different results. If parameters have different length, extra
114+
length of the largest one is ignored.
115+
116+
:param b1:
117+
First bytes object.
118+
:param b2:
119+
Second bytes object.
120+
:returns:
121+
Bytes object, result of XOR operation.
122+
"""
123+
124+
try:
125+
# Python 2
126+
return (
127+
''.join(byte(ord(x) ^ ord(y)) for x, y in zip(b1, b2))
128+
or EMPTY_BYTE
129+
)
130+
except TypeError:
131+
# Python 3
132+
return bytes([x ^ y for x, y in zip(b1, b2)])
133+
134+
108135
def get_word_alignment(num, force_arch=64,
109136
_machine_word_size=MACHINE_WORD_SIZE):
110137
"""

tests/test_compat.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
import struct
1919
import sys
2020

21-
from rsa._compat import is_bytes, byte, b
21+
from rsa._compat import is_bytes, byte, b, xor_bytes, EMPTY_BYTE
2222

2323

2424
class TestByte(unittest.TestCase):
25+
"""Tests for single bytes."""
26+
2527
def test_byte(self):
2628
for i in range(256):
2729
byt = byte(i)
@@ -34,3 +36,32 @@ def test_raises_StructError_on_overflow(self):
3436

3537
def test_byte_literal(self):
3638
self.assertIsInstance(b('abc'), bytes)
39+
40+
41+
class TestBytes(unittest.TestCase):
42+
"""Tests for bytes objects."""
43+
44+
def test_xor_bytes(self):
45+
b1 = b('\xff\xff\xff\xff')
46+
b2 = b('\x00\x00\x00\x00')
47+
b3 = b('\xf0\xf0\xf0\xf0')
48+
49+
self.assertEqual(xor_bytes(b1, b2), b('\xff\xff\xff\xff'))
50+
self.assertEqual(xor_bytes(b1, b3), b('\x0f\x0f\x0f\x0f'))
51+
self.assertEqual(xor_bytes(b2, b3), b('\xf0\xf0\xf0\xf0'))
52+
self.assertEqual(xor_bytes(b1, EMPTY_BYTE), EMPTY_BYTE)
53+
54+
def test_xor_bytes_length(self):
55+
b1 = b('\xff\xff')
56+
b2 = b('\xf0\xf0\xf0\xf0')
57+
58+
self.assertEqual(xor_bytes(b1, b2), b('\x0f\x0f'))
59+
60+
def test_xor_bytes_commutative(self):
61+
b1 = b('\xff\xff\xff\xff')
62+
b2 = b('\x00\x00\x00\x00')
63+
b3 = b('\xf0\xf0\xf0\xf0')
64+
65+
self.assertEqual(xor_bytes(b1, b2), xor_bytes(b2, b1))
66+
self.assertEqual(xor_bytes(b1, b3), xor_bytes(b3, b1))
67+
self.assertEqual(xor_bytes(b2, b3), xor_bytes(b3, b2))

0 commit comments

Comments
 (0)