[windows] pysqlcipher3 사용하기

pysqlcipher3

분석을 하다보면 sqlcipher로 암호화된 데이터베이스를 자주 볼 수 있다.
처음 복호화에 사용할땐 ubuntu를 깔아서 설치했는데 문제 없이 사용할 수 있었지만, 다시 환경을 세팅하려 하니 windows 에서 pip install pysqlcipher3 으로는 아주 많은 에러가 발생해서 직접 빌드를 해야한다.

c8827408-17bd-4910-a910-40441c7788f9
c8827408-17bd-4910-a910-40441c7788f9

환경

  • Windows 11
  • Python 3.10.5

참고 링크

설치

  1. github에서 pysqlcipher3 레포 클론

  2. Win64 OpenSSL 설치 (lite 버전 X)

    • https://slproweb.com/products/Win32OpenSSL.html
    • 시스템 환경변수 추가 OPENSSL_CONF=C:\OpenSSL-Win64\bin\openssl.cfg
    • libcrypto.def/lib, libssl.def/lib 파일 복사 후 → libeay32.def/lib, ssleay32.def/lib 로 이름 변경하고
      C:\Program Files\OpenSSL-Win64\lib 로 이동 64bit openssl이 32bit와 하위 호환이 안되는 것 같다.
      06c4593c-b96f-4ffd-830f-28abc1273c73
      06c4593c-b96f-4ffd-830f-28abc1273c73
  3. sqlite-amalgamation.zip 다운로드

  4. ActiveTcl 설치

  5. visual studio 설치 (x64 Native Tools Command)

  6. x64 Native Tools 터미널에서 sqlcipher clone 경로로 이동 후 nmake /f Makefile.msc 명령실행.
    빌드는 실패하지만 sqlite3.c, sqlite3.h 파일만 생기면 된다.

  7. pysqlcipher 클론 폴더에 amalgamation 폴더를 생성하고 바로 위에서 만들어낸 sqlite3.c, sqlite3.h 파일을 옮긴다. amaligamation\sqlcipher 폴더를 생성하고 sqlite-amalgamation.zip 을 압축 해제해서 나온 파일들을 집어넣는다.

    pysqlcipher3
    ├─amalgamation
    │  │  sqlite3.c
    │  │  sqlite3.h
    │  │
    │  └─sqlcipher
    │          shell.c
    │          sqlite3.c
    │          sqlite3.h
    │          sqlite3ext.h
    
  8. $ python setup.py build_amalgamation 명령을 실행하면 에러가 발생할텐데 고치면서 빌드를 완료한다.

  9. 빌드가 완료되면 $ python setup.py install 명령으로 설치한다. (관리자 권한 터미널이여야 함)
    에러 없이 import 되면 성공!

    0c92b343-4125-4038-998f-20946cff0d53
    0c92b343-4125-4038-998f-20946cff0d53

error C2017: illegal escape sequence

모듈네임이 파싱이 안돼서 생기는 문제기 때문에 에러가 발생하고 있는 파일에서 MODULE_NAME 부분을 전부 "pysqlcipher3.dbapi2" 로 수정해주면 된다.
처음엔 cache.c 겠지만, 계속 실행하다보면 connection.c 등 거의 모든 .c 파일에서 에러가 발생한다.

사용법

from pysqlcipher3 import dbapi2 as sqlite

key_bytes = bytes.fromhex("8e 51 0b 47 c7 25 16 39 4c f4 3d b7 9f bf 41 6f  61 2d b5 3e 43 ad 5f f2 dd 03 ee 4c a8 14 4b 5e ".replace(" ", ""))

conn = sqlite.connect('test.db')
c = conn.cursor()
c.execute(f"PRAGMA key = \"x'{key_bytes.hex()}'\";")
c.execute("PRAGMA cipher_compatibility = 3")
c.execute('''create table stocks (date text, trans text, symbol text, qty real, price real)''')
c.execute("""insert into stocks values ('2006-01-05','BUY','RHAT',100,35.14)""")
conn.commit()

