U.S. Cyber Command Valentine’s Day 2021 Crypto Challenge

Pour la Saint Valentin 2021, l'U.S. Cyber Command propose dans un tweet de résoudre une douzaine de puzzles de cryptographie. Cliquez ici pour les récupérer. Une excellente initiative qui suscitera peut-être des vocations...
Pourquoi ne pas s'y essayer ? Nous verrons bien où cela nous mène... Je publierai sur ce site les solutions auxquelles je serai parvenu, sous la forme des notes prises chemin faisant, rendant donc compte d'éventuels errements, ce qui sera plus vivant.
Après avoir consacré pas mal de temps à ces puzzles, je n'en ai résolu que deux : le puzzle 7 et le puzzle 9. Pour les autres, j'ai dégagé des pistes. Comme je dois m'arrêter là pour passer à autre chose, voici ces pistes. Cela aidera peut-être ceux qui sont en galère, et qui voudront pousser plus loin que moi. Je ne fournis pas tout le code que j'ai écrit pour tester de nombreuses solutions...
Bien entendu, le jeu est de parvenir à trouver les solutions tout seul. Je m'y emploierai de nouveau à l'occasion, et je publierai les solutions si j'en trouve...
Pour trouver une solution à un puzzle, il semble possible de poursuivre deux stragégies :
  • chercher la solution au puzzle ;
  • chercher comment le puzzle a été conçu.
Le premier réflexe est d'adopter la première stratégie. Mais partant du principe que le puzzle a été conçu pour être résolu, il est certainement possible de rendre cette première stratégie plus efficace en s'appuyant sur les résultats de la mise en oeuvre de la seconde, qui viennent restreindre l'éventail des solutions possibles.
Par exemple, pour résoudre le puzzle 0, il est sans doute intéressant de se demander pourquoi les caractères en majuscules figurent là où ils sont. Ou encore, dans le puzzle 8, se demander pourquoi la palette contient 55 couleurs.

Puzzle résolus

Pour l'heure, j'ai trouvé les solutions des puzzles 2, 3, 5, 7 et 9. L'assemblage des images récupérées produit l'image suivante :

Puzzle 0

La concaténation des caractères figurant en majuscules forme la chaîne "RPASSWOD MIXSWAP".
Le flag fait 13 caractères, 2 mots, ce qui signifie 12 caractères et un espace. La chaîne est donc trop longue pour y correspondre, mais elle est aussi trop courte pour se déchiffrer en une phrase du style "The flag is: FLAG".
Cela, et la mention à "MIXSWAP", fait pencher pour un chiffrage par substitution, où des caractères seraient remplacés par des espaces.
Toutefois, j'ai épuisé les délices des chiffres de César et de Vigenère sans rien trouver...
Pourtant, la solution est nécessairement simple, car c'est le premier puzzle.

Puzzle 1

L'image comprend 135 croix. Une codification permet de déterminer qu'il en existe de 16 types, selon :
  • la couleur du "/" ;
  • la couleur du "\" ;
  • la priorité du "/" sur le "\".
