Authenticated Diffie Hellman Key Exchange
Authenticated Diffie Hellman Key Exchange
exchange
i
Dedicated to
My parents, teachers,.....
Declaration
I certify that
1. The work contained in this report is original and has been done by myself and
the general supervision of my supervisor.
3. Whenever I have used materials (data, theoretical analysis, results) from other
sources, I have given due credit to them by citing them in the text of the thesis
and giving their details in the references.
4. Whenever I have quoted written materials from other sources, I have put them
under quotation marks and given due credit to the sources by citing them and
giving required details in the references.
This is to certify that the work contained in this report entitled “Authenticated
Diffie Hellman key exchange ” being submitted by Deepansh Agrawal, Mayank,
Khush Chopra, Keshav Kumar (Roll No. 16074005, 16074009, 16074008,
16074007), carried out in the Department of Computer Science and Engineering,
Indian Institute of Technology (BHU) Varanasi, is a bona fide work of our supervision.
Dr. K. K. Shukla
Place: IIT (BHU) Varanasi Department of Computer Science and Engineering,
Date: 24 Nov 2019 Indian Institute of Technology (BHU) Varanasi,
Varanasi, INDIA 221005.
Acknowledgments
Firstly, We would like to express our sincere gratitude to our supervisor Prof.
Kaushal Kumar Shukla for the continuous support during the study and related re-
search, for his patience, motivation, and immense knowledge. His guidance helped us
in all the time and completion of the project. We could not have imagined having
a better advisor for our project. Without their precious support it would not be
possible to complete this project..
List of Figures 1
1 Introduction 2
1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Cryptographic explanation . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Limitaions of diffie hellman . . . . . . . . . . . . . . . . . . . . . . . 5
3 Application 8
3.1 Uses of Diffie Hellman key exchange Algorithm . . . . . . . . . . . . . 8
4 Code 10
4.1 Client File [1] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.2 Diffie Hellman Code file [2] . . . . . . . . . . . . . . . . . . . . . . . . 16
4.3 File for message Encryption [3] . . . . . . . . . . . . . . . . . . . . . 16
4.4 Public Server File [4] . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.5 Public and Private key For Digital Signature [5] . . . . . . . . . . . . 19
vi
CONTENTS
Bibliography 20
vii
List of Figures
Introduction
1.1 Overview
2
1.1. Overview
starting color that does not need to be kept secret (but should be different every time)
in this example, the color is yellow. Each of them also selects a secret color that they
keep to themselves in this case, red and blue-green. The crucial part of the process
is that Alice and Bob each mix their own secret color together with their mutually
shared color, resulting in orange-tan and light-blue mixtures respectively, and then
publicly exchange the two mixed colors. Finally, each of the two mixes the color
they received from the partner with their own private color. The result is a final
color mixture (yellow-brown in this case) that is identical to the partner’s final color
mixture [7].
If a third party listened to the exchange, it would only know the common color
(yellow) and the first mixed colors (orange-tan and light-blue), but it would be com-
putationally difficult for this party to determine the final secret color (yellow-brown).
In fact, when using large numbers rather than colors, this action is computationally
3
1.2. Cryptographic explanation
The simplest and the original implementation [8] of the protocol uses the multiplica-
tive group of integers modulo p, where p is prime, and g is a primitive root modulo
p. These two values are chosen in this way to ensure that the resulting shared secret
can take on any value from 1 to p.
To implement Diffie-Hellman, the two end users Alice and Bob, while commu-
nicating over a channel they know to be private, mutually agree on positive whole
numbers p and q, such that p is a prime number and q is a generator of p. The
generator q is a number that, when raised to positive whole-number powers less than
p, never produces the same result for any two such whole numbers. The value of p
may be large but the value of q is usually small.
Once Alice and Bob have agreed on p and q in private, they choose positive whole-
number personal keys a and b, both less than the prime-number modulus p. Neither
user divulges their personal key to anyone; ideally they memorize these numbers and
do not write them down or store them anywhere. Next, Alice and Bob compute public
keys a* and b* based on their personal keys according to the formulas
a* = q a mod p
and
b* = q b mod p
The two users can share their public keys a* and b* over a communications
medium assumed to be insecure, such as the Internet or a corporate wide area net-
work (WAN). From these public keys, a number x can be generated by either user on
the basis of their own personal keys. Alice computes x using the formula
x = (b∗)a mod p
4
1.3. Limitaions of diffie hellman
The most serious limitation of Diffie-Hellman in its basic or ”pure” form is the lack of
authentication. Communications using Diffie-Hellman all by itself are vulnerable to
man in the middle attacks. Ideally, Diffie-Hellman should be used in conjunction with
a recognized authentication method such as digital signatures to verify the identities
of the users over the public communications medium. Diffie-Hellman is well suited
for use in data communication but is less often used for data stored or archived over
long periods of time.
5
Chapter 2
6
2.2. Attack on basic Deffie Hellman key transfer
In this attack, an opponent Carol intercepts Alice’s public value and sends her own
public value to Bob. When Bob transmits his public value, Carol substitutes it with
her own and sends it to Alice. Carol and Alice thus agree on one shared key and Carol
and Bob agree on another shared key. After this exchange, Carol simply decrypts
any messages sent out by Alice or Bob, and then reads and possibly modifies them
before re-encrypting with the appropriate key and transmitting them to the other
party. This vulnerability is present because Diffie-Hellman key exchange does not
authenticate the participants. Possible solutions include the use of digital signatures
and other protocol variants.
The basic idea is as follows. Prior to execution of the protocol, the two parties Alice
and Bob each obtain a public/private key pair and a certificate for the public key.
During the protocol, Alice computes a signature on certain messages, covering the
public value
g ab mod p
. Bob proceeds in a similar way. Even though Carol is still able to intercept mes-
sages between Alice and Bob, she cannot forge signatures without Alice’s private key
and Bob’s private key. Hence, the enhanced protocol defeats the man-in-the-middle
attack.
7
Chapter 3
Application
Encryption Public key encryption schemes based on the Diffie Hellman key exchange
have been proposed. The first such scheme is the ElGamal encryption. A more
modern variant is the Integrated Encryption Scheme.
Forward secrecy Protocols that achieve forward secrecy generate new key pairs
for each session and discard them at the end of the session. The Diffie Hellman key
exchange is a frequent choice for such protocols, because of its fast key generation.
Password-authenticated key agreement When Alice and Bob share a password,
they may use a password-authenticated key agreement (PK) form of Diffie Hellman
to prevent man-in-the-middle attacks. One simple scheme is to compare the hash of
s concatenated with the password calculated independently on both ends of channel.
A feature of these schemes is that an attacker can only test one specific password on
each iteration with the other party, and so the system provides good security with
relatively weak passwords. This approach is described in ITU-T Recommendation
X.1035, which is used by the G.hn home networking standard.
An example of such a protocol is the Secure Remote Password protocol.
Public key It is also possible to use Diffie Hellman as part of a public key infras-
8
3.1. Uses of Diffie Hellman key exchange Algorithm
tructure, allowing Bob to encrypt a message so that only Alice will be able to decrypt
it, with no prior communication between them other than Bob having trusted knowl-
edge of Alice’s public key. Alice’s public key is (g a mod p). To send her a message,
Bob chooses a random b and then sends Alice (g b mod p) (unencrypted) together
with the message encrypted with symmetric key (g a )b modp. Only Alice can deter-
mine the symmetric key and hence decrypt the message because only she has a (the
private key). A pre-shared public key also prevents man-in-the-middle attacks.
In practice, DiffieHellman is not used in this way, with RSA being the dominant
public key algorithm. This is largely for historical and commercial reasons[citation
needed], namely that RSA Security created a certificate authority for key signing
that became Verisign. DiffieHellman cannot be used to sign certificates. However,
the ElGamal and DSA signature algorithms are mathematically related to it, as well
as MQV, STS and the IKE component of the IPsec protocol suite for securing Internet
Protocol communications.
9
Chapter 4
Code
10
4.1. Client File [1]
18
19 # r e g i s t e r s t o network // s e n d s p u b l i c key t o p u b l i c
20 def r e g i s t e r T o N e t w o r k ( s e l f ) :
21 print ( ” R e g i s t e r i n g t o network ” )
22 messageDict = {” type ” : ” r e g i s t e r ” , ”
s i g n a t u r e P u b l i c K e y ” : s e l f . s i g n a t u r e P u b l i c K e y , ”name
” : s e l f . myName}
23 s e l f . l o g N e t w o r k A c t i v i t y ( messageDict )
24 s e l f . s o c k . s e n d t o ( s e l f . d i c t T o B i n a r y ( messageDict ) , ( ”
localhost ” , s e l f . addressOfPublicServer ) )
25 print ( ”Done” )
26
27 # get signaturePublicKey
28 def getPublicKeyForNewConnection ( s e l f , c o n n e c t i o n P o r t ) :
29 r e c e i v e r T h r e a d = t h r e a d i n g . Thread ( t a r g e t= s e l f .
receiveFromPublicThreadFunction , name=” s i g n a t u r e
r e c e i v e r thread ” )
30 receiverThread . start ()
31 messageDict = {” type ” : ” v e r i f y ” , ” e n t i t y A d d r e s s ” :
connectionPort }
32 s e l f . l o g N e t w o r k A c t i v i t y ( messageDict )
33 s e l f . s o c k . s e n d t o ( s e l f . d i c t T o B i n a r y ( messageDict ) , ( ’
localhost ’ , s e l f . addressOfPublicServer ) )
34 receiverThread . join ()
35
36 def r e c e i v e F r o m P u b l i c T h r e a d F u n c t i o n ( s e l f ) :
37 while True :
38 data , r e c v A d d r e s s = s e l f . s o c k . r e c v f r o m ( 4 0 9 6 )
39 d a t a D i c t = s e l f . binaryToDict ( data )
40 i f d a t a D i c t [ ” type ”]==” r e c e i v e S i g n a t u r e P u b l i c K e y ” :
41 s e l f . currentNewConnectionPublicKey = d a t a D i c t
[ ” signaturePublicKey ” ]
42 break
43
44 # r e c e i v e e n c r y p t e d message
45 def messageReceived ( s e l f , c o n n e c t i o n P o r t , d a t a D i c t ) :
46 i f s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”dh” ] .
11
4.1. Client File [1]
getSharedKey ( ) :
47 print ( ” Message from ” , s e l f . c o n n e c t i o n s [
c o n n e c t i o n P o r t ] [ ”name” ] , ”−” , d e c r y p t ( d a t a D i c t [ ”
message ” ] , s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”dh
” ] . getSharedKey ( ) ) )
48 else :
49 print ( ” E r r o r − Key not a v a i l a b l e t o d e c r y p t ” )
50
51 # r e c e i v e key
52 def keyReceived ( s e l f , c o n n e c t i o n P o r t , d a t a D i c t ) :
53 d i g i t a l S i g n a t u r e = dataDict [ ” d i g i t a l S i g n a t u r e ” ]
54 s e l f . getPublicKeyForNewConnection ( c o n n e c t i o n P o r t )
55 publicKey = d a t a D i c t [ ” publicKey ” ]
56
57 #p r i n t (” Key r e c e i v e d from −”, c o n n e c t i o n P o r t , ” ,
d i g i t a l S i g n a t u r e −”, d i g i t a l S i g n a t u r e , ” , p u b l i c
key −”, p u b l i c K e y , ” , s i g n a t u r e P u b l i c K e y −”, s e l f .
currentNewConnectionPublicKey )
58 # p r i n t (” f o r debug ” , d e c r y p t o r ( d i g i t a l S i g n a t u r e ,
s e l f . currentNewConnectionPublicKey ) , c o n n e c t i o n P o r t
)
59
60 i f decryptor ( digitalSignature , s e l f .
currentNewConnectionPublicKey ) != publicKey :
61 print ( ” E r r o r − unexpected b e h a v i o u r ” )
62 return
63
64 i f c o n n e c t i o n P o r t in s e l f . c o n n e c t i o n s :
65 # connection port in d i c t i o n a r y
66 s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”dh” ] .
computeSharedKey ( d a t a D i c t [ ” publicKey ” ] )
67 s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”name” ] =
d a t a D i c t [ ”name” ]
68 i f d a t a D i c t [ ” requestKey ” ] :
69 # o t h e r needs key
70 s e l f . sendKeyToConnection ( c o n n e c t i o n P o r t )
71 else :
12
4.1. Client File [1]
72 # c o n n e c t i o n p o r t not i n d i c t i o n a r y
73 # r e c e i v e new c o n n e c t i o n
74 s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] = {”name” :
d a t a D i c t [ ”name” ] , ”dh” : DH( s e l f . mySecretKey ,
d a t a D i c t [ ” publicKey ” ] ) }
75 i f d a t a D i c t [ ” requestKey ” ] :
76 s e l f . sendKeyToConnection ( c o n n e c t i o n P o r t )
77 print ( ”Log − new c o n n e c t i o n ” , d a t a D i c t [ ”name” ] , ”
added ” )
78
79 # t h r e a d t h a t r e c e i v e s messages by l i s t e n i n g t o
connection
80 def r e c e i v e T h r e a d F u n c t i o n ( s e l f ) :
81 while True :
82 data , r e c v A d d r e s s = s e l f . s o c k . r e c v f r o m ( 4 0 9 6 )
83 d a t a D i c t = s e l f . binaryToDict ( data )
84 recvPort = recvAddress [ 1 ]
85 # routing request appropriatly
86 i f d a t a D i c t [ ” type ”]==” message ” :
87 s e l f . messageReceived ( r e c v P o r t , d a t a D i c t )
88 i f d a t a D i c t [ ” type ”]==” key ” :
89 s e l f . keyReceived ( r e c v P o r t , d a t a D i c t )
90
91 # make new conn
92 def addConnection ( s e l f , c o n n e c t i o n P o r t , r e c e i v e d K e y=None )
:
93 i f receivedKey :
94 s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] = {”name” : None ,
”dh” : DH( s e l f . mySecretKey ) }
95 s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”dh” ] .
computeSharedKey ( r e c e i v e d K e y )
96 s e l f . sendKeyToConnection ( c o n n e c t i o n P o r t , F a l s e )
97 else :
98 s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] = {”name” : None ,
”dh” : DH( s e l f . mySecretKey ) }
99 s e l f . sendKeyToConnection ( c o n n e c t i o n P o r t , True )
100 print ( ”Added c o n n e c t i o n ” , c o n n e c t i o n P o r t )
13
4.1. Client File [1]
101
102 # send s h a r e d key t o a l l
103 def sendKeyToConnection ( s e l f , c o n n e c t i o n P o r t , requestKey=
False ) :
104 digitalSignature = s e l f . generateDigitalSignature ( s e l f
.myDH. getPublicKey ( ) )
105 messageDict = {” type ” : ” key ” , ”name” : s e l f . myName, ”
publicKey ” : s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”dh”
] . getPublicKey ( ) , ” requestKey ” : requestKey , ”
digitalSignature ” : digitalSignature}
106
107 # for i n messageDict . k e y s ( ) :
108 # p r i n t ( t y p e ( messageDict [ ] ) )
109 s e l f . l o g N e t w o r k A c t i v i t y ( messageDict )
110 s e l f . s o c k . s e n d t o ( s e l f . d i c t T o B i n a r y ( messageDict ) , ( ’
l o c a l h o s t ’ , connectionPort ) )
111
112 # send e n c r y p t e d message
113 def sendMessage ( s e l f , c o n n e c t i o n P o r t , message ) :
114 i f type ( c o n n e c t i o n P o r t ) i s s t r :
115 for conn in s e l f . c o n n e c t i o n s :
116 i f s e l f . c o n n e c t i o n s [ conn]== c o n n e c t i o n P o r t :
117 c o n n e c t i o n P o r t = conn
118 break
119 i f s e l f . c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”dh” ] .
getSharedKey ( ) i s None :
120 # s h a r e d key not a v a i l a b l e
121 print ( ” E r r o r − c h a n n e l not p r o t e c t e d ” )
122 else :
123 # s h a r e d key a v a i l a b l e
124 encryptedMessage = e n c r y p t ( message , s e l f .
c o n n e c t i o n s [ c o n n e c t i o n P o r t ] [ ”dh” ] . getSharedKey
() )
125 messageDict = {” type ” : ” message ” , ”name” : s e l f .
myName, ” message ” : encryptedMessage }
126 s e l f . l o g N e t w o r k A c t i v i t y ( messageDict )
127 s e l f . s o c k . s e n d t o ( s e l f . d i c t T o B i n a r y ( messageDict ) , (
14
4.1. Client File [1]
’ l o c a l h o s t ’ , connectionPort ) )
128
129 # region u t i l i t y functions
130 def l o g N e t w o r k A c t i v i t y ( s e l f , message ) :
131 i f type ( message ) i s type ( { 1 : 1 } ) :
132 s e l f . s o c k . s e n d t o ( s e l f . d i c t T o B i n a r y ( message ) , ( ”
l o c a l h o s t ” , 10010) )
133 else :
134 s e l f . s o c k . s e n d t o ( message , ( ” l o c a l h o s t ” , 10010) )
135
136 def g e n e r a t e D i g i t a l S i g n a t u r e ( s e l f , c o n n e c t i o n P o r t ) :
137 return e n c r y p t o r ( c o n n e c t i o n P o r t , s e l f .
signaturePrivateKey )
138
139 def c o n n e c t i o n s S t a t u s ( s e l f ) :
140 print ( ”No . o f c o n n e c t i o n s −” , len ( s e l f . c o n n e c t i o n s ) )
141 for conn in s e l f . c o n n e c t i o n s :
142 print ( ” Connection name −” , s e l f . c o n n e c t i o n s [
conn ] [ ”name” ] , end=” , ” )
143 s e l f . c o n n e c t i o n s [ conn ] [ ”dh” ] . t o S t r i n g ( )
144
145 def d i c t T o B i n a r y ( s e l f , i n p u t D i c t ) :
146 tempJSON = p i c k l e . dumps ( i n p u t D i c t )
147 return tempJSON
148
149 def binaryToDict ( s e l f , i n p u t B i n a r y ) :
150 # tempJSON = i n p u t B i n a r y . decode ( )
151 return p i c k l e . l o a d s ( i n p u t B i n a r y )
15
4.2. Diffie Hellman Code file [2]
1 # D i f f i e Hellman C l a s s
2 c l a s s DH:
3 def i n i t ( s e l f , s e c r e t K e y , r e c e i v e d K e y=None ) :
4 s e l f . sharedPrime = 564
5 s e l f . sharedBase = 78
6 s e l f . secretKey = secretKey
7 s e l f . sharedKey = None
8 i f receivedKey :
9 s e l f . computeSharedKey ( r e c e i v e d K e y )
10
11 def getPublicKey ( s e l f ) :
12 return ( s e l f . sharedBase ∗∗ s e l f . s e c r e t K e y )%s e l f .
sharedPrime
13
14 def computeSharedKey ( s e l f , r e c e i v e d K e y ) :
15 s e l f . sharedKey = ( r e c e i v e d K e y ∗∗ s e l f . s e c r e t K e y )%s e l f .
sharedPrime
16
17 def getSharedKey ( s e l f ) :
18 return s e l f . sharedKey
19
20 def t o S t r i n g ( s e l f ) :
21 print ( ” s e c r e t key −” , s e l f . s e c r e t K e y , ” , s h a r e d key −
” , s e l f . sharedKey )
16
4.4. Public Server File [4]
1 import s o c k e t , sys , t h r e a d i n g , j s o n , p i c k l e
2 from p p r i n t import p p r i n t
3
4 PORT = 10009
5
6 p u b l i c K e y s = {}
7
8 s o c k = s o c k e t . s o c k e t ( s o c k e t . AF INET , s o c k e t .SOCK DGRAM)
9 s o c k . bind ( ( ’ l o c a l h o s t ’ ,PORT) )
10
11 # region u t i l i t y functions
12 def d i c t T o B i n a r y ( i n p u t D i c t ) :
13 tempJSON = p i c k l e . dumps ( i n p u t D i c t )
14 return tempJSON
15
16 def binaryToDict ( i n p u t B i n a r y ) :
17 # tempJSON = i n p u t B i n a r y . decode ( )
18 return p i c k l e . l o a d s ( i n p u t B i n a r y )
19 # endregion
20
21 while True :
22 data , r e c v A d d r e s s = s o c k . r e c v f r o m ( 4 0 9 6 )
23 d a t a D i c t = binaryToDict ( data )
24 recvPort = recvAddress [ 1 ]
25
26 i f d a t a D i c t [ ” type ”]==” r e g i s t e r ” :
27 # r e c e i v e s {” t y p e ” : ” r e g i s t e r ” , ” s i g n a t u r e P u b l i c K e y
” : / key / , ”name ” : / name/}
28 p u b l i c K e y s [ r e c v P o r t ]= d a t a D i c t [ ” s i g n a t u r e P u b l i c K e y ” ]
29 print ( ” R e c e i v e s p u b l i c key from ” , d a t a D i c t [ ”name” ] , ” ,
a d d r e s s −” , r e c v P o r t )
30 pprint ( publicKeys ) # debugging
31 i f d a t a D i c t [ ” type ”]==” v e r i f y ” :
17
4.4. Public Server File [4]
32 # r e c e i v e s {” t y p e ” : ” v e r i f y ” , ” e n t i t y A d d r e s s ” : /
a d d r e s s /}
33 print ( ” R ec ei v ed v e r i f i c a t i o n r e q u e s t from ” , r e c v P o r t )
34 messageDict = {” type ” : ” r e c e i v e S i g n a t u r e P u b l i c K e y ” , ”
signaturePublicKey ” : publicKeys [ dataDict [ ”
entityAddress ” ] ] }
35 s o c k . s e n d t o ( d i c t T o B i n a r y ( messageDict ) , ( ’ l o c a l h o s t ’
,10010) )
36 s o c k . s e n d t o ( d i c t T o B i n a r y ( messageDict ) , ( ’ l o c a l h o s t ’ ,
recvPort ) )
37 print ( ” Response g i v e n −>” )
38 p p r i n t ( messageDict )
39 print ( )
18
4.5. Public and Private key For Digital Signature [5]
1 #I m p o r t i n g n e c e s s a r y modules
2 from Crypto . Cipher import PKCS1 OAEP
3 from Crypto . PublicKey import RSA
4 from b i n a s c i i import h e x l i f y
5 import base64
6
7 # int to s e r i a l i z a b l e using s e r i a l i z e d keys
8 # i n p u t key i s t h e p r i v a t e key
9 def e n c r y p t o r ( message , key ) :
10 key = RSA. i m p o r t k e y ( key )
11 c i p h e r = PKCS1 OAEP . new ( key=key )
12 c i p h e r t e x t = c i p h e r . e n c r y p t ( s t r ( message ) . encode ( ) )
13 return base64 . e n c o d e b y t e s ( c i p h e r t e x t )
14
15 # s e r i a l i z a b l e to int using s e r i a l i z e d keys
16 # t h i s i s done w i t h p u b l i c key
17 def d e c r y p t o r ( message , key ) :
18 key = RSA. i m p o r t k e y ( key )
19 decryptObj = PKCS1 OAEP . new ( key=key )
20 # p r i n t ( message )
21 # message = message [ 2 : ] [ : − 1 ]
22 # p r i n t ( message )
23 # d e c r y p t e d m e s s a g e = d e c r y p t O b j . d e c r y p t ( message . decode ( ’
a s c i i ’) )
24 d e c r y p t e d m e s s a g e = decryptObj . d e c r y p t ( base64 . b64decode (
message ) )
25 return int ( d e c r y p t e d m e s s a g e . decode ( ) )
26
27 # s e r i a l i z a b l e k e y s
28 def getKeys ( ) :
29 p r i v a t e K e y = RSA. g e n e r a t e ( 1 0 2 4 )
30 publicKey = p r i v a t e K e y . p u b l i c k e y ( )
31 p r i v a t e K e y = p r i v a t e K e y . e x p o r t k e y ( ) . decode ( )
32 publicKey = publicKey . e x p o r t k e y ( ) . decode ( )
33 return ( privateKey , publicKey )
19
Bibliography
20
Bibliography
[8] Whitfield Diffie and Martin E. Hellman, “New directions in cryptography,” 1976.
21