Nonceとは
Nonce(ノンス / Number used ONCE)は、暗号通信において「一度だけ使用される数値」です。同じ鍵で複数のメッセージを暗号化する際に、各暗号化操作に固有のNonceを使用することで、セキュリティを確保します。
Nonceの主な役割:
- 暗号文の一意性:同じ平文を同じ鍵で暗号化しても、異なる暗号文を生成
- リプレイ攻撃の防止:過去のメッセージの再送信を検出
- 認証プロトコル:チャレンジ-レスポンス認証での使用
NonceとIVの違い
NonceとIV(初期化ベクトル)は関連する概念ですが、厳密には異なります:
| 特性 | Nonce | IV |
|---|---|---|
| 一意性要件 | 絶対に再利用してはならない | 予測不可能であるべき |
| 生成方法 | カウンター or ランダム | 通常ランダム |
| 典型的な使用 | AES-GCM、ChaCha20 | AES-CBC |
AIエンジニアとしての実体験
AIモデルのAPI認証システムでNonceを使用したリプレイ攻撃防止を実装しました。APIリクエストにNonceを含め、サーバー側で使用済みNonceを追跡します。
import os
import time
import hashlib
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
class NonceManager:
"""Nonce管理クラス"""
def __init__(self):
self.used_nonces = set()
self.counter = 0
def generate_random_nonce(self, size: int = 12) -> bytes:
"""ランダムNonceを生成(AES-GCM推奨サイズ: 12バイト)"""
return os.urandom(size)
def generate_counter_nonce(self, prefix: bytes = b'') -> bytes:
"""カウンターベースNonceを生成"""
self.counter += 1
return prefix + self.counter.to_bytes(8, 'big')
def verify_nonce(self, nonce: bytes) -> bool:
"""Nonceの一意性を検証"""
nonce_hash = hashlib.sha256(nonce).hexdigest()
if nonce_hash in self.used_nonces:
return False # 再利用を検出
self.used_nonces.add(nonce_hash)
return True
# AES-GCMでのNonce使用例
def encrypt_with_aes_gcm(key: bytes, plaintext: bytes, associated_data: bytes = b''):
nonce = os.urandom(12) # 96ビットNonce
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
return nonce + ciphertext # Nonceと暗号文を連結
def decrypt_with_aes_gcm(key: bytes, encrypted_data: bytes, associated_data: bytes = b''):
nonce = encrypted_data[:12]
ciphertext = encrypted_data[12:]
aesgcm = AESGCM(key)
return aesgcm.decrypt(nonce, ciphertext, associated_data)
自社サーバー運用への応用
TLSでのNonce使用
TLS 1.3では、各レコードの暗号化にNonceが使用されます。シーケンス番号をXORすることで、一意のNonceを生成します。
API認証でのNonce
# APIリクエストにNonceを含める例
import requests
import time
import hmac
import hashlib
import secrets
def make_authenticated_request(url: str, api_key: str, api_secret: str):
nonce = secrets.token_hex(16) # 32文字のNonce
timestamp = str(int(time.time()))
# 署名の生成
message = f"{nonce}{timestamp}{url}"
signature = hmac.new(
api_secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
headers = {
'X-API-Key': api_key,
'X-Nonce': nonce,
'X-Timestamp': timestamp,
'X-Signature': signature
}
return requests.get(url, headers=headers)
関連ブログ記事
📝 関連記事
最新動向(2026年)
XChaCha20-Poly1305の採用
より長いNonce(24バイト)を使用するXChaCha20-Poly1305が普及しています。ランダムNonceの衝突リスクが大幅に低減されます。
SIV(Synthetic IV)モード
Nonce再利用に対する耐性を持つAES-GCM-SIVなどのモードが注目されています。Nonce誤用時の被害を限定できます。
トラブル事例と対策
🚨 重大な脆弱性:Nonce再利用
問題:AES-GCMで同じNonceを再利用すると、認証タグが破られ、平文が漏洩する可能性
対策:ランダムNonce(十分な長さ)またはカウンターベースNonceを使用。Nonce管理を厳密に
⚠️ ランダムNonceの衝突
問題:96ビットNonceで2^32回以上暗号化すると衝突確率が高くなる(誕生日のパラドックス)
対策:鍵のローテーション、より長いNonceを持つアルゴリズム(XChaCha20)の使用