D'aileurs cette codification permet de produire une image un peu plus lisible, en utilisant des couleurs bien contrastées :
# - 1 quand il n'y a pas de croix, sinon de 0 à 3 selon la couleur du "/"
slashes = [
	1, 3, 0, 3, 2, 3, -1, -1, 3, 1, 3, -1, -1, -1, 0, 1, 3, -1, -1, 3, 0, -1, -1, 3, 1,
	3, 1, 3, 0, 0, 1, -1, 3, 2, 0, 1, 0, -1, 0, 3, 2, 0, 2, -1, 1, 3, -1, -1, 0, 3,
	-1, -1, 3, 1, -1, -1, -1, 3, 3, 1, 3, 1, 3, 0, 3, 0, 3, 3, -1, 0, 3, -1, -1, 1, 3,
	-1, -1, 3, 0, -1, -1, -1, 3, 0, 0, 3, 3, 1, 0, 0, 3, 3, 1, -1, 3, 3, -1, -1, 0, 1,
	-1, -1, 1, 1, -1, -1, -1, -1, 2, 0, 3, 0, 0, 3, 1, 1, 1, -1, -1, 0, 3, -1, -1, 3, 3,
	-1, -1, 2, 0, -1, -1, -1, -1, -1, 1, 3, 1, 1, 3, 1, 3, -1, -1, -1, 3, 1, -1, -1, 2, 3,
	-1, -1, 0, 3, -1, -1, -1, -1, -1, -1, 0, 2, 3, 0, 0, -1, -1, -1, -1, 1, 3, -1, -1, 3, 1,
	0, 1, 3, 1, 1, 3, -1, -1, -1, -1, -1, 0, 0, 3, -1, -1, -1, -1, -1, 1, 0, 3, 1, 3, 3,
	3, 3, 3, 0, 0, 3, -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 0, 3, 0, 3, -1,
]
# - 1 quand il n'y a pas de croix, sinon de 0 à 3 selon la couleur du "\"
backslashes = [
	3, 0, 3, 1, 2, 0, -1, -1, 0, 3, 1, -1, -1, -1, 0, 2, 1, -1, -1, 1, 0, -1, -1, 0, 3,
	0, 1, 0, 2, 3, 2, -1, 1, 2, 3, 2, 3, -1, 2, 0, 2, 3, 2, -1, 3, 0, -1, -1, 3, 1,
	-1, -1, 3, 3, -1, -1, -1, 0, 1, 3, 1, 1, 1, 2, 1, 0, 1, 1, -1, 2, 0, -1, -1, 1, 0,
	-1, -1, 0, 2, -1, -1, -1, 1, 2, 0, 0, 1, 2, 0, 3, 1, 0, 2, -1, 0, 3, -1, -1, 2, 3,
	-1, -1, 2, 3, -1, -1, -1, -1, 2, 2, 1, 3, 0, 1, 2, 2, 3, -1, -1, 0, 1, -1, -1, 0, 1,
	-1, -1, 2, 2, -1, -1, -1, -1, -1, 3, 1, 2, 2, 3, 2, 1, -1, -1, -1, 1, 3, -1, -1, 2, 0,
	-1, -1, 3, 0, -1, -1, -1, -1, -1, -1, 2, 2, 1, 2, 0, -1, -1, -1, -1, 2, 0, -1, -1, 0, 2,
	0, 2, 1, 3, 1, 1, -1, -1, -1, -1, -1, 0, 2, 1, -1, -1, -1, -1, -1, 2, 3, 1, 1, 1, 0,
	1, 0, 1, 0, 3, 0, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 2, 1, 0, 3, -1,
]
# -1 quand il n'y pas de croix, 1 quand "/" est par-dessus "\", 0 quand c'est l'inverse, 2 quand c'est indéfini car les croix sont de la même couleur
priorities = [
	1, 1, 1, 1, 2, 1, -1, -1, 1, 1, 0, -1, -1, -1, 2, 1, 0, -1, -1, 1, 2, -1, -1, 1, 0,
	1, 2, 1, 0, 0, 0, -1, 1, 2, 1, 0, 1, -1, 0, 1, 2, 1, 2, -1, 1, 1, -1, -1, 0, 0,
	-1, -1, 2, 1, -1, -1, -1, 0, 1, 0, 0, 2, 1, 0, 1, 2, 1, 1, -1, 0, 1, -1, -1, 2, 1,
	-1, -1, 0, 0, -1, -1, -1, 0, 0, 2, 1, 0, 1, 2, 1, 0, 0, 1, -1, 0, 2, -1, -1, 1, 1,
	-1, -1, 1, 1, -1, -1, -1, -1, 2, 1, 1, 0, 2, 1, 0, 0, 0, -1, -1, 2, 1, -1, -1, 0, 1,
	-1, -1, 2, 1, -1, -1, -1, -1, -1, 0, 0, 1, 0, 2, 1, 1, -1, -1, -1, 1, 1, -1, -1, 2, 1,
	-1, -1, 0, 0, -1, -1, -1, -1, -1, -1, 1, 2, 1, 1, 2, -1, -1, -1, -1, 1, 0, -1, -1, 0, 0,
	2, 1, 0, 1, 2, 1, -1, -1, -1, -1, -1, 2, 1, 0, -1, -1, -1, -1, -1, 0, 1, 0, 2, 1, 0,
	1, 0, 0, 2, 1, 0, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, 1, 1, 2, 2, -1,
]
WIDTH = 25
HEIGHT = 9
SIDE = 16
THICKNESS = 3
MARGIN = 5
colors = [
	(255, 0, 0, 255),		# rouge
	(0, 255, 0, 255),		# vert
	(128, 128, 128, 255),	# gris
	(255, 255, 255, 255)	# blanc
]

