DES¶
The Data Encryption Standard.
This file implements the Data Encryption Standard and the corresponding key schedule as described in [U.S1999].
This implementation is meant for experimental and educational usage only, do not use it in production code!
EXAMPLES:
Encrypt a message:
sage: from sage.crypto.block_cipher.des import DES
sage: des = DES()
sage: P = 0x01A1D6D039776742
sage: K = 0x7CA110454A1A6E57
sage: C = des.encrypt(plaintext=P, key=K); C.hex()
'690f5b0d9a26939b'
>>> from sage.all import *
>>> from sage.crypto.block_cipher.des import DES
>>> des = DES()
>>> P = Integer(0x01A1D6D039776742)
>>> K = Integer(0x7CA110454A1A6E57)
>>> C = des.encrypt(plaintext=P, key=K); C.hex()
'690f5b0d9a26939b'
And decrypt it again:
sage: des.decrypt(ciphertext=C, key=K).hex()
'1a1d6d039776742'
>>> from sage.all import *
>>> des.decrypt(ciphertext=C, key=K).hex()
'1a1d6d039776742'
Have a look at the used round keys:
sage: from sage.crypto.block_cipher.des import DES_KS
sage: ks = DES_KS()
sage: [k.hex() for k in ks(0x1F08260D1AC2465E)]
['103049bfb90e',
 '808d40f07bf',
  ...
 '231000f2dd97']
>>> from sage.all import *
>>> from sage.crypto.block_cipher.des import DES_KS
>>> ks = DES_KS()
>>> [k.hex() for k in ks(Integer(0x1F08260D1AC2465E))]
['103049bfb90e',
 '808d40f07bf',
  ...
 '231000f2dd97']
