views:

72

answers:

2

Given two classes:

First class performs AES encryption / decryption and returns encrypted / decrypted data given a certain key and chain.

Second class gathers data to be encrypted and then passes it to the encryption / decryption class.

Is it proper design to call directly the encryption class from the class that gathers the data or should there be an object between the two classes which abstracts the process further? Should I have one abstract class instance and one encryption instance to handle all of these types of requests during the program's lifetime?

+3  A: 

Personally, I would create some kind of abstract interface representing an encryption algorithm, with a factory function taking the key and producing a concrete instance of an encryption algorithm with a key installed. So the 'second class' here would call directly to the 'first class', but there would be a 'third class' in charge of instantiating the class. Something like:

/* Core encryption framework definitions */
class CipherInstance {
  // ...
  public:
    virtual void encrypt(void *, size_t) = 0;
    virtual void decrypt(void *, size_t) = 0;
    virtual size_t blocksize() const = 0;
// ...
    virtual ~CipherInstance() { }
};

class Cipher {
  public:
    virtual CipherInstance *instantiate(const void *key, size_t keylen) = 0;
    virtual size_t minkeysize() const = 0;
    virtual size_t maxkeysize() const = 0;
};

/* AES implementation */
class privateAESImpl : public Cipher { /* ... */ };
// This is the only public definition in the AES implementation. The privateAESImpl
// class is a stateless singleton, and this is the only instance. Doing this instead
// of static functions allows AES to be passed to a function taking a Cipher * 
extern privateAESImpl AES;

// Much later:
  CipherInstance *aes = AES.instantiate(key, keylen);
  aes->encrypt(data, datalen);
// or, to be more general:
void frob(Cipher *cipher, void *key, size_t keylen, void *data, size_t datalen) {
    CipherInstance *inst = cipher->instantiate(key, keylen);
    inst->encrypt(data, datalen);
}

C#'s System.Security.Cryptography libraries use a similar approach - see, eg, System.Security.Cryptography.SymmetricAlgorithm. Note however that since C# supports introspection, there's no need for a factory class - instead there's simply a static method taking a name. With C++ a full factory class is needed.

bdonlan
I'm going to try and implement this and come back if I have questions (i.e. can't get it to work)
0A0D
+1  A: 

I would call the encryption object directly, but through an interface. The actual encryption object to invoke would be given during runtime by whatever class is controlling the program.

You'll have to excuse me, my C++ is rusty...

// Interface for encryption.
class Encryptor
{
    public:
        virtual byte* encrypt(byte* data) = 0;
}

// Gathering class
class Gatherer
{
    private:
        Encryptor* encryptor;
    public:
        Gatherer(Encryptor* encryptor)
        {
            this->encryptor = encryptor;
        }

        void doStuff()
        {
            // Do stuff

            // Call encryption on gathered data
            byte* encryptedData = encryptor->encrypt(data);

            // Do more stuff with encrypted data.
        }
}

main()
{
    Encryptor* encryptor = new AESEncryptor(ENCRYPTION_KEY);
    Gatherer gatherer = new Gatherer(encryptor);
    gatherer->doStuff();
}
}
jdmichal