path = '../nsa/svr/puzzle-1/'
from PIL import Image, ImageDraw
image = Image.new ('RGBA', (WIDTH * (SIDE + MARGIN), HEIGHT * (SIDE + MARGIN)), (0, 0, 0, 255))
draw = ImageDraw.Draw (image)
for y in range (HEIGHT):
	for x in range (WIDTH):
		i = y * WIDTH + x
		if priorities[i] == -1:
			continue
		if priorities[i] == 0:
			draw.line (
				(x * (SIDE + MARGIN) + SIDE, y * (SIDE + MARGIN), x * (SIDE + MARGIN), y * (SIDE + MARGIN) + SIDE),
				fill=colors[slashes[i]],
				width=THICKNESS
			)
			draw.line (
				(x * (SIDE + MARGIN), y * (SIDE + MARGIN), x * (SIDE + MARGIN) + SIDE, y * (SIDE + MARGIN) + SIDE),
				fill=colors[backslashes[i]],
				width=THICKNESS
			)
		else:
			draw.line (
				(x * (SIDE + MARGIN), y * (SIDE + MARGIN), x * (SIDE + MARGIN) + SIDE, y * (SIDE + MARGIN) + SIDE),
				fill=colors[backslashes[i]],
				width=THICKNESS
			)
			draw.line (
				(x * (SIDE + MARGIN) + SIDE, y * (SIDE + MARGIN), x * (SIDE + MARGIN), y * (SIDE + MARGIN) + SIDE),
				fill=colors[slashes[i]],
				width=THICKNESS
			)
image.save (f'{path}check.png')
Ce qui donne :
Il y a 16 types de croix, dont pourquoi ne pas remplacer chacune par une des 16 valeurs sur 4 bits de l'hexadécimal, en espérant que cela permette de reconstituer sur les codes ASCII de caractères imprimables sur 8 bits - c'est-à-dire compris entre 0x20 et 0x7e. Certes, mais il y a 135 croix, ce qui n'est pas multiple de 2...
Plusieurs types de croix ne figurent jamais. Il est intéressant de noter que ce sont des couples de couleurs, que le "/" se trouve devant ou derrière le "\". Mais une mise en forme dans l'espoir de dégager une forme de carré de Polybe ne débouche sur rien de flagrant :
Une attaque en fréquence, ciblée sur un passage où deux croix identiques se suivent, par recherche d'un mot court dont comprenant deux caractères identiques consécutifs comme on peut en trouver la liste ici, ne débouche sur rien. Mais je l'ai peut-être mal conduite...

Puzzle 4

Une transposition de colonnes ? Il est vrai qu'on semble pouvoir constituer le mot "PUZZLE" sur la première ligne, mais dans les faits, transposer les colonnes ne suffit pas.
Au cas où, j'ai codé cet outil pour tester des transpositions manuellement.

Puzzle 6

pngcheck ne détecte rien d'anormal, et un examen manuel du fichier dans HxD non plus.
On dirait un texte en Base64 mutilé.
Extraction du texte :
K_Feg_ff_OG2_AS_iPb_C_NqDng_n5_yG3_B_gel5_e_L6B_WM_ne_AG7_Cn_0dL_O_Wt_Feg_fv_M_Nxa

KzUId_p_Q_N4leh7H_u_L0io3JL_M_1qzm_zBL_M_Nwimw_1q_c_20zKgt_l_u_P0DehB_d_e_01_Dm_ud9_oG0zUIdz_e_LY_na

W_E_o_udr_m_J5zUId_p_u_P0DoYd_t_GG2_BKhJH_e_WqDngPb_i_QW_E_pw_9_t_OG3_B_ge_L_N_k_RW_nbG