Validate the Sample Round Outputs for DES (cf. [KeSm1998] p. 124):
sage: from sage.crypto.block_cipher.des import DES
sage: P = 0
sage: K = 0x10316E028C8F3B4A
sage: for r in range(1, 17):
....:     DES(rounds=r, doFinalRound=False).encrypt(P, K).hex()
'47092b5b'
'47092b5b53f372af'
'53f372af9f1d158b'
...
'3f6c3efd5a1e5228'
sage: DES().encrypt(P, K).hex()
'82dcbafbdeab6602'
>>> from sage.all import *
>>> from sage.crypto.block_cipher.des import DES
>>> P = Integer(0)
>>> K = Integer(0x10316E028C8F3B4A)
>>> for r in range(Integer(1), Integer(17)):
...     DES(rounds=r, doFinalRound=False).encrypt(P, K).hex()
'47092b5b'
'47092b5b53f372af'
'53f372af9f1d158b'
...
'3f6c3efd5a1e5228'
>>> DES().encrypt(P, K).hex()
'82dcbafbdeab6602'
Change cipher internals:
sage: from sage.crypto.sbox import SBox
sage: cipher = DES(rounds=1, doFinalRound=False)
sage: cipher.sboxes = [[SBox(range(16))]*4]*8
sage: cipher.keySchedule = lambda x: [0]  # return the 0 key as round key
sage: cipher.encrypt(plaintext=0x1234, key=0x0).hex()
'80004000d08100'
>>> from sage.all import *
>>> from sage.crypto.sbox import SBox
>>> cipher = DES(rounds=Integer(1), doFinalRound=False)
>>> cipher.sboxes = [[SBox(range(Integer(16)))]*Integer(4)]*Integer(8)
>>> cipher.keySchedule = lambda x: [Integer(0)]  # return the 0 key as round key
>>> cipher.encrypt(plaintext=Integer(0x1234), key=Integer(0x0)).hex()
'80004000d08100'
AUTHORS:
- Lukas Stennes (2019-03-29): initial version 
- class sage.crypto.block_cipher.des.DES(rounds=None, keySchedule='DES_KS', keySize=64, doFinalRound=True)[source]¶
- Bases: - SageObject- This class implements DES described in [U.S1999]. - EXAMPLES: - You can invoke DES encryption/decryption either by calling DES with an appropriate flag: - sage: from sage.crypto.block_cipher.des import DES sage: des = DES() sage: P = 0x8000000000000000 sage: K = 0x0 sage: C = des(P, K, 'encrypt'); C.hex() '95f8a5e5dd31d900' sage: des(C, K, 'decrypt').hex() '8000000000000000' - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES >>> des = DES() >>> P = Integer(0x8000000000000000) >>> K = Integer(0x0) >>> C = des(P, K, 'encrypt'); C.hex() '95f8a5e5dd31d900' >>> des(C, K, 'decrypt').hex() '8000000000000000' - Or by calling encryption/decryption methods directly: - sage: C = des.encrypt(P, K) sage: P == des.decrypt(C, K) True - >>> from sage.all import * >>> C = des.encrypt(P, K) >>> P == des.decrypt(C, K) True - The number of rounds can be reduced easily: - sage: des = DES(rounds=15) sage: des(des(P, K, 'encrypt'), K, 'decrypt') == P True - >>> from sage.all import * >>> des = DES(rounds=Integer(15)) >>> des(des(P, K, 'encrypt'), K, 'decrypt') == P True - You can use hex (i.e. integers) or a list-like bit representation for the inputs. If the input is an integer the output will be too. If it is list-like the output will be a bit vector: - sage: des = DES() sage: P = vector(GF(2), 64, [1] + [0]*63) sage: K = vector(GF(2), 64, [0,0,0,0,0,0,0,1]*8) sage: des.encrypt(P, K) (1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0) sage: P = 0x8000000000000000 sage: K = 0x0101010101010101 sage: C = des.encrypt(P, K); C; C.hex() 10806569712552630528 '95f8a5e5dd31d900' - >>> from sage.all import * >>> des = DES() >>> P = vector(GF(Integer(2)), Integer(64), [Integer(1)] + [Integer(0)]*Integer(63)) >>> K = vector(GF(Integer(2)), Integer(64), [Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(1)]*Integer(8)) >>> des.encrypt(P, K) (1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0) >>> P = Integer(0x8000000000000000) >>> K = Integer(0x0101010101010101) >>> C = des.encrypt(P, K); C; C.hex() 10806569712552630528 '95f8a5e5dd31d900' - See also - __init__(rounds=None, keySchedule='DES_KS', keySize=64, doFinalRound=True)[source]¶
- Construct an instance of DES. - INPUT: - rounds– integer (default:- None); the number of rounds. If- Nonethe number of rounds of the key schedule is used.
- keySchedule– (default:- 'DES_KS') the key schedule that will be used for encryption and decryption. If- 'DES_KS'the default DES key schedule is used.
- keySize– (default:- 64) the key length in bits. Must be- 56of- 64. In the latter case the key contains 8 parity bits.
- doFinalRound– boolean (default:- True); if- Falsea swap takes places but the inverse initial permutation is omitted (i.e. you can get the state after- rounds). This only effects encryption.
 - EXAMPLES: - sage: from sage.crypto.block_cipher.des import DES sage: DES() # indirect doctest DES block cipher with 16 rounds and the following key schedule: Original DES key schedule with 16 rounds - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES >>> DES() # indirect doctest DES block cipher with 16 rounds and the following key schedule: Original DES key schedule with 16 rounds - Reducing the number of rounds is simple. But increasing it is only possible if the key schedule can produce enough round keys: - sage: DES(rounds=11) # indirect doctest DES block cipher with 11 rounds and the following key schedule: Original DES key schedule with 16 rounds sage: DES(rounds=42) # indirect doctest Traceback (most recent call last): ... ValueError: number of rounds must be less or equal to the number of rounds of the key schedule - >>> from sage.all import * >>> DES(rounds=Integer(11)) # indirect doctest DES block cipher with 11 rounds and the following key schedule: Original DES key schedule with 16 rounds >>> DES(rounds=Integer(42)) # indirect doctest Traceback (most recent call last): ... ValueError: number of rounds must be less or equal to the number of rounds of the key schedule - You can use arbitrary key schedules. Since it is the only one implemented here the original key schedule is used for demonstration: - sage: from sage.crypto.block_cipher.des import DES_KS sage: DES(keySchedule=DES_KS(11)) # indirect doctest DES block cipher with 11 rounds and the following key schedule: Original DES key schedule with 11 rounds - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES_KS >>> DES(keySchedule=DES_KS(Integer(11))) # indirect doctest DES block cipher with 11 rounds and the following key schedule: Original DES key schedule with 11 rounds 
 - __call__(block, key, algorithm='encrypt')[source]¶
