Python - 해당되는 글 9건

HTML에서 이미지를 읽을 때 대부분의 경우 URL을 이용하지만,
때때로 Data URI Schema를 이용해야 하는 경우도 있다.
다음은 Python에서 이미지 데이터를 Data URI Schema로 얻는 코드이다.

from cStringIO import StringIO

from PIL import Image

import urllib, base64


# 이미지 객체에서 값 얻기

base = Image.new('RGBA', (w, h), (0, 0, 0, 0))

# do something on Image object

raw = StringIO()

base.save(raw, 'PNG')

b64png = 'https://t1.daumcdn.net/cfile/tistory/2362D34056EA60EB26"margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">

file = urllib2.urlopen(url)

buf = StringIO(file.read()) 

b64png = 'https://t1.daumcdn.net/cfile/tistory/2623EE4156EA60EC25
|
어제 (2011/10/26) 개발용 Macbook-Air를 Lion으로 업데이트 했다.
뭐, 여러가지 향상된 UX라던가 iOS와 동질감을 느낄만한 요소들이 많이 생겼지만,
내게 그게 중요한 건 아니었고... ㅋ

문제는 현재 진행 중인 프로젝트와 관련하여 Python 환경이 전부 초기화 되었다는 것이다.
업데이트 된  Lion에는 Python 2.5/2.6/2.7이 설치되어 있었고 기본 버전은 2.5로 되어있었다. 
개인적으로 선호하는 버전은 2.6 인데...

구글링 등을 이용해 찾은 버전 변경은 아무리 해도 먹질 않았다.
다들 Lion에서도 된다고 써있었는데 왜 내겐 안되는지...
취향 상 root 권한으로 시스템에 손대는 것은 좋아하지 않지만,
이번은 어쩔수 없었다.

다음과 같은 방법으로 기본 Python 버전을 2.6으로 변경할 수 있다.

$ cd /opt/local/bin
$ sudo rm python
$ sudo ln -s /opt/local/bin/python2.6 python
$ sudo rm python-config
$ sudo ln -s /opt/local/bin/python2.6-config python-config
$ sudo rm pythonw
$ sudo ln -s /opt/local/bin/pythonw2.6 pythonw

여기서 문제가 한가지 더 발생 했는데,
Python package가 설치되는 site-packages 폴더와
Aptana가 기본으로 인식하고 읽어들이는 site-packages 폴더의  위치가 다르다.
아... 거지같아...
다음과 같이 문제를 해결했다.

$ cd /Library/Python/2.6
$ sudo rm -rf site-packages
$ sudo ln -s /opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/ site-packages

이제 모든 것이 제대로 동작한다.
 
|
여기를 참고하시라.
결과물 괜찮게 나옴... 
|
여기를 참고하시라.
아주 친절하게 설명되어 있다. 

참고한 페이지의 내용을 요약하자면,

1. site.cfg 파일을 열어서 아래와 같이 수정하고
registry_key = SOFTWARE\MySQL AB\MySQL Server 5.0
registry_key = SOFTWARE\MySQL AB\MySQL Server 5.5 

2. 여기에 가서 config-win.h 파일을 다운로드 받은 후
"C:\Program Files\Microsoft Visual Studio 9.0\VC\include" 폴더에 복사하고

3. "C:\Program Files\MySQL\MySQL Server 5.5\lib\mysqlclient.lib" 파일을
"C:\Program Files\Microsoft Visual Studio 9.0\VC\lib" 폴더에 복사한다.

4. 마지막으로 MySQL-python-1.2.3 폴더에 가서
커맨드 라인에 "python.exe setup.py install"이라고 입력한다.

 챠란~
|
개인적으로 개발 환경은 Mac OS X 서버 환경은 Debian을 좋아하지만,
본인 의사와는 상관 없이 윈도우즈 서버와 놀아야 할 때가 있다.
이런 경우 Python Extension을 설치할 때
pyo 또는 dll과 같은 파일들에 대한 바이너리 호환성 문제가 종종 발생한다.
M2Crypto가 그랬고 MySQLdb에서도 경험했다.
Visual Studio로 매번 컴파일 하는 것도 힘들고,
VS2008로 컴파일된 바이너리와 Apache 2.2 충돌 문제를 피하려면
install script 수정도 해줘야 하기에
그냥 웹에서 긁어다 쓰기로 결심...
그 중
이곳이 괜찮아서 기록을 남긴다.
윈도우에서 바이너리 설치가 필요한 Python Extention이 필요한 분들은
링크를 따라가시길 추천한다. 


