http://blog.naver.com/chunter99/25236825
>>> 본 강좌는 RSA 암호화와 JAVA에 대한 기본적인 지식이 있는 분들을 위한

         강좌이므로 이론적인 부분들은 따로 공부하기 바립니다.

         (이 강좌는 제가 절대 자바나 암호학에 대하여 해박한 지식이 있어서 쓰는 것이

         아니라는 것을 먼저 밝혀두는 바입니다.

         그냥 요번 방학동안 배운 것을 한번 정리하는 차원에서 적는 것입니다.)

 

■ 요약

 

  >>> RSA 공개키 암호화 알고리즘은 1977년에 Riverst, Shamir 그리고 Adleman 이라는 세 명의

         수학자들에 의해 제안된 방식이다. 이 알고리즘은 현재 공개키 암호 기법들 중에서 가장 널리

         사용되고 있다. RSA 암호화는 아주 큰 소수(large prime number)로 된 합성수를 인수분해

         하는것이 어렵다는데 그 기반을 두고 있다.

        

         그 기본 원리는 다음과 같다.

 

  >>> RSA 공개키 암호에 사용될 공개키 {N,E}와 개인키{N,D}를 생성하기 위해서는 먼저 모든

         사용자들은 각각 다음의 작업을 수행하여야 한다.

       

         ① 두 개의 큰 소수 p와 q를 선정한 다음에 Modulus N = p * q와 PI(N)을 계산한다.

         ② 공개키 E는 PI(N) = (p - 1)(q - 1)과 서로 소의 관계가 되게 임의 로 선정한다.

         ③ E * D mon PI(N) = 1의 관계에 있는 개인키 D를 "확장된 유 클리드 알고리즘"으로 구한다.

         ④ {E,N}을 공개키로 공개하고, {D,N}을 개인키로 자신이 안전하게 보관한다.

 

  >>> 그 다음  RSA 암호의암호화를 위해서는 먼저 암호화된 메시지를 받을 수신자의 공개키 {E, N}을

         취득한 후에 암호화 할 평문M을 정수 M으로 전환하여 다음과 같은 암호화 작업을 수행한 결과인

         암호문 C를 수신자에게 보내고, 수신자는 자신의 개인키를 이용한 복호화 작업을 통해서 원래의

         평문M을 복원하게 된다.

      

         RSA암호화 :  E(M) = M ^ E mod N = C

         RSA복호화 :  D(C) = C ^ D mod N = ((M ^ E) ^ D) mod N = M

        

