未加星标

PHP: rfc:improve_hash_hkdf_parameter

字体大小 | |
[开发(php) 所属分类 开发(php) | 发布者 店小二05 | 时间 2017 | 作者 红领巾 ] 0人收藏点击收藏
PHP RFC: Improve hash_hkdf() parameter order and handling

Version: 0.9

Create Date: 2017-02-05

Author: Yasuo Ohgaki [email protected]

Status: Draft (or Under Discussion or Accepted or Declined)

First Published at: http://wiki.php.net/rfc/improve_hash_hkdf_parameter

Introduction

HKDF is informational internet standard defined by RFC 5869 . HKDF is designed to generate secure key for encryption/validation/authentication/etc from other key information such as output from hash_password(), API KEY, etc. The RFC states “ designers of applications are therefore encouraged to provide salt values to HKDF if such values can be obtained by the application. ”, but currentphp implementation discourages “salt” parameter use by it signature.

This PHP RFC will not explain HKDF in detail, please refer to RFC 5869 or other references for details.

https://tools.ietf.org/html/rfc5869

https://en.wikipedia.org/wiki/Key_derivation_function

https://en.wikipedia.org/wiki/HKDF

Terms

IKM - Input Key Material which is secret.

salt - Some entropy value which could be both secret and non secret. Poor entropy like timestamp is acceptable when IKM is strong. Ideally random value of used hash size. Poor IKM example is user defined plain password.

info - Context and application specific information such as a protocol number, algorithm identifiers, user identities, etc. These are non secret values by definition.

length - Controls HKDF result length.

Typical HKDF usage with PHP would be:

Generate new encryption keys for user, session, domain, groups, etc, from “IKM”, “salt” and “info”.

Generate security tokens for CSRF protection, Object Access, etc, from e“IKM”, ““salt” and “info”.

hash_hkdf() is added to master without PHP RFC already. It has following signature currently.

string hash_hkdf(string algo, string ikm [, int length = 0 [, string info = '' [, string salt = '']]])

“salt” is the last optional parameter that user would omit blindly.

In most use cases, IKM is strong key. However, in real world, IKM could be user defined poor plain text password.

RFC 5869 “Notes for HKDF Users” states,

3.1. To Salt or not to Salt

HKDF is defined to operate with and without random salt. This is done to accommodate applications where a salt value is not available.We stress, however, that the use of salt adds significantly to the strength of HKDF , ensuring independence between different uses of the hash function, supporting “source-independent” extraction, and strengthening the analytical results that back the HKDF design.

Random salt differs fundamentally from the initial keying material in two ways: it is non-secret and can be re-used. As such, salt values are available to many applications. For example, a pseudorandom number generator (PRNG) that continuously produces outputs by applying HKDF to renewable pools of entropy (e.g., sampled system events) can fix a salt value and use it for multiple applications of HKDF without having to protect the secrecy of the salt. In a different application domain, a key agreement protocol deriving cryptographic keys from a Diffie-Hellman exchange can derive a salt value from public nonces exchanged and authenticated between communicating parties as part of the key agreement (this is the approach taken in [IKEv2]).

Ideally, the salt value is a random (or pseudorandom) string of the length HashLen. Yet, even a salt value of less quality (shorter in size or with limited entropy) may still make a significant contribution to the security of the output keying material; designers of applications are therefore encouraged to provide salt values to HKDF if such values can be obtained by the application.

It is worth noting that, while not the typical case, some applications may even have a secret salt value available for use; in such a case, HKDF provides an even stronger security guarantee. An example of such application is IKEv1 in its “public-key encryption mode”, where the “salt” to the extractor is computed from nonces that are secret; similarly, the pre-shared mode of IKEv1 uses a secret salt derived from the pre-shared key.

Primary purpose of “salt” is to generate stronger key from IKM by “salt” entropy.

3.2. The 'info' Input to HKDF

While the 'info' value is optional in the definition of HKDF, it is often of great importance in applications. Its main objective is to bind the derived key material to application- and context-specific information. For example, 'info' may contain a protocol number, algorithm identifiers, user identities, etc. In particular, it may prevent the derivation of the same keying material for different contexts (when the same input key material (IKM) is used in such different contexts). It may also accommodate additional inputs to the key expansion part, if so desired (e.g., an application may want to bind the key material to its length L, thus making L part of the 'info' field). There is one technical requirement from 'info': it should be independent of the input key material value IKM.

