>  기사  >  php教程  >  Golang 암호화 및 복호화 RSA(php 사용)

Golang 암호화 및 복호화 RSA(php 사용)

高洛峰
高洛峰원래의
2016-12-30 09:08:021799검색

RSA 암호화 알고리즘의 간략한 역사

RSA는 1977년 Ron Rivest, Adi Shamir 및 Leonard Adleman이 함께 발명했습니다. 당시 세 사람 모두 MIT에서 일하고 있었습니다. RSA는 성의 첫 글자를 함께 모아 구성됩니다.

RSA 암호화 알고리즘의 원리

알고리즘을 공부해 본 친구들은 컴퓨터의 알고리즘이 실제로는 수학적 연산이라는 것을 알고 있습니다. 따라서 RSA 암호화 알고리즘을 설명하기 전에 몇 가지 필요한 수학적 지식을 이해하는 것이 필요합니다. 수학적 지식부터 시작해 보겠습니다.

필요한 수학적 지식

RSA 암호화 알고리즘에서는 소수, 서로소, 지수연산, 모듈러연산 등 몇 가지 간단한 수학적 지식만 사용한다. 그러므로 우리는 이러한 개념도 이해해야 합니다.

소수

소수란 1보다 큰 자연수로서 1과 정수 그 자체를 제외한 다른 자연수로는 나누어지지 않는 숫자를 말합니다. 우리 모두 이 개념을 중학교, 심지어 초등학교 때 배웠기 때문에 여기서는 자세히 설명하지 않겠습니다.

공소수

바이두백과사전에 설명된 내용은 다음과 같습니다. 공약수가 1인 두 수를 공소수라고 합니다. ;위키피디아에 대한 설명은 코프라임(co-prime), 코프라임(co-prime)이라고도 합니다. N개의 정수의 최대공약수가 1이면 이 N개의 정수는 상대적으로 소수라고 합니다.

공통소수를 판단하는 일반적인 방법은 다음과 같습니다.

1. 서로 다른 두 소수는 반드시 서로소수여야 합니다. 예를 들어 2와 7, 13과 19입니다.

2. 하나의 소수이고 다른 하나가 그 배수가 아닌 경우, 이 두 수는 서로소입니다. 예를 들어 3과 10, 5와 26입니다.

3. 인접한 두 자연수는 서로소이다. 예를 들어 15와 16입니다.

4. 인접한 두 홀수는 서로소이다. 49와 51 같은 거죠.

5. 소수가 더 큰 두 수는 서로소이다. 97이나 88처럼 말이죠.

6. 소수는 소수이고, 소수의 배수가 아닌 두 수는 서로소이다. 예를 들어 7과 16입니다.

7, 2 및 모든 홀수는 서로소입니다. 예를 들어 2와 87입니다.

8. 1은 소수도 합성수도 아닌 자연수와 서로소이다. 1과 9908과 같은 것입니다.

9. 유클리드 나눗셈.

지수연산

지수연산을 지수연산이라고도 하며, 계산결과를 거듭제곱이라고 합니다. nm은 n을 m번 곱한 것을 의미합니다. nm를 거듭제곱한 결과를 "n의 m제곱" 또는 "n의 m제곱"이라고 합니다. 그 중 n을 "밑", m을 "지수"라고 합니다.

모듈로 연산

모듈로 연산은 나머지 연산입니다. "모듈"은 "모드"를 음역한 것입니다. 모듈러 산술과 밀접하게 관련된 개념은 "합동"입니다. 수학적으로 두 정수를 동일한 양의 정수로 나누고 동일한 나머지를 얻으면 두 정수는 합동입니다.

두 정수 a, b를 양의 정수 m으로 나누어 얻은 나머지가 동일하면 a와 b는 모듈로 m에 합동이라고 하며 다음과 같이 표시됩니다. a ñ b (mod m); 다음과 같이 읽습니다: a는 b mod m과 합동입니다. 또는 a와 b는 모듈로 m과 합동입니다. 예: 26  14(mod 12).

RSA 암호화 알고리즘

공개 키 및 비밀 키 생성

Alice가 신뢰할 수 없는 매체를 통해 Bob으로부터 개인 메시지를 받기를 원한다고 가정합니다. 그녀는 다음과 같은 방법으로 공개 키와 개인 키를 생성할 수 있습니다.

1. 두 개의 큰 소수 p와 q를 무작위로 선택하고 p는 q와 같지 않으며 N=pq를 계산합니다.

2. 오일러 함수에 따라 r = (p-1)(q-1)

을 구합니다. 3. r보다 작은 정수 e를 선택합니다. , 모듈로 r에 대해 e의 모듈러 역원소를 구하고 이름을 d로 지정합니다. (모듈러 역원소는 e와 r이 서로 소수인 경우에만 존재합니다.)

