「Qtの応用 - AES」の版間の差分

ナビゲーションに移動 検索に移動
556行目: 556行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
==== サンプルコード ====
==== サンプルコード : 使用する鍵長の最小値、最大値、標準値の表示 ====
以下の例では、AESが使用する鍵長の最小値、最大値、標準値をダンプしている。(2番目と3番目はパイプラインのフィルターを使用している)<br>
以下の例では、AESが使用する鍵長の最小値、最大値、標準値をダンプしている。(2番目と3番目はパイプラインのフィルターを使用している)<br>
パイプラインは高レベルの抽象化であり、入力のバッファリング、出力のバッファリング、パディングを処理する。<br>
パイプラインは高レベルの抽象化であり、入力のバッファリング、出力のバッファリング、パディングを処理する。<br>
573行目: 573行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
==== サンプルコード : CBCモード ====
以下の例では、CBCモードを使用して、暗号化および復号を行っている。<br>
使用する鍵はINIファイルでを保存して、アプリケーション再起動時にも使用できるようにしている。<br>
<br>
16バイト (128ビット) の鍵を使用しているが、AESは192ビットや256ビットのキーもサポートしている。<br>
暗号化されたデータを保存または送信する場合は、初期化ベクトル (IV) も一緒に保存または送信する必要がある。<br>
<br>
<syntaxhighlight lang="c++">
// SecureAESCrypto.hファイル
#include <QCoreApplication>
#include <QString>
#include <QByteArray>
#include <QSettings>
#include <QFile>
#include <QDebug>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
#include <cryptopp/osrng.h>
#include <cryptopp/hex.h>
class SecureAESCrypto {
public:
    // 鍵の生成
    static QByteArray generateKey()
    {
      QByteArray key;
      key.resize(CryptoPP::AES::DEFAULT_KEYLENGTH);
      CryptoPP::AutoSeededRandomPool prng;
      prng.GenerateBlock(reinterpret_cast<byte*>(key.data()), key.size());
      return key;
    }
    // 初期化ベクトルの生成
    static QByteArray generateIV()
    {
      QByteArray iv;
      iv.resize(CryptoPP::AES::BLOCKSIZE);
      CryptoPP::AutoSeededRandomPool prng;
      prng.GenerateBlock(reinterpret_cast<byte*>(iv.data()), iv.size());
      return iv;
    }
    static QByteArray encrypt(const QByteArray &plaintext, const QByteArray &key, QByteArray &iv)
    {
      try {
          CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryptor;
          encryptor.SetKeyWithIV(reinterpret_cast<const byte*>(key.constData()), key.size(), reinterpret_cast<const byte*>(iv.constData()));
          QByteArray ciphertext;
          CryptoPP::StringSource(reinterpret_cast<const byte*>(plaintext.constData()), plaintext.size(), true,
                                new CryptoPP::StreamTransformationFilter(encryptor, new CryptoPP::StringSink(ciphertext)));
          return ciphertext;
      }
      catch (const CryptoPP::Exception& e) {
          qCritical() << "Encryption error:" << e.what();
          return QByteArray();
      }
    }
    static QByteArray decrypt(const QByteArray &ciphertext, const QByteArray &key, const QByteArray &iv)
    {
      try {
          CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor;
          decryptor.SetKeyWithIV(reinterpret_cast<const byte*>(key.constData()), key.size(), reinterpret_cast<const byte*>(iv.constData()));
          QByteArray plaintext;
          CryptoPP::StringSource(reinterpret_cast<const byte*>(ciphertext.constData()), ciphertext.size(), true,
                                new CryptoPP::StreamTransformationFilter(decryptor, new CryptoPP::StringSink(plaintext)));
          return plaintext;
      }
      catch (const CryptoPP::Exception& e) {
          qCritical() << "Decryption error:" << e.what();
          return QByteArray();
      }
    }
    static bool saveEncryptedData(const QString &filename, const QByteArray &data, const QByteArray &iv)
    {
      QFile file(filename);
      if (!file.open(QIODevice::WriteOnly)) {
          qCritical() << "Unable to open file for writing:" << filename;
          return false;
      }
      QDataStream out(&file);
      out << iv << data;
      file.close();
      return true;
    }
    static bool loadEncryptedData(const QString &filename, QByteArray &data, QByteArray &iv)
    {
      QFile file(filename);
      if (!file.open(QIODevice::ReadOnly)) {
          qCritical() << "Unable to open file for reading:" << filename;
          return false;
      }
      QDataStream in(&file);
      in >> iv >> data;
      file.close();
      return true;
    }
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include "SecureAESCrypto.h"
QByteArray getOrCreateKey()
{
    QSettings settings("MyCompany", "SecureAESApp");
    if (settings.contains("encryption/key")) {
      return QByteArray::fromHex(settings.value("encryption/key").toString().toLatin1());
    }
    else {
      QByteArray key = SecureAESCrypto::generateKey();
      settings.setValue("encryption/key", QString(key.toHex()));
      return key;
    }
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // キーの取得または生成
    QByteArray key = getOrCreateKey();
    qDebug() << "Encryption key:" << key.toHex();
    // テスト用のデータ
    QByteArray plaintext = "Hello, World! This is a secret message.";
    qDebug() << "Original text:" << plaintext;
    // 暗号化
    QByteArray iv = SecureAESCrypto::generateIV();
    QByteArray ciphertext = SecureAESCrypto::encrypt(plaintext, key, iv);
    if (!ciphertext.isEmpty()) {
      qDebug() << "Encrypted text:" << ciphertext.toHex();
      // 暗号化されたデータとIVの保存
      if (SecureAESCrypto::saveEncryptedData("encrypted_data.bin", ciphertext, iv)) {
          qDebug() << "Encrypted data and IV saved successfully.";
          // 暗号化されたデータとIVの読み込み
          QByteArray loadedCiphertext, loadedIV;
          if (SecureAESCrypto::loadEncryptedData("encrypted_data.bin", loadedCiphertext, loadedIV)) {
            qDebug() << "Encrypted data and IV loaded successfully.";
            // 復号
            QByteArray decryptedText = SecureAESCrypto::decrypt(loadedCiphertext, key, loadedIV);
            if (!decryptedText.isEmpty()) {
                qDebug() << "Decrypted text:" << decryptedText;
            }
            else {
                qDebug() << "Decryption failed.";
            }
          }
          else {
            qDebug() << "Failed to load encrypted data and IV.";
          }
      }
      else {
          qDebug() << "Failed to save encrypted data and IV.";
      }
    }
    else {
        qDebug() << "Encryption failed.";
    }
    return a.exec();
}
</syntaxhighlight>
<br>
<u>※注意</u><br>
<u>鍵の保存において、実務ではより安全な方法 (例: OSのキーチェーンやセキュアな暗号化ストレージ) を使用することを推奨する。</u><br>
<u>また、ユーザ認証やアクセス制御等の追加のセキュリティ層を実装することを推奨する。</u><br>
<br>
<u>ファイルの暗号化や大量のデータの暗号化を行う場合は、メモリ使用量を考慮してストリーミング暗号化を行う。</u><br>
<br>
==== サンプルコード : CFBモード ====
以下の例では、CFBモードを使用して、暗号化および復号を行っている。<br>
以下の例では、CFBモードを使用して、暗号化および復号を行っている。<br>
ECBやCBCではないため、データ長をAESのブロックサイズの倍数にする必要は無い。<br>
ECBやCBCではないため、データ長をAESのブロックサイズの倍数にする必要は無い。<br>

案内メニュー