Primary purpose of “info” is to distinguish key context so that generated key is only usable to specific context.

The RFC describes “salt” as “ HKDF is defined to operate with and without random salt. This is done to accommodate applications where a salt value is not available. ”, “ salt adds significantly to the strength of HKDF ” and “ designers of applications are therefore encouraged to provide salt values to HKDF if such values can be obtained by the application. ” while “info” as optional and “ it is often of great importance in applications ”. It is obvious from the RFC “salt” is more important.

In short, if salt value can be used, users should use it whenever it is possible for better security.

hash_hkdf() behavior

md5() is used to obtains shorter result from hash_hkdf().

[[email protected] PHP-master]$ ./php-bin -r 'var_dump(bin2hex(hash_hkdf("md5","123456")));' string(32) "1a4f9cd30ab214082d93ba850f1fa2b0" [[email protected] PHP-master]$ ./php-bin -r 'var_dump(bin2hex(hash_hkdf("md5","123456", 20)));' string(40) "1a4f9cd30ab214082d93ba850f1fa2b054cfcd49" [[email protected] PHP-master]$ ./php-bin -r 'var_dump(bin2hex(hash_hkdf("md5","123456", 20, "1")));' string(40) "d0d1bbee08810d08a1e54f3a401308353cedd30b" [[email protected] PHP-master]$ ./php-bin -r 'var_dump(bin2hex(hash_hkdf("md5","123456", 20, "1", "1")));' string(40) "ca16de591ad40f02e599428bf9f50772ebead3ff"

The result is affected by both “salt” and “info” parameters. Although hash_hkdf() does complex hash calculations to derive secure key from IKM, salt and info, it seems simple hash calculation by using separate parameters from user point of view.

hash_hkdf() applications with PHP

Typical PHP HKDF application can be used with “salt”. Application can provide much better security with “salt”, added entropy. This PHP RFC only describes 2 examples here, but there are many PHP HKDF usages that can/should/must use with salt. Developers must consider salt use for better security rather than omitting salt without proper consideration. If it is possible, developers should use strong salt. When IKM is weak, developer must use strong salt to keep IKM security.

Please note that HKDF is designed for super secret key like master key for critical systems. There is nothing wrong to use with hash_password() generated string as input key like following examples.

Per user data encryption

Get the secret password hash generated by hash_password() for the user. $ikm

Get application secret salt stored in secure place. e.g. $_ENV $salt

Generate HKDF hash value with 1 and 2. hash_hkdf('sha256', $ikm, 0, '', $salt)

Encrypt the user data with the key from 3

Although “salt” can be omitted, per user data encryption can be much stronger for attacks with “salt”.

Suppose your application had SQL injection vulnerability and your data is stolen including password hash and encrypted user data. Secret encrypted data can be decrypted by attackers if “salt” is NOT used.

See also Security Note section blow. The same technique can be used for per user encryption key.

Other way to encrypt per user

Get system shared secret encryption key from secure place. $ikm

Get user ID which is unique in the system as context. $info

Generate HKDF hash value 1 and 2. hash_hkdf('sha256', $ikm, 0, $info)

Note that both method uses “secret” information for $ikm. However, there is notable difference between these 2. This method uses only 1 secret key (encryption key) and info (user ID) is known to public, one stolen key allows attackers to decrypt all encrypted data while previous method requires 2 secret information(password hash and secret salt) to attack. (In addition, attackers have to steal all users password hash)

See 'Other Use Cases' section for more examples.

CSRF token

When session ID is used for CSRF token, there is risk that session ID can leak to others by saving & sending HTML page, by malware web browser plugins that read page content, etc. Therefore, session ID should not be used as CSRF token. HKDF can be used to generate CSRF token belongs to specific session with “salt”.

Setting up CSRF token

Use session ID as secret key. ($ikm)

Get expiration timestamp. ($salt) Weak salt is OK, since session ID must be strong.

Generate HKDF value with 1 and 2. hash_hkdf('sha256', $ikm, 0, '', $salt)

Send key from 3 and timestamp from 2 to browser as CSRF token.

Verifying CSRF token

Get HKDF key and timestamp($salt) value from request.

Check if timestamp is not expired.