- Apply DES encryption or decryption on - blockusing- key. The flag- algorithmcontrols what action is to be performed on- block.- INPUT: - block– integer or bit list-like; the plaintext or ciphertext
- key– integer or bit list-like; the key
- algorithm– string (default:- 'encrypt'); a flag to signify whether encryption or decryption is to be applied to- block. The encryption flag is- 'encrypt'and the decryption flag is- 'decrypt'
 - OUTPUT: - The plaintext or ciphertext corresponding to - block, obtained using- key. If- blockis an integer the output will be too. If- blockis list-like the output will be a bit vector.
 - EXAMPLES: - sage: from sage.crypto.block_cipher.des import DES sage: des = DES() sage: P = 0x480D39006EE762F2 sage: K = 0x025816164629B007 sage: des(P, K, 'encrypt').hex() 'a1f9915541020b56' - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES >>> des = DES() >>> P = Integer(0x480D39006EE762F2) >>> K = Integer(0x025816164629B007) >>> des(P, K, 'encrypt').hex() 'a1f9915541020b56' 
 - decrypt(ciphertext, key)[source]¶
- Return the plaintext corresponding to - ciphertext, using DES decryption with- key.- INPUT: - ciphertext– integer or bit list-like; the ciphertext that will be decrypted
- key– integer or bit list-like; the key
 - OUTPUT: - The plaintext corresponding to - ciphertext, obtained using- key. If- ciphertextis an integer the output will be too. If- ciphertextis list-like the output will be a bit vector.
 - EXAMPLES: - Decrypt a message: - sage: from sage.crypto.block_cipher.des import DES sage: des = DES() sage: K64 = 0x7CA110454A1A6E57 sage: C = 0x690F5B0D9A26939B sage: P = des.decrypt(C, K64).hex(); P '1a1d6d039776742' - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES >>> des = DES() >>> K64 = Integer(0x7CA110454A1A6E57) >>> C = Integer(0x690F5B0D9A26939B) >>> P = des.decrypt(C, K64).hex(); P '1a1d6d039776742' - You can also use 56 bit keys i.e. you can leave out the parity bits: - sage: K56 = 0x7D404224A35BAB sage: des = DES(keySize=56) sage: des.decrypt(C, K56).hex() == P True - >>> from sage.all import * >>> K56 = Integer(0x7D404224A35BAB) >>> des = DES(keySize=Integer(56)) >>> des.decrypt(C, K56).hex() == P True 
 - encrypt(plaintext, key)[source]¶
- Return the ciphertext corresponding to - plaintext, using DES encryption with- key.- INPUT: - plaintext– integer or bit list-like; the plaintext that will be encrypted
- key– integer or bit list-like; the key
 - OUTPUT: - The ciphertext corresponding to - plaintext, obtained using- key. If- plaintextis an integer the output will be too. If- plaintextis list-like the output will be a bit vector.
 - EXAMPLES: - Encrypt a message: - sage: from sage.crypto.block_cipher.des import DES sage: des = DES() sage: K64 = 0x133457799BBCDFF1 sage: P = 0x0123456789ABCDEF sage: C = des.encrypt(P, K64); C.hex() '85e813540f0ab405' - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES >>> des = DES() >>> K64 = Integer(0x133457799BBCDFF1) >>> P = Integer(0x0123456789ABCDEF) >>> C = des.encrypt(P, K64); C.hex() '85e813540f0ab405' - You can also use 56 bit keys i.e. you can leave out the parity bits: - sage: K56 = 0x12695BC9B7B7F8 sage: des = DES(keySize=56) sage: des.encrypt(P, K56) == C True - >>> from sage.all import * >>> K56 = Integer(0x12695BC9B7B7F8) >>> des = DES(keySize=Integer(56)) >>> des.encrypt(P, K56) == C True 
 - round(state, round_key)[source]¶
