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

Fix secretKey bigger than curve order and stack smashing in ECP mul #41

Merged
merged 2 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions blscurve/bls_signature_scheme.nim
Original file line number Diff line number Diff line change
Expand Up @@ -513,11 +513,7 @@ func keyGen*(ikm: openarray[byte], publicKey: var PublicKey, secretKey: var Secr
var prk: MDigest[sha256.bits]

# 1. PRK = HKDF-Extract("BLS-SIG-KEYGEN-SALT-", IKM)
ctx.hkdfExtract(
prk,
cast[ptr byte](salt[0].unsafeAddr), salt.len.uint,
ikm[0].unsafeAddr, ikm.len.uint
)
ctx.hkdfExtract(prk, salt, ikm)

# curve order r = 52435875175126190479447740508185965837690552500527637822603658699938581184513
# const L = ceil((1.5 * ceil(log2(r))) / 8) = 48
Expand All @@ -526,17 +522,18 @@ func keyGen*(ikm: openarray[byte], publicKey: var PublicKey, secretKey: var Secr
# 2. OKM = HKDF-Expand(PRK, "", L)
const L = 48
var okm: array[L, byte]
ctx.hkdfExpand(prk, nil, 0, okm[0].addr, L)
ctx.hkdfExpand(prk, "", okm)

# 3. x = OS2IP(OKM) mod r
# 5. SK = x
if not secretKey.intVal.fromBytes(okm):
var dseckey: DBIG_384
if not dseckey.fromBytes(okm):
return false

{.noSideEffect.}:
BIG_384_mod(secretKey.intVal, CURVE_Order)
BIG_384_dmod(secretKey.intVal, dseckey, CURVE_Order)

# 4. xP = x * P
# 6. PK = point_to_pubkey(xP)
publicKey = privToPub(secretKey)

return true
35 changes: 16 additions & 19 deletions blscurve/hash_to_curve.nim
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ import

func hashToBaseFP2[T](
ctx: var HMAC[T],
msg: ptr byte, msgLen: uint,
msg: ptr byte, msgLen: int,
ctr: range[0'i8 .. 2'i8],
domainSepTag: ptr byte,
domainSepTagLen: uint
domainSepTag: string,
): FP2_BLS381 =
## Implementation of hash_to_base for the G2 curve of BLS12-381
## https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-04#section-5.3
Expand Down Expand Up @@ -84,7 +83,10 @@ func hashToBaseFP2[T](
# with an extra null-byte beyond the declared length.
assert not msg.isNil
assert cast[ptr UncheckedArray[byte]](msg)[msgLen] == 0x00, "Expected message terminated by nul-byte but found " & $cast[ptr UncheckedArray[byte]](msg)[msgLen] & " (decimal value)"
hkdfExtract(ctx, mprime, domainSepTag, domainSepTagLen, msg, msgLen+1)
hkdfExtract(
ctx, mprime, domainSepTag,
toOpenArray(cast[ptr UncheckedArray[byte]](msg), 0, msgLen) # msgLen inclusive
)

info[0] = ord'H'
info[1] = ord'2'
Expand All @@ -96,7 +98,7 @@ func hashToBaseFP2[T](
## for i in 1 .. m
## with m = 2 (extension degree of FP2)
info[4] = byte(i)
hkdfExpand(ctx, mprime, info[0].addr, info.len.uint, t[0].addr, t.len.uint)
hkdfExpand(ctx, mprime, info, t)

block: # HKDF output is greater than 384-bit (64 bytes = 512-bit)
# and need to be stored and reduced in a DBIG
Expand Down Expand Up @@ -404,13 +406,13 @@ func clearCofactor(P: var ECP2_BLS381) =

P.affine() # Convert from Jacobian coordinates (x', y', z') to affine (x, y, 1); (x is not the curve parameter here)

func hashToG2(msg: ptr byte, msgLen: uint, domainSepTag: ptr byte, domainSepTagLen: uint): ECP2_BLS381 =
func hashToG2(msg: ptr byte, msgLen: int, domainSepTag: string): ECP2_BLS381 =
## Hash an arbitrary message to the G2 curve of BLS12-381
## The message should have an extra null byte after its declared length
var ctx: HMAC[sha256]

let u0 = hashToBaseFP2(ctx, msg, msgLen, ctr = 0, domainSepTag, domainSepTagLen)
let u1 = hashToBaseFP2(ctx, msg, msgLen, ctr = 1, domainSepTag, domainSepTagLen)
let u0 = hashToBaseFP2(ctx, msg, msgLen, ctr = 0, domainSepTag)
let u1 = hashToBaseFP2(ctx, msg, msgLen, ctr = 1, domainSepTag)

result = mapToCurveG2(u0)
let Q1 = mapToCurveG2(u1)
Expand All @@ -427,31 +429,27 @@ func hashToG2*(msg: openarray[byte], domainSepTag: string): ECP2_BLS381 =
msgWithNul[0 ..< msg.len] = msg
msgWithNul[msg.len] = 0x00

let
pmsg = cast[ptr byte](msgWithNul[0].unsafeAddr)
pdst = cast[ptr byte](domainSepTag[0].unsafeAddr)
let pmsg = cast[ptr byte](msgWithNul[0].unsafeAddr)

hashToG2(pmsg, msg.len.uint, pdst, domainSepTag.len.uint)
hashToG2(pmsg, msg.len, domainSepTag)

func hashToG2*(message, domainSepTag: string): ECP2_BLS381 =
## Hash an arbitrary message to the G2 curve of BLS12-381
## The message should have an extra null byte

let pdst = cast[ptr byte](domainSepTag[0].unsafeAddr)

if message.len == 0:
# Special-casing empty strings (i.e. not constant-time)
# is not an issue because empty strings are always vulnerable
# to timing attacks.
var empty = [byte 0x00]
let pmsg = cast[ptr byte](empty[0].unsafeAddr)
result = hashToG2(pmsg, 0, pdst, domainSepTag.len.uint)
result = hashToG2(pmsg, 0, domainSepTag)
else:
# Strings are always nul-terminated in Nim so don't need
# extra nul appending compared to openarray[byte]
# to satisfy the spec requirements
let pmsg = cast[ptr byte](message[0].unsafeAddr)
result = hashToG2(pmsg, message.len.uint, pdst, domainSepTag.len.uint)
result = hashToG2(pmsg, message.len, domainSepTag)

# Unofficial test vectors for hashToG2 primitives
# ----------------------------------------------------------------------
Expand Down Expand Up @@ -490,15 +488,14 @@ when isMainModule:

let pmsg = if msg.len == 0: nil
else: cast[ptr byte](msg[0].unsafeAddr)
let pdst = cast[ptr byte](dst[0].unsafeAddr)

var ctx: HMAC[sha256]
# Important: do we need to include the null byte at the end?
let pointFP2 = hashToBaseFP2(
ctx,
pmsg, msg.len.uint,
pmsg, msg.len,
ctr,
pdst, dst.len.uint
dst
)
doAssert fp2 == pointFP2
echo "Success hashToBaseFP2 ", astToStr(id)
Expand Down
55 changes: 29 additions & 26 deletions blscurve/hkdf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -80,49 +80,48 @@

import nimcrypto/hmac

func hkdfExtract*[T](ctx: var HMAC[T],
func hkdfExtract*[T;S,I: char|byte](ctx: var HMAC[T],
prk: var MDigest[T.bits],
salt: ptr byte, saltLen: uint,
ikm: ptr byte, ikmLen: uint
salt: openArray[S],
ikm: openArray[I]
) =
## "Extract" step of HKDF.
## Extract a fixed size pseudom-random key
## from an optional salt value
## and a secret input keying material.
##
## Inputs:
## - salt + saltLen: a buffer to an optional salt value (set to nil if unused)
## - ikm + ikmLen: "input keying material", the secret value to hash.
## - salt: a buffer to an optional salt value (set to nil if unused)
## - ikm: "input keying material", the secret value to hash.
##
## Output:
## - prk: a pseudo random key of fixed size. The size is the same as the cryptographic hash chosen.
##
## Temporary:
## - ctx: a HMAC["cryptographic-hash"] context, for example HMAC[sha256].
mixin init, update, finish
ctx.init(salt, saltLen)
ctx.update(ikm, ikmLen)
ctx.init(salt)
ctx.update(ikm)
discard ctx.finish(prk.data)

# ctx.clear() - TODO: very expensive

func hkdfExpand*[T](ctx: var HMAC[T],
func hkdfExpand*[T;I: char|byte](ctx: var HMAC[T],
prk: MDigest[T.bits],
info: ptr byte, infoLen: uint,
output: ptr byte, outLen: uint
info: openArray[I],
output: var openArray[byte]
) =
## "Expand" step of HKDF
## Expand a fixed size pseudo random-key
## into several pseudo-random keys
##
## Inputs:
## - prk: a pseudo random key (PRK) of fixed size. The size is the same as the cryptographic hash chosen.
## - info + infolen: optional context and application specific information (set to nil if unused)
## - outLen: The target length of the output
## - info: optional context and application specific information (set to nil if unused)
##
## Output:
## - output: OKM (output keying material). The PRK is expanded to match
## outLen, the result is tored in output.
## the output length, the result is tored in output.
##
## Temporary:
## - ctx: a HMAC["cryptographic-hash"] context, for example HMAC[sha256].
Expand All @@ -131,23 +130,23 @@ func hkdfExpand*[T](ctx: var HMAC[T],
const HashLen = T.bits div 8

static: doAssert T.bits >= 0
# assert outLen <= 255*HashLen
# assert output.len <= 255*HashLen

let N = outLen div HashLen
let N = output.len div HashLen
var t: MDigest[T.bits]
let oArray = cast[ptr UncheckedArray[byte]](output)

for i in 0'u .. N:
for i in 0 .. N:
ctx.init(prk.data)
# T(0) = empty string
if i != 0:
ctx.update(t.data)
ctx.update(info, infoLen)
ctx.update(info)
ctx.update([uint8(i+1)])
discard ctx.finish(t.data)

let iStart = i * HashLen
let size = min(HashLen, int(outLen - iStart))
let size = min(HashLen, output.len - iStart)
copyMem(oArray[iStart].addr, t.data.addr, size)

# ctx.clear() - TODO: very expensive
Expand Down Expand Up @@ -178,15 +177,19 @@ when isMainModule:
var ctx: HMAC[HashType]
var prk: MDigest[HashType.bits]

let salt = if bsalt.len == 0: nil
else: bsalt[0].unsafeAddr
let ikm = if bikm.len == 0: nil
else: bikm[0].unsafeAddr
let info = if binfo.len == 0: nil
else: binfo[0].unsafeAddr
# let salt = if bsalt.len == 0: nil
# else: bsalt[0].unsafeAddr
# let ikm = if bikm.len == 0: nil
# else: bikm[0].unsafeAddr
# let info = if binfo.len == 0: nil
# else: binfo[0].unsafeAddr
let
salt = bsalt
ikm = bikm
info = binfo

hkdfExtract(ctx, prk, salt, bsalt.len.uint, ikm, bikm.len.uint)
hkdfExpand(ctx, prk, info, binfo.len.uint, output[0].addr, output.len.uint)
hkdfExtract(ctx, prk, salt, ikm)
hkdfExpand(ctx, prk, info, output)

doAssert @(prk.data) == bprk, "\nComputed 0x" & toHex(prk.data) &
"\nbut expected " & PRK & '\n'
Expand Down