c.execute("select * from stocks")
t = c.fetchall()
for f in t:
    print(f)

c.close() 

파일을 hxd로 열어보면 암호화되어 있고, 같은 비밀번호로 다시 복호화가 잘 된다.

42c94f49-d1f8-4d06-b02d-5b7e16ef9e1c
42c94f49-d1f8-4d06-b02d-5b7e16ef9e1c

PRAGMA 세팅법

암호화할 때 PRAGMA를 세팅할 수 있다. key 세팅 이후에 적용해야 적용되는 듯 하다.

이중에 cipher 라고 암호화 방식을 지정하는게 있는데, sqlcipher는 사실상 AES-256-CBC 하나의 암호화 방식만 지원한다.

import pysqlcipher3.dbapi2 as sqlite

# 이 값들을 반복문으로 돌려볼 수도 있다.
page_sizes = [512, 1024, 2048, 4096, 8192, 16384, 32768, 65536]  # 다양한 페이지 크기
kdf_iters = [1000, 4000, 10000, 64000, 128000, 256000, 512000]  # KDF 반복 횟수
hmac_algorithms = ["HMAC_SHA1", "HMAC_SHA256", "HMAC_SHA512"]  # HMAC 알고리즘
kdf_algorithms = ["PBKDF2_HMAC_SHA1", "PBKDF2_HMAC_SHA256", "PBKDF2_HMAC_SHA512"]  # KDF 알고리즘

# 데이터베이스 연결
conn = sqlite.connect('encrypted_database.db')

# 커서 생성
cursor = conn.cursor()

# 키를 설정하여 데이터베이스 암호화/복호화
cursor.execute("PRAGMA key = 'your_password';")

# 데이터베이스가 새로 만들어졌다면 암호화 시작
cursor.execute("PRAGMA cipher_page_size = 4096;")  # 페이지 크기 설정
cursor.execute("PRAGMA cipher_plaintext_header_size = 32;")  # 헤더 크기 설정 (32의 배수, 페이지 크기 미만)
cursor.execute("PRAGMA kdf_iter = 64000;")  # PBKDF2 키 스트레칭 설정
cursor.execute("PRAGMA kdf_iter;")  # 잘 세팅 됐는지 확인 
t = cursor.fetchone()
print(f"kdf_iter 세팅 확인: {t}")
cursor.execute("PRAGMA cipher_hmac_algorithm = HMAC_SHA512;")  # HMAC 알고리즘 설정
cursor.execute("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA512;")  # KDF 알고리즘 설정
cursor.execute("PRAGMA cipher_use_hmac = ON;")  # HMAC 사용 여부 설정

# 데이터 삽입 예시
cursor.execute("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, data TEXT);")
cursor.execute("INSERT INTO test (data) VALUES ('Hello, SQLCipher!');")

# 변경 사항 저장
conn.commit()

# 연결 종료
cursor.close()
conn.close()

복호화 할때도 동일하게 PRAGMA를 세팅해줘야 복호화가 정상적으로 동작한다.
처음 키만 연결하고 PRAGMA값을 확인해보면 그냥 기본값이 들어가있다.

import pysqlcipher3.dbapi2 as sqlite

# 암호화된 데이터베이스 연결
conn = sqlite.connect('encrypted_database.db')

# 커서 생성
cursor = conn.cursor()

# 복호화 키 설정
cursor.execute("PRAGMA key = 'your_password';")
cursor.execute("PRAGMA cipher_page_size = 4096;")
cursor.execute("PRAGMA cipher_plaintext_header_size = 32;")
cursor.execute("PRAGMA kdf_iter = 64000;")
cursor.execute("PRAGMA cipher_hmac_algorithm = HMAC_SHA512;")
cursor.execute("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA512;")
# cursor.execute("PRAGMA cipher_use_hmac = ON;")

# 데이터 조회 예시
cursor.execute("SELECT * FROM test;")
rows = cursor.fetchall()

for row in rows:
    print(row)

# 연결 종료
cursor.close()
conn.close()

Comments

ESC
Type to search...