나는 1시간만에 위의 '땡잡았다.'라는 생각이 한심한 생각이었다는 것을 깨닳았다.
과거에 M2Crypto의 설치를 직접 했다면 이 깨닳음에 몇 일을 절약할 수 있었을 것이다.
(M2Crypto는 본인의 멘토가 설치하셨다.)
어쨌거나 MySQL-python Extension은 똑바로 동작하지 않았고,
그것이 구 버전의 MySQL 라이브러리와 연결되어 있다는 것을 알게 되었다.
결국 내가 원하는 최신 버전의 조합을 갖는 바이너리를 찾는데 실패했고 
직접 컴파일해야 한다는 사실을 받아들이게 되었다.

하고싶은 말은 설치해보고 안되면, 직접하라는 것이다.
안되는 바이너리 패키지로 시간 낭비 하는 것은 좋지 않다. 
|
django에서 syncdb를 통해 테이블을 생성할 경우
테이블 이름은 '{appname}_{classname}'으로 지정된다.

이와 같은 경우 몇 가지 문제 케이스와 직면할 수 있는데,
1. legacy system에 django를 적용해야 할 경우 기존 database table들의 변경 없이 사용해야 한다.
2. 다양한 시스템(PHP, ASP, JSP, ROR, Etc.)이 하나의 database에 접근할 때,
    django의 naming rule을 강제할 수 없다.
위의 두 가지가 대표적이다. 

때문에, django에서는 table 명을 다음과 같이 강제 지정할 수 있다.

class Sessions(models.Model): 
    {... some fields}
    class Meta:
        db_table = u'sessions' 

위와 같이 지정하면 django는 database에 '{appname}_sessions'가 아닌 'sessions'로 생성 및 접근하게 된다.

'django' 카테고리의 다른 글

database에서 models.py 추출하기  (0) 2011.06.09
aptana에서 django 프로젝트 설정하기  (0) 2011.05.31
|

프로젝트를 진행하다 보면, 랜덤 값이 필요한 경우가 많이 생긴다.
특히 보안이 필요하다면 더욱 더...
암호화 된 값들과 해쉬 값들, 그리고 그것들로 위장한 의미 없는 값들...
단순한 인덱싱 조차도 1, 2, 3, 4, 5, ... 로 사용하는 것이 허용되지 않기도 한다.

다양한 케이스에서 랜덤값이 필요하게 되면서 알게된 것이 두 가지가 있다.
첫째는 python의 기본 random 모듈로는 요구 사항을 만족 시킬수 없는 부분이 있다.
둘째는 기본 random 모듈 이외에 추가적인 좋은 방법들이 있다.

그래서 이번에 사용한 방법들을 정리하고자 한다.

본인은 현재 '열혈강의 파이썬 개정판: 이강성저'를 참고서적으로 보고 있으며,
아래의 정리 내용은 책에 없는 내용만을 포함하고 있다.
아래 방법들을 사용하기에 앞 서
책에서 기본적인 내용을 우선 읽어보기를 권하는 바이다. 


1. random 모듈 [문서]

>>> import random
>>> import string
>>> c = string.letters + string.digits
>>> c
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
>>> v = ''.join(random.sample(c, 6))
>>> v
'yxEeLl' 


2. uuid 모듈 [문서]

세부적인 사항은 문서 링크를 참고하면 된다.
단순히 적당한 길이의 random 문자열이 필요하다면, 아래의 코드도 괜찮은 선택이다.

>>> import uuid
>>> uuid.uuid1()
UUID('8f9f01b8-923e-11e0-889b-1093e9020660')
>>> str(uuid.uuid1())
'98c3d57a-923e-11e0-ae95-1093e9020660'
>>> uuid.uuid4() 
UUID('6a81a0ca-dcfc-4024-883e-5abb29238b4d')
>>> str(uuid.uuid4()) 
'7ed3f7b9-84a5-4066-8e9c-e5e1bc370573' 


3. os 모듈의 urandom

os 모듈에는 urandom이라는 함수가 있다.
이 함수는 원하는 길이(byte단위)의 unsigned 수치값을 만들어 준다.
물론 int 형이나 long 형이 아니기 때문에 약간의 가공이 필요할 수 있다.
아래 방법은 암호화 알고리즘의 키를 생성하는데 유용하다.