- Apply one round of DES to - stateand return the result.- EXAMPLES: - sage: from sage.crypto.block_cipher.des import DES sage: from sage.crypto.block_cipher.des import convert_to_vector sage: des = DES() sage: k1 = convert_to_vector(0xFFFFFFFFFFFF, 48) sage: state = convert_to_vector(0xFFFFFFFF11111111, 64) sage: ZZ(list(des.round(state, k1))[::-1], 2).hex() '11111111b29684b8' - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES >>> from sage.crypto.block_cipher.des import convert_to_vector >>> des = DES() >>> k1 = convert_to_vector(Integer(0xFFFFFFFFFFFF), Integer(48)) >>> state = convert_to_vector(Integer(0xFFFFFFFF11111111), Integer(64)) >>> ZZ(list(des.round(state, k1))[::-Integer(1)], Integer(2)).hex() '11111111b29684b8' 
 - sbox_layer(block)[source]¶
- Apply the Sboxes to - block.- EXAMPLES: - sage: from sage.crypto.block_cipher.des import DES sage: des = DES() sage: B = vector(GF(2), 48, [0,1,1,0,0,0,0,1,0,0,0,1,0,1,1,1,1,0,1, ....: 1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,1,0,0,1, ....: 0,1,0,0,1,0,0,1,1,1]) sage: des.sbox_layer(B) (0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1) - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES >>> des = DES() >>> B = vector(GF(Integer(2)), Integer(48), [Integer(0),Integer(1),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(1),Integer(1),Integer(1),Integer(1),Integer(0),Integer(1), ... Integer(1),Integer(1),Integer(0),Integer(1),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),Integer(1),Integer(0),Integer(0),Integer(1),Integer(1),Integer(0),Integer(0),Integer(1), ... Integer(0),Integer(1),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(1),Integer(1),Integer(1)]) >>> des.sbox_layer(B) (0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1) - See also 
 
- class sage.crypto.block_cipher.des.DES_KS(rounds=16, masterKey=None)[source]¶
- Bases: - SageObject- This class implements the DES key schedules described in [U.S1999]. - EXAMPLES: - Initialise the key schedule with a \(masterKey\) to use it as an iterable: - sage: from sage.crypto.block_cipher.des import DES_KS sage: ks = DES_KS(masterKey=0) sage: ks[0] 0 sage: ks[15] 0 - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES_KS >>> ks = DES_KS(masterKey=Integer(0)) >>> ks[Integer(0)] 0 >>> ks[Integer(15)] 0 - Or omit the \(masterKey\) and pass a key when calling the key schedule: - sage: ks = DES_KS() sage: K = ks(0x584023641ABA6176) sage: K[0].hex() 'd0a2ed2fa124' sage: K[15].hex() '43b42af81183' - >>> from sage.all import * >>> ks = DES_KS() >>> K = ks(Integer(0x584023641ABA6176)) >>> K[Integer(0)].hex() 'd0a2ed2fa124' >>> K[Integer(15)].hex() '43b42af81183' - See also - __init__(rounds=16, masterKey=None)[source]¶
- Construct an instance of DES_KS. - INPUT: - rounds– integer (default: \(16\)); the number of rounds- selfcan create keys for
- masterKey– integer or bit list-like (default:- None); the 64-bit key that will be used
 - EXAMPLES: - sage: from sage.crypto.block_cipher.des import DES_KS sage: DES_KS() Original DES key schedule with 16 rounds - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES_KS >>> DES_KS() Original DES key schedule with 16 rounds - Note - If you want to use a DES_KS object as an iterable you have to pass a - masterKeyvalue on initialisation. Otherwise you can omit- masterKeyand pass a key when you call the object.
 - __call__(key)[source]¶