■ 자바를 이용한 실용적 구현

 

  >>> RSA 공개키 암호화를 구현하기 위하여는 대략 4가지 정도의 암고리즘이 필요하다.

 

        ① 큰 두 소수를 찾기위한 Miller-Rabin 판정법

        ② 공개키를 구하기 위한 유클리드 알고리즘의 변형

        ③ 개인키를 구하기 위한 확장된 유클리드 알고리즘

        ④ 법 연산을 위한 빠른 법-지수 연산 알고리즘

  

  >>> 자 그러면 프로그램의 흐름을 하나하나 생가해보면서 출발해 보자구요^^

         가장 먼저 해야할 일은 당연히 평문을 입력받아서 그것을 계산하기 위하여 10진수로 바꾸는

         작업이겠지요

 

         char charArray[];

         charArray=plainText.toCharArray();

         long temp=(long)charArray[i];  // 이 작업을 평문의 길이 만큼 반복하면 되겠지요^^

 

  >>> 이제 평문은 구했으니까 법N을 구해봅시다.

         법N은 두 소수의 곱으로 이루어 졌으니까 소수를 두개 구하여 곱하면 되겠네요(당연한소리!!!)

         이를 위하여 있는 것이 큰 소수를 구한는 알고리즘인 밀러-라빈 판정법입니다.

 

   while(1==1)

   {

      count=1;

      while(1==1)

      {

          // 자바에서 소수 p와 q가 서로 비슷하게 5자리이상을 가지도록 설정하는 것은 불가능하다.

          // 그래서 여기서는 4자리고 사용하였다.

          randomNum=(long)(Math.random() * 10000);

          if(randomNum<=1000) // 4자리로 제한하기 위하여

             continue;

          prime=millerRabin(randomNum); // 밀러-라빈 판정법을 거친다.

          if(prime==false) // 소수가 아니면 다시 루프를 반복한다.

         {

             count++; // 몇번 루프를 반복하는지 카운터한다.

             continue;

          }

          else // 소수이면 루프를 빠져 나온다.

             break;

       }

       bub[bubCount]=randomNum; // 선택된 난수를 저장

       textarea.append("  ▶ 소수" + (bubCount+1) + " : " + bub[bubCount] + "n");

       textarea.append("      >>> " + count + "개의 난수를 검사하였습니 다.n");                     

       bubCount++; // 두번째 난수를 위한 카운터

       if(bubCount == 2) // 난수가 2개 선정 되었으면 루프를 빠져나온다

         break;                  

    }  

 

    // 밀러-라빈 알고리즘은 그냥 책에 나와있는데로 하시면 되기 때문에

    // 자세한 설명은 생략하기로 하겠습니다.

    public static boolean millerRabin(long n)

    {       

       long r=n-1;

       long k=0;

       long j=0;

       long y=0;

       boolean isPrime=true;   

       long s=0;               

                        

       /* s가 하나 증가하면 r은 반으로 감소해야 균형이 이루어 지므로

           s가 증가할때마다 r은 반으로 감소시키고, 밀러-라빈 조건에서

           r이 홀수 일때 이것이 만족하므로 r이 홀수이면 이 루프를

           빠져 나온다.*/

 

       while(r%2==0)

       {       

          r=r/2;

          s++;                            

       }                                       

                        

       // k =(long)Math.log(n)/2;  

 

 

        for(int i=0;i<100;i++)

        {

           long a=(long)(Math.random()*(n-2));     

           y = fastExp(a,r,n); // 빠른 법-지수 연산을 위한 알고리즘. 뒤에 나오거든요...

           if(y != 1 && y!=n-1)

           {

              j=1;

              while(j<=s-1&&y!=n-1)

              {

                 y=(y*y)%n;

                 if(y==1)

                 {

                    isPrime=false;

                    return isPrime;

                  }

                  j=j+1;

               }

               if(y!=(n-1))

               {

                  isPrime=false;

                  return isPrime;

                }

             }

          }                       

          return isPrime;

       }

 

  >>> 자 일단 한 고비는 넘겼으니까 숨 한번 쉬고 다음으로 넘어갑시다.

         휴~~~

         그럼 소수를 정하였으니까 이제 공개키를 선정해야겠지요.

         공개키 선정은 간단합니다. 임의의 소수를 하나 선정하여 그것이 pi(n)과

         서로 소의 관계에 있는지(최대 공약수가 1인지)를 검사만 하면됩니다.

 

   // 공개키를 구하는 함수

   public static long publicKeyMaker(long temp)

   {

      long ee=0;

      while(1==1)

      {

         ee=(long)(Math.random()*10000);

         long gcd = gcd(ee, temp);

         if(gcd==1)

            break;

      }

      return ee;

   }

   

    // 최대 공약수를 구하는 함수

    public static long gcd(long a, long b)   

   {

      long s = a;

      long t = b;

      long r=0;

      while(t>0)

      {

         r = s % t;

         s = t;

         t = r;

      }

      return s;

   }   

  

  >>> 자 이제 확장된 유클리드 알고리즘을 거쳐서 개인키만 구하면 되는군요

         저도 이부분이 가장 힘들었는데 인터넷에서 누군가가 C로 구현해 놓은것이 있어서

         그것을 자바로 바꾸어 보았습니다.

         자세한 알고리즘을 알고 싶으시면 자료실의 RSA자료를 참조하시기 바랍니다.

 

   // 개인키 d를 구하기 위한 확장된 유클리드 알고리즘

   // 첫 번째 매개변수는 공개키이고, 두 번째는 pi(n) 입니다.

   public static long extendUclide(long first, long second)

   {

      long b,p,x,s,q,e,w,a;  

      b = second;

      a = first;

      x = 0;

      s = 1;

      while(a != 1)

      {

         q = b/a;

         e = b - a*q;

         w = x - s*q;

         b = a;

         a = e;

         x = s;

         s = w;

      }

      if(s < 0)

         s = s + second;

      return s;

   }

 

  >>> 으흐흐흐... 드디어 개인키까지 다 구하였군요. 감기가 무량(?)하군요...(아닌가?)

         자 마지막으로 할 일은 빠른 법-지수 연산을 거쳐서 암호화만 수행하면 되는군요.

  

   // 빠르게 m^e mod n 을 구하기 위한 알고리즘

   public static long fastExp (long m, long e, long n)

   {

      long z = 1 ;

      while (e != 0) //지수의 비트수와 일치할때까지 반복한다.

      {

         while (e % 2 == 0) // 지수의 특징 비트가 1일때

         {

            e = e / 2 ; // 이렇게 함으로써 지수의 비트수가 한 자리 줄어든다

            m = (m * m) % n ;

          }

          e--; // 지수의 특징 비트가 0이 되도록 한다.

          z = (z * m) % n ; // 지수가 0일때 계산

      }

      return z;

   }


