OTR plugin for Gajim 1.0+
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

crypt.py 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. # Copyright 2011-2012 Kjell Braden <afflux@pentabarf.de>
  2. #
  3. # This file is part of the python-potr library.
  4. #
  5. # python-potr is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU Lesser General Public License as published by
  7. # the Free Software Foundation; either version 3 of the License, or
  8. # any later version.
  9. #
  10. # python-potr is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Lesser General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with this library. If not, see <http://www.gnu.org/licenses/>.
  17. # some python3 compatibilty
  18. from __future__ import unicode_literals
  19. import logging
  20. import struct
  21. from potr.compatcrypto import SHA256, SHA1, SHA1HMAC, SHA256HMAC, \
  22. Counter, AESCTR, PK, getrandbits, randrange
  23. from potr.utils import bytes_to_long, long_to_bytes, pack_mpi, read_mpi
  24. from potr import proto
  25. logger = logging.getLogger(__name__)
  26. STATE_NONE = 0
  27. STATE_AWAITING_DHKEY = 1
  28. STATE_AWAITING_REVEALSIG = 2
  29. STATE_AWAITING_SIG = 4
  30. STATE_V1_SETUP = 5
  31. DH_MODULUS = 2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919
  32. DH_MODULUS_2 = DH_MODULUS-2
  33. DH_GENERATOR = 2
  34. DH_BITS = 1536
  35. DH_MAX = 2**DH_BITS
  36. SM_ORDER = (DH_MODULUS - 1) // 2
  37. def check_group(n):
  38. return 2 <= n <= DH_MODULUS_2
  39. def check_exp(n):
  40. return 1 <= n < SM_ORDER
  41. def SHA256HMAC160(key, data):
  42. return SHA256HMAC(key, data)[:20]
  43. class DH(object):
  44. @classmethod
  45. def set_params(cls, prime, gen):
  46. cls.prime = prime
  47. cls.gen = gen
  48. def __init__(self):
  49. self.priv = randrange(2, 2**320)
  50. self.pub = pow(self.gen, self.priv, self.prime)
  51. DH.set_params(DH_MODULUS, DH_GENERATOR)
  52. class DHSession(object):
  53. def __init__(self, sendenc, sendmac, rcvenc, rcvmac):
  54. self.sendenc = sendenc
  55. self.sendmac = sendmac
  56. self.rcvenc = rcvenc
  57. self.rcvmac = rcvmac
  58. self.sendctr = Counter(0)
  59. self.rcvctr = Counter(0)
  60. self.sendmacused = False
  61. self.rcvmacused = False
  62. def __repr__(self):
  63. return '<{cls}(send={s!r},rcv={r!r})>' \
  64. .format(cls=self.__class__.__name__,
  65. s=self.sendmac, r=self.rcvmac)
  66. @classmethod
  67. def create(cls, dh, y):
  68. s = pow(y, dh.priv, DH_MODULUS)
  69. sb = pack_mpi(s)
  70. if dh.pub > y:
  71. sendbyte = b'\1'
  72. rcvbyte = b'\2'
  73. else:
  74. sendbyte = b'\2'
  75. rcvbyte = b'\1'
  76. sendenc = SHA1(sendbyte + sb)[:16]
  77. sendmac = SHA1(sendenc)
  78. rcvenc = SHA1(rcvbyte + sb)[:16]
  79. rcvmac = SHA1(rcvenc)
  80. return cls(sendenc, sendmac, rcvenc, rcvmac)
  81. class CryptEngine(object):
  82. def __init__(self, ctx):
  83. self.ctx = ctx
  84. self.ake = None
  85. self.sessionId = None
  86. self.sessionIdHalf = False
  87. self.theirKeyid = 0
  88. self.theirY = None
  89. self.theirOldY = None
  90. self.ourOldDHKey = None
  91. self.ourDHKey = None
  92. self.ourKeyid = 0
  93. self.sessionkeys = {0:{0:None, 1:None}, 1:{0:None, 1:None}}
  94. self.theirPubkey = None
  95. self.savedMacKeys = []
  96. self.smp = None
  97. self.extraKey = None
  98. def revealMacs(self, ours=True):
  99. if ours:
  100. dhs = self.sessionkeys[1].values()
  101. else:
  102. dhs = ( v[1] for v in self.sessionkeys.values() )
  103. for v in dhs:
  104. if v is not None:
  105. if v.rcvmacused:
  106. self.savedMacKeys.append(v.rcvmac)
  107. if v.sendmacused:
  108. self.savedMacKeys.append(v.sendmac)
  109. def rotateDHKeys(self):
  110. self.revealMacs(ours=True)
  111. self.ourOldDHKey = self.ourDHKey
  112. self.sessionkeys[1] = self.sessionkeys[0].copy()
  113. self.ourDHKey = DH()
  114. self.ourKeyid += 1
  115. self.sessionkeys[0][0] = None if self.theirY is None else \
  116. DHSession.create(self.ourDHKey, self.theirY)
  117. self.sessionkeys[0][1] = None if self.theirOldY is None else \
  118. DHSession.create(self.ourDHKey, self.theirOldY)
  119. logger.debug('{0}: Refreshing ourkey to {1} {2}'.format(
  120. self.ctx.user.name, self.ourKeyid, self.sessionkeys))
  121. def rotateYKeys(self, new_y):
  122. self.theirOldY = self.theirY
  123. self.revealMacs(ours=False)
  124. self.sessionkeys[0][1] = self.sessionkeys[0][0]
  125. self.sessionkeys[1][1] = self.sessionkeys[1][0]
  126. self.theirY = new_y
  127. self.theirKeyid += 1
  128. self.sessionkeys[0][0] = DHSession.create(self.ourDHKey, self.theirY)
  129. self.sessionkeys[1][0] = DHSession.create(self.ourOldDHKey, self.theirY)
  130. logger.debug('{0}: Refreshing theirkey to {1} {2}'.format(
  131. self.ctx.user.name, self.theirKeyid, self.sessionkeys))
  132. def handleDataMessage(self, msg):
  133. if self.saneKeyIds(msg) is False:
  134. raise InvalidParameterError
  135. sesskey = self.sessionkeys[self.ourKeyid - msg.rkeyid] \
  136. [self.theirKeyid - msg.skeyid]
  137. logger.debug('sesskeys: {0!r}, our={1}, r={2}, their={3}, s={4}' \
  138. .format(self.sessionkeys, self.ourKeyid, msg.rkeyid,
  139. self.theirKeyid, msg.skeyid))
  140. if msg.mac != SHA1HMAC(sesskey.rcvmac, msg.getMacedData()):
  141. logger.error('HMACs don\'t match')
  142. raise InvalidParameterError
  143. sesskey.rcvmacused = True
  144. newCtrPrefix = bytes_to_long(msg.ctr)
  145. if newCtrPrefix <= sesskey.rcvctr.prefix:
  146. logger.error('CTR must increase (old %r, new %r)',
  147. sesskey.rcvctr.prefix, newCtrPrefix)
  148. raise InvalidParameterError
  149. sesskey.rcvctr.prefix = newCtrPrefix
  150. logger.debug('handle: enc={0!r} mac={1!r} ctr={2!r}' \
  151. .format(sesskey.rcvenc, sesskey.rcvmac, sesskey.rcvctr))
  152. plaintextData = AESCTR(sesskey.rcvenc, sesskey.rcvctr) \
  153. .decrypt(msg.encmsg)
  154. if b'\0' in plaintextData:
  155. plaintext, tlvData = plaintextData.split(b'\0', 1)
  156. tlvs = proto.TLV.parse(tlvData)
  157. else:
  158. plaintext = plaintextData
  159. tlvs = []
  160. if msg.rkeyid == self.ourKeyid:
  161. self.rotateDHKeys()
  162. if msg.skeyid == self.theirKeyid:
  163. self.rotateYKeys(bytes_to_long(msg.dhy))
  164. return plaintext, tlvs
  165. def smpSecret(self, secret, question=None, appdata=None):
  166. if self.smp is None:
  167. logger.debug('Creating SMPHandler')
  168. self.smp = SMPHandler(self)
  169. self.smp.gotSecret(secret, question=question, appdata=appdata)
  170. def smpHandle(self, tlv, appdata=None):
  171. if self.smp is None:
  172. logger.debug('Creating SMPHandler')
  173. self.smp = SMPHandler(self)
  174. self.smp.handle(tlv, appdata=appdata)
  175. def smpAbort(self, appdata=None):
  176. if self.smp is None:
  177. logger.debug('Creating SMPHandler')
  178. self.smp = SMPHandler(self)
  179. self.smp.abort(appdata=appdata)
  180. def createDataMessage(self, message, flags=0, tlvs=None):
  181. # check MSGSTATE
  182. if self.theirKeyid == 0:
  183. raise InvalidParameterError
  184. if tlvs is None:
  185. tlvs = []
  186. sess = self.sessionkeys[1][0]
  187. sess.sendctr.inc()
  188. logger.debug('create: enc={0!r} mac={1!r} ctr={2!r}' \
  189. .format(sess.sendenc, sess.sendmac, sess.sendctr))
  190. # plaintext + TLVS
  191. plainBuf = message + b'\0' + b''.join([ bytes(t) for t in tlvs])
  192. encmsg = AESCTR(sess.sendenc, sess.sendctr).encrypt(plainBuf)
  193. msg = proto.DataMessage(flags, self.ourKeyid-1, self.theirKeyid,
  194. long_to_bytes(self.ourDHKey.pub), sess.sendctr.byteprefix(),
  195. encmsg, b'', b''.join(self.savedMacKeys))
  196. self.savedMacKeys = []
  197. msg.mac = SHA1HMAC(sess.sendmac, msg.getMacedData())
  198. return msg
  199. def saneKeyIds(self, msg):
  200. anyzero = self.theirKeyid == 0 or msg.skeyid == 0 or msg.rkeyid == 0
  201. if anyzero or (msg.skeyid != self.theirKeyid and \
  202. msg.skeyid != self.theirKeyid - 1) or \
  203. (msg.rkeyid != self.ourKeyid and msg.rkeyid != self.ourKeyid - 1):
  204. return False
  205. if self.theirOldY is None and msg.skeyid == self.theirKeyid - 1:
  206. return False
  207. return True
  208. def startAKE(self, appdata=None):
  209. self.ake = AuthKeyExchange(self.ctx.user.getPrivkey(), self.goEncrypted)
  210. outMsg = self.ake.startAKE()
  211. self.ctx.sendInternal(outMsg, appdata=appdata)
  212. def handleAKE(self, inMsg, appdata=None):
  213. outMsg = None
  214. if not self.ctx.getPolicy('ALLOW_V2'):
  215. return
  216. if isinstance(inMsg, proto.DHCommit):
  217. if self.ake is None or self.ake.state != STATE_AWAITING_REVEALSIG:
  218. self.ake = AuthKeyExchange(self.ctx.user.getPrivkey(),
  219. self.goEncrypted)
  220. outMsg = self.ake.handleDHCommit(inMsg)
  221. elif isinstance(inMsg, proto.DHKey):
  222. if self.ake is None:
  223. return # ignore
  224. outMsg = self.ake.handleDHKey(inMsg)
  225. elif isinstance(inMsg, proto.RevealSig):
  226. if self.ake is None:
  227. return # ignore
  228. outMsg = self.ake.handleRevealSig(inMsg)
  229. elif isinstance(inMsg, proto.Signature):
  230. if self.ake is None:
  231. return # ignore
  232. self.ake.handleSignature(inMsg)
  233. if outMsg is not None:
  234. self.ctx.sendInternal(outMsg, appdata=appdata)
  235. def goEncrypted(self, ake):
  236. if ake.dh.pub == ake.gy:
  237. logger.warning('We are receiving our own messages')
  238. raise InvalidParameterError
  239. # TODO handle new fingerprint
  240. self.theirPubkey = ake.theirPubkey
  241. self.sessionId = ake.sessionId
  242. self.sessionIdHalf = ake.sessionIdHalf
  243. self.theirKeyid = ake.theirKeyid
  244. self.ourKeyid = ake.ourKeyid
  245. self.theirY = ake.gy
  246. self.theirOldY = None
  247. self.extraKey = ake.extraKey
  248. if self.ourKeyid != ake.ourKeyid + 1 or self.ourOldDHKey != ake.dh.pub:
  249. self.ourDHKey = ake.dh
  250. self.sessionkeys[0][0] = DHSession.create(self.ourDHKey, self.theirY)
  251. self.rotateDHKeys()
  252. # we don't need the AKE anymore, free the reference
  253. self.ake = None
  254. self.ctx._wentEncrypted()
  255. logger.info('went encrypted with {0}'.format(self.theirPubkey))
  256. def finished(self):
  257. self.smp = None
  258. class AuthKeyExchange(object):
  259. def __init__(self, privkey, onSuccess):
  260. self.privkey = privkey
  261. self.state = STATE_NONE
  262. self.r = None
  263. self.encgx = None
  264. self.hashgx = None
  265. self.ourKeyid = 1
  266. self.theirPubkey = None
  267. self.theirKeyid = 1
  268. self.enc_c = None
  269. self.enc_cp = None
  270. self.mac_m1 = None
  271. self.mac_m1p = None
  272. self.mac_m2 = None
  273. self.mac_m2p = None
  274. self.sessionId = None
  275. self.sessionIdHalf = False
  276. self.dh = DH()
  277. self.onSuccess = onSuccess
  278. self.gy = None
  279. self.extraKey = None
  280. self.lastmsg = None
  281. def startAKE(self):
  282. self.r = long_to_bytes(getrandbits(128), 16)
  283. gxmpi = pack_mpi(self.dh.pub)
  284. self.hashgx = SHA256(gxmpi)
  285. self.encgx = AESCTR(self.r).encrypt(gxmpi)
  286. self.state = STATE_AWAITING_DHKEY
  287. return proto.DHCommit(self.encgx, self.hashgx)
  288. def handleDHCommit(self, msg):
  289. self.encgx = msg.encgx
  290. self.hashgx = msg.hashgx
  291. self.state = STATE_AWAITING_REVEALSIG
  292. return proto.DHKey(long_to_bytes(self.dh.pub))
  293. def handleDHKey(self, msg):
  294. if self.state == STATE_AWAITING_DHKEY:
  295. self.gy = bytes_to_long(msg.gy)
  296. # check 2 <= g**y <= p-2
  297. if not check_group(self.gy):
  298. logger.error('Invalid g**y received: %r', self.gy)
  299. return
  300. self.createAuthKeys()
  301. aesxb = self.calculatePubkeyAuth(self.enc_c, self.mac_m1)
  302. self.state = STATE_AWAITING_SIG
  303. self.lastmsg = proto.RevealSig(self.r, aesxb, b'')
  304. self.lastmsg.mac = SHA256HMAC160(self.mac_m2,
  305. self.lastmsg.getMacedData())
  306. return self.lastmsg
  307. elif self.state == STATE_AWAITING_SIG:
  308. logger.info('received DHKey while not awaiting DHKEY')
  309. if msg.gy == self.gy:
  310. logger.info('resending revealsig')
  311. return self.lastmsg
  312. else:
  313. logger.info('bad state for DHKey')
  314. def handleRevealSig(self, msg):
  315. if self.state != STATE_AWAITING_REVEALSIG:
  316. logger.error('bad state for RevealSig')
  317. raise InvalidParameterError
  318. self.r = msg.rkey
  319. gxmpi = AESCTR(self.r).decrypt(self.encgx)
  320. if SHA256(gxmpi) != self.hashgx:
  321. logger.error('Hashes don\'t match')
  322. logger.info('r=%r, hashgx=%r, computed hash=%r, gxmpi=%r',
  323. self.r, self.hashgx, SHA256(gxmpi), gxmpi)
  324. raise InvalidParameterError
  325. self.gy = read_mpi(gxmpi)[0]
  326. self.createAuthKeys()
  327. if msg.mac != SHA256HMAC160(self.mac_m2, msg.getMacedData()):
  328. logger.error('HMACs don\'t match')
  329. logger.info('mac=%r, mac_m2=%r, data=%r', msg.mac, self.mac_m2,
  330. msg.getMacedData())
  331. raise InvalidParameterError
  332. self.checkPubkeyAuth(self.enc_c, self.mac_m1, msg.encsig)
  333. aesxb = self.calculatePubkeyAuth(self.enc_cp, self.mac_m1p)
  334. self.sessionIdHalf = True
  335. self.onSuccess(self)
  336. self.ourKeyid = 0
  337. self.state = STATE_NONE
  338. cmpmac = struct.pack(b'!I', len(aesxb)) + aesxb
  339. return proto.Signature(aesxb, SHA256HMAC160(self.mac_m2p, cmpmac))
  340. def handleSignature(self, msg):
  341. if self.state != STATE_AWAITING_SIG:
  342. logger.error('bad state (%d) for Signature', self.state)
  343. raise InvalidParameterError
  344. if msg.mac != SHA256HMAC160(self.mac_m2p, msg.getMacedData()):
  345. logger.error('HMACs don\'t match')
  346. raise InvalidParameterError
  347. self.checkPubkeyAuth(self.enc_cp, self.mac_m1p, msg.encsig)
  348. self.sessionIdHalf = False
  349. self.onSuccess(self)
  350. self.ourKeyid = 0
  351. self.state = STATE_NONE
  352. def createAuthKeys(self):
  353. s = pow(self.gy, self.dh.priv, DH_MODULUS)
  354. sbyte = pack_mpi(s)
  355. self.sessionId = SHA256(b'\x00' + sbyte)[:8]
  356. enc = SHA256(b'\x01' + sbyte)
  357. self.enc_c = enc[:16]
  358. self.enc_cp = enc[16:]
  359. self.mac_m1 = SHA256(b'\x02' + sbyte)
  360. self.mac_m2 = SHA256(b'\x03' + sbyte)
  361. self.mac_m1p = SHA256(b'\x04' + sbyte)
  362. self.mac_m2p = SHA256(b'\x05' + sbyte)
  363. self.extraKey = SHA256(b'\xff' + sbyte)
  364. def calculatePubkeyAuth(self, key, mackey):
  365. pubkey = self.privkey.serializePublicKey()
  366. buf = pack_mpi(self.dh.pub)
  367. buf += pack_mpi(self.gy)
  368. buf += pubkey
  369. buf += struct.pack(b'!I', self.ourKeyid)
  370. MB = self.privkey.sign(SHA256HMAC(mackey, buf))
  371. buf = pubkey
  372. buf += struct.pack(b'!I', self.ourKeyid)
  373. buf += MB
  374. return AESCTR(key).encrypt(buf)
  375. def checkPubkeyAuth(self, key, mackey, encsig):
  376. auth = AESCTR(key).decrypt(encsig)
  377. self.theirPubkey, auth = PK.parsePublicKey(auth)
  378. receivedKeyid, auth = proto.unpack(b'!I', auth)
  379. if receivedKeyid == 0:
  380. raise InvalidParameterError
  381. authbuf = pack_mpi(self.gy)
  382. authbuf += pack_mpi(self.dh.pub)
  383. authbuf += self.theirPubkey.serializePublicKey()
  384. authbuf += struct.pack(b'!I', receivedKeyid)
  385. if self.theirPubkey.verify(SHA256HMAC(mackey, authbuf), auth) is False:
  386. raise InvalidParameterError
  387. self.theirKeyid = receivedKeyid
  388. SMPPROG_OK = 0
  389. SMPPROG_CHEATED = -2
  390. SMPPROG_FAILED = -1
  391. SMPPROG_SUCCEEDED = 1
  392. class SMPHandler:
  393. def __init__(self, crypto):
  394. self.crypto = crypto
  395. self.state = 1
  396. self.g1 = DH_GENERATOR
  397. self.g2 = None
  398. self.g3 = None
  399. self.g3o = None
  400. self.x2 = None
  401. self.x3 = None
  402. self.prog = SMPPROG_OK
  403. self.pab = None
  404. self.qab = None
  405. self.questionReceived = False
  406. self.secret = None
  407. self.p = None
  408. self.q = None
  409. def abort(self, appdata=None):
  410. self.state = 1
  411. self.sendTLV(proto.SMPABORTTLV(), appdata=appdata)
  412. def sendTLV(self, tlv, appdata=None):
  413. self.crypto.ctx.sendInternal(b'', tlvs=[tlv], appdata=appdata)
  414. def handle(self, tlv, appdata=None):
  415. logger.debug('handling TLV {0.__class__.__name__}'.format(tlv))
  416. self.prog = SMPPROG_CHEATED
  417. if isinstance(tlv, proto.SMPABORTTLV):
  418. self.state = 1
  419. return
  420. is1qTlv = isinstance(tlv, proto.SMP1QTLV)
  421. if isinstance(tlv, proto.SMP1TLV) or is1qTlv:
  422. if self.state != 1:
  423. self.abort(appdata=appdata)
  424. return
  425. msg = tlv.mpis
  426. if not check_group(msg[0]) or not check_group(msg[3]) \
  427. or not check_exp(msg[2]) or not check_exp(msg[5]) \
  428. or not check_known_log(msg[1], msg[2], self.g1, msg[0], 1) \
  429. or not check_known_log(msg[4], msg[5], self.g1, msg[3], 2):
  430. logger.error('invalid SMP1TLV received')
  431. self.abort(appdata=appdata)
  432. return
  433. self.questionReceived = is1qTlv
  434. self.g3o = msg[3]
  435. self.x2 = randrange(2, DH_MAX)
  436. self.x3 = randrange(2, DH_MAX)
  437. self.g2 = pow(msg[0], self.x2, DH_MODULUS)
  438. self.g3 = pow(msg[3], self.x3, DH_MODULUS)
  439. self.prog = SMPPROG_OK
  440. self.state = 0
  441. return
  442. if isinstance(tlv, proto.SMP2TLV):
  443. if self.state != 2:
  444. self.abort(appdata=appdata)
  445. return
  446. msg = tlv.mpis
  447. mp = msg[6]
  448. mq = msg[7]
  449. if not check_group(msg[0]) or not check_group(msg[3]) \
  450. or not check_group(msg[6]) or not check_group(msg[7]) \
  451. or not check_exp(msg[2]) or not check_exp(msg[5]) \
  452. or not check_exp(msg[9]) or not check_exp(msg[10]) \
  453. or not check_known_log(msg[1], msg[2], self.g1, msg[0], 3) \
  454. or not check_known_log(msg[4], msg[5], self.g1, msg[3], 4):
  455. logger.error('invalid SMP2TLV received')
  456. self.abort(appdata=appdata)
  457. return
  458. self.g3o = msg[3]
  459. self.g2 = pow(msg[0], self.x2, DH_MODULUS)
  460. self.g3 = pow(msg[3], self.x3, DH_MODULUS)
  461. if not self.check_equal_coords(msg[6:11], 5):
  462. logger.error('invalid SMP2TLV received')
  463. self.abort(appdata=appdata)
  464. return
  465. r = randrange(2, DH_MAX)
  466. self.p = pow(self.g3, r, DH_MODULUS)
  467. msg = [self.p]
  468. qa1 = pow(self.g1, r, DH_MODULUS)
  469. qa2 = pow(self.g2, self.secret, DH_MODULUS)
  470. self.q = qa1*qa2 % DH_MODULUS
  471. msg.append(self.q)
  472. msg += self.proof_equal_coords(r, 6)
  473. inv = invMod(mp)
  474. self.pab = self.p * inv % DH_MODULUS
  475. inv = invMod(mq)
  476. self.qab = self.q * inv % DH_MODULUS
  477. msg.append(pow(self.qab, self.x3, DH_MODULUS))
  478. msg += self.proof_equal_logs(7)
  479. self.state = 4
  480. self.prog = SMPPROG_OK
  481. self.sendTLV(proto.SMP3TLV(msg), appdata=appdata)
  482. return
  483. if isinstance(tlv, proto.SMP3TLV):
  484. if self.state != 3:
  485. self.abort(appdata=appdata)
  486. return
  487. msg = tlv.mpis
  488. if not check_group(msg[0]) or not check_group(msg[1]) \
  489. or not check_group(msg[5]) or not check_exp(msg[3]) \
  490. or not check_exp(msg[4]) or not check_exp(msg[7]) \
  491. or not self.check_equal_coords(msg[:5], 6):
  492. logger.error('invalid SMP3TLV received')
  493. self.abort(appdata=appdata)
  494. return
  495. inv = invMod(self.p)
  496. self.pab = msg[0] * inv % DH_MODULUS
  497. inv = invMod(self.q)
  498. self.qab = msg[1] * inv % DH_MODULUS
  499. if not self.check_equal_logs(msg[5:8], 7):
  500. logger.error('invalid SMP3TLV received')
  501. self.abort(appdata=appdata)
  502. return
  503. md = msg[5]
  504. msg = [pow(self.qab, self.x3, DH_MODULUS)]
  505. msg += self.proof_equal_logs(8)
  506. rab = pow(md, self.x3, DH_MODULUS)
  507. self.prog = SMPPROG_SUCCEEDED if self.pab == rab else SMPPROG_FAILED
  508. if self.prog != SMPPROG_SUCCEEDED:
  509. logger.error('secrets don\'t match')
  510. self.abort(appdata=appdata)
  511. self.crypto.ctx.setCurrentTrust('')
  512. return
  513. logger.info('secrets matched')
  514. if not self.questionReceived:
  515. self.crypto.ctx.setCurrentTrust('smp')
  516. self.state = 1
  517. self.sendTLV(proto.SMP4TLV(msg), appdata=appdata)
  518. return
  519. if isinstance(tlv, proto.SMP4TLV):
  520. if self.state != 4:
  521. self.abort(appdata=appdata)
  522. return
  523. msg = tlv.mpis
  524. if not check_group(msg[0]) or not check_exp(msg[2]) \
  525. or not self.check_equal_logs(msg[:3], 8):
  526. logger.error('invalid SMP4TLV received')
  527. self.abort(appdata=appdata)
  528. return
  529. rab = pow(msg[0], self.x3, DH_MODULUS)
  530. self.prog = SMPPROG_SUCCEEDED if self.pab == rab else SMPPROG_FAILED
  531. if self.prog != SMPPROG_SUCCEEDED:
  532. logger.error('secrets don\'t match')
  533. self.abort(appdata=appdata)
  534. self.crypto.ctx.setCurrentTrust('')
  535. return
  536. logger.info('secrets matched')
  537. self.crypto.ctx.setCurrentTrust('smp')
  538. self.state = 1
  539. return
  540. def gotSecret(self, secret, question=None, appdata=None):
  541. ourFP = self.crypto.ctx.user.getPrivkey().fingerprint()
  542. if self.state == 1:
  543. # first secret -> SMP1TLV
  544. combSecret = SHA256(b'\1' + ourFP +
  545. self.crypto.theirPubkey.fingerprint() +
  546. self.crypto.sessionId + secret)
  547. self.secret = bytes_to_long(combSecret)
  548. self.x2 = randrange(2, DH_MAX)
  549. self.x3 = randrange(2, DH_MAX)
  550. msg = [pow(self.g1, self.x2, DH_MODULUS)]
  551. msg += proof_known_log(self.g1, self.x2, 1)
  552. msg.append(pow(self.g1, self.x3, DH_MODULUS))
  553. msg += proof_known_log(self.g1, self.x3, 2)
  554. self.prog = SMPPROG_OK
  555. self.state = 2
  556. if question is None:
  557. self.sendTLV(proto.SMP1TLV(msg), appdata=appdata)
  558. else:
  559. self.sendTLV(proto.SMP1QTLV(question, msg), appdata=appdata)
  560. if self.state == 0:
  561. # response secret -> SMP2TLV
  562. combSecret = SHA256(b'\1' + self.crypto.theirPubkey.fingerprint() +
  563. ourFP + self.crypto.sessionId + secret)
  564. self.secret = bytes_to_long(combSecret)
  565. msg = [pow(self.g1, self.x2, DH_MODULUS)]
  566. msg += proof_known_log(self.g1, self.x2, 3)
  567. msg.append(pow(self.g1, self.x3, DH_MODULUS))
  568. msg += proof_known_log(self.g1, self.x3, 4)
  569. r = randrange(2, DH_MAX)
  570. self.p = pow(self.g3, r, DH_MODULUS)
  571. msg.append(self.p)
  572. qb1 = pow(self.g1, r, DH_MODULUS)
  573. qb2 = pow(self.g2, self.secret, DH_MODULUS)
  574. self.q = qb1 * qb2 % DH_MODULUS
  575. msg.append(self.q)
  576. msg += self.proof_equal_coords(r, 5)
  577. self.state = 3
  578. self.sendTLV(proto.SMP2TLV(msg), appdata=appdata)
  579. def proof_equal_coords(self, r, v):
  580. r1 = randrange(2, DH_MAX)
  581. r2 = randrange(2, DH_MAX)
  582. temp2 = pow(self.g1, r1, DH_MODULUS) \
  583. * pow(self.g2, r2, DH_MODULUS) % DH_MODULUS
  584. temp1 = pow(self.g3, r1, DH_MODULUS)
  585. cb = SHA256(struct.pack(b'B', v) + pack_mpi(temp1) + pack_mpi(temp2))
  586. c = bytes_to_long(cb)
  587. temp1 = r * c % SM_ORDER
  588. d1 = (r1-temp1) % SM_ORDER
  589. temp1 = self.secret * c % SM_ORDER
  590. d2 = (r2 - temp1) % SM_ORDER
  591. return c, d1, d2
  592. def check_equal_coords(self, coords, v):
  593. (p, q, c, d1, d2) = coords
  594. temp1 = pow(self.g3, d1, DH_MODULUS) * pow(p, c, DH_MODULUS) \
  595. % DH_MODULUS
  596. temp2 = pow(self.g1, d1, DH_MODULUS) \
  597. * pow(self.g2, d2, DH_MODULUS) \
  598. * pow(q, c, DH_MODULUS) % DH_MODULUS
  599. cprime = SHA256(struct.pack(b'B', v) + pack_mpi(temp1) + pack_mpi(temp2))
  600. return long_to_bytes(c, 32) == cprime
  601. def proof_equal_logs(self, v):
  602. r = randrange(2, DH_MAX)
  603. temp1 = pow(self.g1, r, DH_MODULUS)
  604. temp2 = pow(self.qab, r, DH_MODULUS)
  605. cb = SHA256(struct.pack(b'B', v) + pack_mpi(temp1) + pack_mpi(temp2))
  606. c = bytes_to_long(cb)
  607. temp1 = self.x3 * c % SM_ORDER
  608. d = (r - temp1) % SM_ORDER
  609. return c, d
  610. def check_equal_logs(self, logs, v):
  611. (r, c, d) = logs
  612. temp1 = pow(self.g1, d, DH_MODULUS) \
  613. * pow(self.g3o, c, DH_MODULUS) % DH_MODULUS
  614. temp2 = pow(self.qab, d, DH_MODULUS) \
  615. * pow(r, c, DH_MODULUS) % DH_MODULUS
  616. cprime = SHA256(struct.pack(b'B', v) + pack_mpi(temp1) + pack_mpi(temp2))
  617. return long_to_bytes(c, 32) == cprime
  618. def proof_known_log(g, x, v):
  619. r = randrange(2, DH_MAX)
  620. c = bytes_to_long(SHA256(struct.pack(b'B', v) + pack_mpi(pow(g, r, DH_MODULUS))))
  621. temp = x * c % SM_ORDER
  622. return c, (r-temp) % SM_ORDER
  623. def check_known_log(c, d, g, x, v):
  624. gd = pow(g, d, DH_MODULUS)
  625. xc = pow(x, c, DH_MODULUS)
  626. gdxc = gd * xc % DH_MODULUS
  627. return SHA256(struct.pack(b'B', v) + pack_mpi(gdxc)) == long_to_bytes(c, 32)
  628. def invMod(n):
  629. return pow(n, DH_MODULUS_2, DH_MODULUS)
  630. class InvalidParameterError(RuntimeError):
  631. pass