- Return all round keys in a list. - INPUT: - key– integer or bit list-like; the 64-bit key
 - OUTPUT: - A list containing the round keys. If - keyis an integer the elements of the output list will be too. If- keyis list-like the element of the output list will be bit vectors.
 - EXAMPLES: - This implementation is using bit vectors for all internal representations. So you can invoke the key schedule with a bit vector: - sage: from sage.crypto.block_cipher.des import DES_KS sage: K = vector(GF(2),[0,0,0,1,0,0,1,1,0,0,1,1,0,1,0,0,0,1,0,1,0, ....: 1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0, ....: 1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1]) sage: ks = DES_KS(16, K) sage: [k for k in ks] [(0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0), (0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1), ... (1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1)] - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import DES_KS >>> K = vector(GF(Integer(2)),[Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(1),Integer(1),Integer(0),Integer(0),Integer(1),Integer(1),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(1),Integer(0), ... Integer(1),Integer(1),Integer(1),Integer(0),Integer(1),Integer(1),Integer(1),Integer(1),Integer(0),Integer(0),Integer(1),Integer(1),Integer(0),Integer(0),Integer(1),Integer(1),Integer(0),Integer(1),Integer(1),Integer(1),Integer(0), ... Integer(1),Integer(1),Integer(1),Integer(1),Integer(0),Integer(0),Integer(1),Integer(1),Integer(0),Integer(1),Integer(1),Integer(1),Integer(1),Integer(1),Integer(1),Integer(1),Integer(1),Integer(1),Integer(0),Integer(0),Integer(0),Integer(1)]) >>> ks = DES_KS(Integer(16), K) >>> [k for k in ks] [(0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0), (0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1), ... (1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1)] - But of course you can invoke it with hex representation as well: - sage: K = 0x133457799bbcdff1 sage: ks = DES_KS(16, K) sage: [k.hex() for k in ks] ['1b02effc7072', '79aed9dbc9e5', ... 'cb3d8b0e17f5'] - >>> from sage.all import * >>> K = Integer(0x133457799bbcdff1) >>> ks = DES_KS(Integer(16), K) >>> [k.hex() for k in ks] ['1b02effc7072', '79aed9dbc9e5', ... 'cb3d8b0e17f5'] - Note - If you want to use a DES_KS object as an iterable you have to pass a - masterKeyvalue on initialisation. Otherwise you can omit- masterKeyand pass a key when you call the object.
 
- sage.crypto.block_cipher.des.convert_to_vector(I, L)[source]¶
- Convert - Ito a bit vector of length- L.- INPUT: - I– integer or bit list-like
- L– integer; the desired bit length of the ouput
 - OUTPUT: the - L-bit vector representation of- I- EXAMPLES: - sage: from sage.crypto.block_cipher.des import convert_to_vector sage: convert_to_vector(0x1F, 8) (0, 0, 0, 1, 1, 1, 1, 1) sage: v = vector(GF(2), 4, [1,0,1,0]) sage: convert_to_vector(v, 4) (1, 0, 1, 0) - >>> from sage.all import * >>> from sage.crypto.block_cipher.des import convert_to_vector >>> convert_to_vector(Integer(0x1F), Integer(8)) (0, 0, 0, 1, 1, 1, 1, 1) >>> v = vector(GF(Integer(2)), Integer(4), [Integer(1),Integer(0),Integer(1),Integer(0)]) >>> convert_to_vector(v, Integer(4)) (1, 0, 1, 0)