728x90

RSA 공개키, 개인키 생성 방법

# 리눅스 SSH 에서 RSA 공개키, 개인키 생성방법
mkdir -/home/rsa/key/
cd /home/rsa/key/
 
# Private Key 생성
openssl genrsa -out rsa_pri.pem 1024
 
# Public Key 생성
openssl rsa -pubout -in rsa_pri.pem -out rsa_pub.pem
 

 

rsa_key.php

Javascript 에서 RSA 암호화를 하고, PHP에서 복호화 시 아래 주석처리한 $key 부분을 주석처리 안해도 잘 동작된다.

그런데 Python 에서는 동작이 잘 안되더라. Python 에서도 동작되도록 Key 변수를 약간 수정했다.

<?php
function get_publickey() {
    // 경로 : 절대경로로 설정 필요
    $rsakeyfile = '/home/rsa/key/rsa_pub.pem';
    
    $fp = fopen($rsakeyfile,"r");
    $key = "";
    while(!feof($fp)) {
        $key .= fgets($fp,4096);
    } 
    fclose($fp);
 
    $key = preg_replace('/\r\n|\r|\n/','\n',$key);
    //$key = str_replace('-----BEGIN PUBLIC KEY-----','',$key);
    //$key = str_replace('-----END PUBLIC KEY-----','',$key);
    return $key;
 
function get_privatekey() {
    // 경로 : 절대경로로 설정 필요
    $rsakeyfile = '/home/rsa/key/rsa_pri.pem';
    
    $fp = fopen($rsakeyfile,"r");
    $key = "";
    while(!feof($fp)) {
        $key .= fgets($fp,4096);
    } 
    fclose($fp);
 
    $key = preg_replace('/\r\n|\r|\n/','\n',$key);
    //$key = str_replace('-----BEGIN RSA PRIVATE KEY-----','',$key);
    //$key = str_replace('-----END RSA PRIVATE KEY-----','',$key);
    return $key;
 
?>

 

login.html

pubkey는 예시로 일부만 발췌한 것이라 이 코드를 그대로 복사하면 동작되는게 아니다.

위에서 PHP코드로 발췌한 공개키를 복사하여 붙여녛기 해야 동작한다.

{% extends 'base.html' %}
{% load static %}
{% load bootstrap4 %}
 
{% block content %}
    <form method="POST" id="post-form">
        {% csrf_token %}
        {% bootstrap_form form %}
        <button type="submit" class="btn btn-primary">로그인</button>
        <a href="{% url 'home' %}">
            <button type="button" class="btn btn-warning">취소</button>
        </a>
    </form>
    <script type="text/javascript" src="{% static 'js/jsencrypt.min.js' %}"></script>
    <script>
        $(document).on('submit''#post-form'function (e) {
            e.preventDefault();
            var plainpw = $("input[name=password]").val();
            var pubkey = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCQAB\n-----END PUBLIC KEY-----";
            var crypt = new JSEncrypt();
            crypt.setPrivateKey(pubkey);
            var password = crypt.encrypt(plainpw);
 
            $.ajax({
                type: 'POST',
                url: '{% url 'login' %}',
                data: {
                    username: $("input[name=username]").val(),
                    password: password,
                    csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
                    action: 'post'
                },
                success: function (json) {
                    console.log(json);
                    if (json.data == 1) {
                        window.location.href = '/';
                        alert(json.message);
                    } else if (json.data == 0) {
                        alert(json.message);
                    }
                },
                error: function (xhr, errmsg, err) {
                    alert('에러가 발생했습니다.');
                    console.log(xhr.status + ": " + xhr.responseText);
                }
            });
        });
    </script>
{% endblock content %}
 

 

 

Javascript 에서 암호화한 비밀번호를 views.py 파일에서 복호화한다.

# accounts/views.py
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from .forms import SignUpForm, LoginForm
from .RSACipher import *
 
def login_view(request):
    context = {}
 
    if request.method == "POST":
        form = LoginForm(request.POST)
        if form.is_valid():
            # 유효성 검사, 내부적으로 form.clean()을 실행한다.
            username = form.cleaned_data.get("username")
            enc_password = form.cleaned_data.get("password")
            password = RSACipher().decrypt(enc_password)
 
            try:
                user = User.objects.get(username=username)
                if check_password(password, user.password):
                    access = authenticate(username=username, password=password)
                    login(request, access)
                    context['data'= '1'
                    context['message'= '로그인 되었습니다.'
                else:
                    context['data'= '0'
                    context['message'= '입력 정보를 확인하세요.'
                    # context['message'] = '비밀번호가 다릅니다.'
                return JsonResponse(context)
            except User.DoesNotExist:  # 대문자 User 임에 주의
                # 가입된 회원인지 미가입된 회원인지 알 수 없는 메시지 출력이 중요
                context['data'= '0'
                context['message'= '입력 정보를 확인하세요.'
                return JsonResponse(context)
        else:
            context['form'= form
    else:
        form = LoginForm()
        context['form'= form
 
    return render(request, "accounts/login.html", context)
 
 
def logout_view(request):
    logout(request)
    return redirect("home")
 

 

 

라이브러리 설치

pip install pycryptodomex (for window)

pip install pycryptodome (for linux)

 

 

RSACipher 클래스는 아래 게시글을 참조하여 직접 구현하면 될 것이다.

https://stackoverflow.com/questions/30056762/rsa-encryption-and-decryption-in-python

 

RSA encryption and decryption in Python

I need help using RSA encryption and decryption in Python. I am creating a private/public key pair, encrypting a message with keys and writing message to a file. Then I am reading ciphertext from...

stackoverflow.com

https://pycryptodome.readthedocs.io/en/latest/src/cipher/pkcs1_v1_5.html

 

PKCS#1 v1.5 encryption (RSA) — PyCryptodome 3.14.0 documentation

A cipher object PKCS115_Cipher.

pycryptodome.readthedocs.io

 

 

Custom User Model 기반으로 jQuery ajax 처리하는 전체 코드는 https://github.com/jsk005/PythonDjango/tree/main/customUserModel2 를 참조하면 도움될 것이다.

이 코드에서 RSACipher 클래스의 함수 코드 일부를 삭제했으나, 공부해서 충분히 해결할 수 있을 것으로 본다.

728x90
블로그 이미지

Link2Me

,