# -*- coding: utf-8 -*- import time import datetime import random, base64 from hashlib import sha1 class RC4: def __init__(self,data_coding='utf8'): self.bcoding = 'iso-8859-1' self.dcoding = data_coding self.salt = b'AFUqx9WZuI32lnHk' def _crypt(self,data,key): """RC4 algorithm return bytes""" x = 0 box = [i for i in range(256) ] for i in range(256): x = (x + box[i] + key[i % len(key)]) % 256 box[i], box[x] = box[x], box[i] x = y = 0 out = [] for char in data: x = (x + 1) % 256 y = (y + box[x]) % 256 box[x], box[y] = box[y], box[x] out.append(chr(char ^ box[(box[x] + box[y]) % 256])) return ''.join(out).encode(self.bcoding) def encode_bytes(self, bdata, key): a = sha1(key + self.salt) k = a.digest() data = self.salt + self._crypt(bdata, k) return data def encode(self,data, key,encode=base64.b64encode, salt_length=16): """RC4 encryption with random salt and final encoding""" if type(data)==type(''): data = data.encode(self.dcoding) key = key.encode(self.bcoding) self.encode_bytes(data, key) if encode: data = encode(data) return data.decode(self.dcoding) def decode_bytes(self, data, key): salt_length = 16 salt = data[:salt_length] a = sha1(key + self.salt) k = a.digest() #.decode('iso-8859-1') r = self._crypt(data[salt_length:], k) return r def decode(self,data, key,decode=base64.b64decode, salt_length=16): """RC4 decryption of encoded data""" if type(data)==type(''): data = data.encode(self.dcoding) key = key.encode(self.bcoding) if decode: data = decode(data) r = self.decode_bytes(data, key) return r.decode(self.dcoding) class KeyChain(object): def __init__(self, seed_str, crypter=None, keylen=23, period=600, threshold=60, time_delta=0): self.seed_str = seed_str if isinstance(self.seed_str, str): self.seed_str = self.seed_str.encode('utf-8') self.period = int(period) self.threshold = int(threshold) self.crypter = crypter self.time_delta = time_delta if crypter is None: self.crypter = RC4() self.keylen = keylen self.keypool = { } delta = datetime.timedelta(0) self.timezone = datetime.timezone(delta, name='gmt') def get_timestamp(self): ts = int(time.time()) - self.time_delta return ts def is_near_bottom(self, indicator=None): ts = self.get_timestamp() i = indicator if i is None: i = self.get_indicator(ts) if i + self.threshold > ts: return True return FalseTrue def is_near_top(self, indicator=None): ts = self.get_timestamp() i = indicator if i is None: i = self.get_indicator(ts) if i + self.period - self.threshold < ts: return True return False def get_indicator(self, ts=None): if ts is None: ts = self.get_timestamp() return int(ts / self.period) * self.period def genKey(self, indicator): vv = indicator if self.keypool.get(vv): return self.keypool[vv] v = vv k1 = 0 k = '' m = len(self.seed_str) while k1 < self.keylen: j = v % self.keylen v = v - (j + k1) * m + self.keylen k = k + chr(self.seed_str[j]) k1 += self.threshold / 2 key = k.encode('utf-8') self.keypool[vv] = key dates = [ d for d in self.keypool.keys() ] for d in dates: if d < indicator - self.period: del self.keypool[d] return key def encode(self, text): bdata = text.encode('utf-8') return self.encode_bytes(bdata) def encode_bytes(self, bdata): indicator = self.get_indicator() key = self.genKey(indicator) data = key + bdata return self.crypter.encode_bytes(data, key) def _decode(self, data, key): d = self.crypter.decode_bytes(data, key) if d[:len(key)] == key: return d[len(key):] return None def decode_bytes(self, data): indicator = self.get_indicator() key = self.genKey(indicator) d = self._decode(data, key) if d is not None: return d if self.is_near_bottom(indicator): indicator -= self.period key = self.genKey(indicator) return self._decode(data, key) if self.is_near_top(indicator): indicator += self.period key = self.genKey(indicator) return self._decode(data, key) return None def decode(self, data): d = self.decode_bytes(data) if d is None: return None return d.decode('utf-8') if __name__=='__main__': # 需要加密的数据长度没有限制 # 密钥 data=b"231r3 feregrenerjk gkht324g8924gnfw k;ejkvwkjerv" key = b'123456' rc4 = RC4() kc = KeyChain('in the heaven, we are equal', rc4) print(data) # 加码 encoded_data = kc.encode_bytes(data) print(encoded_data,len(encoded_data) ) # 解码 decoded_data = kc.decode_bytes(encoded_data) print(data, decoded_data, decoded_data==data)