Search code examples
c++compatibilitybotan

Why does botan ask for a random number generator that it ignores for compatibility?


I am starting to use the botan cryptographic library and I ran into an odd function signature:

/**
* Load an encrypted key from a data source.
* @param source the data source providing the encoded key
* @param rng ignored for compatability
* @param get_passphrase a function that returns passphrases
* @return loaded private key object
*/
BOTAN_DLL Private_Key* load_key(DataSource& source,
                                RandomNumberGenerator& rng,
                                std::function<std::string ()> get_passphrase);

I am wondering why should I pass a RandomNumberGenerator to a function that promises to ignore it?

The documentation says that it is for compatibility, but I cannot imagine what type of compatibility they are talking about? If it is backwards/forwards compatibility, it means that in the past/future the function has/will accept a random number generator to do a deterministic operation.

Please, what am I missing here?


Solution

  • It looks that it's meant for backward compatibility, to not change the API for the user and possibly to not break applications.
    Let's start to have a look at the master branch:
    https://github.com/randombit/botan/blob/master/src/lib/pubkey/pkcs8.cpp

    /*
    * Extract an encrypted private key and return it
    */
    Private_Key* load_key(DataSource& source,
                          RandomNumberGenerator& rng,
                          std::function<std::string ()> get_pass)
       {
       return load_key(source, rng, get_pass, true);
       } 
    

    calls

    /*
    * Extract a private key (encrypted/unencrypted) and return it
    */
    Private_Key* load_key(DataSource& source,
                          RandomNumberGenerator& /*rng*/,
                          std::function<std::string ()> get_pass,
                          bool is_encrypted)
       {
       AlgorithmIdentifier alg_id;
       secure_vector<uint8_t> pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted);
    
       const std::string alg_name = OIDS::lookup(alg_id.oid);
       if(alg_name.empty() || alg_name == alg_id.oid.as_string())
          throw PKCS8_Exception("Unknown algorithm OID: " +
                                alg_id.oid.as_string());
    
       return load_private_key(alg_id, pkcs8_key).release();
       }
    
    }
    

    to do the work, which in turn doesn't use rng.
    Now, let's see previous versions of the library. Same happens for version 2.0.0 (https://github.com/randombit/botan/blob/master/src/lib/pubkey/pkcs8.cpp)
    In version (tag in GitHub) 1.11.33 (https://github.com/randombit/botan/blob/1.11.33/src/lib/pubkey/pkcs8.cpp) one can see that rng is used and it looks that versions after this one dropped it:

    /*
    * Extract a private key (encrypted/unencrypted) and return it
    */
    Private_Key* load_key(DataSource& source,
                          RandomNumberGenerator& rng,
                          std::function<std::string ()> get_pass,
                          bool is_encrypted)
       {
       AlgorithmIdentifier alg_id;
       secure_vector<byte> pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted);
    
       const std::string alg_name = OIDS::lookup(alg_id.oid);
       if(alg_name.empty() || alg_name == alg_id.oid.as_string())
          throw PKCS8_Exception("Unknown algorithm OID: " +
                                alg_id.oid.as_string());
    
       return load_private_key(alg_id, pkcs8_key, rng).release();
       }
    
    }
    

    in

    load_private_key(alg_id, pkcs8_key, rng).release();
    

    which seems to be defined in https://github.com/randombit/botan/blob/1.11.33/src/lib/pubkey/pk_algs.cpp and starts with

    std::unique_ptr<Private_Key>
    load_private_key(const AlgorithmIdentifier& alg_id,
                     const secure_vector<byte>& key_bits,
                     RandomNumberGenerator& rng)
       {
       const std::string alg_name = OIDS::lookup(alg_id.oid);
       if(alg_name == "")
          throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string());
    
    #if defined(BOTAN_HAS_RSA)
       if(alg_name == "RSA")
          return std::unique_ptr<Private_Key>(new RSA_PrivateKey(alg_id, key_bits, rng));
    #endif
    
    #if defined(BOTAN_HAS_CURVE_25519)
       if(alg_name == "Curve25519")
          return std::unique_ptr<Private_Key>(new Curve25519_PrivateKey(alg_id, key_bits, rng));
    #endif
    

    Now, if you compare it with master branch or version 2.0.0, you can see that rng was dropped from the same calls

    https://github.com/randombit/botan/blob/master/src/lib/pubkey/pk_algs.cpp

    std::unique_ptr<Private_Key>
    load_private_key(const AlgorithmIdentifier& alg_id,
                     const secure_vector<uint8_t>& key_bits)
       {
       const std::string alg_name = OIDS::lookup(alg_id.oid);
       if(alg_name == "")
          throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string());
    
    #if defined(BOTAN_HAS_RSA)
       if(alg_name == "RSA")
          return std::unique_ptr<Private_Key>(new RSA_PrivateKey(alg_id, key_bits));
    #endif  
    

    In the version that you are using it looks they dropped it too and you have similar to the one in master:

    std::unique_ptr<Private_Key>
    load_private_key(const AlgorithmIdentifier& alg_id,
                     const secure_vector<uint8_t>& key_bits)
       {
       const std::string alg_name = OIDS::lookup(alg_id.oid);
       if(alg_name == "")
          throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string());
    
    #if defined(BOTAN_HAS_RSA)
       if(alg_name == "RSA")
          return std::unique_ptr<Private_Key>(new RSA_PrivateKey(alg_id, key_bits));
    #endif
    

    So it looks that to maintain the same API for the user they didn't change the signature but they changed the implementation.