-3

So I've been writing a simple command-line program for encrypting and decrypting files with Node's built-in crypto module:

        if( deciphered_object.multibase_digest != null ){
            ciphered_object.multibase_digest = deciphered_object.multibase_digest;
            try{
                iv_buffer = Crypto.randomBytes(32);
                try{
                    cipher = Crypto.createCipheriv( 'aes-256-ofb', secret_keyobject, iv_buffer );
                    if( cipher != null && typeof(cipher) === 'object' ){
                        encrypted_buffer = cipher.update( deciphered_object.deciphered_data_buffer );
                        encrypted_buffer += cipher.final();
                        if( encrypted_buffer != null && Buffer.isBuffer(encrypted_buffer) === true ){
                            try{
                                ciphered_object.ciphered_data_buffer = Buffer.alloc( (1 + iv_buffer.length + encrypted_buffer.length) );
                                buffer_offset = ciphered_object.ciphered_data_buffer.writeUInt8( iv_buffer.length, 0 );
                                buffer_offset += iv_buffer.copy( ciphered_object.ciphered_data_buffer, buffer_offset );
                                buffer_offset += encrypted_buffer.copy( ciphered_object.ciphered_data_buffer, buffer_offset );
                                if( buffer_offset === ciphered_object.ciphered_data_buffer.length ){
                                    _return = [0, ciphered_object];
                                } else{
                                    _return = [-256, 'Error: "buffer_offset" is not equal to "ciphered_object.ciphered_data_buffer.length"'];
                                }
                            } catch(error){
                                _return = [-128, Utility.format('Buffer.alloc threw: %s', error)];
                            }
                        } else{
                            _return = [-64, 'Error: "ciphered_buffer" is either null or not a buffer.'];
                        }
                    } else{
                        _return = [-32, 'Error: "cipher" is either null or not an object.'];
                    }
                } catch(error){
                    _return = [-16, Utility.format('Crypto.createCipheriv threw: %s', error)];
                }
            } catch(error){
                _return = [-8, Utility.format('Crypto.randomBytes threw: %s', error)];
            }
        } else{
            _return = [-4, 'Error: "deciphered_object.multibase_digest" is either null or undefined.'];
        }

However, as I've discovered through brute-force testing, apparently, createCipheriv only accepts key and IV lengths of exactly 16 bytes; against the 32 bytes for the IV and 4096 bytes for the Scrypt-derived secret key, I initially planned on using:

        password = function_return[1];
        function_return = SaltFile.LoadSaltFile();
        if( function_return[0] === 0 ){
            try{
                scrypt_buffer = Crypto.scryptSync( password, function_return[1], 4096 );
                secret_keyobject = Crypto.createSecretKey( scrypt_buffer );
                if( secret_keyobject != null && typeof(secret_keyobject) === 'object' ){
                    _return = [0, secret_keyobject];
                } else{
                    _return = [-32, 'Error: "secret_keyobject" is either null or not an object.'];
                }
            } catch(error){
                _return = [-16,Utility.format('Crypto.scryptSync threw: %s', error)];
            }
        } else{
            _return = [function_return[0], 'SaltFile.LoadSaltFile: '+function_return[1]];
        }

Worst yet, neither of these size limits are mentioned in the documentation for createCipheriv: https://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options

So, really what I'm wondering is why: Why these arbitrary limits? Why have a crypto suite that forces the use ridiculously-weak keys that any old computer could brute force in a matter of minutes? Why aren't these caveats mentioned in the documentation? This 16-byte key limit seems so absurd to me and it makes the whole crypto module useless. Can this be circumvented by using a different algorithm or something? These limits don't make any sense....

Edit:

AES keys are 16, 24 and 32 bytes, which is 128, 192 and 256 bits respectively. The iv is always 16 bytes. That's the AES spec. (@jww)

Why are RSA keys commonly 4096 bits (512 bytes) but AES is capped at 32 bytes? Why is a bit entropy of 256 sufficient for AES but not RSA? What makes AES keys less susceptible to brute-force attacks than an RSA key?

If you want a 32-byte iv, then you need to switch to Rijndael. (@jww)

But I thought AES is Rijndael.

A brush-up on basic symmetric cryptography might help you determine why this question doesn't make much sense. (@Luke Joshua Park)

