Heim >php教程 >PHP开发 >Golang-Verschlüsselung und -Entschlüsselung RSA (mit PHP)

Golang-Verschlüsselung und -Entschlüsselung RSA (mit PHP)

高洛峰
高洛峰Original
2016-12-30 09:08:021882Durchsuche

Eine kurze Geschichte des RSA-Verschlüsselungsalgorithmus

RSA wurde 1977 von Ron Rivest, Adi Shamir und Leonard Adleman erfunden und gemeinsam vorgeschlagen. Alle drei arbeiteten zu dieser Zeit am MIT. RSA besteht aus den Anfangsbuchstaben ihrer Nachnamen, die zusammen geschrieben werden.

Prinzip des RSA-Verschlüsselungsalgorithmus

Freunde, die Algorithmen studiert haben, wissen, dass Algorithmen in Computern tatsächlich mathematische Operationen sind. Daher ist es vor der Erläuterung des RSA-Verschlüsselungsalgorithmus erforderlich, einige notwendige mathematische Kenntnisse zu verstehen. Beginnen wir mit mathematischen Kenntnissen.

Notwendige mathematische Kenntnisse

Im RSA-Verschlüsselungsalgorithmus werden nur wenige einfache mathematische Kenntnisse wie Primzahlen, Koprimzahlen, Exponentialoperationen und modulare Operationen verwendet. Deshalb müssen wir auch diese Konzepte verstehen.

Primzahl

Eine Primzahl, auch Primzahl genannt, bezieht sich auf eine natürliche Zahl größer als 1, die nicht durch andere natürliche Zahlen außer 1 und der ganzen Zahl selbst teilbar ist. Wir alle haben dieses Konzept in der Mittelschule und sogar in der Grundschule gelernt, daher werde ich es hier nicht zu ausführlich erklären.

Koprimzahlzahlen

Die Erklärung in der Baidu-Enzyklopädie lautet: Zwei Zahlen mit einem gemeinsamen Faktor von nur 1 werden Koprimzahlzahlen genannt. ; Die Erklärung auf Wikipedia lautet: Co-Prime, auch Co-Prime genannt. Wenn der größte gemeinsame Teiler von N ganzen Zahlen 1 ist, dann nennt man diese N ganzen Zahlen teilerfremd.

Zu den gängigen Methoden zur Beurteilung von Koprimzahlen gehören die folgenden:

1. Zwei verschiedene Primzahlen müssen Koprimzahlen sein. Zum Beispiel 2 und 7, 13 und 19.

2. Wenn eine Primzahl und die andere kein Vielfaches davon ist, sind diese beiden Zahlen teilerfremd. Zum Beispiel 3 und 10, 5 und 26.

3. Zwei benachbarte natürliche Zahlen sind teilerfremd. Wie 15 und 16.

4. Zwei benachbarte ungerade Zahlen sind teilerfremd. Wie 49 und 51.

5. Zwei Zahlen, deren größere Zahl eine Primzahl ist, sind teilerfremd. Wie 97 und 88.

6. Dezimalzahlen sind Primzahlen, und zwei Zahlen, die keine Vielfachen einer Dezimalzahl sind, sind Koprimzahlen. Zum Beispiel 7 und 16.

7, 2 und jede ungerade Zahl sind Koprimzahlen. Zum Beispiel 2 und 87.

8. 1 ist weder eine Primzahl noch eine zusammengesetzte Zahl. Sie ist mit jeder natürlichen Zahl teilerfremd. Wie 1 und 9908.

9. Euklidische Division.

Exponentialoperation

Die Exponentialoperation wird auch Potenzierungsberechnung genannt, und das Berechnungsergebnis wird Potenz genannt. nm bezieht sich auf die m-fache Multiplikation von n mit sich selbst. Das Ergebnis der Behandlung von nm als Potenz wird „n hoch m hoch“ oder „n hoch m hoch“ genannt. Unter diesen wird n als „Basis“ und m als „Exponent“ bezeichnet.

Modulo-Operation

Die Modulo-Operation ist die Restoperation. „Module“ ist die Transliteration von „Mod“. Ein mit der modularen Arithmetik eng verwandtes Konzept ist die „Kongruenz“. Mathematisch gesehen sind die beiden ganzen Zahlen kongruent, wenn zwei ganze Zahlen durch dieselbe positive ganze Zahl dividiert werden und den gleichen Rest erhalten.

Zwei ganze Zahlen a, b, wenn die durch Division durch eine positive ganze Zahl m erhaltenen Reste gleich sind, dann werden a und b als kongruent modulo m bezeichnet, bezeichnet als: a ≡ b (mod m); gelesen als: a ist kongruent zu b mod m, oder a und b sind kongruent modulo m. Zum Beispiel: 26 ≡ 14 (mod 12).