W_D_o_edf_M_VY_Beg_Tv_EGZAS_4_f_t_u_WZ_kn_4_Zb_o_X3_Ff_I_s
Dans cette hypothèse, les caractères du Base64 qui n'apparaissent pas sont "8", "j", "+" et "/". C'est un bien petit jeu de caractères pour remplacer les 97 coeurs. En effet, la fréquence moyenne de ces caractères serait alors proche de 25, ce qui est netttement plus élevé que celle des caractères du texte : le caractère le plus fréquent est "e", et il n'apparaît que 13 fois...
Tenter de les substituer au premier coeur de la second phrase ne permet pas de décoder du texte, mais du binaire. Après, il est possible que le décodage du Base64 ne constitue qu'une étape du puzzle...
Si jamais c'était un texte en Base64 mutilé, il serait possible d'en décoder des parties. En effet, le décodage consiste à remplacer chaque caractère du texte Base64 par 6 bits, puis à découper la séquence de bits ainsi formée par paquets de 8 pour retrouver des octets. Par conséquent, dans une ligne, toute chaîne qui débute après n caractères, tel que n * 6 est multiple de 8, peut être décodée indépendamment de ces n caractères. Par exemple, pour toutes les chaînes d'au moins 4 caractères présumés Base64, cela donne (version corrigée, après que j'ai constaté une erreur dans mon programme Python) :
00-05	KzUI		b'+5\x08'
12-17	leh7		b'\x95\xe8{'
20-27	L0io3JL=	b'/H\xa8\xdc\x92'
52-58	20zKgt==	b'\xdbL\xca\x82'
64-69	0Deh		b'\xd07\xa1'
84-92	oG0zUIdz	b'\xa0m3P\x87s'
12-18	J5zUId==	b"'\x9c\xd4!"
24-29	0DoY		b'\xd0:\x18'
36-41	BKhJ		b'\x04\xa8I'
44-51	WqDngPb=	b'Z\xa0\xe7\x80\xf6'
Bref, à chaque fois du binaire, ce qui renforce l'hypothèse présentée plus tôt.

Puzzle 8

pngcheck ne détecte rien d'anormal, et un examen manuel du fichier dans HxD non plus.
Les deux dernières lignes de texte composant le dessins sont différentes. Entourées de drapeaux, ce sont des séquences de paires d'entiers. Les paires d'une séquence sont séparées par ,, et les séquences séparées par ,,,.
Une extraction des séquences :
06:07 07:07 18:07 04:00 06:07 07:22
09:00 08:52 10:37 19:22 23:52
06:07 22:37 16:30 07:45 23:52
22:37 19:22 10:30 19:45 06:07 04:45
10:37 16:45
19:30
07:22 07:30 19:22 08:52 04:45 18:07 10:30 20:52 07:22 06:00
Le flag fait 41 caractères, 7 mots, ce qui signifie 35 caractères et 6 espaces. Il y autant de paires que de caractères dans le flag, et autant de séquences que de mots dans le flag. Hypothèse que le déchiffrement d'une paire donne un caractère du flag...
Le premier nombre d'une paire compris entre 4 et 23, le second est compris entre 0 et 52. Notation décimale ou hexadécimale, limitée aux chiffres ? Plusieurs éléments font pencher pour le décimal :
  • Si les seconds nombres sont considérés comme décimaux, ils forment les termes d'une suite arithmétique dont la raison alterne entre 7 et 8, dont il manque simplement le 15 :
  • 0
    0 + 7 = 7
    7 + 8 = 15
    15 + 7 = 22
    22 + 8 = 30
    30 + 7 = 37
    37 + 8 = 45
    45 + 7 = 52
    
  • La palette de l'image comprend 55 couleurs. Si les nombres sont considérés décimaux, ils peuvent être les indices d'une couleur dans la palette. Ce point semble important, car il permet d'établir un lien entre le texte lu dans l'image, et l'image elle-même. Or nous en sommes au puzzle 8, et les puzzles nécessitent visiblement toujours plus de rentrer dans les fichiers pour y trouver de l'information, comme vu lors de la résolution du puzzle 7 et du puzzle 9.