Generate HKDF value from session ID($ikm) and timestamp($salt). hash_hkdf('sha256', $ikm, 0, '', $salt)

Compare HKDF value sent by browser and server generated HKDF value if it matches.

Secure CSRF token expiration can be defined with this method regardless of session ID lifetime. i.e. You can set short CSRF token expiration securely.

Security Note

Developers must regenerate session ID periodically regardless of SSL usage for security reasons. Current OWASP recommends to regenerate rather short period. (Absolute timeout discussion is described in next section. OWASP seems updated the document since Enable session.use_strict_mode by default and Precise Session Management discussion, many aspects and issues are coverted by the OWASP document as problems.)

Common idle timeouts ranges are 2-5 minutes for high-value applications and 15- 30 minutes for low risk applications.

https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Session_Expiration

Therefore, use of session ID as CSRF token key source is not recommended. You are better to use separate key for CSRF token generation in $_SESSION. e.g. $_SESSION['CSRF_TOKEN_IKM'] = session_create_id(); Use secret $_SESSION['CSRF_TOKEN_IKM'] where above example uses session ID. With this method, you can generate secure HKDF CSRF token with your defined token expiration time even when session ID is regenerated in short period. Use of info parameter

“info” parameter may be used to specify generated key context. Context could be “admin”, “editor”, “user”, “visitor”, etc. For example, if “admin” is required for all administrative features, even when administrator's “user” context token is stolen, administrative features are protected from CSRF attacks.

Proposal

Change hash_hkdf() signature from

string hash_hkdf(string algo, string ikm [, int length = 0 [, string info = '' [, string salt = '']]])

to

string hash_hkdf(string algo, string ikm, string salt [, string info = '' [, int length = 0 [, bool raw = FALSE]]) - Return value: HEX string hash value by default, i.e. raw = FALSE - algo: Hash algorithm. e.g. "sha1", "sha256" - ikm: Secret Input Key Material. Some kind of key. e.g. Super secret master key, password, API key, etc. - salt: Secret or non secret salt value. Set NULL to use without salt, raise exception for empty string. e.g Random value such as nonce, timestamp, etc. - info: Generated key context. e.g Protocol number, user ID, group ID, applicable URI, etc. - length: Output length. If omitted, default output size of specified hash function.

Note: Parameter order and internal salt parameter handling is changed. i.e. Type and salt length check is changed. Make return HEX string by default by considering PHP use case and consistency for existing hash functions.

From user perspective, “salt” and “info” parameters could be used interchangeably. However, it would be good idea to follow RFC 5869 semantics. Unlike “info”(context) which could be an optional in many cases, “salt”(entropy) cannot be an optional with expiration enabled keys for instance. This kind of expiration is common. e.g. Amazon AWS S3 uses HKDF with expiration to allow access to objects.

Typical PHP applications that need HKDF can use (or should use) salt for security reasons as examples above. Users should consider if salt can be used or not. If salt could be secret, it should be kept as secret. Users shouldn't omit salt blindly. It could lead serious security issue. i.e. When input key is weak, input key can be guessed from hash_hkdf() output without salt. Salt makes derived keys considerably stronger.

Salt is better to be required parameter because typical PHP applications can supply salt. Salt should set to be empty only when salt cannot be used.

Salt summary for typical PHP HKDF usage:

Use salt always when it is possible.

Use strong salt if possible.

Use secret salt if possible.

When input key is weak, must use strong secret salt.

Omit salt only when salt cannot be used.

Omitting salt is likely to result in weaker implementation, see 'Other Use Cases' section.

Return value:

Most use cases with PHP will require string return values. Make it default.

HEX string return value and “raw” flag parameter is required to be consistent with existing hash functions.

Discussions

Salt is optional. - Salt could be optional, but it should be provided always whenever it is possible.

On Mon, Jan 16, 2017 at 8:16 PM, Andrey Andreev [email protected] wrote:

There's no comment from you on the PR, inline or not, but I can assure you this was not overlooked.

Salt is optional because RFC 5869 allows it to be optional. There's a reason for each of the current defaults work as they do, as well as the parameter positions:

- Length is in no way actually described as optional, and that makes sense as the function's purpose is to create cryptographic keys, which by nature have fixed lengths. The only reason we could make Length optional is because hash functions' output sizes are known values, and matching the desired OKM length with the hash function size makes for better performance.

- Info can be empty, but the algorithm is pretty much meaningless without it. The purpose of HKDF is to derive 2+ outputs from a single input, with the Info parameter serving as the differentiating factor.

- Salt is … while recommended, the only thing actually optional.

Incorrect argument. Salt could be optional, but as the RFC describes “salt” as “ salt adds significantly to the strength of HKDF ” and “ designers of applications are therefore encouraged to provide salt values to HKDF if such values can be obtained by the application. ”, “info” is actually optional. “Salt” should be used always whenever it is possible as the RFC recommends.

In any cases, 'info'(context) has less importance than 'salt'(entropy) at least.

On Mon, Jan 16, 2017 at 8:08 PM, Nikita Popov [email protected] wrote:

Making the salt required makes no sense to me.

HKDF has a number of different applications:

a) Derive multiple strong keys from strong keying material. Typical case for this is deriving independent encryption and authentication keys from a master key. This requires only specification of $length. A salt is neither necessary nor useful in this case, because you start with strong cryptographic keying material.

