ホームページ  >  記事  >  php教程  >  Golang 暗号化および復号化 RSA (php を使用)

Golang 暗号化および復号化 RSA (php を使用)

高洛峰
高洛峰オリジナル
2016-12-30 09:08:021834ブラウズ

RSA暗号化アルゴリズムの簡単な歴史

RSAは1977年にRon Rivest、Adi Shamir、Leonard Adlemanによって提案されました。当時、3 人全員が MIT で働いていました。 RSA は、姓の頭文字を綴ったものです。

RSA暗号化アルゴリズムの原理

アルゴリズムを勉強したことのある友人は、コンピューターのアルゴリズムが実際には数学的な演算であることを知っています。したがって、RSA 暗号化アルゴリズムを説明する前に、必要な数学的知識を理解する必要があります。数学的な知識から始めましょう。

必須の数学的知識

RSA暗号化アルゴリズムでは、素数、素数、指数演算、剰余演算などのいくつかの簡単な数学的知識のみが使用されます。したがって、これらの概念も理解する必要があります。

素数

素数とは、素数とも呼ばれ、1と整数そのものを除く他の自然数では割り切れない、1より大きい自然数を指します。この概念は中学校や小学校でも習ったことがあるので、ここではあまり説明しません。

共素数

百度百科の説明は、 共通約数が1だけの2つの数を共素数と呼ぶ。 ; Wikipedia の説明は「共素」、「共素」とも呼ばれます。 N 個の整数の最大公約数が 1 の場合、これらの N 個の整数は互いに素であると言われます。

互いに素数を判断するための一般的な方法は主に次のとおりです:

1. 2 つの異なる素数は互いに素数である必要があります。たとえば、2 と 7、13 と 19 などです。

2. 一方の素数がもう一方の素数の倍数でない場合、これら 2 つの数は互いに素です。たとえば、3 と 10、5 と 26 などです。

3. 隣接する 2 つの自然数は互いに素な数です。 15とか16とか。

4. 隣接する 2 つの奇数は互いに素な数です。 49や51など。

5. 大きいほうの数が素数である 2 つの数は互いに素です。 97とか88とか。数 6. 小数は品質を表し、2 つの数字は小数の倍数ではありません。たとえば、7 と 16。

7、2、および任意の奇数は互いに素数です。たとえば、2 と 87。

8. 1 は素数でも合成数でもありません。どの自然数とも素です。 1 や 9908 など。

9. ユークリッドの割り算。

指数演算

指数演算はべき乗計算とも呼ばれ、計算結果はべき乗と呼ばれます。 nm は、n を m 回掛けることを指します。 nm をべき乗として扱った結果を「n の m 乗」または「n の m 乗」と呼びます。このうち、nを「基数」、mを「指数」と呼びます。

剰余演算

剰余演算とは剰余演算のことです。 「モジュール」は「Mod」の音訳です。剰余算術と密接に関係する概念に「合同」があります。数学的には、2 つの整数を同じ正の整数で割って同じ余りが得られる場合、2 つの整数は合同です。

2 つの整数 a と b を正の整数 m で除算して得られる剰余が等しい場合、a と b は合同な法 m であると言われ、次のように表されます。 a ≡ b (mod m) と読みます。 m を法として b に変換するか、または a と b が m を法として合同です。例: 26 ≡ 14 (mod 12)。

RSA 暗号化アルゴリズム

公開鍵と鍵の生成

アリスが信頼できないメディアを通じてボブからプライベートメッセージを受信したいと仮定します。彼女は次の方法で公開鍵と秘密鍵を生成できます:

1. 2 つの大きな素数 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) は秘密キーです。アリスは自分の公開鍵 (N,e) をボブに渡し、自分の秘密鍵 (N,d) を隠します。

暗号化されたメッセージ

ボブがアリスにメッセージ m を送信したいとしますが、彼はアリスによって生成された N と e を知っています。彼は、最初にアリスと合意した形式を使用して、m を N 未満の整数 n に変換します。たとえば、各単語をその単語の Unicode コードに変換し、これらの数値を結合して数値を形成できます。メッセージが非常に長い場合は、メッセージをいくつかの段落に分割し、各段落を n に変換できます。次の式を使用すると、n を c に暗号化できます:

ne ≡ c (mod N)

c の計算は複雑ではありません。ボブは c を見つけたら、それをアリスに渡すことができます。

メッセージを復号化

アリスはボブのメッセージ c を取得した後、自分のキー d を使用してメッセージを復号化できます。彼女は次の式を使用して c を n に変換できます:

cd ≡ n (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) そしてn e・d ≡ n (mod q)

これは、(pとqが違うから)ということを示しています。素数、したがって p と q は相対的に素です)

n e·d ≡ n (mod pq)

署名付きメッセージ

RSA はメッセージの署名にも使用できます。 A が署名付きメッセージを B に配信したい場合、メッセージのハッシュ値 (メッセージ ダイジェスト) を計算し、自分のキー (秘密キー) を使用してハッシュ値を暗号化し、この「署名」をメッセージの最後に追加します。メッセージ。このメッセージは、彼女の公開キーを使用してのみ復号化できます。 B はメッセージを取得した後、A の公開キーを使用してハッシュ値を復号し、このデータをメッセージに対して計算された自分のハッシュ値と比較できます。 2 つが一致する場合、送信者は A のキーを保持していること、およびメッセージが伝播経路中に改ざんされていないことを知ることができます。

Golang の暗号化と復号化 RSA

PHP では、多くの関数が 1 つの関数で解決されることがよくありますが、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 で、encoding/pem パッケージと crypto/x509 パッケージをチェックアウトします。

暗号化と復号化には多くの標準が関係しますが、必要に応じて一時的に学習することをお勧めします。

2. RSA 暗号化と復号化に進みます

1. RSA 暗号化と復号化については、crypto/ras パッケージを必ず確認します

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

これは、PKCS に基づいた RSA 暗号化テクノロジを実装します。 #1仕様。

PKCS#1とは何かについては、関連情報を確認できます。 PKCS (Public Key Cryptozoology Standard)、#1 は RSA 標準です。ご覧いただけます: PKCS シリーズの紹介

このパッケージの関数名から、暗号化関数と復号化関数の 2 つのペアがあることがわかります。

EncryptOAEP和DecryptOAEP
EncryptPKCS1v15和DecryptPKCS1v15

これは、PKCS #1 v2.1 RSA アルゴリズム標準で詳細を確認できます

他の言語と対話する場合、どのスキームを使用するかを決定する必要があることがわかります。 。

PublicKey と PrivateKey の 2 つのタイプは、それぞれ公開鍵と秘密鍵を表します。この記事では、これら 2 つのタイプの例は、パスワードを解析することによって取得されます。記事の冒頭で生成されたKeyを取得します。

2. キーを解析して PublicKey と PrivateKey のインスタンスを取得します

私もこのプロセスに多くの時間を費やしました (主にさまざまな暗号化について詳しくありません): openssl によって生成されたキー ファイルを解析して public についてはどうするか秘密鍵インスタンスは?

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 までご連絡ください。