번호 제목 글쓴이 날짜 조회 수
공지 [계속 추가중] SBOM 용어 정의 황제낙엽 2025.04.10 21565
공지 [계속 추가중] Keycloak 용어 및 설정 옵션 정의 황제낙엽 2024.02.02 20405
146 SPDX 2.3, 계속 써도 되나요? — 3.0으로 넘어갈 때를 판단하는 실무 기준 황제낙엽 2026.08.11 55
145 같은 OSS 지만 여러 버전을 등록해야 하는 경우 황제낙엽 2026.04.24 1972
144 [FOSSLight Dependency Scanner] Android Project 의 Dependency Scan 을 위한 Android SDK 설치와 설정 황제낙엽 2026.04.23 1843
143 FOSSLight Hub 의 REST API 이용 (v2) 황제낙엽 2026.03.19 2500
142 [FOSSLight/검토용] 개발그룹의 sbom-info.yaml 분석 및 피드백 절차 황제낙엽 2026.03.16 1983
141 [FOSSLight/관리용] Project Identification 진행에서 최종 SBOM SPDX 문서 추출 황제낙엽 2026.02.09 1917
140 [FOSSLight] 'Download Location' 컬럼 값에 'Different from DB' 라는 푸른색 메세지가 출력 file 황제낙엽 2026.02.06 3613
139 [FOSSLight] Project Identification 진행시의 신규 OSS 등록 처리 방법 황제낙엽 2026.02.06 3750
138 [FOSSLight Hub] License 정보를 직접 등록시 필요한 항목 목록 황제낙엽 2026.02.06 3579
137 [FOSSLight Hub] Open Source 정보를 직접 등록시 필요한 항목 목록 황제낙엽 2026.02.06 3352
136 [OSS] Microsoft.Web.WebView2 황제낙엽 2026.02.06 3352
135 [FOSSLight] fosslight 프로젝트의 'Pre-Review' > 'Open Source' 팝업창의 세 버튼에 대한 용도 황제낙엽 2026.02.06 3572
134 [FOSSLight/검토용] prechecker convert 결과 Hub 등록후 Identification 처리 file 황제낙엽 2026.02.05 3289
133 python venv 설치, fosslight source scanner , binary scanner 설치, 버전 확인 황제낙엽 2026.02.02 3508
132 SPDX 템플릿 다운로드 및 온라인 변환기 황제낙엽 2026.01.22 3870
131 SBOM(Software Bill of Materials) 및 소프트웨어 공급망 보안 관련 주요 정부 기관 및 단체 황제낙엽 2026.01.22 3605
130 [FOSSLight] online guide link 황제낙엽 2026.01.14 1844
129 identification 에서 출력하는 warning, error 메세지 황제낙엽 2025.12.29 1427
128 sbom-info.yaml 을 이용한 dependency scan excel 작성 file 황제낙엽 2025.12.29 3578
127 binary scan 결과물에 대해 취약점이 없는데 왜 SBOM에 넣어야 하나? 황제낙엽 2025.12.17 3484