b) Generating per-session (or similar) keys from a (strong cryptographic) master key. For this purpose you can specify the $info parameter. again, a salt is neither necessary nor useful in this case. (You could probably also use $salt instead of $info in this case, but the design of the function implies that $info should be used for this purpose.)

c) Extracting strong cryptographic keying material from weak cryptographic keying material. Standard example here is extracting strong keys from DH g^xy values (which are non-uniform) and similar. This is the usage that benefits from a $salt.

d) Combinations thereof.

Remember that HKDF is an extract-and-expand algorithm, and the extract step (which uses the salt) is only necessary if the input keying material is weak. We always include the extract step for compatibility with the overall HKDF construction (per the RFCs recommendation), but it's essentially just an unnecessary operation if you work on strong keying material.

The only thing that we may want to discuss is whether we should swap the $info and the $salt parameters. This depends on which usage (b or c) we consider more likely.

a) When deriving keys, “salt” should be supplied whenever it's possible. Simply deriving other key w/o salt would not be typical, not recommended at least, usage with PHP because PHP is not used to implement basic cryptographic algorithms.

b) If I assume 'user identity' is used for “info”, then derived key wouldn't be “per session” key, but “per user” key. So assuming session ID is used as “info”. While it works, the RFC states “info” as are non secret information, i.e. “a protocol number, algorithm identifiers, user identities, etc.”. Session ID is secret key. We don't have to follow RFC recommendations always, but storing secret key in “info”(context) violates the RFC .

For per-session encryption/etc, simple choice for secret input key(IKM) would be per-session master key stored in $_SESSION, random string as “salt” which is a part of final key, optional “info”(context) could be used for additional information such as “confidential”,”public“, etc.

We are implementing RFC 5869. Not following the RFC recommendation does not make sense.

c) True, but “salt” is not only good for generating strong key from weak key according to the RFC . “salt” can be used as part of final key just like crypt() calculates password hash by “salt and password”.

d) True, but you seems to be missed “non secret salt” usage. 'Other Use Cases' section includes many “non secret salt” that are used as final key.

“ the extract step (which uses the salt) is only necessary if the input keying material is weak ”, this cannot be true by the RFC .

What the RFC states is

Yet, even a salt value of less quality (shorter in size or with limited entropy) may still make a significant contribution to the security of the output keying material

It does not say salt is only good for weak input keys, but generated key will have significantly better security.

Should not be used with weak key. - It is ok by HKDF definition.

On Sun, Feb 5, 2017 at 1:20 AM, Tom Worster [email protected] wrote: The salt defends against certain attacks on predictable input key material, i.e. weak passwords. But HKDF should not normally be used for passwords because it is unsuitable.

Strong key is prefered, but input key shouldn't not have to be strong. For weak keys, strong salt should be used though.

Other Use Cases

Following use case examples are using new hash_hkdf() signiture. $ikm could be any valid keys. Secret master key is assumed for convenience. Generally speaking, secret master key is difficult to maintain, developers are better to avoid it if it is possible.

As you can understand from bad examples, omitting salt is as optional parameter results in optimal implementation.

Create Strong Key From Weak Key For a User

Bad example first

Get plain text password. ($ikm)

Get random string to make strong password. ($info)

Generate encryption key. hash('sha256', $ikm, NULL, $info);

Although it works, developers shouldn't do this because $info is intended for context which is public information as per the RFC .

