DHT: ECC Auth and PoW.
[brdnet.git] / CRAuth.pas
blobcf34be5475c809cedb8f7ba43783ce1f4ddc89a7
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 RPub:^tEccKey;
52 var resp:^tEccKey;
53 var vresp:tSha1Digest;
54 begin
55 if not data then exit;
56 status:=r.readbyte; {todo, set error (eg: unsuported meth)}
57 RPub:=r.readptr(sizeof(tEccKey));
58 resp:=r.readptr(sizeof(tEccKey));
59 ECC.CreateResponse(Challenge,vresp,RPub^);
60 Valid:=CompareByte(resp^,vresp,sizeof(vresp))=0;
61 if (status and 128)=1 then begin
62 {expecting pow}
63 Ch.Callback:=@ReplyPow;
64 Ch.Ack;
65 end else Conclusion;
66 end;
67 procedure tAuth.ReplyPow(msg:tSMsg; data:boolean);
68 var r:tMemoryStream absolute msg.Stream;
69 var ptp:byte;{Proof TyPe}
70 var nonce:^tEccKey;
71 var pts: ^tPoWTimeStamp;
72 begin
73 if not data then exit;
74 ptp:=r.readbyte; {todo}
75 nonce:=r.ReadPtr(sizeof(tEccKey));
76 pts:=r.ReadPtr(2);
77 PoWValid:=VerifyPoW(nonce^,RemotePub,pts^);
78 Conclusion;
79 end;
80 procedure tAuth.Timeout;
81 begin
82 error:=251;
83 Callback;
84 Ch.Close;
85 end;
86 procedure tAuth.Conclusion;
87 var ms:tMemoryStream;
88 begin
89 error:=0;
90 Ch.StreamInit(ms,2);
91 ms.WriteByte(byte(Valid));
92 ms.WriteByte(byte(PowValid));
93 Ch.Send(ms);
94 Callback;
95 ch.Close;
96 end;
97 procedure tAuth.Done;
98 begin
99 {called by chat}
100 FreeMem(@self,sizeof(self));
101 end;
103 type tServer=object
104 ch:^tChat;
105 pub:tEccKey;
106 procedure SendRep(msg:tSMsg; data:boolean);
107 procedure SendPow(msg:tSMsg; data:boolean);
108 procedure Last(msg:tSMsg; data:boolean);
109 procedure Close;
110 end;
112 procedure AuthHandler(var ch:tChat; msg:tSMsg);
113 var srv:^tServer;
114 begin
115 msg.stream.skip(1); {initcode}
116 new(srv);
117 srv^.ch:=@ch;
118 ch.OnTimeout:=@srv^.Close;
119 srv^.SendRep(msg,true);
120 {reply with hash}
121 {wait ack}
122 {reply pow}
123 {wait reply}
124 end;
126 procedure tServer.SendRep(msg:tSMsg; data:boolean);
127 var r:tMemoryStream absolute msg.Stream;
128 var ms:tMemoryStream;
129 var ver:byte;
130 var chal:^tEccKey;
131 var resp:tSha1Digest;
132 begin
133 ver:=r.ReadByte; {todo}
134 r.Read(pub,sizeof(pub));
135 chal:=r.readptr(sizeof(tEccKey));
136 CreateResponse(chal^,resp,pub);
137 ch^.StreamInit(ms,66); {todo}
138 ms.WriteByte(128);
139 ms.Write(PublicKey,sizeof(PublicKey));
140 ms.Write(resp,sizeof(resp));
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^.SetTimeout(8000,2000);
154 ch^.send(ms);
155 end;
157 procedure tServer.Last(msg:tSMsg; data:boolean);
158 var r:tMemoryStream absolute msg.Stream;
159 var Valid,ValidPoW:byte;
160 begin
161 if not data then exit; {unlikely}
162 Valid:=r.ReadByte;
163 ValidPoW:=r.ReadByte;
164 if (Valid>0)or(ValidPoW>0) then begin
165 writeln('CRAuth: Our auth failed on remote, reason pub=',Valid,' pow=',ValidPoW);
166 Writeln('CRAuth: remote ',string(ch^.remote),' ',string(pub));
167 end;
168 Close;
169 end;
170 procedure tServer.Close;
171 begin
172 ch^.Close;
173 FreeMem(@self,sizeof(self));
174 end;
176 procedure tAuth.Cancel;
177 begin
178 error:=247;
179 Ch.Close;
180 end;
182 BEGIN
183 SetChatHandler(opcode.crAuthReq,@AuthHandler);
184 END.