Really, not helpful; what reading on "basic symmetric cryptography" should I have done before asking this question? Obviously, I'm no expert, nor did I claim to be one, but, in what I have read about symmetric cryptography, it doesn't make sense that 128 bit key is sufficiently secure for AES but not RSA. If you want me to RTFM that's fine but where's this manual I was supposed to have read before asking this question? I was hoping somebody could explain why a key size of 16 bytes in secure despite that not making much intuitive sense.

Anadian
  • 3
  • 4
  • 1
    What? You could never brute-force a 16-byte AES key in your lifetime, with all the computers in the world. But I'm sure it accepts 32 byte keys since that's what aes-256 means. And the IV size is set by the AES block size which is 16 bytes. – President James K. Polk Jun 21 '19 at 02:45
  • *"... against the 32 bytes for the IV and 4096 bytes for the Scrypt-derived secret key"* - AES keys are 16, 24 and 32 bytes, which is 128, 192 and 256 bits respectively. The iv is always 16 bytes. That's the AES spec. You can't use a 32-byte iv, or an arbitrarily sized key. – jww Jun 21 '19 at 03:59
  • If you want a 32-byte iv, then you need to switch to Rijndael. But the key sizes are still 16, 24 and 32 bytes. You still cannot use an arbitrarily sized key. – jww Jun 21 '19 at 04:02
  • "But I thought AES is Rijndael." -- Almost, but no. AES is a specific case of Rijndael using a specific key size of 128, 192, or 256-bits. However in all cases of both AES and Rijndael, the block size is 128-bits. OTOH, one could generalise AES to make it larger block size, which would imply larger IV size (IV size = bock size), but neither would be "AES" or "Rijndael". – TheGreatContini Jun 26 '19 at 04:32
  • (So jww has this backwards: the block size and iv size are fixed for both AES and Rijndael, at 128-bits. The only difference between Rijndael and AES is that Rijndael allows many different key sizes, whereas AES restricts to the 3 sizes of 128-bit, 192-bit, and 256-bit). – TheGreatContini Jun 26 '19 at 04:46
  • @TheGreatContini That isn't actually correct - Rijndael can operate at 128, 192, and 256 bit *block* sizes. AES is the subset of Rijndael that only uses a 128 bit block size. – Luke Joshua Park Jul 24 '19 at 19:36
  • 1
    @LukeJoshuaPark It seems I am getting old. You are correct. – TheGreatContini Jul 28 '19 at 01:38

1 Answers1

3

Why have a crypto suite that forces the use of ridiculously weak keys that any old computer could brute-force in a matter of minutes?

You are severly underestimating how big a number 2^128 is. If you could try one trillion keys per second it would take you 10e18 years to try all keys, give or take. The universe is less than 14e9 years old. You see the problem.

AES keys (or more generally all keys for symmetric ciphers) are assumed to be chosen completely randomly. One key is as good as the other as long as the source of randomness is sufficiently unpredictable. Therefore there is no "clever" attack against the key. It's either exhaustive search of the keyspace, or attacking the algorithm itself (i.e. independently of any key).

RSA is a totally different story, namely asymmetric cryptography. The key cannot be chosen completely randomly. It is the result of a series of computations that start out with two numbers that have specific properties. This computation is reversible, at least in principle. In the case of RSA it's the well-known factorization problem (given a number find all of its prime factors). The chosen numbers must be large enough to make factorization impossible in any reasonable amount of time.

In summary, the key sizes for AES and RSA are not comparable whatsoever, because AES and RSA are very different cryptographic algorithms and the kinds of attacks on the respective keys are vastly different.

Peter
  • 29,454
  • 5
  • 48
  • 60
  • Agree with Peter but wanted to add that RSA is not attacked via brute force, but instead very clever algorithms (most notably the general number field sieve, but also elliptic curve factoring method) that take advantage of algebraic properties of integers. See: https://en.wikipedia.org/wiki/General_number_field_sieve . Such algorithms are sub-exponential (faster than exponential time but slower than polynomial) so are vastly faster than brute force attacks on algorithms like AES. AES has no algebraic structure that anybody knows how to exploit, which allows it to have smaller key sizes. – TheGreatContini Jun 26 '19 at 04:35