>>> import os
>>> import binascii
>>> os.urandom(16)
'h\xb4\xaa<\x12\xa5\xc8\xaf\xa2sCr\x93\x01f\xdc'
>>> binascii.hexlify(os.urandom(16))
'7a26ada27ace29eb422c04efe7313526'
>>> int(binascii.hexlify(os.urandom(16)), 16)
69812220901636122490437131090184792388L 

|
오늘 보안 알고리즘에 약간의 변경을 가하기로 결정되어
RSA와 함께 AES를 섞어 쓰기로 결정 되었다.
때문에 python으로 AES 관련 코드 추가 작업을 진해하였다.

이미 M2Crypto를 쓰고 있으니
따로 암호화 모듈을 추가할 필요 없이 이를 이용했다.
M2Crypto를 보면서 문서화가 좀 거지같다는 생각을 했는데,
이번에도 역시...
그나마 테스트 케이스라도 있어서 다행이었다.
휴~

처음에는 AES 128bit CBC로 할까 했다가
IV가 필요없는 AES 128bit ECB로 결정...

아래 코드는 임의의 128bit 키를 만들어 짧은 평문을 암/복호화 한다.
 

import os
import cStringIO
from M2Crypto import EVP

skey = os.urandom(16)
plaintext = '12345'

# encrypt

aes = EVP.Cipher(alg='aes_128_ecb', key=skey, iv='', op=1)

buf = cStringIO.StringIO()

buf.write(aes.update(plaintext))

buf.write(aes.final())

ciphertext = buf.getvalue()

# decrypt

aes = EVP.Cipher(alg='aes_128_ecb', key=skey, iv='', op=0)

buf = cStringIO.StringIO()

buf.write(aes.update(ciphertext))

buf.write(aes.final())

plaintext = buf.getvalue() 

 
|

지난 주 작업 중 클라이언트로부터 HTTP Request로 RSA Public Key를 받아서
보안 토큰을 암호화한 후 Response에 실어서 보내는 작업이 있었다.
클라이언트는 Crypto++이라는 C++ 라이브러리를 사용하고 있었다.

이 작업을 위해 RSA 2.0과 PyCrypto를 먼저 사용해 보았으나
Crypto++과 결과물이 맞지 않았다. 
같은 RSA 알고리즘을 사용했다면 기대대로 동작을 해야할텐데
이상하다고 생각했으나 일단 작업은 진행을 해야하니까...
(혹시, 필자가 삽질해서 안된거라면 성공 경험이 있으신 분은 커멘트 부탁드립니다.) 
M2Crypto에서 Crypto++에서 생성한 키들을 이용한 암복호화를 검증하여
옳바르게 작업하는 것을 확인 후 사용하였다.

아래 코드는 해당 작업을 위하여
python 콘솔에서 검증 작업한 코드르 정리/재구성 한 것이다.
사용된 패키지 및 함수에 대해서는 레퍼런스 문서를 찾아보길 바란다.

아래 코드에서 pub_key_hex, priv_key_hex는 DER 포맷의 RSA 키 쌍 이다.
HTTP로 전달하기 위해서는 문자열을 사용해야만 했으며,
Base64 인코딩 시 종종 개행문자가 들어가기도 하는데 이 경우 문제의 소지가 있어
16진수 문자열로 변환하여 전달했다.
PEM 형식은 Base64를 쓸 뿐만 아니라 Crypto++에서 직접 지원하지 않기 때문에
DER 포맷을 사용하였다.
(아이러니 하게도 M2Crypto는 PEM 포맷만 직접 지원한다.)

아래 코드는 16진수 문자열로 된 DER 포맷을 PEM 포맷으로 전환하여
키 객체를 만든 후 값을 처리한다.


import base64

import binascii

from M2Crypto import BIO, RSA

plain_text = '12345' 


TEMPLATE = """-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----"""

raw = binascii.a2b_hex(pub_key_hex)

data = TEMPLATE % base64.encodestring(raw).rstrip()

bio = BIO.MemoryBuffer(data)

pub_key = RSA.load_pub_key_bio(bio)

enc = pub_key.public_encrypt(plain_text, RSA.pkcs1_oaep_padding)

enc_text = binascii.b2a_hex(enc_text)


TEMPLATE = """-----BEGIN RSA PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----"""

raw = binascii.b2a_hex(priv_key_hex)

data = TEMPLATE % base64.encodestring(raw).rstrip()

priv_key = RSA.load_key_string(data)
enc = binascii.a2b_hex(
enc_text)

plain_text = priv_key.private_decrypt(enc, M2Crypto.RSA.pkcs1_oaep_padding)

 
|

ghilbut's Blog is powered by Daum & tistory