mirror of
https://github.com/Inndy/twnhi-smartcard-agent.git
synced 2025-07-17 20:53:22 +00:00
First public release
This commit is contained in:
121
cryptos.py
Normal file
121
cryptos.py
Normal file
@ -0,0 +1,121 @@
|
||||
# This file is part of twnhi-smartcard-agent.
|
||||
#
|
||||
# twnhi-smartcard-agent is free software: you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# twnhi-smartcard-agent is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with twnhi-smartcard-agent.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import datetime
|
||||
import hashlib
|
||||
from Cryptodome.Cipher import DES, DES3
|
||||
|
||||
bKEY = b'12345678123456780' * 10
|
||||
K_BOX = [
|
||||
0x56, 0x28, 0x34, 0x2E, 0x78, 0x5, 0xF, 0x5A,
|
||||
0x36, 0x44, 0x42, 0x19, 0x26, 0x95, 0x26, 0x4D,
|
||||
0x3, 0x10, 0x15, 0x58, 0x3, 0x40, 0x5A, 0x72,
|
||||
0x1E, 0xB, 0x49, 0x69, 0x4B, 0x15, 0x29, 0x6
|
||||
]
|
||||
K_BOX1 = [
|
||||
0x56, 0x28, 0x34, 0x2E, 0x78, 0x5, 0xF, 0x5A,
|
||||
0x36, 0x44, 0x42, 0x19, 0x26, 0x95, 0x26, 0x4D,
|
||||
0x2D, 0x41, 0x4D, 0x1F, 0x41, 0x62, 0x15, 0x2F
|
||||
]
|
||||
|
||||
L_KEY = bytes(bKEY[K_BOX[i]] for i in range(16)) + b'\0' * 8
|
||||
L_KEY1 = bytes(bKEY[K_BOX1[i]] for i in range(24))
|
||||
|
||||
KEY_SUFFIX = b'\x27\x06\x58\x66'
|
||||
|
||||
TDesLKey = DES3.new(L_KEY, DES3.MODE_ECB)
|
||||
TDesLKey1 = DES3.new(L_KEY1, DES3.MODE_ECB)
|
||||
|
||||
def iv_pad(d):
|
||||
def rand_byte():
|
||||
return os.urandom(1)
|
||||
bcount = len(d) // 7
|
||||
if len(d) % 7:
|
||||
bcount += 1
|
||||
|
||||
blocks = [ d[i*7:i*7 + 7].ljust(7, b'\0') + rand_byte() for i in range(bcount) ]
|
||||
return b''.join(blocks)
|
||||
|
||||
def iv_remove(d, flag=True):
|
||||
c = b''.join(d[i*8:i*8+7] for i in range(len(d) // 8))
|
||||
if flag:
|
||||
unpad_size = (len(c) // 8) * 8
|
||||
return c[:unpad_size]
|
||||
return c
|
||||
|
||||
def pkcs5_tail(n):
|
||||
return bytes([n]) * n
|
||||
|
||||
def pkcs5_pad(data):
|
||||
padding_size = 8 - len(data) % 8
|
||||
return data + pkcs5_tail(padding_size)
|
||||
|
||||
def pkcs5_unpad(data):
|
||||
last_byte = data[-1]
|
||||
tail = data[-last_byte:]
|
||||
if last_byte > 8 or bytes(tail) != pkcs5_tail(last_byte):
|
||||
raise ValueError('Inalid PKCS5 padding')
|
||||
return data[:-last_byte]
|
||||
|
||||
def card_encrypt(data, cardid):
|
||||
t = datetime.date.today().strftime('%Y%m%d')
|
||||
tdeskey = hashlib.sha1((cardid + t).encode('ascii')).digest() + KEY_SUFFIX
|
||||
cipher = DES3.new(tdeskey, DES3.MODE_ECB)
|
||||
|
||||
data = cipher.encrypt(pkcs5_pad(data))
|
||||
return TDesLKey1.encrypt(iv_pad(data))
|
||||
|
||||
def card_decrypt(data, cardid):
|
||||
t = datetime.date.today().strftime('%Y%m%d')
|
||||
tdeskey = hashlib.sha1((cardid + t).encode('ascii')).digest() + KEY_SUFFIX
|
||||
cipher = DES3.new(tdeskey, DES3.MODE_ECB)
|
||||
|
||||
data = TDesLKey1.decrypt(data)
|
||||
data = iv_remove(data)
|
||||
data = cipher.decrypt(data)
|
||||
return pkcs5_unpad(data)
|
||||
|
||||
def basic_encrypt(data):
|
||||
key = datetime.date.today().strftime('%m%d%Y').encode('ascii')
|
||||
cipher = DES.new(key, DES.MODE_ECB)
|
||||
return cipher.encrypt(iv_pad(data))
|
||||
|
||||
def basic_decrypt(data):
|
||||
key = datetime.date.today().strftime('%m%d%Y').encode('ascii')
|
||||
cipher = DES.new(key, DES.MODE_ECB)
|
||||
decrypted = cipher.decrypt(data)
|
||||
return iv_remove(decrypted, False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
data, card_id = b'123456123456', '000000000001'
|
||||
if card_decrypt(card_encrypt(data, card_id), card_id) == data:
|
||||
print('card_* : Pass')
|
||||
else:
|
||||
print('card_* : Failed')
|
||||
|
||||
for i in range(40, 40+2*6):
|
||||
test_data = bytes(range(i))
|
||||
if basic_decrypt(basic_encrypt(test_data + b'\xff')).split(b'\xff')[0] != test_data:
|
||||
print('basic_* : Failed')
|
||||
break
|
||||
else:
|
||||
print('basic_* : Pass')
|
||||
|
||||
import sys
|
||||
if len(sys.argv) > 1:
|
||||
data = bytes.fromhex(sys.argv[1])
|
||||
print(basic_decrypt(data).decode('big5-hkscs'))
|
Reference in New Issue
Block a user