RSA-Verschlüsselungsalgorithmus

Erzeugung eines öffentlichen Schlüssels und eines geheimen Schlüssels

Angenommen, Alice möchte eine private Nachricht von Bob über ein unzuverlässiges Medium erhalten. Sie kann einen öffentlichen Schlüssel und einen privaten Schlüssel auf folgende Weise generieren:

1. Wählen Sie zufällig zwei große Primzahlen p und q aus, p ist nicht gleich q, und berechnen Sie N=pq.

2. Finden Sie gemäß der Euler-Funktion r = (p-1)(q-1)

3. Wählen Sie eine ganze Zahl e, die kleiner als r ist , und finden Sie das modulare Umkehrelement von e bezüglich Modulo r und nennen Sie es d. (Das modulare Umkehrelement existiert genau dann, wenn e und r zueinander prim sind)

4. Zerstöre die Datensätze von p und q.
(N,e) ist der öffentliche Schlüssel, (N,d) ist der private Schlüssel. Alice gibt ihren öffentlichen Schlüssel (N,e) an Bob weiter und versteckt ihren privaten Schlüssel (N,d).

Verschlüsselte Nachricht

Angenommen, Bob möchte eine Nachricht m an Alice senden und kennt das von Alice generierte N und e. Er verwendet das Format, das er ursprünglich mit Alice vereinbart hatte, um m in eine ganze Zahl n kleiner als N umzuwandeln. Beispielsweise kann er jedes Wort in den Unicode-Code des Wortes umwandeln und diese Zahlen dann zu einer Zahl verbinden. Wenn seine Nachricht sehr lang ist, kann er die Nachricht in mehrere Absätze unterteilen und dann jeden Absatz in n umwandeln. Mit der folgenden Formel kann er n in c verschlüsseln:

 ne ≡ c (mod N)

Die Berechnung von c ist nicht kompliziert. Nachdem Bob c herausgefunden hat, kann er es an Alice weitergeben.

Nachricht entschlüsseln

Nachdem Alice Bobs Nachricht c erhalten hat, kann sie sie mit ihrem Schlüssel d entschlüsseln. Sie kann die folgende Formel verwenden, um c in n umzuwandeln:

cd ≡ n (mod N)

Nachdem sie n erhalten hat, kann sie die ursprünglichen Informationen m wiederherstellen.

Das Prinzip der Dekodierung ist:

 cd ≡ n e·d(mod N)

und ed ≡ 1 (mod p-1) und ed ≡ 1 (mod q - 1). Es kann durch Fermats kleinen Satz bewiesen werden (weil p und q Primzahlen sind)

 n e·d ≡ n (mod p)  Und n e·d ≡ n (mod q)

Das zeigt (weil p und q unterschiedliche Primzahlen sind, also sind p und q relativ prim)

 n e·d ≡ n (mod pq)

Signierte Nachricht

 RSA kann auch verwendet werden, um eine Nachrichtensignatur zu erstellen. Wenn A eine signierte Nachricht an B senden möchte, kann sie einen Hash-Wert (Message Digest) für ihre Nachricht berechnen und dann ihren Schlüssel (privaten Schlüssel) verwenden, um den Hash-Wert zu verschlüsseln und diese „Signatur“ am Ende hinzuzufügen die Nachricht. Diese Nachricht kann nur mit ihrem öffentlichen Schlüssel entschlüsselt werden. Nachdem B die Nachricht erhalten hat, kann er den öffentlichen Schlüssel von A verwenden, um den Hash-Wert zu entschlüsseln, und diese Daten dann mit seinem eigenen, für die Nachricht berechneten Hash-Wert vergleichen. Wenn die beiden übereinstimmen, kann er wissen, dass der Absender den Schlüssel von A besitzt und dass die Nachricht während des Ausbreitungspfads nicht manipuliert wurde.

Golang-Verschlüsselung und -Entschlüsselung RSA

In PHP werden viele Funktionen oft durch eine Funktion gelöst, in Go ist dies jedoch nicht der Fall. In diesem Artikel lernen Sie die RSA-bezogene API von Go durch PHP-Verschlüsselung, Go-Entschlüsselung und Go-Verschlüsselung kennen.

In diesem Artikel geht es um die Go RSA-Verschlüsselung und -Entschlüsselung. Alle Vorgänge werden unter Linux ausgeführt.

1. Übersicht