4. p와 q의 레코드를 삭제합니다.
(N,e)는 공개 키이고, (N,d)는 개인 키입니다. Alice는 공개 키(N,e)를 Bob에게 전달하고 개인 키(N,d)를 숨깁니다.

암호화된 메시지

Bob이 Alice에게 메시지 m을 보내고 싶어하고 Alice가 생성한 N과 e를 알고 있다고 가정합니다. 그는 원래 Alice와 합의한 형식을 사용하여 m을 N보다 작은 정수 n으로 변환합니다. 예를 들어, 그는 각 단어를 단어의 유니코드 코드로 변환한 다음 이 숫자를 함께 연결하여 숫자를 형성할 수 있습니다. 메시지가 너무 길면 메시지를 여러 단락으로 나눈 다음 각 단락을 n개로 변환할 수 있습니다. 다음 공식을 사용하여 n을 c로 암호화할 수 있습니다.

 ne EMA(mod N)

c를 계산하는 것은 복잡하지 않습니다. Bob은 c를 알아낸 후 이를 Alice에게 전달할 수 있습니다.

메시지 복호화

Alice는 Bob의 메시지 c를 받은 후 자신의 키 d를 사용하여 이를 복호화할 수 있습니다. 다음 공식을 사용하여 c를 n으로 변환할 수 있습니다.

cd ל(mod N)

n을 얻은 후 원래 정보 m을 복원할 수 있습니다.

디코딩 원리는 다음과 같습니다.

 cd Ā n e·d(mod N)

및 ed ė 1(mod p-1) 및 ed ė 1(mod q) - 1). 페르마의 소정리(p와 q는 소수이기 때문에)로 증명할 수 있습니다.

 n e·d ñ n (mod p)  And n e·d ñ n (mod q)

이는 다음과 같습니다. (p와 q는 서로 다른 소수이므로 p와 q는 상대적으로 소수이다)

 n e·d zzo n (mod pq)

서명된 메시지

 RSA도 가능 메시지 서명에 사용됩니다. A가 서명된 메시지를 B에게 전달하려는 경우 그녀는 메시지에 대한 해시 값(메시지 다이제스트)을 계산한 다음 자신의 키(개인 키)를 사용하여 해시 값을 암호화하고 이 "서명"을 추가할 수 있습니다. 메시지. 이 메시지는 공개 키를 통해서만 해독될 수 있습니다. B는 메시지를 얻은 후 A의 공개 키를 사용하여 해시 값을 해독한 다음 이 데이터를 메시지에 대해 계산된 자신의 해시 값과 비교할 수 있습니다. 두 가지가 일치하면 보낸 사람이 A의 키를 보유하고 있고 메시지가 전파 경로 동안 변조되지 않았음을 알 수 있습니다.

Golang 암호화 및 복호화 RSA

PHP에서는 많은 기능이 하나의 기능으로 해결되는 경우가 많지만 Go에서는 그렇지 않습니다. 이 기사에서는 PHP 암호화, Go 암호화, PHP 복호화를 통해 Go의 RSA 관련 API를 학습합니다.

이 기사에서는 Go RSA 암호화 및 복호화에 대해 설명합니다. 모든 작업은 Linux에서 완료됩니다.

1. 개요

일반적으로 공개키 암호화와 개인키 복호화를 사용하는 비대칭 암호화 알고리즘입니다.

암호화 및 복호화 과정에서 openssl을 사용하여 키를 생성합니다. 다음 작업을 수행합니다.

1) 개인 키 생성:

openssl genrsa -out private.pem 1024 //密钥长度,1024觉得不够安全的话可以用2048,但是代价也相应增大

2) 공개 키 생성:

openssl rsa -in private.pem -pubout -out public.pem
这样便生产了密钥。

일반적으로 각 언어마다 키 생성을 위한 API도 제공합니다. Go에서는 인코딩/pem 패키지와 crypto/x509 패키지를 확인하세요.

암호화와 복호화에는 많은 표준이 포함됩니다. 개인적으로 필요할 때 임시로 학습하는 것을 권장합니다.

2. RSA 암호화 및 복호화 진행

1. rsa 암호화 및 복호화는 반드시 crypto/ras 패키지를 확인하세요

Package rsa implements RSA encryption as specified in PKCS#1.

>

패키지에 대한 설명은 다음과 같습니다. PKCS#1 사양을 기반으로 RSA 암호화 기술을 구현합니다.

PKCS#1이 무엇인지 관련 내용을 확인하실 수 있습니다. PKCS(공개 키 암호동물학 표준), #1은 RSA 표준입니다. 다음을 볼 수 있습니다: PKCS 시리즈 소개

이 패키지에 포함된 기능 이름을 보면 암호화 및 복호화 기능이 두 쌍으로 구성되어 있음을 알 수 있습니다.

