-
Notifications
You must be signed in to change notification settings - Fork 61
is my code constant time?
Sun Yimin edited this page Feb 2, 2024
·
18 revisions
Non-constant time crypto code is dangerous.
- Dude, is my code constant time?
- proposal: math/big: support for constant-time arithmetic
- crypto/elliptic: deprecate big.Int interface
- proposal: a new crypto/ecdh package that exposes a safe, []byte-based API for ECDH
- cmd/compile: use devirtualization in escape analysis
- cmd/compile: inlining after devirtualization
- crypto/elliptic: automatically upgrade CurveParams for known curves and deprecate custom ones
- PLANNING GO 1.20 CRYPTOGRAPHY WORK
- crypto/internal/bigmod: add amd64 assembly core
- The Marvin Attack
- CVE-2023-45287 Detail
- Vulnerability Report: GO-2023-2375
SM2 Key Exchange要去除big.Int依赖,看起来比ECDH困难得多,主要是第三、四和五步。
来自ipp-crypto的实现可供参考,待十月份取消golang 1.15后再考虑实现一个用于TLCP的不用big.Int的SM2 Key Exchange。
/**
* @brief
* reduction for the SM2 Key Exchange standard
* x` = 2^w + (x & (2^w – 1))
* when
* w = log2(n)/2 - 1, n - number bytes order
* @param[out] r reduction value x`
* @param[in] a value x
* @param[in] pEC context Elliptic Curve
*/
__INLINE void cpSM2KE_reduction_x2w(BNU_CHUNK_T *r, const BNU_CHUNK_T *a, const IppsGFpECState *pEC)
{
const gsModEngine *pME = GFP_PMA(ECP_GFP(pEC));
const int elemBits = GFP_FEBITLEN(pME); /* size Bits */
const int elemSize = GFP_FELEN(pME); /* size BNU_CHUNK */
/* compute w = [log2(n)/2 - 1] */
const int w = ((elemBits + 1) / 2 - 1);
/* compute copy BNU_CHUNK */
const int num_copy_bc = (w + (BNU_CHUNK_BITS - 1)) / BNU_CHUNK_BITS; // 2, 假定BNU_CHUNK_BITS=64
const int num_bit_shift = (w - (num_copy_bc - 1) * BNU_CHUNK_BITS); // 63
const BNU_CHUNK_T vadd = (BNU_CHUNK_T)(1ULL << num_bit_shift); // 1<<63 = 0x8000000000000000
const BNU_CHUNK_T mask = (BNU_CHUNK_T)(vadd - 1); // 0x7fffffffffffffff
ZEXPAND_COPY_BNU(r, elemSize, a, num_copy_bc); // copy 2 64 bits from a to r
r[num_copy_bc - 1] = (r[num_copy_bc - 1] & mask) + vadd;
return;
}
相对而言,第四步计算tB运算需要实现素数为Order n的montgomery运算:
- 纯golang可以通过代码生成。
- amd64/arm64,至少需要实现加法,乘法已经有了。
type Curve interface {
// ECDH performs a ECDH exchange and returns the shared secret.
//
// For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
// Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
// Version 2.0, Section 2.3.5. In particular, if the result is the point at
// infinity, ECDH returns an error. (Note that for NIST curves, that's only
// possible if the private key is the all-zero value.)
//
// For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If
// the result is the all-zero value, ECDH returns an error.
ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error)
// SM2MQV performs a SM2 specific style ECMQV exchange and return the shared secret.
SM2MQV(sLocal, eLocal *PrivateKey, sRemote, eRemote *PublicKey) (*PublicKey, error)
// SM2SharedKey performs SM2 key derivation to generate shared keying data, the uv was generated by SM2MQV.
SM2SharedKey(isResponder bool, kenLen int, uv, sPub, sRemote *PublicKey, uid []byte, remoteUID []byte) ([]byte, error)
// GenerateKey generates a new PrivateKey from rand.
GenerateKey(rand io.Reader) (*PrivateKey, error)
// NewPrivateKey checks that key is valid and returns a PrivateKey.
//
// For NIST curves, this follows SEC 1, Version 2.0, Section 2.3.6, which
// amounts to decoding the bytes as a fixed length big endian integer and
// checking that the result is lower than the order of the curve. The zero
// private key is also rejected, as the encoding of the corresponding public
// key would be irregular.
//
// For X25519, this only checks the scalar length. Adversarially selected
// private keys can cause ECDH to return an error.
NewPrivateKey(key []byte) (*PrivateKey, error)
// NewPublicKey checks that key is valid and returns a PublicKey.
//
// For NIST curves, this decodes an uncompressed point according to SEC 1,
// Version 2.0, Section 2.3.4. Compressed encodings and the point at
// infinity are rejected.
//
// For X25519, this only checks the u-coordinate length. Adversarially
// selected public keys can cause ECDH to return an error.
NewPublicKey(key []byte) (*PublicKey, error)
// privateKeyToPublicKey converts a PrivateKey to a PublicKey. It's exposed
// as the PrivateKey.PublicKey method.
//
// This method always succeeds: for X25519, it might output the all-zeroes
// value (unlike the ECDH method); for NIST curves, it would only fail for
// the zero private key, which is rejected by NewPrivateKey.
//
// The private method also allow us to expand the ECDH interface with more
// methods in the future without breaking backwards compatibility.
privateKeyToPublicKey(*PrivateKey) *PublicKey
}
其实,sm2 key exchange和SEC 1, Version 2.0, Section 3.4 Elliptic Curve MQV Primitive 描述的方法类似,只是最后取shared secret方法不同: ECMQV和DH一样,都只取X轴值。
https://github.com/emmansun/gmsm/commit/8f7a7626baba61ba9c44371a71cd8bec0dbedc6f