Dies ist ein asymmetrischer Verschlüsselungsalgorithmus, der im Allgemeinen die Verschlüsselung mit öffentlichem Schlüssel und die Entschlüsselung mit privatem Schlüssel verwendet.

Während des Verschlüsselungs- und Entschlüsselungsprozesses wird OpenSSL verwendet, um den Schlüssel zu generieren. Führen Sie die folgenden Vorgänge aus:

1) Erstellen Sie einen privaten Schlüssel:

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

2) Erstellen Sie einen öffentlichen Schlüssel:

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

Im Allgemeinen stellt jede Sprache auch eine API zum Generieren von Schlüsseln bereit. Sehen Sie sich in Go das Paket „encoding/pem“ und das Paket „crypto/x509“ an.

Verschlüsselung und Entschlüsselung beinhalten viele Standards. Ich persönlich empfehle, sie bei Bedarf vorübergehend zu erlernen.

2. Gehen Sie zur RSA-Verschlüsselung und -Entschlüsselung

1. Für die RSA-Verschlüsselung und -Entschlüsselung überprüfen Sie auf jeden Fall das Krypto-/Ras-Paket

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

Dies ist die Beschreibung des Pakets: Implementiert die RSA-Verschlüsselungstechnologie, basierend auf der PKCS#1-Spezifikation.

Was PKCS#1 ist, können Sie die relevanten Informationen überprüfen. PKCS (Public Key Cryptozoology Standard) und Nr. 1 ist der RSA-Standard. Sie können Folgendes anzeigen: Einführung in die PKCS-Serie

Anhand der Namen der Funktionen in diesem Paket können Sie erkennen, dass es zwei Paare von Verschlüsselungs- und Entschlüsselungsfunktionen gibt.

EncryptOAEP和DecryptOAEP
EncryptPKCS1v15和DecryptPKCS1v15

Dies wird als Verschlüsselungsschema bezeichnet. Die Details des PKCS #1 v2.1 RSA-Algorithmus sind bei der Interaktion mit anderen sichtbar Sprachen ist es erforderlich, zu entscheiden, welche Lösung verwendet werden soll.

Die beiden Typen PublicKey und PrivateKey stellen öffentliche Schlüssel bzw. private Schlüssel dar. In diesem Artikel werden Beispiele für diese beiden Typen analysiert Der Artikel Der zu Beginn generierte Schlüssel wird abgerufen.

2. Analysieren Sie den Schlüssel, um Instanzen von PublicKey und PrivateKey zu erhalten


Dieser Vorgang hat auch lange gedauert (hauptsächlich bin ich nicht mit verschiedenen Verschlüsselungsdingen vertraut): So analysieren Sie den Schlüssel Datei, die von OpenSSL generiert wurde, in Instanzen mit öffentlichem Schlüssel und privatem Schlüssel umwandeln?

Im Paket „encoding/pem“ habe ich die Wörter „--BEGIN Type ---“ gesehen. Dies ähnelt der von openssl generierten Schlüsselform, also probieren Sie es aus.

In diesem Paket stellt ein Block die Struktur der PEM-Codierung dar. Bitte überprüfen Sie die entsprechenden Informationen. Wir wollen den Schlüssel analysieren, natürlich mit der Decode-Methode:

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

Auf diese Weise erhalten wir eine Blockinstanz (Zeiger).

Analyse, um Krypto/x509 zu sehen. Warum x509? Dies beinhaltet wiederum eine Reihe von Konzepten. Unabhängig davon habe ich es auch herausgefunden, indem ich mir die Unterpakete der Encoding- und Crypto-Pakete angeschaut habe.


Im x509-Paket gibt es eine Funktion:

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

Aus der Beschreibung der Funktion: ParsePKIXPublicKey analysiert einen DER-codierten öffentlichen Schlüssel Werte werden typischerweise in PEM-Blöcken mit „BEGIN PUBLIC KEY“ gefunden. Es ist ersichtlich, dass dies das Parsen von PublicKey ist. Wenn es hier um PEM geht, kann außerdem die obige Kodierung/PEM korrekt sein.

Es gibt mehrere Methoden zum Parsen des privaten Schlüssels. Aus der obigen Einführung wissen wir, dass RSA PKCS#1 ist, und es gibt nur eine Methode:

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

Was zurückgegeben wird, ist rsa.PrivateKey.

3. Entschlüsselung und Entschlüsselungsimplementierung


Durch die obige Einführung ist es nicht schwierig, RSA-Entschlüsselung und -Entschlüsselung in Go zu implementieren. Der Code lautet wie folgt:

// Verschlüsselung

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)
}

// Entschlüsselung

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中文网!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn