...

Source file src/gopkg.in/go-jose/go-jose.v2/cipher/ecdh_es.go

Documentation: gopkg.in/go-jose/go-jose.v2/cipher

     1  /*-
     2   * Copyright 2014 Square Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package josecipher
    18  
    19  import (
    20  	"bytes"
    21  	"crypto"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"encoding/binary"
    25  )
    26  
    27  // DeriveECDHES derives a shared encryption key using ECDH/ConcatKDF as described in JWE/JWA.
    28  // It is an error to call this function with a private/public key that are not on the same
    29  // curve. Callers must ensure that the keys are valid before calling this function. Output
    30  // size may be at most 1<<16 bytes (64 KiB).
    31  func DeriveECDHES(alg string, apuData, apvData []byte, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, size int) []byte {
    32  	if size > 1<<16 {
    33  		panic("ECDH-ES output size too large, must be less than or equal to 1<<16")
    34  	}
    35  
    36  	// algId, partyUInfo, partyVInfo inputs must be prefixed with the length
    37  	algID := lengthPrefixed([]byte(alg))
    38  	ptyUInfo := lengthPrefixed(apuData)
    39  	ptyVInfo := lengthPrefixed(apvData)
    40  
    41  	// suppPubInfo is the encoded length of the output size in bits
    42  	supPubInfo := make([]byte, 4)
    43  	binary.BigEndian.PutUint32(supPubInfo, uint32(size)*8)
    44  
    45  	if !priv.PublicKey.Curve.IsOnCurve(pub.X, pub.Y) {
    46  		panic("public key not on same curve as private key")
    47  	}
    48  
    49  	z, _ := priv.Curve.ScalarMult(pub.X, pub.Y, priv.D.Bytes())
    50  	zBytes := z.Bytes()
    51  
    52  	// Note that calling z.Bytes() on a big.Int may strip leading zero bytes from
    53  	// the returned byte array. This can lead to a problem where zBytes will be
    54  	// shorter than expected which breaks the key derivation. Therefore we must pad
    55  	// to the full length of the expected coordinate here before calling the KDF.
    56  	octSize := dSize(priv.Curve)
    57  	if len(zBytes) != octSize {
    58  		zBytes = append(bytes.Repeat([]byte{0}, octSize-len(zBytes)), zBytes...)
    59  	}
    60  
    61  	reader := NewConcatKDF(crypto.SHA256, zBytes, algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{})
    62  	key := make([]byte, size)
    63  
    64  	// Read on the KDF will never fail
    65  	_, _ = reader.Read(key)
    66  
    67  	return key
    68  }
    69  
    70  // dSize returns the size in octets for a coordinate on a elliptic curve.
    71  func dSize(curve elliptic.Curve) int {
    72  	order := curve.Params().P
    73  	bitLen := order.BitLen()
    74  	size := bitLen / 8
    75  	if bitLen%8 != 0 {
    76  		size++
    77  	}
    78  	return size
    79  }
    80  
    81  func lengthPrefixed(data []byte) []byte {
    82  	out := make([]byte, len(data)+4)
    83  	binary.BigEndian.PutUint32(out, uint32(len(data)))
    84  	copy(out[4:], data)
    85  	return out
    86  }
    87  

View as plain text