ecdh_es.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  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. package josecipher
  17. import (
  18. "crypto"
  19. "crypto/ecdsa"
  20. "encoding/binary"
  21. )
  22. // DeriveECDHES derives a shared encryption key using ECDH/ConcatKDF as described in JWE/JWA.
  23. // It is an error to call this function with a private/public key that are not on the same
  24. // curve. Callers must ensure that the keys are valid before calling this function. Output
  25. // size may be at most 1<<16 bytes (64 KiB).
  26. func DeriveECDHES(alg string, apuData, apvData []byte, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, size int) []byte {
  27. if size > 1<<16 {
  28. panic("ECDH-ES output size too large, must be less than or equal to 1<<16")
  29. }
  30. // algId, partyUInfo, partyVInfo inputs must be prefixed with the length
  31. algID := lengthPrefixed([]byte(alg))
  32. ptyUInfo := lengthPrefixed(apuData)
  33. ptyVInfo := lengthPrefixed(apvData)
  34. // suppPubInfo is the encoded length of the output size in bits
  35. supPubInfo := make([]byte, 4)
  36. binary.BigEndian.PutUint32(supPubInfo, uint32(size)*8)
  37. if !priv.PublicKey.Curve.IsOnCurve(pub.X, pub.Y) {
  38. panic("public key not on same curve as private key")
  39. }
  40. z, _ := priv.PublicKey.Curve.ScalarMult(pub.X, pub.Y, priv.D.Bytes())
  41. reader := NewConcatKDF(crypto.SHA256, z.Bytes(), algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{})
  42. key := make([]byte, size)
  43. // Read on the KDF will never fail
  44. _, _ = reader.Read(key)
  45. return key
  46. }
  47. func lengthPrefixed(data []byte) []byte {
  48. out := make([]byte, len(data)+4)
  49. binary.BigEndian.PutUint32(out, uint32(len(data)))
  50. copy(out[4:], data)
  51. return out
  52. }