RSA에서 공개키를 만드는 방법은 이렇다 

 

1.두 개의 큰 소수(p, q) 선택.
2.n = p * q 계산.
3.φ(n) = (p - 1) * (q - 1) 계산.
4.작은 소수 e 선택 (일반적으로 65537).
5.e에 대한 φ(n)의 역원을 찾아 개인키 d 계산.
6.공개키: (n, e), 개인키: (n, d) 생성됨.

 

이 일련의 과정을 통해 암호문을 구할 수 있다 

text = 12
p = 17
q = 23
n = p * q
e = 65537
print(pow(text,e,n))

암호화 하려는 평문과 정해져있는 공개키중 하나인 E를 제곱 한 뒤 

N, 주어진 두 소수 q,p의 곱으로 모듈러스 지수화 ( 나머지연산 ) 을 해주면 값이 나오게 된다 

 = 301

~ RSA의 모든 연산 모든 문제에는 모듈러 지수화 ( 나머지 연산 ) 을 사용하게 된다 ~

 

mod는 나머지 연산자이다 

10 mod 3이면 10%3과 같은건데 쉽게 다시 말하면 

나머지가 3보다 작을때까지 계속 뺀다고 생각하면 된다 

10 - 3 = 7

7 - 3 = 4

4 - 3 = 1

결국 답은 1이되는것이다 

실제로, 10%3 하면 몫은 3 나머지는 1이 나오게 된다 

% = mod 

 

다시 문제로 돌아와서 

101¹⁷ mod 22663 을 구하라고 했는데 거듭제곱과 나머지연산자를 한번에 수행해주는 

pow 함수를 사용할 것이다 

result = pow(2, 3)  # 2의 3승인 8을 계산합니다.
print(result)       # 출력: 8

result_with_modulus = pow(2, 3, 5)  # (2의 3승)을 5로 나눈 나머지를 계산합니다. 결과는 3입니다.
print(result_with_modulus)          # 출력: 3

pow ( base,exponent,modulus ) 

이런 식의 함수인데 설명하자면 이렇다 

 

base: 거듭 제곱할 밑 숫자
exponent: 밑을 거듭 제곱할 지수
modulus (선택적): 제공된 경우, 결과는 해당 모듈러 값으로 나눈 나머지로 계산

 

문제를 말로 풀면

1. 101의 17을 제곱하고 그 값을  22663을 22663보다 작은 값이 나올때까지 빼준다

2. 101의 17을 제곱하고 그 값을 22663으로 나머지연산을해 나머지를 구한다 

같은 말이다 

 

print(pow(101,17,22663))

코드로 표현해보면 이런식으로 나오게된다 

 = 19906

 

 

이상해진 고양이

 

어느날, 고먐미의 초상화가 이상해졌다
누군가 임의로 초상화를 바꿔놓은것이다

범인이 남기고 간 유일한 단서는 ,

이사진속에 단일바이트와 XOR해서 만들어진 암호를 심어놨다는 단서 뿐.
과연 고먐미 초상화 사건의 범인을 찾을 수 있을 것인가…!
flag format: hsoc{}

Cryptohack 에서 제일 안되는 부분이
XOR 개념이였기 때문에 따로 정리를 할것이다
그리고 부족했던 ascii 개념을 더 정리해보자면 

                                           ASCII 코드표


ascii 코드 = 7bit 
영문 알파벳을 사용하는 대표적인 문자 인코딩이다 
chr() ord()
chr 함수는 ascii숫자를 대응하는 문자로 바꿔주고 
ord 는 문자를 ascii 값으로 변환해주는거임

 

print(type(chr(99)))

print(chr(99) == "c")

print(99 == ord("c"))


99를 ascii 코드에 대응하게 chr 을 써서 문자 "C" 로 바꾸었으니까 <class 'str'>
같은이유로 TRUE
C를 다시 ord를 사용해 ascii 코드로 변환시키면 99이니까  TRUE

# Favourite byte

For the next few challenges, you'll use what you've just learned to solve some more XOR puzzles.
I've hidden some data using XOR with a single byte, but that byte is a secret. Don't forget to decode from hex first.
73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d

다음 몇 가지 챌린지에서는 방금 배운 것을 사용하여 더 많은 XOR 퍼즐을 풀게 됩니다.
단일 바이트로 XOR을 사용하여 일부 데이터를 숨겼지만 해당 바이트는 비밀입니다. 
먼저 16진수에서 디코딩하는 것을 잊지 마십시오.

