Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openssl_cipher_iv_length #22304

Closed
lagden opened this issue Aug 14, 2018 · 10 comments
Closed

openssl_cipher_iv_length #22304

lagden opened this issue Aug 14, 2018 · 10 comments
Labels
crypto Issues and PRs related to the crypto subsystem. feature request Issues that request new features to be added to Node.js.

Comments

@lagden
Copy link

lagden commented Aug 14, 2018

I see some issues about invalid IV length or Invalid key length.
In PHP, there is a helper method (openssl_cipher_iv_length) that return the correct length for IV.

Node could have a static method for this, something like:

  • crypto.cipherivLength(algorithm: string): number
  • crypto.cipherkeyLength(algorithm: string): number

Simple example:

const ivLen = crypto.cipherivLength('des-ede3-ofb') // => 8
const keyLen = crypto.cipherkeyLength('des-ede3-ofb') // => 24

Complex example:

'use strict'

const assert = require('assert').strict
const crypto = require('crypto')

const SALT = 'foobar'

function genKey(alg) {
	const keyLen = 24 // => crypto.cipherkeyLength(alg)
	const hash = crypto.createHash('sha256').update(SALT).digest()
	return hash.slice(0, keyLen)
}

function encrypt(value, alg = 'des-ede3-ofb') {
	const ivLen = 8 // => crypto.cipherivLength(alg)
	const iv = crypto.randomBytes(ivLen)
	const key = genKey(alg)
	const cipher = crypto.createCipheriv(alg, key, iv, {authTagLength: ivLen})
	const encryptedUpdate = cipher.update(value)
	const encryptedFinal = cipher.final()
	const encrypted = Buffer.concat([encryptedUpdate, encryptedFinal], encryptedUpdate.byteLength + encryptedFinal.byteLength)
	return [encrypted, iv]
}

function decrypt([encrypted, iv], alg = 'des-ede3-ofb') {
	const ivLen = iv.byteLength
	const key = genKey(alg)
	const cipher = crypto.createDecipheriv(alg, key, iv, {authTagLength: ivLen})
	const decryptedUpdate = cipher.update(encrypted)
	const decryptedFinal = cipher.final()
	return Buffer.concat([decryptedUpdate, decryptedFinal], decryptedUpdate.byteLength + decryptedFinal.byteLength)
}

// Testing
const input = 'test'
const output = decrypt(encrypt(input)).toString('utf8')
assert.strictEqual(input, output) // => OK
@Trott
Copy link
Member

Trott commented Aug 14, 2018

@nodejs/security-wg (proposed new API, I don't think there's any security implications but being cautious)

@maclover7 maclover7 added crypto Issues and PRs related to the crypto subsystem. feature request Issues that request new features to be added to Node.js. labels Aug 14, 2018
@tniessen
Copy link
Member

What about ciphers such as CCM or OCB that don't have a single fixed IV length?

@Trott
Copy link
Member

Trott commented Nov 22, 2018

@nodejs/crypto Is this something we'd consider adding? If likely not, should this be closed?

@tniessen
Copy link
Member

@Trott I can see that this might be useful. However, there is no single correct IV length for some ciphers. I believe OpenSSL simply returns the shortest permitted length.

@mcollina
Copy link
Member

I think this could be a nice addition. Is this easy information to get from openssl?

@sam-github
Copy link
Contributor

Even a minimum would be useful. It doesn't seem reasonable that an API can return "length invalid", and yet somehow not know what lengths are valid. I'll take a look at this when I have some time.

@bnoordhuis
Copy link
Member

Is this easy information to get from openssl?

EVP_CIPHER_key_length() and EVP_CIPHER_iv_length(). The latter returns 0 for ciphers that don't take an IV (ECB mode ciphers, RC4, maybe more.)

Even a minimum would be useful.

I don't know. What business do you have using a cipher if you don't know its key size or IV size? Adding functions to help automate key/IV creation seems like setting up people to shoot themselves in the foot.

(Same argument goes for the block size, that currently isn't exposed either. Anyone want to argue that it should be?)

Take the OP's example code. If it derived the key/IV size automatically and you tricked it into picking RC4-40, you can guess the key in at most 2^40 tries. Foot, meet bullet.

@tniessen
Copy link
Member

I don't know. What business do you have using a cipher if you don't know its key size or IV size? Adding functions to help automate key/IV creation seems like setting up people to shoot themselves in the foot.

I share this concern.

@sam-github
Copy link
Contributor

What business do you have using a cipher if you don't know its key size or IV size?

Example, a file encryption tool where the user specifies the file, algorithm, and a pass phrase, and the utility runs the PBKDF, generates the key, creates a random sufficiently large IV, and writes CMS encrypted data to disk.

The tool could have a data structure of acceptable algorithms, and with each alg keep its key size, its IV size, etc. But if OpenSSL already includes this, why duplicate this into user-land?

@lagden
Copy link
Author

lagden commented Nov 26, 2018

In Go lang we have a helper: https://golang.org/pkg/crypto/aes/ (BlockSize)
In PHP we have a helper: http://php.net/manual/en/function.openssl-cipher-iv-length.php

...and why not in Node.js?

I don't know. What business do you have using a cipher if you don't know its key size or IV size? Adding functions to help automate key/IV creation seems like setting up people to shoot themselves in the foot.

I have one
In my app, the user can choose which cipher he want use to chat with another person
So, I had to make a small map (key/IV) for that, but I'd like to make like in Golang: iv := ciphertext[:aes.BlockSize]

@tniessen tniessen reopened this Nov 26, 2018
jasnell added a commit to jasnell/node that referenced this issue Oct 10, 2020
Simple method for retrieving basic information about a cipher
(such as block length, expected or default iv length, key length,
etc)

Signed-off-by: James M Snell <jasnell@gmail.com>
Fixes: nodejs#22304
joesepi pushed a commit to joesepi/node that referenced this issue Jan 8, 2021
Simple method for retrieving basic information about a cipher
(such as block length, expected or default iv length, key length,
etc)

Signed-off-by: James M Snell <jasnell@gmail.com>
Fixes: nodejs#22304

PR-URL: nodejs#35368
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crypto Issues and PRs related to the crypto subsystem. feature request Issues that request new features to be added to Node.js.
Projects
None yet
Development

No branches or pull requests

7 participants