EncryptOAEP和DecryptOAEP
EncryptPKCS1v15和DecryptPKCS1v15

이를 암호화 방식이라고 합니다. PKCS #1 v2.1 RSA 알고리즘 표준

이 표시됩니다. 어떤 솔루션을 사용할지 결정하세요.

PublicKey와 PrivateKey 두 가지 유형은 각각 공개 키와 개인 키를 나타냅니다. 이 두 유형의 멤버를 설정하는 방법은 RSA 암호화 알고리즘을 통해 분석됩니다. 기사 처음에 생성된 키를 얻습니다.

2. 키를 구문 분석하여 PublicKey 및 PrivateKey 인스턴스를 얻습니다.


이 과정에도 시간이 오래 걸렸습니다(주로 다양한 암호화에 익숙하지 않음): 키를 구문 분석하는 방법 openssl이 생성한 파일을 공개 키와 개인 키 인스턴스로 변환할 수 있나요?

encoding/pem 패키지에서 --BEGIN Type---이라는 단어를 봤습니다. 이는 openssl에서 생성된 키 형식과 유사하므로 한번 시도해 보세요.

이 패키지에서 블록은 PEM 인코딩 구조를 나타냅니다. PEM의 경우 관련 정보를 확인하세요. 물론 Decode 메서드를 사용하여 키를 구문 분석하려고 합니다.

func Decode(data []byte) (p *Block, rest []byte)

이러한 방식으로 Block 인스턴스(포인터)를 얻습니다.

crypto/x509를 보기 위한 분석. 왜 x509인가? 여기에는 다시 많은 개념이 포함됩니다. 그럼에도 불구하고 인코딩 패키지와 암호화 패키지의 하위 패키지를 살펴보며 알게 되었습니다.


x509 패키지에는 다음 함수가 있습니다.

func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)

함수 설명에 따르면 ParsePKIXPublicKey는 DER로 인코딩된 공개 키를 구문 분석합니다. 값은 일반적으로 "BEGIN PUBLIC KEY"가 있는 PEM 블록에서 발견됩니다. 이것이 PublicKey의 파싱임을 알 수 있다. 또한 여기서 PEM의 경우 위의 인코딩/pem이 정확할 수 있습니다.

개인 키를 구문 분석하는 방법은 여러 가지가 있습니다. 위의 소개에서 RSA가 PKCS#1이라는 것을 알고 있으며,

func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)

반환되는 것은 rsa.PrivateKey입니다.

3. 복호화 및 복호화 구현


위의 소개를 통해 Go에서 RSA 복호화를 구현하는 것은 어렵지 않습니다. 코드는 다음과 같습니다.

// 암호화

func RsaEncrypt(origData []byte) ([]byte, error) {
  block, _ := pem.Decode(publicKey)
  if block == nil {
    return nil, errors.New("public key error")
  }
  pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
  if err != nil {
    return nil, err
  }
  pub := pubInterface.(*rsa.PublicKey)
  return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}

// 복호화

func RsaDecrypt(ciphertext []byte) ([]byte, error) {
  block, _ := pem.Decode(privateKey)
  if block == nil {
    return nil, errors.New("private key error!")
  }
  priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  if err != nil {
    return nil, err
  }
  return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
}

其中,publicKey和privateKey是openssl生成的密钥,我生成的如下:

// 公钥和私钥可以从文件中读取

var privateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y
7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7
Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQAB
AoGBAJlNxenTQj6OfCl9FMR2jlMJjtMrtQT9InQEE7m3m7bLHeC+MCJOhmNVBjaM
ZpthDORdxIZ6oCuOf6Z2+Dl35lntGFh5J7S34UP2BWzF1IyyQfySCNexGNHKT1G1
XKQtHmtc2gWWthEg+S6ciIyw2IGrrP2Rke81vYHExPrexf0hAkEA9Izb0MiYsMCB
/jemLJB0Lb3Y/B8xjGjQFFBQT7bmwBVjvZWZVpnMnXi9sWGdgUpxsCuAIROXjZ40
IRZ2C9EouwJBAOPjPvV8Sgw4vaseOqlJvSq/C/pIFx6RVznDGlc8bRg7SgTPpjHG
4G+M3mVgpCX1a/EU1mB+fhiJ2LAZ/pTtY6sCQGaW9NwIWu3DRIVGCSMm0mYh/3X9
DAcwLSJoctiODQ1Fq9rreDE5QfpJnaJdJfsIJNtX1F+L3YceeBXtW0Ynz2MCQBI8
9KP274Is5FkWkUFNKnuKUK4WKOuEXEO+LpR+vIhs7k6WQ8nGDd4/mujoJBr5mkrw
DPwqA3N5TMNDQVGv8gMCQQCaKGJgWYgvo3/milFfImbp+m7/Y3vCptarldXrYQWO
AQjxwc71ZGBFDITYvdgJM1MTqc8xQek1FXn1vfpy2c6O
-----END RSA PRIVATE KEY-----
`)
  
var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZsfv1qscqYdy4vY+P4e3cAtmv
ppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0Dgacd
wYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NL
AUeJ6PeW+DAkmJWF6QIDAQAB
-----END PUBLIC KEY-----
`)

   