일단 문제를 먼저 바이트 형태로 바꿔서 디코딩을 해준뒤 
모든 경우의 수를 찾아 무차별적으로 1btyes에 xor 을 각각해줌으로써 플래그값을 알아낼 것이다.

from Crypto.Util.number import *
fl = bytes.fromhex("73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d")

for i in range(256):
    for char in fl:
        print(chr(char ^ i), end="")
    print()

계속 증가하는 변수인 i를 1bytes에 경우의 수를 다 넣는 것인데 
이때 1bytes = 8bit
1bit = 0과1을 나타내기 때문에 2⁸ = 256을 대응하는것이다.
그럼 char이라는 변수 안에 문제를 넣고 문제와 증가하는 변수 i를 xor 시켜서 chr 함수로 문자로 나오게 해보면

Þ
ß
Þ
±
ß
Û
± ....

이런식으로 나오기 때문에 end 함수를 써주면 많은 결과값중에 

nelhsg,d-,C-)CqeCz(j,in-+/C~e+ya
~odmirf-e,-B,(BpdB{)k-ho,*.Bd*x`
}lgnjqe.f/.A/+AsgAx*h.kl/)-A|g){c
|mfokpd/g./@.*@rf@y+i/jm.(,@}f(zb
crypto{0x10_15_my_f4v0ur173_by7e}
bsxqunz1y01^04^lx^g5w1ts062^cx6d|

이렇게 플래그를 찾을 수 있다 하지만
플래그만 딱 출력 하는, 더 좋은 코드를 짤 수 있는데  if 문을 사용해서
문제 첫글자, 1byte가 flag 포맷일때만 출력이 되게끔 코드를 짜보겠다 

from Crypto.Util.number import *
fl = bytes.fromhex("73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d")

for i in range(256):
    if fl[0] ^ i == ord("c"):
        for char in fl:
            print(chr(char ^ i),end="")

 

이 문제에서 flag 포맷은 crypto{}
만약 fl 변수의 0번째 i랑 xor 했을때가 c 일때만 다음 for문으로 넘어가게끔 코드를 짠것이다.
이때 C는 ord 함수를 사용해서 ascii 코드로 변환해 조건문을 작성해준다. 
만약 조건문이 성립이 되지않는다면 다음 for문으로 안넘어가기 때문에 결국 print 까지도달을 안해서 아무것도 출력이 되지 않을것이다.
crypto{0x10_15_my_f4v0ur173_by7e}
그럼  flag만 뽑아서 출력 해 줄 수 있다
flag 포맷을 잘이용하면 된다는 사실을 알았다.. 이 경험으로 ,, flag 포맷에 대한 설명도 세미콜론때  나름 잘했다 ㅋㅋㅋ

 

# SingleByteXor

dramhack에 비슷한 예제가 있다 

똑같이 단일 바이트라는 점을 이용해서 작성하면 된다 

from Crypto.Util.number import*

fl = bytes.fromhex("54586b6458754f7b215c7c75424f21634f744275517d6d")

for i in range(256):
    if fl[0] ^ i == ord("D"):
        for ch in fl:
            print(chr(ch ^ i), end="")

 

문제를 빼다 박아 놓은 수준으로 똑같이 풀었다 flag 포맷은 다르니까 그 점만 다른걸 제외하면 코드는 똑같다.
DH{tHe_k1LleR_1s_dReAm} 

 

글을 마치며 

xor 개념 자체도 나름 이해한거 같고 ascii에 대한 이해는 확실하게 되었다

 C+F 해서 flag 값을 찾아도 되는데 더 완벽한 코드를 짤 순 없을까 하면서 고민해보고 

이것저것 시도하는 과정이 나름 재미있었다 이런 경험으로 

코드작성할때 이거에는 이 함수 써야지, 이렇게 해야지 이런 생각 범위가 처음보다 확실히 늘어난거 같다 

 

Basic_Crypto1

This Problem Basic_Crpyto(Roman emperor’s cipher)

FLAG FORMAT(A~Z) and empty is “_”

DH{decode_Text}

 

txt 폴더안에 

EDVLF FUBSWR GUHDPKDFN 

이렇게 적혀 있는거 보고 카이사르 암호문인걸 알았다 

caesar decoder라고 구글링을 해서 dcode 사이트에 돌렸더니 

https://www.dcode.fr/caesar-cipher

 

Caesar Cipher (Shift) - Online Decoder, Encoder, Solver, Translator

Tool to decrypt/encrypt with Caesar cipher (or Caesar code), a shift cipher, one of the most easy and most famous encryption systems, that uses the substitution of a letter by another one further in the alphabet.

www.dcode.fr

BASIC CRYPTO DREAMHACK

이 형식으로 나와서 문제에서 말한 플래그 형식으로 넣었음

DH{BASIC_CRYPTO_ DREAMHACK}  

 

 

 

 

 

 

 

 

 

ENCODING

ASCII is a 7-bit encoding standard which allows the representation of text using the integers 0-127.
Using the below integer array, convert the numbers to their corresponding ASCII characters to obtain a flag.
ASCII =  7비트 인코딩
아래 정수 배열로 숫자를 ASCII로 변환해 플래그를 얻어라 

In Python, the chr() function can be used to convert an ASCII ordinal number to a character (the ord() function does the opposite.
 chr() ord()를 쓰면 되는데, chr은 ASCII 서수를 문자로 ord는 문자를 서수로 바꾸어준다.

문제에선 chr 함수를 써야하는걸 알 수 있다.
[99, 114, 121, 112, 116, 111, 123, 65, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125]

s = [99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125]
for a in s:
    print(chr(a),end="")

해석해보면 리스트를 변수에 넣고 
for 함수를 사용해서 리스트값을 하나하나 서수를 문자로 변환해 a에 넣고 end를 이용해 하나의 값으로 출력한것
crypto{ASCII_pr1nt4bl3} 

 

HEX

When we encrypt something the resulting ciphertext commonly has bytes which are not printable ASCII characters. If we want to share our encrypted data, it's common to encode it into something more user-friendly and portable across different systems.
Hexadecimal can be used in such a way to represent ASCII strings. First each letter is converted to an ordinal number according to the ASCII table (as in the previous challenge). Then the decimal numbers are converted to base-16 numbers, otherwise known as hexadecimal. The numbers can be combined together, into one long hex string.
Included below is a flag encoded as a hex string. Decode this back into bytes to get the flag.
 
무언가를 암호화 할때 암호문에는 일반적으로 
인쇄가능한 ASCII 문자가 아닌 바이트라는게 있다
이 문제는 16진수 문자열로 인코딩된 플래그가 포함 되있다  
이걸 바이트로 다시 디코딩 해서 플래그 찾으셈 
 
In Python, the bytes.fromhex() function can be used to convert hex to bytes. The .hex() instance method can be called on byte strings to get the hex representation\
 
이럴때 bytes.fromhex() 함수를 사용해서 
16진수 바이트로 변환 할수 있음 
.hex() 는 바이트 문자열에서 호출 되어서 16진수 표현을 얻을수있다함 
 
63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6

a = "63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d"
print(bytes.fromhex(a))

 bytes.fromhex를 이용해서 16진수로 표현된 문자열 a을 바이트로 변환 시켜서 출력시킨것이다 
crypto{You_will_be_working_with_hex_strings_a_lot}

BASE64

Another common encoding scheme is Base64, which allows us to represent binary data as an ASCII string using an alphabet of 64 characters. One character of a Base64 string encodes 6 binary digits (bits), and so 4 characters of Base64 encode three 8-bit bytes.
Base64 is most commonly used online, so binary data such as images can be easily included into HTML or CSS files.
Take the below hex string, decode it into bytes and then encode it into Base64
 
인코딩 체계에
base64 라고 64자의 알파벳을 사용해서 이진데이터를 
ASCII 문자열로 나타낼수 있다 
base64 문자열의 한 문자는 6개의 이진수를 인코딩하므로,
base64의 4문자는 3개의 8비트 바이트를 인코딩한다 
온라인에서 일반적으로 사용되서 이미지와 같은 이진 데이터를 
HTML 또는 CSS 파일에 쉽게 포함할수 있음 
아래 16진수 문자열을 바이트로 디코딩 하고 Base64로 인코딩 해라 
 
 In Python, after importing the base64 module with import base64, you can use the base64.b64encode() function. Remember to decode the hex first as the challenge description states.
 
import base64로 모듈을 가져오고
base64.b64encode()
함수를 사용 할 수 있다 
먼저 16진수먼저 인코딩 해라(해독)
 
72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf
 
일단 16진수를 어떻게 해야할지 생각해보고 있었는데 아까 decoding 할때 썼던 bytes.fromhex를 사용하면 될거같다 근데 
16진수를 먼저 해독하고 모듈을 또 사용해서 답을 하나를 만들어야 하니까 result 사용하면 되겠다 라고 생각했는데 딱히 필요가 없었다 

import base64
a = "72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf"
b = bytes.fromhex(a)
print(base64.b64encode(b))

 import base64로 base64 모듈을 가져와서 
a변수에 문제 넣고 
b변수에서 a를 16진수를 바이트로 해독해주고
결국에 b에들어있는건 바이트 a
그걸 base64.b64encode 출력할때 저 함수를 적용 시켜버리면  
crypto/Base+64+Encoding+is+Web+Safe/

Bytes and Big integers

Cryptosystems like RSA works on numbers, but messages are made up of characters. How should we convert our messages into numbers so that mathematical operations can be applied?
The most common way is to take the ordinal bytes of the message, convert them into hexadecimal, and concatenate. This can be interpreted as a base-16/hexadecimal number, and also represented in base-10/decimal.

RSA와 같은 암호 시스템은 숫자로 작동하지만 메시지는 문자로 구성
수학 연산을 적용할 수 있도록 메시지를 숫자로 어떻게 변환하는
가장 일반적인 방법은
메시지의 서수 바이트를 가져와 16진수로 변환하고 연결하는 것
이는 16진수/16진수로 해석할 수 있으며 10진수/10진수로도 표시

Python's PyCryptodome library implements this with the methods bytes_to_long() and long_to_bytes(). You will first have to install PyCryptodome and import it with from Crypto.Util.number import *

Python의 PyCryptodome 라이브러리는 bytes_to_long() 및 long_to_bytes() 메서드로 이를 구현합니다. 먼저 PyCryptodome을 설치하고 from Crypto.Util.number import *로 가져와야 합니다.
 
해석을 들어보니 모듈을 설치하고 그 안에서 선언 (import)를
한 뒤에
코드를 짜는것이엿다

from Crypto.Util.number import *
 
a = "label"

for i in range(len(a)):
    s = ord(a[i])
    b = s^13
    print(chr(b))

a
l
o
h
a
라고 나온다
플래그 포맷 형식에 맞춰서 입력해주면 된다. 
 

XOR Properties

bytes_to_long() 함수는 바이트 값을 정수(long)형태의 값으로 변환한다.
long_to_bytes() 함수는 정수(long)형태 값을 바이트 
로 변환함 이라는 원리를 알고 해야함 근데 여기서
바이트는 그냥 로마자나 뭐 이런 숫자의 최소 단위라는데 ))
여기서 중요한건 위에서 했던..
xor starter
 bytes.fromhex() 함수를 사용해서
16진수 바이트로 변환 할수 있음 
.hex() 는 바이트 문자열에서 호출 되어서 16진수 표현을 얻을수있다함
이라고 했던 이 개념을 떠올려야한다.
 
bytes.fromhex  = 16진수를 바이트로 바꾸는거임 
근데 문제에서 정수로 바꾸라는 힌트를 줬으니까
bytes.fromhex 로만 쓰면 바이트로만 나오는거임 정수로 나오려면 
bytes_to_long(bytes.fromhex
이렇게 쓸 생각을 해야함 해석하면
16진수를 바이트 (bytes.fromhex)로 바이트를 다시 정수로 (bytes_to_long)     
 
또 멘토링 하면서 알게된 xor성질중에 
xor한 값xor한요소 하나를 xor하면 
나머지 한 요소가 나오는거 
ex))
a^b = c
c^a = b 이렇게 
 

from Crypto.Util.number import*

key1 = bytes_to_long(bytes.fromhex("a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313"))
key2 =key1^bytes_to_long(bytes.fromhex("37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e"))
key3 =key2^bytes_to_long(bytes.fromhex( "c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1"))
flag = bytes_to_long(bytes.fromhex( "04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf"))

 근데
Print 소스를 어떻게 짜야할지 모르겠을 뿐더러 소스코드에
오류가 있는거같다

from Crypto.Util.number import*

key1 = bytes_to_long(bytes.fromhex("a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313"))
key2 =key1^bytes_to_long(bytes.fromhex("37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e"))
key3 =key2^bytes_to_long(bytes.fromhex( "c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1"))
flag = bytes_to_long(bytes.fromhex( "04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf"))^key1^key2^key3

print((long_to_bytes(flag)))

그래서 생각해보니 bytes to long 쓰고 flag 값은 key1^key2^key3을 해야 나온다고 했으니까 flag 값에 
xor을 해주는것을 까먹었다 
print는 다시 bytes_to_long을
long_to_bytes로 바꾸어서
flag 값을
원래의 형태(bytes)로 바꾸어서 출력 해보려고 하니까 
flag값이 나왔다
*crypto{x0r_i5_ass0c1at1v3}  

 
 
 
 

+ Recent posts