Correct way is

Get plain text password for user. ($ikm)

Get random string to make strong password. ($salt)

Generate encryption key. hash('sha256', $ikm, $salt);

Note: “salt” is intended to be secret or non secret as per the RFC .

Per User Encryption Key

Bad example first

Get secure secret master key. ($ikm)

Get user ID. ($info)

Generate encryption key. hash('sha256', $ikm, NULL, $info);

Developers shouldn't do this because once encryption key is stolen, they cannot issue new encryption key.

Correct way is

Get secure secret master key. ($ikm)

Generate secret or non secret random slat. ($salt) Save salt and provide salt as part of key to user also if it is needed.

Get user ID. ($info)

Generate encryption key. hash('sha256', $ikm, $salt, $info);

Developers can issue new encryption keys as many as they needed with this way for user.

Per Session Encryption Key

Bad example first

Get secure secret master key. ($ikm)

Get session ID. ($info)

Generate encryption key. hash('sha256', $ikm, NULL, $info);

Although it works, developers shouldn't do this because $info is intended for context(public information) as per the RFC .

Correct way is

Get secure secret master key. ($ikm)

Get session ID as secret salt. ($salt)

Generate encryption key. hash('sha256', $ikm, $salt);

URL access key

Bad example first

Get secure secret master key. ($ikm)

Get URL should be protected. ($info)

Generate access key. hash('sha256', $ikm, NULL, $info);

Developers shouldn't do this unless they are absolutely sure that URL is accessible with the generated key regardless of stolen key.

Better way is

Get secure secret master key. ($ikm)

Get random salt. ($salt) Save salt and provide salt as a part of key to user.

Get URL should be protected. ($info)

Generate encryption key. hash('sha256', $ikm, $salt, $info);

By keeping track valid $salt values, developers can control key validity.

Limited URL access key

Good example only

Get secure secret master key. ($ikm)

Get timestamp for access control as non secret salt. ($salt) Provide salt as a part of key.

Get URL should be protected. ($info) Accessed URL is known to server when user accesses it.

Generate access key. hash('sha256', $ikm, $salt, $info);

Any keys that have timeout can build similarly.

Generate Key with Timeout

Good example only

Get secure secret master key. ($ikm)

Get timestamp + random string for access control as non secret salt. ($salt) Provide salt as a part of key.

Generate access key. hash('sha256', $ikm, $salt);

Generate Key Whatever Purpose For a User

Bad example first

Get user's password information. ($ikm)

Get user ID. ($info)

Generate access key. hash('sha256', $ikm, NULL, $info);

Developers shouldn't do this because developers cannot issue new key for the user.

Better way is

Get user's password information. ($ikm)

Get random salt. ($salt) Save salt and provide salt as a part of key.

Generate access key. hash('sha256', $ikm, $salt);

By keeping track valid $salt values, developers can control key validity and can issue as many as new keys as needed.

Generate Key for Group

Good example only

Get secure secret master key. ($ikm)

Get random salt. ($salt) Save salt and provide salt as a part of key.

Get group ID. ($info)

Generate access key. hash('sha256', $ikm, $salt, $info);

By keeping track valid $salt values, developers can control key validity and can issue as many as new keys as needed.

Backward Incompatible Changes

None. hash_hkdf() is new function.

Proposed PHP Version(s)

Next PHP 7.x

RFC Impact

None.

Open Issues

Please comment if any.

Unaffected PHP Functionality

Nothing is affected. hash_hkdf() is new function does not affect any.

Future Scope

Please comment if any

Proposed Voting Choices

State whether this project requires a 2/3

Patches and Tests

TBD

Implementation

After the project is implemented, this section should contain

the version(s) it was merged to

a link to the git commit(s)

a link to the PHP manual entry for the feature

a link to the language specification section (if any)

References

Links to external references, discussions or RFCs

Rejected Features

Keep this updated with features that were discussed on the mail lists.

本文开发(php)相关术语:php代码审计工具 php开发工程师 移动开发者大会 移动互联网开发 web开发工程师 软件开发流程 软件开发工程师

主题: PHPSQLHTML
分页:12
转载请注明
本文标题:PHP: rfc:improve_hash_hkdf_parameter
本站链接:http://www.codesec.net/view/530992.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 开发(php) | 评论(0) | 阅读(44)