Une extraction de la palette, qui donne les composantes R, G et B en décimal puis en héxadécimal :
00	(170, 85, 119)	AA:55:77
01	(170, 85, 136)	AA:55:88
02	(170, 85, 153)	AA:55:99
03	(170, 85, 170)	AA:55:AA
04	(170, 85, 102)	AA:55:66
05	(170, 102, 136)	AA:66:88
06	(170, 119, 136)	AA:77:88
07	(170, 136, 153)	AA:88:99
08	(170, 102, 153)	AA:66:99
09	(170, 136, 136)	AA:88:88
10	(170, 119, 153)	AA:77:99
11	(170, 102, 119)	AA:66:77
12	(204, 204, 204)	CC:CC:CC
13	(255, 255, 255)	FF:FF:FF
14	(187, 187, 187)	BB:BB:BB
15	(170, 153, 153)	AA:99:99
16	(170, 119, 119)	AA:77:77
17	(170, 153, 170)	AA:99:AA
18	(238, 255, 238)	EE:FF:EE
19	(238, 238, 238)	EE:EE:EE
20	(255, 238, 238)	FF:EE:EE
21	(238, 255, 255)	EE:FF:FF
22	(238, 238, 255)	EE:EE:FF
23	(255, 255, 238)	FF:FF:EE
24	(170, 153, 136)	AA:99:88
25	(255, 238, 255)	FF:EE:FF
26	(170, 170, 170)	AA:AA:AA
27	(221, 221, 221)	DD:DD:DD
28	(221, 221, 238)	DD:DD:EE
29	(238, 238, 221)	EE:EE:DD
30	(221, 238, 221)	DD:EE:DD
31	(187, 170, 170)	BB:AA:AA
32	(187, 187, 170)	BB:BB:AA
33	(187, 204, 187)	BB:CC:BB
34	(187, 204, 204)	BB:CC:CC
35	(204, 187, 204)	CC:BB:CC
36	(238, 221, 221)	EE:DD:DD
37	(204, 204, 187)	CC:CC:BB
38	(170, 187, 170)	AA:BB:AA
39	(170, 187, 187)	AA:BB:BB
40	(170, 170, 187)	AA:AA:BB
41	(204, 221, 204)	CC:DD:CC
42	(187, 170, 187)	BB:AA:BB
43	(238, 221, 238)	EE:DD:EE
44	(187, 187, 204)	BB:BB:CC
45	(170, 170, 153)	AA:AA:99
46	(204, 204, 221)	CC:CC:DD
47	(170, 136, 119)	AA:88:77
48	(204, 187, 187)	CC:BB:BB
49	(221, 238, 238)	DD:EE:EE
50	(221, 204, 204)	DD:CC:CC
51	(221, 204, 221)	DD:CC:DD
52	(221, 221, 204)	DD:DD:CC
53	(170, 102, 102)	AA:66:66
54	(204, 221, 221)	CC:DD:DD
La palette présente quelques particularités :
  • Chaque couleur est unique.
  • Les valeurs hexadécimales des composantes des couleurs sont toujours des répétitions de quadruplets : 0x00, 0x11, ..., 0xff.
L'enjeu, ce serait de trouver le moyen de combiner les deux triplets de valeurs des composantes des couleurs pointées par une paire pour produire un caractère du flag.
Une attaque en fréquence doit-elle être exclue car elle permettrait de ne pas être obligé de faire de lien entre le texte et la palette pour trouver le flag ? C'est possible...

Puzzle 10

