Path: blob/master/src/sage/crypto/block_cipher/sdes.py
8817 views
r"""1Simplified DES23A simplified variant of the Data Encryption Standard (DES). Note that4Simplified DES or S-DES is for educational purposes only. It is a5small-scale version of the DES designed to help beginners understand the6basic structure of DES.78AUTHORS:910- Minh Van Nguyen (2009-06): initial version11"""1213###########################################################################14# Copyright (c) 2009 Minh Van Nguyen <[email protected]>15#16# This program is free software; you can redistribute it and/or modify17# it under the terms of the GNU General Public License as published by18# the Free Software Foundation; either version 2 of the License, or19# (at your option) any later version.20#21# This program is distributed in the hope that it will be useful,22# but WITHOUT ANY WARRANTY; without even the implied warranty of23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the24# GNU General Public License for more details.25#26# http://www.gnu.org/licenses/27###########################################################################2829from sage.monoids.string_monoid import BinaryStrings30from sage.structure.sage_object import SageObject3132class SimplifiedDES(SageObject):33r"""34This class implements the Simplified Data Encryption Standard (S-DES)35described in [Sch96]_. Schaefer's S-DES is for educational purposes36only and is not secure for practical purposes. S-DES is a version of37the DES with all parameters significantly reduced, but at the same time38preserving the structure of DES. The goal of S-DES is to allow a39beginner to understand the structure of DES, thus laying a foundation40for a thorough study of DES. Its goal is as a teaching tool in the same41spirit as Phan's42:mod:`Mini-AES <sage.crypto.block_cipher.miniaes>` [Pha02]_.4344EXAMPLES:4546Encrypt a random block of 8-bit plaintext using a random key, decrypt47the ciphertext, and compare the result with the original plaintext::4849sage: from sage.crypto.block_cipher.sdes import SimplifiedDES50sage: sdes = SimplifiedDES(); sdes51Simplified DES block cipher with 10-bit keys52sage: bin = BinaryStrings()53sage: P = [bin(str(randint(0, 1))) for i in xrange(8)]54sage: K = sdes.random_key()55sage: C = sdes.encrypt(P, K)56sage: plaintxt = sdes.decrypt(C, K)57sage: plaintxt == P58True5960We can also encrypt binary strings that are larger than 8 bits in length.61However, the number of bits in that binary string must be positive62and a multiple of 8::6364sage: from sage.crypto.block_cipher.sdes import SimplifiedDES65sage: sdes = SimplifiedDES()66sage: bin = BinaryStrings()67sage: P = bin.encoding("Encrypt this using S-DES!")68sage: Mod(len(P), 8) == 069True70sage: K = sdes.list_to_string(sdes.random_key())71sage: C = sdes(P, K, algorithm="encrypt")72sage: plaintxt = sdes(C, K, algorithm="decrypt")73sage: plaintxt == P74True7576REFERENCES:7778.. [Pha02] R. C.-W. Phan. Mini advanced encryption standard (mini-AES): a79testbed for cryptanalysis students. Cryptologia, 26(4):283--306, 2002.8081.. [Sch96] E. Schaefer. A simplified data encryption algorithm.82Cryptologia, 20(1):77--84, 1996.83"""8485def __init__(self):86r"""87A simplified variant of the Data Encryption Standard (DES).8889EXAMPLES::9091sage: from sage.crypto.block_cipher.sdes import SimplifiedDES92sage: sdes = SimplifiedDES(); sdes93Simplified DES block cipher with 10-bit keys94sage: B = BinaryStrings()95sage: P = [B(str(randint(0, 1))) for i in xrange(8)]96sage: K = sdes.random_key()97sage: C = sdes.encrypt(P, K)98sage: plaintxt = sdes.decrypt(C, K)99sage: plaintxt == P100True101"""102from sage.crypto.mq import SBox103# the number of bits in a secret key104self._key_size = 10105# the S-box S_0106self._sbox0 = SBox(1, 0, 3, 2, 3, 2, 1, 0, 0, 2, 1, 3, 3, 1, 3, 2)107# the S-box S_1108self._sbox1 = SBox(0, 1, 2, 3, 2, 0, 1, 3, 3, 0, 1, 0, 2, 1, 0, 3)109110def __call__(self, B, K, algorithm="encrypt"):111r"""112Apply S-DES encryption or decryption on the binary string ``B``113using the key ``K``. The flag ``algorithm`` controls what action is114to be performed on ``B``.115116INPUT:117118- ``B`` -- a binary string, where the number of bits is positive and119a multiple of 8.120121- ``K`` -- a secret key; this must be a 10-bit binary string122123- ``algorithm`` -- (default: ``"encrypt"``) a string; a flag to signify124whether encryption or decryption is to be applied to the binary125string ``B``. The encryption flag is ``"encrypt"`` and the decryption126flag is ``"decrypt"``.127128OUTPUT:129130- The ciphertext (respectively plaintext) corresponding to the131binary string ``B``.132133EXAMPLES:134135Encrypt a plaintext, decrypt the ciphertext, and compare the136result with the original plaintext::137138sage: from sage.crypto.block_cipher.sdes import SimplifiedDES139sage: sdes = SimplifiedDES()140sage: bin = BinaryStrings()141sage: P = bin.encoding("Encrypt this using DES!")142sage: K = sdes.random_key()143sage: K = sdes.list_to_string(K)144sage: C = sdes(P, K, algorithm="encrypt")145sage: plaintxt = sdes(C, K, algorithm="decrypt")146sage: plaintxt == P147True148149TESTS:150151The binary string ``B`` must be non-empty and the number of bits must152be a multiple of 8::153154sage: from sage.crypto.block_cipher.sdes import SimplifiedDES155sage: sdes = SimplifiedDES()156sage: sdes("B", "K")157Traceback (most recent call last):158...159TypeError: input B must be a non-empty binary string with number of bits a multiple of 8160sage: bin = BinaryStrings()161sage: B = bin("101")162sage: sdes(B, "K")163Traceback (most recent call last):164...165ValueError: the number of bits in the binary string B must be positive and a multiple of 8166167The secret key ``K`` must be a block of 10 bits::168169sage: B = bin.encoding("abc")170sage: sdes(B, "K")171Traceback (most recent call last):172...173TypeError: secret key must be a 10-bit binary string174sage: K = bin("1010")175sage: sdes(B, K)176Traceback (most recent call last):177...178ValueError: secret key must be a 10-bit binary string179180The value for ``algorithm`` must be either ``"encrypt"`` or181``"decrypt"``::182183sage: B = bin.encoding("abc")184sage: K = sdes.list_to_string(sdes.random_key())185sage: sdes(B, K, algorithm="e")186Traceback (most recent call last):187...188ValueError: algorithm must be either 'encrypt' or 'decrypt'189sage: sdes(B, K, algorithm="d")190Traceback (most recent call last):191...192ValueError: algorithm must be either 'encrypt' or 'decrypt'193sage: sdes(B, K, algorithm="abc")194Traceback (most recent call last):195...196ValueError: algorithm must be either 'encrypt' or 'decrypt'197"""198from sage.monoids.string_monoid_element import StringMonoidElement199from sage.rings.finite_rings.integer_mod import Mod200# S-DES operates on 8-bit ciphertext/plaintext blocks201Blength = 8202203if not isinstance(B, StringMonoidElement):204raise TypeError, "input B must be a non-empty binary string with number of bits a multiple of 8"205if (len(B) == 0) or (Mod(len(B), Blength).lift() != 0):206raise ValueError, "the number of bits in the binary string B must be positive and a multiple of 8"207if not isinstance(K, StringMonoidElement):208raise TypeError, "secret key must be a 10-bit binary string"209if len(K) != self._key_size:210raise ValueError, "secret key must be a 10-bit binary string"211212N = len(B) / Blength # the number of 8-bit blocks213S = ""214bin = BinaryStrings()215# encrypt each 8-bit block in succession216if algorithm == "encrypt":217for i in xrange(N):218# get an 8-bit block219block = B[i*Blength : (i+1)*Blength]220block = self.string_to_list(str(block))221key = self.string_to_list(str(K))222# encrypt the block using key223C = self.encrypt(block, key)224C = self.list_to_string(C)225# append encrypted block to ciphertext string226S = "".join([S, str(C)])227return bin(S)228# decrypt each 8-bit block in succession229elif algorithm == "decrypt":230for i in xrange(N):231# get an 8-bit block232block = B[i*Blength : (i+1)*Blength]233block = self.string_to_list(str(block))234key = self.string_to_list(str(K))235# decrypt the block using key236P = self.decrypt(block, key)237P = self.list_to_string(P)238# append decrypted block to plaintext string239S = "".join([S, str(P)])240return bin(S)241# invalid value for algorithm option242else:243raise ValueError, "algorithm must be either 'encrypt' or 'decrypt'"244245def __eq__(self, other):246r"""247Compare ``self`` with ``other``.248249Simplified DES objects are the same if they have the same key size250and S-boxes.251252EXAMPLES::253254sage: from sage.crypto.block_cipher.sdes import SimplifiedDES255sage: s = SimplifiedDES()256sage: s == loads(dumps(s))257True258"""259return ( (self._key_size == other._key_size) and260(self._sbox0 == other._sbox0) and261(self._sbox1 == other._sbox1) )262263def __repr__(self):264r"""265A string representation of this Simplified DES.266267EXAMPLES::268269sage: from sage.crypto.block_cipher.sdes import SimplifiedDES270sage: SimplifiedDES()271Simplified DES block cipher with 10-bit keys272"""273return "Simplified DES block cipher with 10-bit keys"274275def block_length(self):276r"""277Return the block length of Schaefer's S-DES block cipher. A key in278Schaefer's S-DES is a block of 10 bits.279280OUTPUT:281282- The block (or key) length in number of bits.283284EXAMPLES::285286sage: from sage.crypto.block_cipher.sdes import SimplifiedDES287sage: sdes = SimplifiedDES()288sage: sdes.block_length()28910290"""291return self._key_size292293def decrypt(self, C, K):294r"""295Return an 8-bit plaintext corresponding to the ciphertext ``C``,296using S-DES decryption with key ``K``. The decryption process of297S-DES is as follows. Let `P` be the initial permutation function,298`P^{-1}` the corresponding inverse permutation, `\Pi_F` the299permutation/substitution function, and `\sigma` the switch function.300The ciphertext block ``C`` first goes through `P`, the output of301which goes through `\Pi_F` using the second subkey. Then we apply302the switch function to the output of the last function, and the303result is then fed into `\Pi_F` using the first subkey. Finally,304run the output through `P^{-1}` to get the plaintext.305306INPUT:307308- ``C`` -- an 8-bit ciphertext; a block of 8 bits309310- ``K`` -- a 10-bit key; a block of 10 bits311312OUTPUT:313314The 8-bit plaintext corresponding to ``C``, obtained using the315key ``K``.316317EXAMPLES:318319Decrypt an 8-bit ciphertext block::320321sage: from sage.crypto.block_cipher.sdes import SimplifiedDES322sage: sdes = SimplifiedDES()323sage: C = [0, 1, 0, 1, 0, 1, 0, 1]324sage: K = [1, 0, 1, 0, 0, 0, 0, 0, 1, 0]325sage: sdes.decrypt(C, K)326[0, 0, 0, 1, 0, 1, 0, 1]327328We can also work with strings of bits::329330sage: C = "01010101"331sage: K = "1010000010"332sage: sdes.decrypt(sdes.string_to_list(C), sdes.string_to_list(K))333[0, 0, 0, 1, 0, 1, 0, 1]334335TESTS:336337The ciphertext must be a block of 8 bits::338339sage: from sage.crypto.block_cipher.sdes import SimplifiedDES340sage: sdes = SimplifiedDES()341sage: sdes.decrypt("C", "K")342Traceback (most recent call last):343...344TypeError: ciphertext must be a list of 8 bits345sage: sdes.decrypt([], "K")346Traceback (most recent call last):347...348ValueError: ciphertext must be a list of 8 bits349sage: sdes.decrypt([1, 2, 3, 4], "K")350Traceback (most recent call last):351...352ValueError: ciphertext must be a list of 8 bits353354The key must be a block of 10 bits::355356sage: sdes.decrypt([1, 0, 1, 0, 1, 1, 0, 1], "K")357Traceback (most recent call last):358...359TypeError: the key must be a list of 10 bits360sage: sdes.decrypt([1, 0, 1, 0, 1, 1, 0, 1], [])361Traceback (most recent call last):362...363TypeError: the key must be a list of 10 bits364sage: sdes.decrypt([1, 0, 1, 0, 1, 1, 0, 1], [1, 2, 3, 4, 5])365Traceback (most recent call last):366...367TypeError: the key must be a list of 10 bits368369The value of each element of ``C`` or ``K`` must be either 0 or 1::370371sage: C = [1, 2, 3, 4, 5, 6, 7, 8]372sage: K = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]373sage: sdes.decrypt(C, K)374Traceback (most recent call last):375...376TypeError: Argument x (= 2) is not a valid string.377sage: C = [0, 1, 0, 0, 1, 1, 1, 0]378sage: K = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]379sage: sdes.decrypt(C, K)380Traceback (most recent call last):381...382TypeError: Argument x (= 13) is not a valid string.383"""384# sanity check385if not isinstance(C, list):386raise TypeError, "ciphertext must be a list of 8 bits"387if len(C) != 8:388raise ValueError, "ciphertext must be a list of 8 bits"389if not isinstance(K, list):390raise TypeError, "the key must be a list of 10 bits"391if len(K) != 10:392raise TypeError, "the key must be a list of 10 bits"393394# run through initial permutation395P = self.initial_permutation(C, inverse=False)396# run through Pi_F with subkey 2397P = self.permute_substitute(P, self.subkey(K, n=2))398# run through switch function399P = self.switch(P)400# run through Pi_F with subkey 1401P = self.permute_substitute(P, self.subkey(K, n=1))402# run through inverse permutation403P = self.initial_permutation(P, inverse=True)404# output the plaintext405return P406407def encrypt(self, P, K):408r"""409Return an 8-bit ciphertext corresponding to the plaintext ``P``,410using S-DES encryption with key ``K``. The encryption process of411S-DES is as follows. Let `P` be the initial permutation function,412`P^{-1}` the corresponding inverse permutation, `\Pi_F` the413permutation/substitution function, and `\sigma` the switch function.414The plaintext block ``P`` first goes through `P`, the output of415which goes through `\Pi_F` using the first subkey. Then we apply416the switch function to the output of the last function, and the417result is then fed into `\Pi_F` using the second subkey. Finally,418run the output through `P^{-1}` to get the ciphertext.419420INPUT:421422- ``P`` -- an 8-bit plaintext; a block of 8 bits423424- ``K`` -- a 10-bit key; a block of 10 bits425426OUTPUT:427428The 8-bit ciphertext corresponding to ``P``, obtained using the429key ``K``.430431EXAMPLES:432433Encrypt an 8-bit plaintext block::434435sage: from sage.crypto.block_cipher.sdes import SimplifiedDES436sage: sdes = SimplifiedDES()437sage: P = [0, 1, 0, 1, 0, 1, 0, 1]438sage: K = [1, 0, 1, 0, 0, 0, 0, 0, 1, 0]439sage: sdes.encrypt(P, K)440[1, 1, 0, 0, 0, 0, 0, 1]441442We can also work with strings of bits::443444sage: P = "01010101"445sage: K = "1010000010"446sage: sdes.encrypt(sdes.string_to_list(P), sdes.string_to_list(K))447[1, 1, 0, 0, 0, 0, 0, 1]448449TESTS:450451The plaintext must be a block of 8 bits::452453sage: from sage.crypto.block_cipher.sdes import SimplifiedDES454sage: sdes = SimplifiedDES()455sage: sdes.encrypt("P", "K")456Traceback (most recent call last):457...458TypeError: plaintext must be a list of 8 bits459sage: sdes.encrypt([], "K")460Traceback (most recent call last):461...462ValueError: plaintext must be a list of 8 bits463sage: sdes.encrypt([1, 2, 3, 4], "K")464Traceback (most recent call last):465...466ValueError: plaintext must be a list of 8 bits467468The key must be a block of 10 bits::469470sage: sdes.encrypt([1, 0, 1, 0, 1, 1, 0, 1], "K")471Traceback (most recent call last):472...473TypeError: the key must be a list of 10 bits474sage: sdes.encrypt([1, 0, 1, 0, 1, 1, 0, 1], [])475Traceback (most recent call last):476...477TypeError: the key must be a list of 10 bits478sage: sdes.encrypt([1, 0, 1, 0, 1, 1, 0, 1], [1, 2, 3, 4, 5])479Traceback (most recent call last):480...481TypeError: the key must be a list of 10 bits482483The value of each element of ``P`` or ``K`` must be either 0 or 1::484485sage: P = [1, 2, 3, 4, 5, 6, 7, 8]486sage: K = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]487sage: sdes.encrypt(P, K)488Traceback (most recent call last):489...490TypeError: Argument x (= 2) is not a valid string.491sage: P = [0, 1, 0, 0, 1, 1, 1, 0]492sage: K = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]493sage: sdes.encrypt(P, K)494Traceback (most recent call last):495...496TypeError: Argument x (= 13) is not a valid string.497"""498# sanity check499if not isinstance(P, list):500raise TypeError, "plaintext must be a list of 8 bits"501if len(P) != 8:502raise ValueError, "plaintext must be a list of 8 bits"503if not isinstance(K, list):504raise TypeError, "the key must be a list of 10 bits"505if len(K) != 10:506raise TypeError, "the key must be a list of 10 bits"507508# run through initial permutation509C = self.initial_permutation(P, inverse=False)510# run through Pi_F with subkey 1511C = self.permute_substitute(C, self.subkey(K, n=1))512# run through switch function513C = self.switch(C)514# run through Pi_F with subkey 2515C = self.permute_substitute(C, self.subkey(K, n=2))516# run through inverse permutation517C = self.initial_permutation(C, inverse=True)518# output the ciphertext519return C520521def initial_permutation(self, B, inverse=False):522r"""523Return the initial permutation of ``B``. Denote the initial524permutation function by `P` and let `(b_0, b_1, b_2, \dots, b_7)`525be a vector of 8 bits, where each `b_i \in \{ 0, 1 \}`. Then526527.. MATH::528529530P(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7)531= (b_1, b_5, b_2, b_0, b_3, b_7, b_4, b_6)532533The inverse permutation is `P^{-1}`:534535.. MATH::536537P^{-1}(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7)538= (b_3, b_0, b_2, b_4, b_6, b_1, b_7, b_5)539540INPUT:541542- ``B`` -- list; a block of 8 bits543544- ``inverse`` -- (default: ``False``) if ``True`` then use the545inverse permutation `P^{-1}`; if ``False`` then use the initial546permutation `P`547548OUTPUT:549550The initial permutation of ``B`` if ``inverse=False``, or the551inverse permutation of ``B`` if ``inverse=True``.552553EXAMPLES:554555The initial permutation of a list of 8 bits::556557sage: from sage.crypto.block_cipher.sdes import SimplifiedDES558sage: sdes = SimplifiedDES()559sage: B = [1, 0, 1, 1, 0, 1, 0, 0]560sage: P = sdes.initial_permutation(B); P561[0, 1, 1, 1, 1, 0, 0, 0]562563Recovering the original list of 8 bits from the permutation::564565sage: Pinv = sdes.initial_permutation(P, inverse=True)566sage: Pinv; B567[1, 0, 1, 1, 0, 1, 0, 0]568[1, 0, 1, 1, 0, 1, 0, 0]569570We can also work with a string of bits::571572sage: S = "10110100"573sage: L = sdes.string_to_list(S)574sage: P = sdes.initial_permutation(L); P575[0, 1, 1, 1, 1, 0, 0, 0]576sage: sdes.initial_permutation(sdes.string_to_list("01111000"), inverse=True)577[1, 0, 1, 1, 0, 1, 0, 0]578579TESTS:580581The input block must be a list::582583sage: from sage.crypto.block_cipher.sdes import SimplifiedDES584sage: sdes = SimplifiedDES()585sage: sdes.initial_permutation("B")586Traceback (most recent call last):587...588TypeError: input block must be a list of 8 bits589sage: sdes.initial_permutation(())590Traceback (most recent call last):591...592TypeError: input block must be a list of 8 bits593594The input block must be a list of 8 bits::595596sage: sdes.initial_permutation([])597Traceback (most recent call last):598...599ValueError: input block must be a list of 8 bits600sage: sdes.initial_permutation([1, 2, 3, 4, 5, 6, 7, 8, 9])601Traceback (most recent call last):602...603ValueError: input block must be a list of 8 bits604605The value of each element of the list must be either 0 or 1::606607sage: sdes.initial_permutation([1, 2, 3, 4, 5, 6, 7, 8])608Traceback (most recent call last):609...610TypeError: Argument x (= 2) is not a valid string.611"""612# sanity check613if not isinstance(B, list):614raise TypeError, "input block must be a list of 8 bits"615if len(B) != 8:616raise ValueError, "input block must be a list of 8 bits"617618bin = BinaryStrings()619620# use the initial permutation P621if not inverse:622return [ bin(str(B[1])), bin(str(B[5])),623bin(str(B[2])), bin(str(B[0])),624bin(str(B[3])), bin(str(B[7])),625bin(str(B[4])), bin(str(B[6])) ]626627# use the inverse permutation P^-1628if inverse:629return [ bin(str(B[3])), bin(str(B[0])),630bin(str(B[2])), bin(str(B[4])),631bin(str(B[6])), bin(str(B[1])),632bin(str(B[7])), bin(str(B[5])) ]633634def left_shift(self, B, n=1):635r"""636Return a circular left shift of ``B`` by ``n`` positions. Let637`B = (b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9)` be a vector638of 10 bits. Then the left shift operation `L_n` is performed on the639first 5 bits and the last 5 bits of `B` separately. That is, if the640number of shift positions is ``n=1``, then `L_1` is defined as641642.. MATH::643644L_1(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9)645= (b_1, b_2, b_3, b_4, b_0, b_6, b_7, b_8, b_9, b_5)646647If the number of shift positions is ``n=2``, then `L_2` is given by648649.. MATH::650651L_2(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9)652= (b_2, b_3, b_4, b_0, b_1, b_7, b_8, b_9, b_5, b_6)653654INPUT:655656- ``B`` -- a list of 10 bits657658- ``n`` -- (default: 1) if ``n=1`` then perform left shift by 1659position; if ``n=2`` then perform left shift by 2 positions. The660valid values for ``n`` are 1 and 2, since only up to 2 positions661are defined for this circular left shift operation.662663OUTPUT:664665The circular left shift of each half of ``B``.666667EXAMPLES:668669Circular left shift by 1 position of a 10-bit string::670671sage: from sage.crypto.block_cipher.sdes import SimplifiedDES672sage: sdes = SimplifiedDES()673sage: B = [1, 0, 0, 0, 0, 0, 1, 1, 0, 0]674sage: sdes.left_shift(B)675[0, 0, 0, 0, 1, 1, 1, 0, 0, 0]676sage: sdes.left_shift([1, 0, 1, 0, 0, 0, 0, 0, 1, 0])677[0, 1, 0, 0, 1, 0, 0, 1, 0, 0]678679Circular left shift by 2 positions of a 10-bit string::680681sage: B = [0, 0, 0, 0, 1, 1, 1, 0, 0, 0]682sage: sdes.left_shift(B, n=2)683[0, 0, 1, 0, 0, 0, 0, 0, 1, 1]684685Here we work with a string of bits::686687sage: S = "1000001100"688sage: L = sdes.string_to_list(S)689sage: sdes.left_shift(L)690[0, 0, 0, 0, 1, 1, 1, 0, 0, 0]691sage: sdes.left_shift(sdes.string_to_list("1010000010"), n=2)692[1, 0, 0, 1, 0, 0, 1, 0, 0, 0]693694TESTS:695696The input block must be a list::697698sage: from sage.crypto.block_cipher.sdes import SimplifiedDES699sage: sdes = SimplifiedDES()700sage: sdes.left_shift("B")701Traceback (most recent call last):702...703TypeError: input block must be a list of 10 bits704sage: sdes.left_shift(())705Traceback (most recent call last):706...707TypeError: input block must be a list of 10 bits708709The input block must be a list of 10 bits::710711sage: sdes.left_shift([])712Traceback (most recent call last):713...714ValueError: input block must be a list of 10 bits715sage: sdes.left_shift([1, 2, 3, 4, 5])716Traceback (most recent call last):717...718ValueError: input block must be a list of 10 bits719720The value of each element of the list must be either 0 or 1::721722sage: sdes.left_shift([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])723Traceback (most recent call last):724...725TypeError: Argument x (= 2) is not a valid string.726727The number of shift positions must be either 1 or 2::728729sage: B = [0, 0, 0, 0, 1, 1, 1, 0, 0, 0]730sage: sdes.left_shift(B, n=-1)731Traceback (most recent call last):732...733ValueError: input n must be either 1 or 2734sage: sdes.left_shift(B, n=3)735Traceback (most recent call last):736...737ValueError: input n must be either 1 or 2738"""739# sanity check740if not isinstance(B, list):741raise TypeError, "input block must be a list of 10 bits"742if len(B) != 10:743raise ValueError, "input block must be a list of 10 bits"744745bin = BinaryStrings()746# circular left shift by 1 position747if n == 1:748return [ bin(str(B[1])), bin(str(B[2])),749bin(str(B[3])), bin(str(B[4])),750bin(str(B[0])), bin(str(B[6])),751bin(str(B[7])), bin(str(B[8])),752bin(str(B[9])), bin(str(B[5])) ]753# circular left shift by 2 positions754elif n == 2:755return [ bin(str(B[2])), bin(str(B[3])),756bin(str(B[4])), bin(str(B[0])),757bin(str(B[1])), bin(str(B[7])),758bin(str(B[8])), bin(str(B[9])),759bin(str(B[5])), bin(str(B[6])) ]760# an invalid number of shift positions761else:762raise ValueError, "input n must be either 1 or 2"763764def list_to_string(self, B):765r"""766Return a binary string representation of the list ``B``.767768INPUT:769770- ``B`` -- a non-empty list of bits771772OUTPUT:773774The binary string representation of ``B``.775776EXAMPLES:777778A binary string representation of a list of bits::779780sage: from sage.crypto.block_cipher.sdes import SimplifiedDES781sage: sdes = SimplifiedDES()782sage: L = [0, 0, 0, 0, 1, 1, 0, 1, 0, 0]783sage: sdes.list_to_string(L)7840000110100785786TESTS:787788Input ``B`` must be a non-empty list::789790sage: from sage.crypto.block_cipher.sdes import SimplifiedDES791sage: sdes = SimplifiedDES()792sage: sdes.list_to_string("L")793Traceback (most recent call last):794...795TypeError: input B must be a non-empty list of bits796sage: sdes.list_to_string([])797Traceback (most recent call last):798...799ValueError: input B must be a non-empty list of bits800801Input must be a non-empty list of bits::802803sage: sdes.list_to_string([0, 1, 2])804Traceback (most recent call last):805...806IndexError: tuple index out of range807"""808# sanity check809if not isinstance(B, list):810raise TypeError, "input B must be a non-empty list of bits"811if len(B) == 0:812raise ValueError, "input B must be a non-empty list of bits"813814# perform the conversion from list to binary string815from sage.rings.integer import Integer816bin = BinaryStrings()817return bin([Integer(str(b)) for b in B])818819def permutation4(self, B):820r"""821Return a permutation of a 4-bit string. This permutation is called822`P_4` and is specified as follows. Let823`(b_0, b_1, b_2, b_3)` be a vector of 4 bits where each824`b_i \in \{ 0, 1 \}`. Then `P_4` is defined by825826.. MATH::827828P_4(b_0, b_1, b_2, b_3) = (b_1, b_3, b_2, b_0)829830INPUT:831832- ``B`` -- a block of 4-bit string833834OUTPUT:835836A permutation of ``B``.837838EXAMPLES:839840Permute a 4-bit string::841842sage: from sage.crypto.block_cipher.sdes import SimplifiedDES843sage: sdes = SimplifiedDES()844sage: B = [1, 1, 0, 0]845sage: sdes.permutation4(B)846[1, 0, 0, 1]847sage: sdes.permutation4([0, 1, 0, 1])848[1, 1, 0, 0]849850We can also work with a string of bits::851852sage: S = "1100"853sage: L = sdes.string_to_list(S)854sage: sdes.permutation4(L)855[1, 0, 0, 1]856sage: sdes.permutation4(sdes.string_to_list("0101"))857[1, 1, 0, 0]858859TESTS:860861The input block must be a list::862863sage: from sage.crypto.block_cipher.sdes import SimplifiedDES864sage: sdes = SimplifiedDES()865sage: sdes.permutation4("B")866Traceback (most recent call last):867...868TypeError: input block must be a list of 4 bits869sage: sdes.permutation4(())870Traceback (most recent call last):871...872TypeError: input block must be a list of 4 bits873874The input block must be a list of 4 bits::875876sage: sdes.permutation4([])877Traceback (most recent call last):878...879ValueError: input block must be a list of 4 bits880sage: sdes.permutation4([1, 2, 3, 4, 5])881Traceback (most recent call last):882...883ValueError: input block must be a list of 4 bits884885The value of each element of the list must be either 0 or 1::886887sage: sdes.permutation4([1, 2, 3, 4])888Traceback (most recent call last):889...890TypeError: Argument x (= 2) is not a valid string.891"""892# sanity check893if not isinstance(B, list):894raise TypeError, "input block must be a list of 4 bits"895if len(B) != 4:896raise ValueError, "input block must be a list of 4 bits"897898# perform the permutation899bin = BinaryStrings()900return [ bin(str(B[1])), bin(str(B[3])),901bin(str(B[2])), bin(str(B[0])) ]902903def permutation8(self, B):904r"""905Return a permutation of an 8-bit string. This permutation is called906`P_8` and is specified as follows. Let907`(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9)` be a vector of90810 bits where each `b_i \in \{ 0, 1 \}`. Then `P_8` picks out 8 of909those 10 bits and permutes those 8 bits:910911.. MATH::912913P_8(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9)914=915(b_5, b_2, b_6, b_3, b_7, b_4, b_9, b_8)916917INPUT:918919- ``B`` -- a block of 10-bit string920921OUTPUT:922923Pick out 8 of the 10 bits of ``B`` and permute those 8 bits.924925EXAMPLES:926927Permute a 10-bit string::928929sage: from sage.crypto.block_cipher.sdes import SimplifiedDES930sage: sdes = SimplifiedDES()931sage: B = [1, 1, 0, 0, 1, 0, 0, 1, 0, 1]932sage: sdes.permutation8(B)933[0, 0, 0, 0, 1, 1, 1, 0]934sage: sdes.permutation8([0, 1, 1, 0, 1, 0, 0, 1, 0, 1])935[0, 1, 0, 0, 1, 1, 1, 0]936sage: sdes.permutation8([0, 0, 0, 0, 1, 1, 1, 0, 0, 0])937[1, 0, 1, 0, 0, 1, 0, 0]938939We can also work with a string of bits::940941sage: S = "1100100101"942sage: L = sdes.string_to_list(S)943sage: sdes.permutation8(L)944[0, 0, 0, 0, 1, 1, 1, 0]945sage: sdes.permutation8(sdes.string_to_list("0110100101"))946[0, 1, 0, 0, 1, 1, 1, 0]947948TESTS:949950The input block must be a list::951952sage: from sage.crypto.block_cipher.sdes import SimplifiedDES953sage: sdes = SimplifiedDES()954sage: sdes.permutation8("B")955Traceback (most recent call last):956...957TypeError: input block must be a list of 10 bits958sage: sdes.permutation8(())959Traceback (most recent call last):960...961TypeError: input block must be a list of 10 bits962963The input block must be a list of 10 bits::964965sage: sdes.permutation8([])966Traceback (most recent call last):967...968ValueError: input block must be a list of 10 bits969sage: sdes.permutation8([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])970Traceback (most recent call last):971...972ValueError: input block must be a list of 10 bits973974The value of each element of the list must be either 0 or 1::975976sage: sdes.permutation8([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])977Traceback (most recent call last):978...979TypeError: Argument x (= 6) is not a valid string.980"""981# sanity check982if not isinstance(B, list):983raise TypeError, "input block must be a list of 10 bits"984if len(B) != 10:985raise ValueError, "input block must be a list of 10 bits"986987# perform the permutation988bin = BinaryStrings()989return [ bin(str(B[5])), bin(str(B[2])),990bin(str(B[6])), bin(str(B[3])),991bin(str(B[7])), bin(str(B[4])),992bin(str(B[9])), bin(str(B[8])) ]993994def permutation10(self, B):995r"""996Return a permutation of a 10-bit string. This permutation is called997`P_{10}` and is specified as follows. Let998`(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9)` be a vector of99910 bits where each `b_i \in \{ 0, 1 \}`. Then `P_{10}` is given by10001001.. MATH::10021003P_{10}(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9)1004=1005(b_2, b_4, b_1, b_6, b_3, b_9, b_0, b_8, b_7, b_5)10061007INPUT:10081009- ``B`` -- a block of 10-bit string10101011OUTPUT:10121013A permutation of ``B``.10141015EXAMPLES:10161017Permute a 10-bit string::10181019sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1020sage: sdes = SimplifiedDES()1021sage: B = [1, 1, 0, 0, 1, 0, 0, 1, 0, 1]1022sage: sdes.permutation10(B)1023[0, 1, 1, 0, 0, 1, 1, 0, 1, 0]1024sage: sdes.permutation10([0, 1, 1, 0, 1, 0, 0, 1, 0, 1])1025[1, 1, 1, 0, 0, 1, 0, 0, 1, 0]1026sage: sdes.permutation10([1, 0, 1, 0, 0, 0, 0, 0, 1, 0])1027[1, 0, 0, 0, 0, 0, 1, 1, 0, 0]10281029Here we work with a string of bits::10301031sage: S = "1100100101"1032sage: L = sdes.string_to_list(S)1033sage: sdes.permutation10(L)1034[0, 1, 1, 0, 0, 1, 1, 0, 1, 0]1035sage: sdes.permutation10(sdes.string_to_list("0110100101"))1036[1, 1, 1, 0, 0, 1, 0, 0, 1, 0]10371038TESTS:10391040The input block must be a list::10411042sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1043sage: sdes = SimplifiedDES()1044sage: sdes.permutation10("B")1045Traceback (most recent call last):1046...1047TypeError: input block must be a list of 10 bits1048sage: sdes.permutation10(())1049Traceback (most recent call last):1050...1051TypeError: input block must be a list of 10 bits10521053The input block must be a list of 10 bits::10541055sage: sdes.permutation10([])1056Traceback (most recent call last):1057...1058ValueError: input block must be a list of 10 bits1059sage: sdes.permutation10([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])1060Traceback (most recent call last):1061...1062ValueError: input block must be a list of 10 bits10631064The value of each element of the list must be either 0 or 1::10651066sage: sdes.permutation10([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])1067Traceback (most recent call last):1068...1069TypeError: Argument x (= 3) is not a valid string.1070"""1071# sanity check1072if not isinstance(B, list):1073raise TypeError, "input block must be a list of 10 bits"1074if len(B) != 10:1075raise ValueError, "input block must be a list of 10 bits"10761077# perform the permutation1078bin = BinaryStrings()1079return [ bin(str(B[2])), bin(str(B[4])),1080bin(str(B[1])), bin(str(B[6])),1081bin(str(B[3])), bin(str(B[9])),1082bin(str(B[0])), bin(str(B[8])),1083bin(str(B[7])), bin(str(B[5])) ]10841085def permute_substitute(self, B, key):1086r"""1087Apply the function `\Pi_F` on the block ``B`` using subkey ``key``.1088Let `(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7)`1089be a vector of 8 bits where each `b_i \in \{ 0, 1 \}`, let `L` and1090`R` be the leftmost 4 bits and rightmost 4 bits of ``B``1091respectively, and let `F` be a function mapping 4-bit strings to10924-bit strings. Then10931094.. MATH::10951096\Pi_F(L, R) = (L \oplus F(R, S), R)10971098where `S` is a subkey and `\oplus` denotes the bit-wise1099exclusive-OR function.11001101The function `F` can be described as follows. Its 4-bit input block1102`(n_0, n_1, n_2, n_3)` is first expanded into an 8-bit block1103to become `(n_3, n_0, n_1, n_2, n_1, n_2, n_3, n_0)`. This is1104usually represented as follows11051106.. MATH::11071108\begin{tabular}{c|cc|c}1109$n_3$ & $n_0$ & $n_1$ & $n_2$ \\1110$n_1$ & $n_2$ & $n_3$ & $n_0$1111\end{tabular}11121113Let `K = (k_0, k_1, k_2, k_3, k_4, k_5, k_6, k_7)` be an 8-bit1114subkey. Then `K` is added to the above expanded input block using1115exclusive-OR to produce11161117.. MATH::11181119\begin{tabular}{c|cc|c}1120$n_3 + k_0$ & $n_0 + k_1$ & $n_1 + k_2$ & $n_2 + k_3$ \\1121$n_1 + k_4$ & $n_2 + k_5$ & $n_3 + k_6$ & $n_0 + k_7$1122\end{tabular}1123=1124\begin{tabular}{c|cc|c}1125$p_{0,0}$ & $p_{0,1}$ & $p_{0,2}$ & $p_{0,3}$ \\1126$p_{1,0}$ & $p_{1,1}$ & $p_{1,2}$ & $p_{1,3}$1127\end{tabular}11281129Now read the first row as the 4-bit string1130`p_{0,0} p_{0,3} p_{0,1} p_{0,2}` and input this 4-bit string through1131S-box `S_0` to get a 2-bit output.11321133.. MATH::11341135S_01136=1137\begin{tabular}{cc|cc} \hline1138Input & Output & Input & Output \\\hline11390000 & 01 & 1000 & 00 \\11400001 & 00 & 1001 & 10 \\11410010 & 11 & 1010 & 01 \\11420011 & 10 & 1011 & 11 \\11430100 & 11 & 1100 & 11 \\11440101 & 10 & 1101 & 01 \\11450110 & 01 & 1110 & 11 \\11460111 & 00 & 1111 & 10 \\\hline1147\end{tabular}11481149Next read the second row as the 4-bit string1150`p_{1,0} p_{1,3} p_{1,1} p_{1,2}` and input this 4-bit string through1151S-box `S_1` to get another 2-bit output.11521153.. MATH::11541155S_11156=1157\begin{tabular}{cc|cc} \hline1158Input & Output & Input & Output \\\hline11590000 & 00 & 1000 & 11 \\11600001 & 01 & 1001 & 00 \\11610010 & 10 & 1010 & 01 \\11620011 & 11 & 1011 & 00 \\11630100 & 10 & 1100 & 10 \\11640101 & 00 & 1101 & 01 \\11650110 & 01 & 1110 & 00 \\11660111 & 11 & 1111 & 11 \\\hline1167\end{tabular}11681169Denote the 4 bits produced by `S_0` and `S_1` as `b_0 b_1 b_2 b_3`.1170This 4-bit string undergoes another permutation called `P_4` as1171follows:11721173.. MATH::11741175P_4(b_0, b_1, b_2, b_3) = (b_1, b_3, b_2, b_0)11761177The output of `P_4` is the output of the function `F`.11781179INPUT:11801181- ``B`` -- a list of 8 bits11821183- ``key`` -- an 8-bit subkey11841185OUTPUT:11861187The result of applying the function `\Pi_F` to ``B``.11881189EXAMPLES:11901191Applying the function `\Pi_F` to an 8-bit block and an 8-bit subkey::11921193sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1194sage: sdes = SimplifiedDES()1195sage: B = [1, 0, 1, 1, 1, 1, 0, 1]1196sage: K = [1, 1, 0, 1, 0, 1, 0, 1]1197sage: sdes.permute_substitute(B, K)1198[1, 0, 1, 0, 1, 1, 0, 1]11991200We can also work with strings of bits::12011202sage: B = "10111101"1203sage: K = "11010101"1204sage: B = sdes.string_to_list(B); K = sdes.string_to_list(K)1205sage: sdes.permute_substitute(B, K)1206[1, 0, 1, 0, 1, 1, 0, 1]12071208TESTS:12091210The input ``B`` must be a block of 8 bits::12111212sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1213sage: sdes = SimplifiedDES()1214sage: sdes.permute_substitute("B", "K")1215Traceback (most recent call last):1216...1217TypeError: input B must be an 8-bit string1218sage: sdes.permute_substitute([], "K")1219Traceback (most recent call last):1220...1221ValueError: input B must be an 8-bit string12221223The input ``key`` must be an 8-bit subkey::12241225sage: sdes.permute_substitute([0, 1, 0, 0, 1, 1, 1, 0], "K")1226Traceback (most recent call last):1227...1228TypeError: input key must be an 8-bit subkey1229sage: sdes.permute_substitute([0, 1, 0, 0, 1, 1, 1, 0], [])1230Traceback (most recent call last):1231...1232ValueError: input key must be an 8-bit subkey12331234The value of each element of ``B`` or ``key`` must be either 0 or 1::12351236sage: B = [1, 2, 3, 4, 5, 6, 7, 8]1237sage: K = [0, 1, 2, 3, 4, 5, 6, 7]1238sage: sdes.permute_substitute(B, K)1239Traceback (most recent call last):1240...1241TypeError: Argument x (= 2) is not a valid string.1242sage: B = [0, 1, 0, 0, 1, 1, 1, 0]1243sage: K = [1, 2, 3, 4, 5, 6, 7, 8]1244sage: sdes.permute_substitute(B, K)1245Traceback (most recent call last):1246...1247TypeError: Argument x (= 2) is not a valid string.1248"""1249# sanity check1250if not isinstance(B, list):1251raise TypeError, "input B must be an 8-bit string"1252if len(B) != 8:1253raise ValueError, "input B must be an 8-bit string"1254if not isinstance(key, list):1255raise TypeError, "input key must be an 8-bit subkey"1256if len(key) != 8:1257raise ValueError, "input key must be an 8-bit subkey"12581259from sage.rings.finite_rings.constructor import FiniteField1260GF = FiniteField(2, "x")1261bin = BinaryStrings()1262bin_to_GF2 = {bin("0"): GF(0), bin("1"): GF(1)}12631264# the leftmost 4 bits of B1265L = [ bin_to_GF2[bin(str(B[i]))] for i in xrange(4) ]1266# the rightmost 4 bits of B1267R = [ bin_to_GF2[bin(str(B[i]))] for i in xrange(4, len(B)) ]1268# get the GF(2) representation of the subkey1269K = [ bin_to_GF2[bin(str(key[i]))] for i in xrange(len(key)) ]1270# expand the rightmost 4 bits into an 8-bit block1271RX = [ R[3], R[0], R[1], R[2], R[1], R[2], R[3], R[0] ]1272# add the subkey to the expanded 8-bit block using exclusive-OR1273P = [ RX[i] + K[i] for i in xrange(len(K)) ]1274# run each half of P separately through the S-boxes1275left = self._sbox0([ P[0], P[3], P[1], P[2] ])1276right = self._sbox1([ P[4], P[7], P[5], P[6] ])1277# First concatenate the left and right parts, then get the1278# output of the function F.1279F = self.permutation4(left + right)1280F = [ bin_to_GF2[F[i]] for i in xrange(len(F)) ]1281# Add L to F using exclusive-OR. Then concatenate the result with1282# the rightmost 4 bits of B. This is the output of the function Pi_F.1283L = [ L[i] + F[i] for i in xrange(len(F)) ]1284return L + R12851286def random_key(self):1287r"""1288Return a random 10-bit key.12891290EXAMPLES:12911292The size of each key is the same as the block size::12931294sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1295sage: sdes = SimplifiedDES()1296sage: key = sdes.random_key()1297sage: len(key) == sdes.block_length()1298True1299"""1300from sage.misc.prandom import randint1301bin = BinaryStrings()1302return [bin(str(randint(0, 1))) for i in xrange(self._key_size)]13031304def sbox(self):1305r"""1306Return the S-boxes of simplified DES.13071308EXAMPLES::13091310sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1311sage: sdes = SimplifiedDES()1312sage: sbox = sdes.sbox()1313sage: sbox[0]; sbox[1]1314(1, 0, 3, 2, 3, 2, 1, 0, 0, 2, 1, 3, 3, 1, 3, 2)1315(0, 1, 2, 3, 2, 0, 1, 3, 3, 0, 1, 0, 2, 1, 0, 3)1316"""1317return [self._sbox0, self._sbox1]13181319def string_to_list(self, S):1320r"""1321Return a list representation of the binary string ``S``.13221323INPUT:13241325- ``S`` -- a string of bits13261327OUTPUT:13281329A list representation of the string ``S``.13301331EXAMPLES:13321333A list representation of a string of bits::13341335sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1336sage: sdes = SimplifiedDES()1337sage: S = "0101010110"1338sage: sdes.string_to_list(S)1339[0, 1, 0, 1, 0, 1, 0, 1, 1, 0]13401341TESTS:13421343Input must be a non-empty string::13441345sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1346sage: sdes = SimplifiedDES()1347sage: sdes.string_to_list("")1348Traceback (most recent call last):1349...1350ValueError: input S must be a non-empty string of bits1351sage: sdes.string_to_list(1)1352Traceback (most recent call last):1353...1354TypeError: input S must be a non-empty string of bits13551356Input must be a non-empty string of bits::13571358sage: sdes.string_to_list("0123")1359Traceback (most recent call last):1360...1361TypeError: Argument x (= 2) is not a valid string.1362"""1363# sanity check1364if not isinstance(S, str):1365raise TypeError, "input S must be a non-empty string of bits"1366if len(S) == 0:1367raise ValueError, "input S must be a non-empty string of bits"13681369# perform the conversion from string to list1370bin = BinaryStrings()1371return [bin(s) for s in S]13721373def subkey(self, K, n=1):1374r"""1375Return the ``n``-th subkey based on the key ``K``.13761377INPUT:13781379- ``K`` -- a 10-bit secret key of this Simplified DES13801381- ``n`` -- (default: 1) if ``n=1`` then return the first subkey based1382on ``K``; if ``n=2`` then return the second subkey. The valid1383values for ``n`` are 1 and 2, since only two subkeys are defined1384for each secret key in Schaefer's S-DES.13851386OUTPUT:13871388The ``n``-th subkey based on the secret key ``K``.13891390EXAMPLES:13911392Obtain the first subkey from a secret key::13931394sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1395sage: sdes = SimplifiedDES()1396sage: key = [1, 0, 1, 0, 0, 0, 0, 0, 1, 0]1397sage: sdes.subkey(key, n=1)1398[1, 0, 1, 0, 0, 1, 0, 0]13991400Obtain the second subkey from a secret key::14011402sage: key = [1, 0, 1, 0, 0, 0, 0, 0, 1, 0]1403sage: sdes.subkey(key, n=2)1404[0, 1, 0, 0, 0, 0, 1, 1]14051406We can also work with strings of bits::14071408sage: K = "1010010010"1409sage: L = sdes.string_to_list(K)1410sage: sdes.subkey(L, n=1)1411[1, 0, 1, 0, 0, 1, 0, 1]1412sage: sdes.subkey(sdes.string_to_list("0010010011"), n=2)1413[0, 1, 1, 0, 1, 0, 1, 0]14141415TESTS:14161417Input ``K`` must be a 10-bit key::14181419sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1420sage: sdes = SimplifiedDES()1421sage: sdes.subkey("K")1422Traceback (most recent call last):1423...1424TypeError: input K must be a 10-bit key1425sage: sdes.subkey([])1426Traceback (most recent call last):1427...1428ValueError: input K must be a 10-bit key14291430There are only two subkeys::14311432sage: key = [1, 0, 1, 0, 0, 0, 0, 0, 1, 0]1433sage: sdes.subkey(key, n=0)1434Traceback (most recent call last):1435...1436ValueError: input n must be either 1 or 21437sage: sdes.subkey(key, n=3)1438Traceback (most recent call last):1439...1440ValueError: input n must be either 1 or 21441"""1442# sanity check1443if not isinstance(K, list):1444raise TypeError, "input K must be a 10-bit key"1445if len(K) != self._key_size:1446raise ValueError, "input K must be a 10-bit key"14471448# get the first subkey1449if n == 1:1450key1 = self.permutation10(K)1451key1 = self.left_shift(key1, n=1)1452return self.permutation8(key1)1453# get the second subkey1454elif n == 2:1455key2 = self.permutation10(K)1456key2 = self.left_shift(key2, n=1)1457key2 = self.left_shift(key2, n=2)1458return self.permutation8(key2)1459# an invalid subkey number1460else:1461raise ValueError, "input n must be either 1 or 2"14621463def switch(self, B):1464r"""1465Interchange the first 4 bits with the last 4 bits in the list ``B``1466of 8 bits. Let `(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7)`1467be a vector of 8 bits, where each `b_i \in \{ 0, 1 \}`. Then the1468switch function `\sigma` is given by14691470.. MATH::14711472\sigma(b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7)1473= (b_4, b_5, b_6, b_7, b_0, b_1, b_2, b_3)14741475INPUT:14761477- ``B`` -- list; a block of 8 bits14781479OUTPUT:14801481A block of the same dimension, but in which the first 4 bits from1482``B`` has been switched for the last 4 bits in ``B``.14831484EXAMPLES:14851486Interchange the first 4 bits with the last 4 bits::14871488sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1489sage: sdes = SimplifiedDES()1490sage: B = [1, 1, 1, 0, 1, 0, 0, 0]1491sage: sdes.switch(B)1492[1, 0, 0, 0, 1, 1, 1, 0]1493sage: sdes.switch([1, 1, 1, 1, 0, 0, 0, 0])1494[0, 0, 0, 0, 1, 1, 1, 1]14951496We can also work with a string of bits::14971498sage: S = "11101000"1499sage: L = sdes.string_to_list(S)1500sage: sdes.switch(L)1501[1, 0, 0, 0, 1, 1, 1, 0]1502sage: sdes.switch(sdes.string_to_list("11110000"))1503[0, 0, 0, 0, 1, 1, 1, 1]15041505TESTS:15061507The input block must be a list::15081509sage: from sage.crypto.block_cipher.sdes import SimplifiedDES1510sage: sdes = SimplifiedDES()1511sage: sdes.switch("B")1512Traceback (most recent call last):1513...1514TypeError: input block must be a list of 8 bits1515sage: sdes.switch(())1516Traceback (most recent call last):1517...1518TypeError: input block must be a list of 8 bits15191520The input block must be a list of 8 bits::15211522sage: sdes.switch([])1523Traceback (most recent call last):1524...1525ValueError: input block must be a list of 8 bits1526sage: sdes.switch([1, 2, 3, 4, 5, 6, 7, 8, 9])1527Traceback (most recent call last):1528...1529ValueError: input block must be a list of 8 bits15301531The value of each element of the list must be either 0 or 1::15321533sage: sdes.switch([1, 2, 3, 4, 5, 6, 7, 8])1534Traceback (most recent call last):1535...1536TypeError: Argument x (= 5) is not a valid string.1537"""1538# sanity check1539if not isinstance(B, list):1540raise TypeError, "input block must be a list of 8 bits"1541if len(B) != 8:1542raise ValueError, "input block must be a list of 8 bits"15431544# perform the switch1545bin = BinaryStrings()1546return [ bin(str(B[4])), bin(str(B[5])),1547bin(str(B[6])), bin(str(B[7])),1548bin(str(B[0])), bin(str(B[1])),1549bin(str(B[2])), bin(str(B[3])) ]155015511552