test_decoder_kora.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. # %%
  2. import csv
  3. '''
  4. ## Premessa 1
  5. La mia prima versione di convertitore è stata fatta ad occhio. Ora, tornando sulla questione, ho individuato funzioni _built-in_ (e quindi, in teoria, altamente ottimizzate) che fanno il grosso del lavoro: in particolare:
  6. - int
  7. - hex
  8. - chr
  9. - ord
  10. '''
  11. '''
  12. ## Premessa 2
  13. *Unicode* assegna ad 'ogni' (o meglio: ad un numero parecchio grande di) carattere un codice numerico. Seguendo lo standard, il codice Unicode di un carattere si scrive 'U+' seguito da un numero _esadecimale_ da 4 a 6 cifre (con le prime cifre che possono essere zeri).
  14. Ad esempio, le lettere latine maiuscole A-Z sono rappresentate dai codici
  15. U+0041 -- U+005A
  16. e le minuscole dai codici
  17. U+0061 -- U+007A .
  18. I codici dei primi 128 caratteri (da U+0000 a U+007F) corrispondono ai codici ASCII degli stessi caratteri.
  19. Questi codici hanno anche una versione _decimale_, che si ottiene semplicemente convertendo il numero dopo 'U+' da base 16 a base 10. Per fare la conversione in GATTO, ci occorrono entrambe le versioni.
  20. '''
  21. # %%
  22. # 1. Le funzioni 'int' e 'hex' permettono di convertire al volo numeri decimali in esadecimali e viceversa.
  23. # Da esadecimale a int:
  24. print('Da base 16 a base 10:', int("AF", 16) )
  25. # Da int a esadecimale:
  26. print ('Da base 10 a base 16 -- notare il prefisso:', hex(175) )
  27. '''
  28. Note:
  29. 1. In 'int', il secondo parametro specifica la base: la funzione può essere usata anche per convertire numeri da altre basi.
  30. 2. Sempre in 'int', l'input va dato come stringa, per evitare che il Python lo interpreti come variabile data la possibile presenza di lettere. La string *non* è case-sensitive.
  31. 3. In 'hex', si può notare che l'output ha un prefisso '0x'. Questo serve per specificare
  32. '''
  33. # Altri esempi:
  34. print('La stringa in int ignora il prefisso:', int('0xaf', 16) )
  35. print('e non è case-sensitive:', int('Af', 16) )
  36. # %%
  37. # Le funzioni 'ord' e 'chr' convertono un carattere nel suo codice Unicode *DECIMALE* e viceversa.
  38. print( 'Il codice decimale non è (chiaramente) uguale a quello esadecimale, altrimenti il prossimo carattere sarebbe una A:' )
  39. print( chr(41) )
  40. print( 'Ma combinando chr ed int:' )
  41. print( chr(int("41", 16)) )
  42. # %%
  43. # Credo convenga caricare 'vettSpec' una volta per tutte invece che inserire il caricamento della tabella nella funzione:
  44. with open("vettSpec.csv", 'r') as file1:
  45. reader = csv.DictReader(file1)
  46. vettSpec = [row for row in reader]
  47. # %%
  48. # Una volta che uno ha vettSpec, la conversione *di un singolo carattere* si fa in 3 passaggi:
  49. def db_decode(string0):
  50. res = ""
  51. for char0 in string0:
  52. #1
  53. char0Dec = ord(char0) # Dal carattere al codice Unicode DECIMALE corrispondente
  54. #2
  55. char0ConvDec = next((el['unicode'] for el in vettSpec if el['intcode'] == str(char0Dec)), None) # Il codice DECIMALE (passato come stringa) viene ricercato in vettSpec, ritornando l'Unicode ESADECIMALE del carattere decriptato o None se non c'è riscontro -- il che non DOVREBBE succedere.
  56. #3
  57. res += chr(int(char0ConvDec, 16)) # Si converte il codice esadecimale a decimale e si usa la built-in chr per recuperare il carattere
  58. return res
  59. def db_encode(string0):
  60. res = ""
  61. for char0 in string0:
  62. #1
  63. char0Hex = hex(ord(char0)) # Dal carattere al codice Unicode ESADECIMALE corrispondente
  64. #2
  65. char0ConvDec = next((el['intcode'] for el in vettSpec if el['unicode'] == char0Hex[2:].upper()), None) # Il codice ESADECIMALE, senza il prefisso '0x' (rimosso tramite [2:]) e convertito in maiuscole per rispettare il formato di vettSpec, viene ricercato in vettSpec, ritornando l'Unicode DECIMALE del carattere criptato o None se non c'è riscontro -- il che non DOVREBBE succedere.
  66. #3
  67. res += chr(int(char0ConvDec)) # Si usa la built-in chr per recuperare il carattere
  68. return res
  69. # %%
  70. # Test:
  71. testEncrNorm = 'КѢӗГԂғМϩϩ'
  72. testEncrSpec = 'ГѢӗГԂғМϩϩ'
  73. testDecrNorm = db_decode(testEncrNorm)
  74. testDecrSpec = db_decode(testEncrSpec)
  75. print( testDecrNorm )
  76. print( testDecrSpec )
  77. print( db_encode(testDecrNorm) )
  78. print( db_encode(testDecrSpec) )
  79. # %%
  80. # Altri test:
  81. testdec = 'ӗЫГҨғϩҘМϩӲѢҨҘ'
  82. testenc = "recomandaţion"
  83. testdec2 = 'ӻ'
  84. testenc2 = "çà"
  85. print( db_decode(testdec) )
  86. print( db_encode(testenc) )
  87. print( db_decode(testdec2) )
  88. print( db_encode(testenc2) )
  89. # %%
  90. # La prova sui testi!
  91. # %%
  92. def GenerateKeyParam(sigla, parametersObj):
  93. vals = []
  94. vals.append(parametersObj[sigla]['notea'])
  95. vals.append(parametersObj[sigla]['noteb'])
  96. vals.append(parametersObj[sigla]['notec'])
  97. partial = vals[0] + vals[1]
  98. keyLength = 50 + (vals[2] % 300)
  99. if (keyLength // 2) * 2 != keyLength:
  100. keyLength = keyLength + 1
  101. seed = partial % (vals[2] + 123)
  102. return seed, keyLength
  103. # %%
  104. priva = {'p07': {'notea': 557968080, 'noteb': 8457403318, 'notec': 561881}}
  105. print( GenerateKeyParam('p07', priva) )
  106. with open("key_p07.csv", 'r') as file1:
  107. aaa = csv.reader(file1)
  108. key_p07 = [int(val[0]) for val in aaa]
  109. with open('../../../db/ndg2.gat4/itxt/p07', 'rb') as file1:
  110. file1.seek(4)
  111. p07 = file1.read().decode(encoding="utf-32-le")
  112. # %%
  113. def code(char0, shift):
  114. return chr(ord(char0) + shift)
  115. def decodeText(text, key, startInFile):
  116. initialOffset = startInFile % len(key)
  117. res = ""
  118. for k, char0 in enumerate(text):
  119. offset = k + initialOffset
  120. if offset >= len(key):
  121. offset = offset % len(key)
  122. res += code(char0, -key[offset])
  123. return res
  124. # %%
  125. p07micro = p07[:100]
  126. ii = 0
  127. for char in p07micro:
  128. ii = ii+1
  129. if ii>20:
  130. break
  131. print(ii, ord(char), char)
  132. # %%
  133. decodeText(p07micro, key_p07, 6)
  134. # %%
  135. def CifraS(stringa, StartInFile, key, verso):
  136. # Cifra o decifra una stringa
  137. # StartInFile = posizione, all'interno del testo cifrato, del primo carattere della stringa da cifrare (base 1)
  138. # stringa = stringa da cifrare o decifrare
  139. # verso = 1 => cifra; 2 => decifra
  140. # FirstInStringa = indice del primo byte considerato all'interno del vettore da decifrare
  141. # LastInStringa = indice dell'ultimo byte considerato all'interno del vettore da decifrare
  142. # PosizInKey = indice del primo carattere da utilizzare all'interno della chiave fissa
  143. NumCharsToConv = 0
  144. LastInStringa = 0
  145. LengKey2 = len(key) // 2
  146. while LastInStringa < len(stringa):
  147. StartInFile = StartInFile + NumCharsToConv
  148. NumKeyAppl = 1 + (StartInFile - 1) // LengKey2
  149. FirstInStringa = LastInStringa + 1
  150. PosizInKey = StartInFile % LengKey2
  151. if PosizInKey == 0:
  152. PosizInKey = LengKey2
  153. MaxCharsToConv = len(key) - PosizInKey + 1
  154. if MaxCharsToConv > LengKey2 - PosizInKey + 1:
  155. MaxCharsToConv = LengKey2 - PosizInKey + 1
  156. NumCharsToConv = len(stringa) - FirstInStringa + 1
  157. if NumCharsToConv > MaxCharsToConv:
  158. NumCharsToConv = MaxCharsToConv
  159. LastInStringa = FirstInStringa + NumCharsToConv - 1
  160. for k in range(FirstInStringa - 1, LastInStringa):
  161. if verso == 1:
  162. stringa = stringa[:k] + chr(ord(stringa[k]) + key[PosizInKey-1]) + stringa[k+1:]
  163. else:
  164. stringa = stringa[:k] + chr(ord(stringa[k]) - key[PosizInKey-1]) + stringa[k+1:]
  165. print("Stringa: "+stringa)
  166. PosizInKey += 1
  167. return stringa
  168. # %%
  169. CifraS(p07micro, 1, key_p07, 1)
  170. # %%
  171. ## ANCORA!
  172. ###
  173. # %%
  174. def code(char0, shift):
  175. return chr(ord(char0) + shift)
  176. def decodeText(text, key, startInFile):
  177. initialOffset = startInFile % len(key)
  178. res = ""
  179. for k, char0 in enumerate(text):
  180. offset = k + initialOffset
  181. if offset >= len(key):
  182. offset = offset % len(key)
  183. res += code(char0, -key[offset])
  184. return res
  185. def CifraS(stringa, StartInFile, key, verso):
  186. # Cifra o decifra una stringa
  187. # StartInFile = posizione, all'interno del testo cifrato, del primo carattere della stringa da cifrare (base 1)
  188. # stringa = stringa da cifrare o decifrare
  189. # verso = 1 => cifra; 2 => decifra
  190. # FirstInStringa = indice del primo byte considerato all'interno del vettore da decifrare
  191. # LastInStringa = indice dell'ultimo byte considerato all'interno del vettore da decifrare
  192. # PosizInKey = indice del primo carattere da utilizzare all'interno della chiave fissa
  193. NumCharsToConv = 0
  194. LastInStringa = 0
  195. LengKey2 = len(key) // 2
  196. while LastInStringa < len(stringa):
  197. StartInFile = StartInFile + NumCharsToConv
  198. #NumKeyAppl = 1 + (StartInFile - 1) // LengKey2
  199. FirstInStringa = LastInStringa + 1
  200. PosizInKey = StartInFile % LengKey2
  201. if PosizInKey == 0:
  202. PosizInKey = LengKey2
  203. MaxCharsToConv = len(key) - PosizInKey + 1
  204. if MaxCharsToConv > LengKey2 - PosizInKey + 1:
  205. MaxCharsToConv = LengKey2 - PosizInKey + 1
  206. NumCharsToConv = len(stringa) - FirstInStringa + 1
  207. if NumCharsToConv > MaxCharsToConv:
  208. NumCharsToConv = MaxCharsToConv
  209. LastInStringa = FirstInStringa + NumCharsToConv - 1
  210. for k in range(FirstInStringa - 1, LastInStringa):
  211. if verso == 1:
  212. stringa = stringa[:k] + chr(ord(stringa[k]) + key[PosizInKey-1]) + stringa[k+1:]
  213. else:
  214. stringa = stringa[:k] + chr(ord(stringa[k]) - key[PosizInKey-1]) + stringa[k+1:]
  215. #print("Stringa: "+stringa)
  216. PosizInKey += 1
  217. return stringa
  218. # %%
  219. # Tira fuori la chiave A FORZA!
  220. with open('../../../db/ndg2.gat4/itxt/p07', 'rb') as file1:
  221. file1.seek(4)
  222. p07_enc = file1.read().decode(encoding="utf-32-le")
  223. with open('../../../db/first_db/itxt/p07', 'rb') as file1:
  224. file1.seek(4)
  225. p07_dec = file1.read().decode(encoding="utf-32-le")
  226. # %%
  227. # Stesso testo? Check lunghezza!
  228. len(p07_enc)==len(p07_dec)
  229. # %%
  230. ii = 0
  231. for char in p07_dec[:1000]:
  232. ii = ii+1
  233. if ii>20:
  234. break
  235. print(ii, ord(char), char)
  236. caz_dec = [ord(char) for char in p07_dec[:1000]]
  237. caz_enc = [ord(char) for char in p07_enc[:1000]]
  238. # %%
  239. appela = []
  240. for i in range(len(caz_dec)):
  241. appela.append(caz_enc[i] - caz_dec[i])
  242. # %%
  243. with open('matto.csv', 'w') as file1:
  244. wtr = csv.writer(file1)
  245. for row in appela:
  246. wtr.writerow([row])
  247. # %%
  248. affa = appela[:332]
  249. nculo = appela[332:664]
  250. # %%
  251. affa == nculo
  252. # %%
  253. min(appela)
  254. # %%
  255. with open('furioso.csv', 'w') as file1:
  256. wtr = csv.writer(file1)
  257. for row in appela[:332]:
  258. wtr.writerow([row])
  259. # %%
  260. # Ok, 'furioso.csv' è -- sperabilmente -- la chiave
  261. # Riapro furioso
  262. with open('furioso.csv', 'r') as file1:
  263. rdr = csv.reader(file1)
  264. affa2 = [int(row[0]) for row in rdr]
  265. # %%
  266. decodeText(p07_enc[:100], affa2, 0)
  267. # %%
  268. chiaro = decodeText(p07_enc, affa2, 0)
  269. print(chiaro)
  270. # %%
  271. CifraS(p07_enc[:100], 1, affa2, 2) == decodeText(p07_enc[:100], affa2, 0)
  272. # ... e funziona!
  273. # %%
  274. '''
  275. Programmino in VB che DOVREBBE tirar fuori la chiave (è copiato praticamente verbatim da GeneraKey di Gatto4), ma non lo fa -- differenza di implementazione di Rnd? Altro?
  276. Module VBModule
  277. Sub Main()
  278. Dim k, a, dato, iniziale, valore(3) As Integer
  279. Dim LengKey, KeyBody() as Integer
  280. valore(1) = 557968080
  281. valore(2) = 845740318
  282. valore(3) = 561881
  283. dato = valore(1) + valore(2)
  284. LengKey = 50 + (valore(3) Mod (300))
  285. If (LengKey \ 2) * 2 <> LengKey Then LengKey = LengKey + 1
  286. ReDim KeyBody(LengKey)
  287. iniziale = dato Mod (valore(3) + 123)
  288. a = Rnd(-1)
  289. Randomize(iniziale)
  290. Console.WriteLine("Iniziale: " + Str(iniziale))
  291. Console.WriteLine("Lunghezza chiave: " + Str(LengKey))
  292. For k = 1 To LengKey
  293. KeyBody(k) = 1000 * Rnd()
  294. Console.WriteLine(Str(k) + ": " + Str(KeyBody(k)))
  295. Next k
  296. End Sub
  297. End Module
  298. '''
  299. # %%
  300. # Un esperimento
  301. aVB = 1140671485
  302. cVB = 12820163
  303. mVB = 2**24
  304. aMS = 214013
  305. cMS = 2531011
  306. mMS = 2**31
  307. class randomLCG:
  308. def __init__(self, a=134775813, c=1, m=2**32, seed=0):
  309. self.seed = seed
  310. self._initial_seed = seed
  311. self.a = a
  312. self.c = c
  313. self.m = m
  314. def random(self):
  315. pre = (self.a*self.seed + self.c) % self.m
  316. self.seed = pre
  317. return pre/self.m
  318. def setSeed(self, seed):
  319. self.seef = seed
  320. def reset(self):
  321. self.seed = self._initial_seed
  322. # %%
  323. seed0 = 384410
  324. rnd1 = randomLCG(seed=seed0)
  325. rnd2 = randomLCG(aVB, cVB, mVB, seed0+327680)
  326. rnd3 = randomLCG(aMS, cMS, mMS, seed=seed0)
  327. # %%
  328. rnd1.reset()
  329. for ind in range(4):
  330. print( round(1000*rnd1.random()) )
  331. # %%
  332. rnd2.reset()
  333. for ind in range(4):
  334. print( round(1000*rnd2.random()) )
  335. # %%
  336. rnd3.reset()
  337. for ind in range(4):
  338. print( round(1000*rnd3.random()) )
  339. # %%
  340. # THE LAST TEST
  341. import csv
  342. def getKeyByCode(keyFile):
  343. with open(keyFile, 'r') as file1:
  344. reader = csv.reader(file1)
  345. key = [int(row[0]) for index, row in enumerate(reader) if index>1]
  346. # Apparently, only the first half of the key is actually used!
  347. halfKeyLen = len(key)//2
  348. key=key[:halfKeyLen]
  349. return key
  350. def decodeTextByKey(text, key, startInFile):
  351. initialOffset = startInFile % len(key)
  352. res = ""
  353. for k, char0 in enumerate(text):
  354. offset = k + initialOffset
  355. if offset >= len(key):
  356. offset = offset % len(key)
  357. try:
  358. res += shiftchar(char0, -key[offset])
  359. except:
  360. res+=' -- Error in key!'
  361. break
  362. return res
  363. #
  364. def codeTextByKey(text, key, startInFile):
  365. initialOffset = startInFile % len(key)
  366. res = ""
  367. for k, char0 in enumerate(text):
  368. offset = k + initialOffset
  369. if offset >= len(key):
  370. offset = offset % len(key)
  371. try:
  372. res += shiftchar(char0, +key[offset])
  373. except:
  374. res+=' -- Error in key!'
  375. break
  376. return res
  377. #
  378. def shiftchar(char0, shift):
  379. return chr(ord(char0) + shift)
  380. # %%
  381. from os import listdir
  382. keyPath = 'keys/'
  383. itxtPath = '../../../db/ndg2.gat4/itxt/'
  384. files = listdir(keyPath)
  385. keyFiles = [file for file in files if (file.startswith('key_') and file.endswith('.csv'))]
  386. keys = {}
  387. files = {}
  388. for keyFile in keyFiles:
  389. code = keyFile.replace('key_', '').replace('.csv', '')
  390. try:
  391. keys[code] = getKeyByCode(keyPath+keyFile)
  392. with open('../../../db/ndg2.gat4/itxt/'+code, 'rb') as file1:
  393. file1.seek(4)
  394. files[code] = file1.read().decode(encoding="utf-32-le")
  395. except:
  396. pass
  397. #
  398. codes = keys.keys()
  399. # %%
  400. import random
  401. decoded = {}
  402. for ind, code in enumerate(codes):
  403. rand1 = random.randint(1, 15)
  404. rand2 = random.randint(1, 15)+500
  405. decoded[code] = decodeTextByKey(files[code][rand1:rand2], keys[code], rand1)
  406. print(ind, code)
  407. print(decoded[code])
  408. print()
  409. # %%
  410. codes
  411. # %%
  412. decoded['fq']
  413. # %%