Menu

RSA Example

saeed atalla

CELIB::RSA class has a rich interface which can used for many operations, such as generating keys, encrypt, decrypt, sign, ...ect.

Create RSA object:

There are many Constructors that can used to create rsa object, sipmle one is create rsa object with key size, constructor will generate keys (private & public) with specific size:
For more security, CryptoEngine uses X917RNG standard - from ANSI 9.17 - (if available) to generate keys.

    CELIB::RSA rsa(1024);
    //! connect rsa object with caller object to catch errors (see Error Handling page):
    //connect(&rsa, SIGNAL(error(QString)), this, SLOT(errorString(QString)));

Note that NIST recommend to use key with size 3072 bits or higher for more security.
We can print-out object's data in (human-readable) form:

    std::cout << "\nrsa.toString:\n" << rsa.toString().toStdString() << std::endl;

output:

rsa.toString:
([CELIB::RSA::toString()]:
 [Size(Bytes):[128],
 n-Hex:
 [8A592CCC3C9278D9EE247AAC25BE44DAA7CBD504191A1FAF8BF71B7A54A030DAF4C062798B8CBBFA2E9E7F3EC056F7884358FC0ADB12EE9BE388B3D835087BCB601D918FB308A8443E7F5EDAE5EC41CAC40E511AB7C180AD139C2B14AF0F36AAC42F8CAF9F56FF042DBB7A759DCFAE46E0FCCDA8509734CA8C5E230CD55758D1],
 e-Hex:[11].]
 d:[!HIDDEN!].)

Encrypt/Decrypt:

    QByteArray plain("RSA Example"), cipher, recover, signature;
    bool isOk(false);
    std::cout << "\nPlain: " << plain.data() << std::endl;

    cipher = rsa.encrypt(plain, &isOk);
    if(isOk)
        std::cout << "\nEncryption successful." << std::endl;
    else
        std::cout << "\nEncryption FAILED." << std::endl;

    std::cout << "\nCipher-Hex:\n" << cipher.toHex().toUpper().data() << std::endl;

    recover = rsa.decrypt(cipher, &isOk);
    if(isOk)
        std::cout << "\nDecryption successful." << std::endl;
    else
        std::cout << "\nDecryption FAILED." << std::endl;

    std::cout << "\nRecover: " << recover.data() << std::endl;

    Q_ASSERT(plain == recover);

output:

Plain: RSA Example

Encryption successful.

Cipher-Hex:
4EBF69EBDD5AA1F562176BD94B2A17A48FA6EB69A639D5EB03E6F097355A892B3E860A6FD1F8D88A848C2135A3239DFB67B44EA6019C43105FC22090D1B603AA7048A17322016289BE2299B3019F7D023D79BEBA550B724225ABD97D16183596F480175043A4378A77AB8F4A34ECF65EBA89B86D76FFE718D9D9A6B895DE30EC

Decryption successful.

Recover: RSA Example

Sign/Verify:

We can use rsa object for generating signatur of a plaintext and we can verify it later, we must assign the Hash Algorithm to use when signing; supported algorithms are SHA1, SHA2 and SHA3, default is SHA2-512:

    signature = rsa.sign(plain, &isOk, CELIB::SHT_SHA2_256);
    if(isOk)
        std::cout << "\nSigning successful." << std::endl;
    else
        std::cout << "\nSigning FAILED." << std::endl;

    std::cout << "\nSignature-Hex:\n" << signature.toHex().toUpper().data() << std::endl;

    //! Attack first & last bytes:
    //signature[0] = 'A';
    //signature[signature.size()-1] = 'A';

    isOk = rsa.Verify(signature, plain, CELIB::SHT_SHA2_256);
    if(isOk)
        std::cout << "\nVerfying successful." << std::endl;
    else
        std::cout << "\nVerfying FAILED." << std::endl;

output:

Signing successful.

Signature-Hex:
04FAD1A8A4C19683AAE2EEB3E8524D8294AB2A97A39EC7F7B6E8A39B436AE7FC8334143BB484F83D701E3EBA473A420A2B4E2FBE5FF2C78FB01ED216C0691B9726CC7AEB2470B9D7508EBAF4FE977E56B4BE4AEF0665DD17B5746795BE7BCE96DCCC87396C164639AAAC4339D2697D95E2A280F10CBCB8BE7E956F0D7CAE429B

Verfying successful.

Signing with recovery

RSA Algorithm can used for generating a signature that can used later for recover plaintext:

    signature = rsa.signWithRecovery(plain, &isOk, CELIB::SHT_SHA3_224);
    if(isOk)
        std::cout << "\nSigning-with-recovery successful." << std::endl;
    else
        std::cout << "\nSigning-with-recovery FAILED." << std::endl;

    std::cout << "\nSignature-Hex:\n" << signature.toHex().toUpper().data() << std::endl;

    //! Attack first & last bytes:
    //signature[0] = 'A';
    //signature[signature.size()-1] = 'A';

    recover = rsa.recoveryFromSignature(signature, &isOk, CELIB::SHT_SHA3_224);
    if(isOk)
        std::cout << "\nRecover-from-signature successful." << std::endl;
    else
        std::cout << "\nRecover-from-signature FAILED." << std::endl;

    std::cout << "\nRecover: " << recover.data() << std::endl;

    Q_ASSERT(plain == recover);

output:

Signing-with-recovery successful.

Signature-Hex:
49FA280E14629327412048456D546A0EA5752000F057791FAF159D74948EAFA348F84E299B059FA18CC2CFD5000EF84BC6F188A71CBD7FBFD2B37E4379DE20373F14D39D764388F23836DBD84C1F0B1CE33C663DB796B7FA67FD3BFFCECA06E2A3F04D823E338D2E203875C685D71C367A255C672083FAF8AB8677562BE99622

Recover-from-signature successful.

Recover: RSA Example

Save/Load Keys

If we need to save keys (private or public keys) to files, or if we need to load existing key file:
Note that private key is saved using (PKCS8) encoding, and public key is saved using (X509) encoding.

    //create another RSA object to load keys:
    CELIB::RSA rsa2;
    //Load both keys together:
    isOk = rsa2.loadKeys(privKeyFile, pubKeyFile);
    /*
    Or load each key alone:
    isOk = rsa2.loadPrivateKey(privKeyFile);
    isOk = rsa2.loadPublicKey(pubKeyFile);
    */
    if(isOk)
        std::cout << "\nKey load successful." << std::endl;
    else
        std::cout << "\nKey load FAILED." << std::endl;

    Q_ASSERT(rsa == rsa2);

We can also change keys private & public, at any time we need-to, using setKeys(...) functions.

Static functions:

For more flexibility, CELIB::RSA provide many Static Functions that can do all above operations, plus another operations, such as generating and validating keys ...etc.

[Error Handling]


Related

Wiki: Home
Wiki: Error Handling

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.