handle nested roster group. TODO: Improve the way it's displayed in roster. Fixes...
[gajim.git] / src / common / crypto.py
blobc787df6aadd69f10974b3e317f52b9f5cf369d27
1 # common crypto functions (mostly specific to XEP-0116, but useful elsewhere)
2 # -*- coding:utf-8 -*-
3 ## src/common/crypto.py
4 ##
5 ## Copyright (C) 2007 Brendan Taylor <whateley AT gmail.com>
6 ##
7 ## This file is part of Gajim.
8 ##
9 ## Gajim is free software; you can redistribute it and/or modify
10 ## it under the terms of the GNU General Public License as published
11 ## by the Free Software Foundation; version 3 only.
13 ## Gajim is distributed in the hope that it will be useful,
14 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ## GNU General Public License for more details.
18 ## You should have received a copy of the GNU General Public License
19 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
22 import os
23 import math
25 from hashlib import sha256 as SHA256
27 # convert a large integer to a big-endian bitstring
28 def encode_mpi(n):
29 if n >= 256:
30 return encode_mpi(n / 256) + chr(n % 256)
31 else:
32 return chr(n)
34 # convert a large integer to a big-endian bitstring, padded with \x00s to
35 # a multiple of 16 bytes
36 def encode_mpi_with_padding(n):
37 return pad_to_multiple(encode_mpi(n), 16, '\x00', True)
39 # pad 'string' to a multiple of 'multiple_of' with 'char'.
40 # pad on the left if 'left', otherwise pad on the right.
41 def pad_to_multiple(string, multiple_of, char, left):
42 mod = len(string) % multiple_of
43 if mod == 0:
44 return string
45 else:
46 padding = (multiple_of - mod) * char
48 if left:
49 return padding + string
50 else:
51 return string + padding
53 # convert a big-endian bitstring to an integer
54 def decode_mpi(s):
55 if len(s) == 0:
56 return 0
57 else:
58 return 256 * decode_mpi(s[:-1]) + ord(s[-1])
60 def sha256(string):
61 sh = SHA256()
62 sh.update(string)
63 return sh.digest()
65 base28_chr = "acdefghikmopqruvwxy123456789"
67 def sas_28x5(m_a, form_b):
68 sha = sha256(m_a + form_b + 'Short Authentication String')
69 lsb24 = decode_mpi(sha[-3:])
70 return base28(lsb24)
72 def base28(n):
73 if n >= 28:
74 return base28(n / 28) + base28_chr[n % 28]
75 else:
76 return base28_chr[n]
78 def random_bytes(bytes_):
79 return os.urandom(bytes_)
81 def generate_nonce():
82 return random_bytes(8)
84 # generate a random number between 'bottom' and 'top'
85 def srand(bottom, top):
86 # minimum number of bytes needed to represent that range
87 bytes = int(math.ceil(math.log(top - bottom, 256)))
89 # in retrospect, this is horribly inadequate.
90 return (decode_mpi(random_bytes(bytes)) % (top - bottom)) + bottom
92 # a faster version of (base ** exp) % mod
93 # taken from <http://lists.danga.com/pipermail/yadis/2005-September/001445.html>
94 def powmod(base, exp, mod):
95 square = base % mod
96 result = 1
98 while exp > 0:
99 if exp & 1: # exponent is odd
100 result = (result * square) % mod
102 square = (square * square) % mod
103 exp /= 2
105 return result