pngcheck permet de détecter des données supplémentaires après le chunck IEND. Leur extraction permet de récupérer un GZIP dont la décompression débouche sur la déclaration d'un tableau de chaînes, visiblement en Python :
['T', 'RD24', 'RD24', 'RD23', 'RD22', 'RL37', 'RL36', ...]
Exception faite de la première, les chaînes débutent toujours par : "RD", "RU", "RL" et "RR". Le nombre qui suit varie entre 2 et 40. Il n'y a pas de logique apparente dans la manière dont les chaînes se succèdent, ni dans la manière dont les nombre évoluent.
L'image est à base de gros "pixels", de 41 x 41. Après avoir résolu le puzzle 9, je pense que c'est un QR Code mutilé à l'aide d'un algorithme dont le tableau précédent - la liste dans la terminologie de Python - fournit les étapes.
L'algorithme n'est pas un automate cellulaire, car ce serait trop compliqué. Comme le nombre qui suit les chaînes est toujours inférieur ou égal à 40, je penche pour une tortue qui aurait été promenée aléatoirement dans les quatre directions que suggèrent les chaînes : "D" pour "Down", "U" pour "Up", etc. En se baladant, la tortue aurait inversé un ou des "pixels" sur son passage, par exemple le "pixel" à l'arrivée.
Quelle position de départ pour la tortue ? Comme le nombre mentionné à une étape - qui décrit donc l'amplitude d'un déplacement dans une direction donnée - est toujours inférieur ou égal à 40, qui est la coordonnée maximale dans un repère de 41 x 41, il est possible de faire l'hypothèse que le terrain n'est pas un tore. Dans ce cas, pour localiser la position de départ, il faut travailler à partir des déplacements d'ampitude maximale, car il est certain qu'une fois que la tortue a effectué l'un de ces déplacements, elle se retrouve sur un bord, ce qui réduit considérablement les possibilités.
Toutefois, une simulation du déplacement de la tortue à partir de (0, 0), en testant plusieurs interprétations des directions "U", "D", "R" et "L" combinées chaque fois une hypothèse de comportement de la tortue - elle tourne nécessairement sur elle-même à chaque étape, sans quoi elle aurait tôt fait de sortir du terrain - ne m'a pas permis de trouver un comportement où la tortue ne sort pas d'un terrain de 41 x 41.
Le code de cette simulation est le suivant. Il faut décommenter le comportement que l'on souhaite donner à la tortue :
# moves[] contient les 4 mouvements possibles pour la tortue selon ses 4 orientations possibles
moves = [
	[(0, -1), (1, 0), (0, 1), (-1, 0)],
	[(1, 0), (0, 1),  (-1, 0), (0, -1)],
	[(0, 1), (-1, 0), (0, -1), (1, 0)],
	[(-1, 0), (0, -1), (1, 0), (0, 1)]
]
import itertools
for d in itertools.permutations ([0, 1, 2, 3], 4):
	# directions[] décrit à quelle orientation dans move[] correspond une orientation lue ("U", "D", "R" ou "L")
	directions = {'U': d[0], 'R': d[1], 'D': d[2], 'L': d[3]}
	print (directions)
	# Pour une interprétation des directions lues données, déplacer la tortue à partir de chacune des 4 orientations initiales possibles
	for direction in range (4):
		pixels = []
		x = 0
		y = 0
		xMax = 0
		xMin = 0
		yMax = 0
		yMin = 0
		pixels.append ((x, y))
		for s in key[1:]:
			d = directions[s[1]]
			n = int (s[2:])
			x += moves[direction][d][0] * n
			y += moves[direction][d][1] * n
			# Après un déplacement, la tortue se tourne dans le sens du déplacement
			# direction = d
			# Après un déplacement, la tortue fait un quart de tour indépendamment du déplacement
			direction = (direction + 1) % 4
			# Après un déplacement, la tortue fait un demi-tour indépendamment du déplacement
			# direction = (direction + 2) % 4
			# Après un déplacement, la tortue fait trois quarts de tour indépendamment du déplacement
			# direction = (direction + 3) % 4
			pixels.append ((x, y))
			if x < xMin:
				xMin = x
			elif x > xMax:
				xMax = x
			if y < yMin:
				yMin = y
			elif y > yMax:
				yMax = y
		print (f'({xMin}, {yMin}) to ({xMax}, {yMax}) : {abs (xMax - xMin)} x {abs (yMax - yMin)}')
quit ()
En passant, dans ma grande bonté, voici la codification de l'image générée à partir d'un programme analysant la couleur des pixels :
puzzle = [
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
	[0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0],
	[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
	[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0],
	[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0],
	[1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
	[1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
]
U.S. Cyber Command Valentine’s Day 2021 Crypto Challenge