ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python] cryptography 라이브러리로 RSA encrypt와 sign하기
    Python 2023. 10. 25. 00:33
    728x90
    반응형

    이번에는 이전 포스팅에서 로드했던 public key와 private key를 이용하여 encryption과 signature를 진행해보려한다.

     

    코드는 먼저 public key를 이용하여 encryption부터 보여주면

    from cryptography.hazmat.backends import default_backend
    from cryptography import x509
    from cryptography.hazmat.primitives.asymmetric import padding
    
    with open(pubkey_path, 'rb') as content:
        public_key = (x509.load_pem_x509_certificate(content.read(), default_backend)).public_key()
    ciphertext = public_key.encrypt(bytes(message), padding.PKCS1v15())

    다음과 같다.

    public key를 잘 로드했다면 message와 padding을 이용하여 encryption을 진행할 수 있다.

    bytes(message)를 한 이유는 message가 bytearray로 되어있어 바꿔주었기 때문이다.

    만약 byte로 되어있다면 그냥 넣어주면된다. 그리고 padding은 본인이 원하는대로!

    나는 decryption을 하는 부분에서 PKCS1v15를 요청했기에 이렇게 진행했다.

     

    다음으로는 private key를 이용한 signature다.

     

    from cryptography.hazmat.primitives import serialization
    from cryptography.hazmat.primitives.asymmetric import padding
    from cryptography.hazmat.primitives import hashes
    
    with open(privkey_path, 'rb') as content:
        private_key= serialization.load_pem_private_key(content.read(), None)
    
    signature = private_key.sign(
        ciphertext,
        padding.PKCS1v15(),
        hashes.SHA256()
    )

    다음과같이 진행하면된다.

    signature는 private key를 이용하여 진행하고 이전에 encryption에서 나왔던 결과인 ciphertext를 그대로 이용해준다.

     

    그런데 여기서 궁금한 점이 있을 수 있는게

    encryption으로 나온 ciphertext는 256bytes였고 이를 digest(간단하게 해쉬로 만들기?)하고

    signature를 진행했는데 여기서는 그런 시스템이 없어 조금 신기했다.

     

    그래서 rsa.py를 찾아보니

    def sign(
        self,
        data: bytes,
        padding: AsymmetricPadding,
        algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
        ) -> bytes:
            self._enable_blinding()
            data, algorithm = _calculate_digest_and_algorithm(data, algorithm)
            return _rsa_sig_sign(self._backend, padding, algorithm, self, data)
            
    def _calculate_digest_and_algorithm(
    data: bytes,
    algorithm: typing.Union[Prehashed, hashes.HashAlgorithm],
        ) -> typing.Tuple[bytes, hashes.HashAlgorithm]:
        if not isinstance(algorithm, Prehashed):
            hash_ctx = hashes.Hash(algorithm)
            hash_ctx.update(data)
            data = hash_ctx.finalize()
        else:
            algorithm = algorithm._algorithm

    다음과같이 되어있는데 Prehashed를 쓰지 않는다면 알아서 digest를 해준다.

    hash_ctx ~ data의 세줄이 digest코드이다.

    그래서 만약 미리 사용하고싶다면 저 코드를 사용하고

    Prehased를 작성해주면되는데 굳이 사용해야하나 싶다?!

    그냥 적어도 되는듯~~

     

    더 궁금하다면

    https://cryptography.io/en/2.7/hazmat/primitives/asymmetric/rsa/#signing

     

    RSA — Cryptography 2.7 documentation

    The computed salt length.

    cryptography.io

    여기 내용을 확인해보면된다.

     

    그리고 만약 sign이 잘 이루어졌는지 확인하는 방법은

    private_key.public_key().verify(
        signature,
        ciphertext,
        padding.PKCS1v15(),
        hashes.SHA256()
    )

    private_key.public_key()를 해주면 public key를 부를 수 있으므로 저렇게 코드를 작성하고

    signature와 이전의 ciphertext를 비교해주는 인자로 넣고 진행했을 때

    오류가 발생하지않는다면 잘 이루어진걸로 생각할 수 있다.

    이렇게 signature까지 완료했다.

     

    사실 나는 다른 부분에서 계속 실수하고있었지만 이 encryption과 signature가 문제인줄알고

    3일동안 계속 찾아봤는데 결국 확인해보니 다 맞는 코드였고

    다른 부분의 실수를 찾아 다음으로 진행하게되었다.

     

    앞으로 내가 실수하는 부분이나 확신이 없는 부분들은 바로바로 올리도록 노력해야겠다..

     

    ㅎㅎ.

    728x90
    반응형
Designed by Tistory.