Use Edwards curve instead of the motogomery version.
[brdnet.git] / CRAuth.pas
blob039e022bca38eb7837d47685495d71af02663804
1 unit CRAuth;
2 {Challenge-Response Authenticator}
3 INTERFACE
4 USES NetAddr,ECC,SHA1,Chat,ServerLoop,MemStream,opcode;
5 type
6 tAuth=object
7 ch:tChat;
8 Challenge:tEccKey;
9 RemotePub:tEccKey;
10 Valid:Boolean;
11 PoWValid:Boolean;
12 error:byte;
13 Callback:procedure of object;
14 procedure Init(const iRemote:tNetAddr);
15 procedure Cancel;
16 private
17 procedure ReplyRes(msg:tSMsg; data:boolean);
18 procedure ReplyPow(msg:tSMsg; data:boolean);
19 procedure Done;
20 procedure Timeout;
21 procedure Conclusion;
22 end;
24 IMPLEMENTATION
26 procedure tAuth.Init(const iRemote:tNetAddr);
27 var ms:tMemoryStream;
28 begin
29 Assert(assigned(Callback) and (not iRemote.isNil));
30 Valid:=FALSE;
31 PoWValid:=FALSE;
32 Error:=255;
33 Ch.Init(iRemote);
34 Ch.OnDispose:=@Done;
35 Ch.OnTimeout:=@Timeout;
36 Ch.Callback:=@ReplyRes;
37 Ch.SetTimeout(8001,3000);
38 {generate and send challenge}
39 Ch.StreamInit(ms,66);
40 ECC.CreateChallenge(challenge);
41 Ms.WriteByte(opcode.crAuthReq);
42 Ms.WriteByte(1);
43 Ms.Write(ECC.PublicKey,sizeof(PublicKey));
44 Ms.Write(challenge,sizeof(challenge));
45 Ch.Send(Ms);
46 end;
48 procedure tAuth.ReplyRes(msg:tSMsg; data:boolean);
49 var r:tMemoryStream absolute msg.Stream;
50 var status:byte;
51 var resp:^tEccKey;
52 var vresp:tSha1Digest;
53 begin
54 if not data then exit;
55 status:=r.readbyte; {todo, set error (eg: unsuported meth)}
56 r.Read(RemotePub,sizeof(tEccKey));
57 resp:=r.readptr(sizeof(tEccKey));
58 ECC.CreateResponse(Challenge,vresp,RemotePub);
59 Valid:=CompareByte(resp^,vresp,sizeof(vresp))=0;
60 if (status and 128)>0 then begin
61 {expecting pow}
62 Ch.Callback:=@ReplyPow;
63 Ch.Ack;
64 end else Conclusion;
65 end;
66 procedure tAuth.ReplyPow(msg:tSMsg; data:boolean);
67 var r:tMemoryStream absolute msg.Stream;
68 var ptp:byte;{Proof TyPe}
69 var nonce:^tEccKey;
70 var pts: ^tPoWTimeStamp;
71 begin
72 if not data then exit;
73 ptp:=r.readbyte; {todo}
74 nonce:=r.ReadPtr(sizeof(tEccKey));
75 pts:=r.ReadPtr(2);
76 PoWValid:=VerifyPoW(nonce^,RemotePub,pts^);
77 Conclusion;
78 end;
79 procedure tAuth.Timeout;
80 begin
81 error:=251;
82 Callback;
83 Ch.Close;
84 end;
85 procedure tAuth.Conclusion;
86 var ms:tMemoryStream;
87 begin
88 error:=0;
89 Ch.StreamInit(ms,2);
90 ms.WriteByte(byte(Valid));
91 ms.WriteByte(byte(PowValid));
92 Ch.Send(ms);
93 Callback;
94 ch.Close;
95 end;
96 procedure tAuth.Done;
97 begin
98 {called by chat}
99 FreeMem(@self,sizeof(self));
100 end;
102 type tServer=object
103 ch:^tChat;
104 pub:tEccKey;
105 procedure SendRep(msg:tSMsg; data:boolean);
106 procedure SendPow(msg:tSMsg; data:boolean);
107 procedure Last(msg:tSMsg; data:boolean);
108 procedure Close;
109 end;
111 procedure AuthHandler(var ch:tChat; msg:tSMsg);
112 var srv:^tServer;
113 begin
114 msg.stream.skip(1); {initcode}
115 new(srv);
116 srv^.ch:=@ch;
117 ch.OnTimeout:=@srv^.Close;
118 srv^.SendRep(msg,true);
119 {reply with hash}
120 {wait ack}
121 {reply pow}
122 {wait reply}
123 end;
125 procedure tServer.SendRep(msg:tSMsg; data:boolean);
126 var r:tMemoryStream absolute msg.Stream;
127 var ms:tMemoryStream;
128 var ver:byte;
129 var chal:^tEccKey;
130 var resp:tSha1Digest;
131 begin
132 ver:=r.ReadByte; {todo}
133 r.Read(pub,sizeof(pub));
134 chal:=r.readptr(sizeof(tEccKey));
135 CreateResponse(chal^,resp,pub);
136 ch^.StreamInit(ms,66); {todo}
137 ms.WriteByte(128);
138 ms.Write(PublicKey,sizeof(PublicKey));
139 ms.Write(resp,sizeof(resp));
140 ch^.Callback:=@SendPoW;
141 ch^.SetTimeout(8000,0);{no reply expected}
142 ch^.send(ms);
143 end;
145 procedure tServer.SendPow(msg:tSMsg; data:boolean);
146 var ms:tMemoryStream;
147 begin
148 if data then exit;
149 ch^.StreamInit(ms,66); {todo}
150 ms.WriteByte(1);
151 ms.Write(PublicPoW,sizeof(PublicPoW));
152 ms.Write(PublicPoWTS,2);
153 ch^.Callback:=@Last;
154 ch^.SetTimeout(8000,2000);
155 ch^.send(ms);
156 end;
158 procedure tServer.Last(msg:tSMsg; data:boolean);
159 var r:tMemoryStream absolute msg.Stream;
160 var Valid,ValidPoW:byte;
161 begin
162 if not data then exit; {unlikely}
163 Valid:=r.ReadByte;
164 ValidPoW:=r.ReadByte;
165 if (Valid<>1)or(ValidPoW<>1) then begin
166 write('CRAuth: Our auth failed on remote, reason pub=',Valid,' pow=',ValidPoW);
167 Writeln(' remote ',string(ch^.remote),' ',string(pub));
168 end;
169 Close;
170 end;
171 procedure tServer.Close;
172 begin
173 ch^.Close;
174 FreeMem(@self,sizeof(self));
175 end;
177 procedure tAuth.Cancel;
178 begin
179 error:=247;
180 Ch.Close;
181 end;
183 BEGIN
184 SetChatHandler(opcode.crAuthReq,@AuthHandler);
185 END.