4、使用例子

package main
  
import (
  "fmt"
)
 
func main() {
  data, err := RsaEncrypt([]byte("git@github.com/mrkt"))
  if err != nil {
    panic(err)
  }
  origData, err := RsaDecrypt(data)
  if err != nil {
    panic(err)
  }
  fmt.Println(string(origData))
}

  

该例子是加密完git@github.com/mrkt后立马解密

三、跨语言加解密

语言内部正常,还得看看和其他语言是否一致,即:其他语言加密,Go语言得正确解密;Go语言加密,其他语言正确解密

1、PHP RSA加解密

这里,我选择PHP,使用的是openssl扩展。PHP中加解密很简单,如下两个方法(这里只考虑用公钥加密,私钥解密):

bool openssl_public_encrypt ( string $data , string &$crypted , mixed
$key [, int $padding = OPENSSL_PKCS1_PADDING ] ) bool
openssl_private_decrypt ( string $data , string &$decrypted , mixed
$key [, int $padding = OPENSSL_PKCS1_PADDING ] )

   

最后一个参数是加密方案(补齐方式)。由于Go中使用的是PKCS1而不是OAEP,所以,使用默认值即可。

PHP代码如下:

$privateKey = '-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y
7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7
Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQAB
AoGBAJlNxenTQj6OfCl9FMR2jlMJjtMrtQT9InQEE7m3m7bLHeC+MCJOhmNVBjaM
ZpthDORdxIZ6oCuOf6Z2+Dl35lntGFh5J7S34UP2BWzF1IyyQfySCNexGNHKT1G1
XKQtHmtc2gWWthEg+S6ciIyw2IGrrP2Rke81vYHExPrexf0hAkEA9Izb0MiYsMCB
/jemLJB0Lb3Y/B8xjGjQFFBQT7bmwBVjvZWZVpnMnXi9sWGdgUpxsCuAIROXjZ40
IRZ2C9EouwJBAOPjPvV8Sgw4vaseOqlJvSq/C/pIFx6RVznDGlc8bRg7SgTPpjHG
4G+M3mVgpCX1a/EU1mB+fhiJ2LAZ/pTtY6sCQGaW9NwIWu3DRIVGCSMm0mYh/3X9
DAcwLSJoctiODQ1Fq9rreDE5QfpJnaJdJfsIJNtX1F+L3YceeBXtW0Ynz2MCQBI8
9KP274Is5FkWkUFNKnuKUK4WKOuEXEO+LpR+vIhs7k6WQ8nGDd4/mujoJBr5mkrw
DPwqA3N5TMNDQVGv8gMCQQCaKGJgWYgvo3/milFfImbp+m7/Y3vCptarldXrYQWO
AQjxwc71ZGBFDITYvdgJM1MTqc8xQek1FXn1vfpy2c6O
-----END RSA PRIVATE KEY-----'; $publicKey = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZsfv1qscqYdy4vY+P4e3cAtmv
ppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0Dgacd
wYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NL
AUeJ6PeW+DAkmJWF6QIDAQAB
-----END PUBLIC KEY-----';
function rsaEncrypt($data)
{
  global $publicKey;
  openssl_public_encrypt($data, $crypted, $publicKey);
  return $crypted;
 
}
function rsaDecrypt($data)
{
  global $privateKey;
  openssl_private_decrypt($data, $decrypted, $privateKey);
  return $decrypted;
}
 
function main()
{
 
  $crypted = rsaEncrypt("git@github.com/mrk");
  $decrypted = rsaDecrypt($crypted);
  echo "encrypt and decrypt:" . $decrypted;
 
}

   


main();

这里也是用PHP加解密git@github.com/mrkt

2、Go和PHP一起工作

这里要注意的一点是,由于加密后是字节流,直接输出查看会乱码,因此,为了便于语言直接加解密,这里将加密之后的数据进行base64编码。

3、使用

示例中,php和Go版本都支持-d参数传入加密好的字符串,将其解密;不传时,会输出加密好并base64编码的串,可用于其他语言解密。

总结

以上就是用Go语言实现了RSA的加密解密的全部内容,文章很深入的讲解了RSA的加密解密过程,对学习相关知识的朋友很有帮助。如果有疑问欢迎留言讨论。

更多Golang加密解密之RSA(附带php)相关文章请关注PHP中文网!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.