#!/usr/bin/env python3 import os import secrets import sys def pe(s):print(s,file=sys.stderr);sys.exit(1) q=lambda b:sum(b[i]<<(i*8)for i in range(len(b))) w=lambda n,l:bytes(n>>i&255 for i in range(0,l,8)) add=lambda x,y:x+y&0xffffffff rl=lambda x,n:x<>32-n def qr(a,b,c,d):a=add(a,b);d^=a;d=rl(d,16);c=add(c,d);b^=c;b=rl(b,12);a=add(a,b);d^=a;d=rl(d,8);c=add(c,d);b^=c;b=rl(b,7);return a,b,c,d def ccb(k,c,n,f): if c>=1<<32:pe('Error: input too big') s=[0x61707865,857760878,0x79622d32,0x6b206574,q(k[:4]),q(k[4:8]),q(k[8:12]),q(k[12:16]),q(k[16:20]),q(k[20:24]),q(k[24:28]),q(k[28:]),c,q(n[:4]),q(n[4:8]),q(n[8:])];o=s[:] if f:o=[0]*16 def x(a,b,c,d):s[a],s[b],s[c],s[d]=qr(s[a],s[b],s[c],s[d]) for _ in range(10):x(0,4,8,12);x(1,5,9,13);x(2,6,10,14);x(3,7,11,15);x(0,5,10,15);x(1,6,11,12);x(2,7,8,13);x(3,4,9,14) return b''.join(w(add(o[i],s[i]),32)for i in range(len(s))) def cc20(k,n,m): for i in range((len(m)+63)//64):yield from(a^b for a,b in zip(m[i*64:i*64+64],ccb(k,i+1,n,0))) def tag(k,n,c): m=b''.join((c,b'\x00'*(-len(c)%16),w(0,64),w(len(c),64)));k=ccb(k,0,n,0)[:32];r=bytearray(k[:16]);r[3]&=15;r[7]&=15;r[11]&=15;r[15]&=15;r[4]&=252;r[8]&=252;r[12]&=252;r=q(r);s=q(k[16:]);P=2**130-5;a=0 for i in range((len(m)+15)//16):a=(a+q(m[i*16:i*16+16]+b'\x01'))*r%P return w(a+s,128) def hcc20(k,n):s=ccb(k,q(n[:4]),n[4:],1);return s[:16]+s[48:] p=2**255-19 def cs(s,a,b):d=-s&((1<<255)-1)&(a^b);a=a^d;b=b^d;return a,b def x(k,u): k=bytearray(k);k[0]&=248;k[31]&=127;k[31]|=64;k=q(k);u=q(u[:-1]+bytes([u[-1]&127]));x=u;y=1;z=0;w=u;v=1;s=0 for t in range(254,-1,-1):kt=(k>>t)&1;s^=kt;y,w=cs(s,y,w);z,v=cs(s,z,v);s=kt;A=(y+z)%p;AA=pow(A,2,p);B=(y-z)%p;BB=pow(B,2,p);E=(AA-BB)%p;C=(w+v)%p;D=(w-v)%p;DA=(D*A)%p;CB=(C*B)%p;w=pow((DA+CB)%p,2,p);v=(x*pow((DA-CB)%p,2,p))%p;y=(AA*BB)%p;z=(E*((AA+(121665*E)%p)%p)%p)%p y,w=cs(s,y,w);z,v=cs(s,z,v);u=(y*pow(z,p-2,p))%p;return bytes(u>>i&255 for i in range(0,255,8)) def ecdh(pk,sk): k=x(sk,pk);o=0 for i in k:o|=i if o==0:raise ValueError else:return k def kg():sk=os.urandom(32);pk=x(sk,b'\x09'+b'\x00'*31);return sk,pk def us():pe('Usage: qrcrypt.py -G|-E|-D seckeyfile/pubkey') if __name__ == '__main__': if len(sys.argv)!=3:us() if sys.argv[1]=='-G': sk,pk=kg() with open(sys.argv[2],'wb')as f:f.write(sk) print('pk:',pk.hex()) elif sys.argv[1]=='-E': esk,epk=kg();rss=ecdh(bytes.fromhex(sys.argv[2]),esk);k=hcc20(rss,b'\x00'*24);o=os.urandom(24);k=hcc20(k, o[:16]);n=b'\x00'*4+o[16:];c=bytes(cc20(k,n,sys.stdin.buffer.read()));sys.stdout.buffer.write(epk+o+c+tag(k,n,c)) elif sys.argv[1] == '-D': with open(sys.argv[2],'rb')as f:sk=f.read() e=sys.stdin.buffer.read();epk=e[:32];n=e[32:56];rss=ecdh(epk,sk);k=hcc20(rss,b'\x00'*24);k=hcc20(k, n[:16]);n=b'\x00'*4+n[16:];c=e[56:-16] if not secrets.compare_digest(e[-16:],tag(k,n,c)):pe('Error: auth fail') else:sys.stdout.buffer.write(bytes(cc20(k,n,c))) else:us()