公開鍵暗号と「署名」とは?
公開鍵暗号は、現代のセキュリティ技術の基盤となる仕組みです。しかし、「署名って具体的に何をしているの?」と疑問に思うこともあるかもしれません。そこで、ここでは署名の仕組みを整理します。
署名とは、一言で言えば、秘密鍵を使ってデータのハッシュ値を暗号化して作成するものです。この署名を受け取った人は、対応する公開鍵を使って署名を復号し、元のデータから計算したハッシュ値と比較することで、データが改ざんされていないかを確認します。また、この仕組みにより、署名者がそのデータを送った本人であること(本人性)も保証されます。
さらに、公開鍵暗号のもう1つの特徴は、公開鍵でも暗号化が可能であり、秘密鍵でも暗号化が可能という点です。ただし、暗号化の目的によってその使い方が異なります。以下で、目的別に詳しく整理していきましょう。
ちょっと難しいかもしれないですが、まとめていきます。
公開鍵で暗号化し、秘密鍵で復号: データを特定の受信者にだけ読ませるために使用。
秘密鍵で暗号化(署名)し、公開鍵で復号(検証): データの正当性や送信者の本人性を保証するために使用。
1. 公開鍵で暗号化し、秘密鍵で復号
まずは、「公開鍵で暗号化し、秘密鍵で復号」する仕組みを見てみましょう。
目的
誰でもデータを暗号化できるが、復号は特定の受信者(秘密鍵の所有者)に限定される。
これにより、データの秘匿性が保証されます。
仕組みの流れ
送信者: データを受信者の公開鍵で暗号化し、送信。
受信者: 受信したデータを自分の秘密鍵で復号して元のデータを取得。
送信者: 元データ -> 公開鍵で暗号化 -> 暗号化データを送信
受信者: 暗号化データ -> 秘密鍵で復号 -> 元データを取得
具体例
HTTPS通信:
ブラウザがサーバーの公開鍵でセッションキーを暗号化して送信。
サーバーが秘密鍵でセッションキーを復号し、安全な通信を開始します。
SSH初期接続: クライアントがサーバーの公開鍵で暗号化したデータを送信し、サーバーが秘密鍵で復号します。
2. 秘密鍵で暗号化(署名)、公開鍵で復号(検証)
次に、「秘密鍵で暗号化(署名)し、公開鍵で復号(検証)」する仕組みを解説します。
目的
データが改ざんされていないこと、そして送信者が本人であることを保証します。
暗号化されたデータ(署名)は誰でも復号できますが、署名を作成できるのは秘密鍵を持つ送信者だけです。
仕組みの流れ
送信者: データのハッシュ値を秘密鍵で暗号化し、署名を作成。
受信者: データのハッシュ値を計算し、公開鍵で署名を復号して比較。
送信者: 元データ -> ハッシュ化 -> ハッシュ値を秘密鍵で暗号化 -> 署名
受信者: 元データ -> ハッシュ化 -> 公開鍵で署名を復号 -> 復号したハッシュ値と比較
具体例
SSH認証:
クライアントが秘密鍵で署名したデータを送信。
サーバーが公開鍵で署名を検証し、クライアントの正当性を確認。
HTTPS証明書の検証:
サーバーが証明書をクライアントに送信。
クライアントが証明書の署名をCA(認証局)の公開鍵で検証。
ブロックチェーン:
トランザクションに秘密鍵で署名。
ノードが公開鍵で署名を検証し、取引の正当性を確認。
ソフトウェア署名:
開発者が秘密鍵でソフトウェアに署名。
ユーザーが公開鍵で署名を検証し、改ざんされていないことを確認。
署名は暗号化の一種?
署名は、「秘密鍵で暗号化」することで作成されます。ただし、通常の暗号化とは目的が異なります:
暗号化: データの秘匿性を確保。
署名: データの正当性と送信者の本人性を保証。
署名では、元データ全体ではなく、効率を重視してデータのハッシュ値を暗号化します。これにより、データが改ざんされていないことを迅速に確認できます。
Golangでの具体例
以下に、公開鍵暗号での署名と検証をGolangで実装するコードを示します。
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"fmt"
"log"
)
func main() {
// 1. 鍵ペアの生成
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("鍵生成エラー: %v", err)
}
publicKey := &privateKey.PublicKey
// 2. 元データの準備
message := []byte("Hello, Blockchain!")
// 3. ハッシュ化
hashed := sha256.Sum256(message)
// 4. 秘密鍵で署名(暗号化)
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])
if err != nil {
log.Fatalf("署名エラー: %v", err)
}
fmt.Printf("署名: %x\n", signature)
// 5. 公開鍵で署名を検証(復号)
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], signature)
if err != nil {
log.Fatalf("署名検証エラー: %v", err)
}
fmt.Println("署名の検証に成功しました!")
}
コードの解説
鍵ペアの生成:
rsa.GenerateKeyで秘密鍵を生成。公開鍵はそこから派生します。
ハッシュ化:
sha256.Sum256でデータをハッシュ化して、固定長のハッシュ値を作成。
署名の作成:
rsa.SignPKCS1v15でハッシュ値を秘密鍵で暗号化(署名)。
署名の検証:
rsa.VerifyPKCS1v15で公開鍵を使って署名を復号し、元データのハッシュ値と比較。
まとめ: どんな場面で使われるか
公開鍵で暗号化 & 秘密鍵で復号
データを秘匿する場合に使用。
主な利用例: HTTPS通信、SSH初期接続、メール暗号化。
秘密鍵で暗号化(署名) & 公開鍵で復号(検証)
データの正当性や送信者の本人性を保証する場合に使用。
主な利用例: SSH公開鍵認証、ブロックチェーン、ソフトウェア署名。
この仕組みを正しく理解することで、公開鍵暗号がどのようにセキュリティを実現しているかを深く知ることができます!