| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| /* Elliptic Curve API high-level functions */ |
| |
| package XXX |
| |
| //import "fmt" |
| import "github.com/milagro-crypto/amcl/version3/go/amcl" |
| |
| const INVALID_PUBLIC_KEY int = -2 |
| const ERROR int = -3 |
| const INVALID int = -4 |
| const EFS int = int(MODBYTES) |
| const EGS int = int(MODBYTES) |
| |
| /* Convert Integer to n-byte array */ |
| func inttoBytes(n int, len int) []byte { |
| var b []byte |
| var i int |
| for i = 0; i < len; i++ { |
| b = append(b, 0) |
| } |
| i = len |
| for n > 0 && i > 0 { |
| i-- |
| b[i] = byte(n & 0xff) |
| n /= 256 |
| } |
| return b |
| } |
| |
| func ehashit(sha int, A []byte, n int, B []byte, pad int) []byte { |
| var R []byte |
| if sha == amcl.SHA256 { |
| H := amcl.NewHASH256() |
| H.Process_array(A) |
| if n > 0 { |
| H.Process_num(int32(n)) |
| } |
| if B != nil { |
| H.Process_array(B) |
| } |
| R = H.Hash() |
| } |
| if sha == amcl.SHA384 { |
| H := amcl.NewHASH384() |
| H.Process_array(A) |
| if n > 0 { |
| H.Process_num(int32(n)) |
| } |
| if B != nil { |
| H.Process_array(B) |
| } |
| R = H.Hash() |
| } |
| if sha == amcl.SHA512 { |
| H := amcl.NewHASH512() |
| H.Process_array(A) |
| if n > 0 { |
| H.Process_num(int32(n)) |
| } |
| if B != nil { |
| H.Process_array(B) |
| } |
| R = H.Hash() |
| } |
| if R == nil { |
| return nil |
| } |
| |
| if pad == 0 { |
| return R |
| } |
| var W []byte |
| for i := 0; i < pad; i++ { |
| W = append(W, 0) |
| } |
| if pad <= sha { |
| for i := 0; i < pad; i++ { |
| W[i] = R[i] |
| } |
| } else { |
| for i := 0; i < sha; i++ { |
| W[i+pad-sha] = R[i] |
| } |
| for i := 0; i < pad-sha; i++ { |
| W[i] = 0 |
| } |
| } |
| return W |
| } |
| |
| /* Key Derivation Functions */ |
| /* Input octet Z */ |
| /* Output key of length olen */ |
| func ECDH_KDF1(sha int, Z []byte, olen int) []byte { |
| /* NOTE: the parameter olen is the length of the output K in bytes */ |
| hlen := sha |
| var K []byte |
| k := 0 |
| |
| for i := 0; i < olen; i++ { |
| K = append(K, 0) |
| } |
| |
| cthreshold := olen / hlen |
| if olen%hlen != 0 { |
| cthreshold++ |
| } |
| |
| for counter := 0; counter < cthreshold; counter++ { |
| B := ehashit(sha, Z, counter, nil, 0) |
| if k+hlen > olen { |
| for i := 0; i < olen%hlen; i++ { |
| K[k] = B[i] |
| k++ |
| } |
| } else { |
| for i := 0; i < hlen; i++ { |
| K[k] = B[i] |
| k++ |
| } |
| } |
| } |
| return K |
| } |
| |
| func ECDH_KDF2(sha int, Z []byte, P []byte, olen int) []byte { |
| /* NOTE: the parameter olen is the length of the output k in bytes */ |
| hlen := sha |
| var K []byte |
| k := 0 |
| |
| for i := 0; i < olen; i++ { |
| K = append(K, 0) |
| } |
| |
| cthreshold := olen / hlen |
| if olen%hlen != 0 { |
| cthreshold++ |
| } |
| |
| for counter := 1; counter <= cthreshold; counter++ { |
| B := ehashit(sha, Z, counter, P, 0) |
| if k+hlen > olen { |
| for i := 0; i < olen%hlen; i++ { |
| K[k] = B[i] |
| k++ |
| } |
| } else { |
| for i := 0; i < hlen; i++ { |
| K[k] = B[i] |
| k++ |
| } |
| } |
| } |
| return K |
| } |
| |
| /* Password based Key Derivation Function */ |
| /* Input password p, salt s, and repeat count */ |
| /* Output key of length olen */ |
| func ECDH_PBKDF2(sha int, Pass []byte, Salt []byte, rep int, olen int) []byte { |
| d := olen / sha |
| if olen%sha != 0 { |
| d++ |
| } |
| |
| var F []byte |
| var U []byte |
| var S []byte |
| var K []byte |
| |
| for i := 0; i < sha; i++ { |
| F = append(F, 0) |
| U = append(U, 0) |
| } |
| |
| for i := 1; i <= d; i++ { |
| for j := 0; j < len(Salt); j++ { |
| S = append(S, Salt[j]) |
| } |
| N := inttoBytes(i, 4) |
| for j := 0; j < 4; j++ { |
| S = append(S, N[j]) |
| } |
| |
| HMAC(sha, S, Pass, F[:]) |
| |
| for j := 0; j < sha; j++ { |
| U[j] = F[j] |
| } |
| for j := 2; j <= rep; j++ { |
| HMAC(sha, U[:], Pass, U[:]) |
| for k := 0; k < sha; k++ { |
| F[k] ^= U[k] |
| } |
| } |
| for j := 0; j < sha; j++ { |
| K = append(K, F[j]) |
| } |
| } |
| var key []byte |
| for i := 0; i < olen; i++ { |
| key = append(key, K[i]) |
| } |
| return key |
| } |
| |
| /* Calculate HMAC of m using key k. HMAC is tag of length olen (which is length of tag) */ |
| func HMAC(sha int, M []byte, K []byte, tag []byte) int { |
| /* Input is from an octet m * |
| * olen is requested output length in bytes. k is the key * |
| * The output is the calculated tag */ |
| var B []byte |
| b := 64 |
| if sha > 32 { |
| b = 128 |
| } |
| |
| var K0 [128]byte |
| olen := len(tag) |
| |
| if olen < 4 { |
| return 0 |
| } |
| |
| for i := 0; i < b; i++ { |
| K0[i] = 0 |
| } |
| |
| if len(K) > b { |
| B = ehashit(sha, K, 0, nil, 0) |
| for i := 0; i < sha; i++ { |
| K0[i] = B[i] |
| } |
| } else { |
| for i := 0; i < len(K); i++ { |
| K0[i] = K[i] |
| } |
| } |
| |
| for i := 0; i < b; i++ { |
| K0[i] ^= 0x36 |
| } |
| B = ehashit(sha, K0[0:b], 0, M, 0) |
| |
| for i := 0; i < b; i++ { |
| K0[i] ^= 0x6a |
| } |
| B = ehashit(sha, K0[0:b], 0, B, olen) |
| |
| for i := 0; i < olen; i++ { |
| tag[i] = B[i] |
| } |
| |
| return 1 |
| } |
| |
| /* AES encryption/decryption. Encrypt byte array M using key K and returns ciphertext */ |
| func AES_CBC_IV0_ENCRYPT(K []byte, M []byte) []byte { /* AES CBC encryption, with Null IV and key K */ |
| /* Input is from an octet string M, output is to an octet string C */ |
| /* Input is padded as necessary to make up a full final block */ |
| a := amcl.NewAES() |
| fin := false |
| |
| var buff [16]byte |
| var C []byte |
| |
| a.Init(amcl.AES_CBC, len(K), K, nil) |
| |
| ipt := 0 //opt:=0 |
| var i int |
| for true { |
| for i = 0; i < 16; i++ { |
| if ipt < len(M) { |
| buff[i] = M[ipt] |
| ipt++ |
| } else { |
| fin = true |
| break |
| } |
| } |
| if fin { |
| break |
| } |
| a.Encrypt(buff[:]) |
| for i = 0; i < 16; i++ { |
| C = append(C, buff[i]) |
| } |
| } |
| |
| /* last block, filled up to i-th index */ |
| |
| padlen := 16 - i |
| for j := i; j < 16; j++ { |
| buff[j] = byte(padlen) |
| } |
| |
| a.Encrypt(buff[:]) |
| |
| for i = 0; i < 16; i++ { |
| C = append(C, buff[i]) |
| } |
| a.End() |
| return C |
| } |
| |
| /* returns plaintext if all consistent, else returns null string */ |
| func AES_CBC_IV0_DECRYPT(K []byte, C []byte) []byte { /* padding is removed */ |
| a := amcl.NewAES() |
| var buff [16]byte |
| var MM []byte |
| var M []byte |
| |
| var i int |
| ipt := 0 |
| opt := 0 |
| |
| a.Init(amcl.AES_CBC, len(K), K, nil) |
| |
| if len(C) == 0 { |
| return nil |
| } |
| ch := C[ipt] |
| ipt++ |
| |
| fin := false |
| |
| for true { |
| for i = 0; i < 16; i++ { |
| buff[i] = ch |
| if ipt >= len(C) { |
| fin = true |
| break |
| } else { |
| ch = C[ipt] |
| ipt++ |
| } |
| } |
| a.Decrypt(buff[:]) |
| if fin { |
| break |
| } |
| for i = 0; i < 16; i++ { |
| MM = append(MM, buff[i]) |
| opt++ |
| } |
| } |
| |
| a.End() |
| bad := false |
| padlen := int(buff[15]) |
| if i != 15 || padlen < 1 || padlen > 16 { |
| bad = true |
| } |
| if padlen >= 2 && padlen <= 16 { |
| for i = 16 - padlen; i < 16; i++ { |
| if buff[i] != byte(padlen) { |
| bad = true |
| } |
| } |
| } |
| |
| if !bad { |
| for i = 0; i < 16-padlen; i++ { |
| MM = append(MM, buff[i]) |
| opt++ |
| } |
| } |
| |
| if bad { |
| return nil |
| } |
| |
| for i = 0; i < opt; i++ { |
| M = append(M, MM[i]) |
| } |
| |
| return M |
| } |
| |
| /* Calculate a public/private EC GF(p) key pair W,S where W=S.G mod EC(p), |
| * where S is the secret key and W is the public key |
| * and G is fixed generator. |
| * If RNG is NULL then the private key is provided externally in S |
| * otherwise it is generated randomly internally */ |
| func ECDH_KEY_PAIR_GENERATE(RNG *amcl.RAND, S []byte, W []byte) int { |
| res := 0 |
| var s *BIG |
| var G *ECP |
| |
| G = ECP_generator() |
| |
| r := NewBIGints(CURVE_Order) |
| |
| if RNG == nil { |
| s = FromBytes(S) |
| s.Mod(r) |
| } else { |
| s = Randomnum(r, RNG) |
| } |
| |
| s.ToBytes(S) |
| |
| WP := G.mul(s) |
| |
| WP.ToBytes(W, false) // To use point compression on public keys, change to true |
| |
| return res |
| } |
| |
| /* validate public key */ |
| func ECDH_PUBLIC_KEY_VALIDATE(W []byte) int { |
| WP := ECP_fromBytes(W) |
| res := 0 |
| |
| r := NewBIGints(CURVE_Order) |
| |
| if WP.Is_infinity() { |
| res = INVALID_PUBLIC_KEY |
| } |
| if res == 0 { |
| |
| q := NewBIGints(Modulus) |
| nb := q.nbits() |
| k := NewBIGint(1) |
| k.shl(uint((nb + 4) / 2)) |
| k.add(q) |
| k.div(r) |
| |
| for k.parity() == 0 { |
| k.shr(1) |
| WP.dbl() |
| } |
| |
| if !k.isunity() { |
| WP = WP.mul(k) |
| } |
| if WP.Is_infinity() { |
| res = INVALID_PUBLIC_KEY |
| } |
| |
| } |
| return res |
| } |
| |
| /* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */ |
| func ECDH_ECPSVDP_DH(S []byte, WD []byte, Z []byte) int { |
| res := 0 |
| var T [EFS]byte |
| |
| s := FromBytes(S) |
| |
| W := ECP_fromBytes(WD) |
| if W.Is_infinity() { |
| res = ERROR |
| } |
| |
| if res == 0 { |
| r := NewBIGints(CURVE_Order) |
| s.Mod(r) |
| W = W.mul(s) |
| if W.Is_infinity() { |
| res = ERROR |
| } else { |
| W.GetX().ToBytes(T[:]) |
| for i := 0; i < EFS; i++ { |
| Z[i] = T[i] |
| } |
| } |
| } |
| return res |
| } |
| |
| /* IEEE ECDSA Signature, C and D are signature on F using private key S */ |
| func ECDH_ECPSP_DSA(sha int, RNG *amcl.RAND, S []byte, F []byte, C []byte, D []byte) int { |
| var T [EFS]byte |
| |
| B := ehashit(sha, F, 0, nil, int(MODBYTES)) |
| G := ECP_generator() |
| |
| r := NewBIGints(CURVE_Order) |
| |
| s := FromBytes(S) |
| f := FromBytes(B[:]) |
| |
| c := NewBIGint(0) |
| d := NewBIGint(0) |
| V := NewECP() |
| |
| for d.iszilch() { |
| u := Randomnum(r, RNG) |
| w := Randomnum(r, RNG) /* side channel masking */ |
| V.Copy(G) |
| V = V.mul(u) |
| vx := V.GetX() |
| c.copy(vx) |
| c.Mod(r) |
| if c.iszilch() { |
| continue |
| } |
| u.copy(Modmul(u, w, r)) |
| u.Invmodp(r) |
| d.copy(Modmul(s, c, r)) |
| d.add(f) |
| d.copy(Modmul(d, w, r)) |
| d.copy(Modmul(u, d, r)) |
| } |
| |
| c.ToBytes(T[:]) |
| for i := 0; i < EFS; i++ { |
| C[i] = T[i] |
| } |
| d.ToBytes(T[:]) |
| for i := 0; i < EFS; i++ { |
| D[i] = T[i] |
| } |
| return 0 |
| } |
| |
| /* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */ |
| func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { |
| res := 0 |
| |
| B := ehashit(sha, F, 0, nil, int(MODBYTES)) |
| |
| G := ECP_generator() |
| r := NewBIGints(CURVE_Order) |
| |
| c := FromBytes(C) |
| d := FromBytes(D) |
| f := FromBytes(B[:]) |
| |
| if c.iszilch() || Comp(c, r) >= 0 || d.iszilch() || Comp(d, r) >= 0 { |
| res = INVALID |
| } |
| |
| if res == 0 { |
| d.Invmodp(r) |
| f.copy(Modmul(f, d, r)) |
| h2 := Modmul(c, d, r) |
| |
| WP := ECP_fromBytes(W) |
| if WP.Is_infinity() { |
| res = ERROR |
| } else { |
| P := NewECP() |
| P.Copy(WP) |
| |
| P = P.Mul2(h2, G, f) |
| |
| if P.Is_infinity() { |
| res = INVALID |
| } else { |
| d = P.GetX() |
| d.Mod(r) |
| |
| if Comp(d, c) != 0 { |
| res = INVALID |
| } |
| } |
| } |
| } |
| |
| return res |
| } |
| |
| /* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */ |
| func ECDH_ECIES_ENCRYPT(sha int, P1 []byte, P2 []byte, RNG *amcl.RAND, W []byte, M []byte, V []byte, T []byte) []byte { |
| var Z [EFS]byte |
| var VZ [3*EFS + 1]byte |
| var K1 [AESKEY]byte |
| var K2 [AESKEY]byte |
| var U [EGS]byte |
| |
| if ECDH_KEY_PAIR_GENERATE(RNG, U[:], V) != 0 { |
| return nil |
| } |
| if ECDH_ECPSVDP_DH(U[:], W, Z[:]) != 0 { |
| return nil |
| } |
| |
| for i := 0; i < 2*EFS+1; i++ { |
| VZ[i] = V[i] |
| } |
| for i := 0; i < EFS; i++ { |
| VZ[2*EFS+1+i] = Z[i] |
| } |
| |
| K := ECDH_KDF2(sha, VZ[:], P1, 2*AESKEY) |
| |
| for i := 0; i < AESKEY; i++ { |
| K1[i] = K[i] |
| K2[i] = K[AESKEY+i] |
| } |
| |
| C := AES_CBC_IV0_ENCRYPT(K1[:], M) |
| |
| L2 := inttoBytes(len(P2), 8) |
| |
| var AC []byte |
| |
| for i := 0; i < len(C); i++ { |
| AC = append(AC, C[i]) |
| } |
| for i := 0; i < len(P2); i++ { |
| AC = append(AC, P2[i]) |
| } |
| for i := 0; i < 8; i++ { |
| AC = append(AC, L2[i]) |
| } |
| |
| HMAC(sha, AC, K2[:], T) |
| |
| return C |
| } |
| |
| /* constant time n-byte compare */ |
| func ncomp(T1 []byte, T2 []byte, n int) bool { |
| res := 0 |
| for i := 0; i < n; i++ { |
| res |= int(T1[i] ^ T2[i]) |
| } |
| if res == 0 { |
| return true |
| } |
| return false |
| } |
| |
| /* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */ |
| func ECDH_ECIES_DECRYPT(sha int, P1 []byte, P2 []byte, V []byte, C []byte, T []byte, U []byte) []byte { |
| var Z [EFS]byte |
| var VZ [3*EFS + 1]byte |
| var K1 [AESKEY]byte |
| var K2 [AESKEY]byte |
| |
| var TAG []byte = T[:] |
| |
| if ECDH_ECPSVDP_DH(U, V, Z[:]) != 0 { |
| return nil |
| } |
| |
| for i := 0; i < 2*EFS+1; i++ { |
| VZ[i] = V[i] |
| } |
| for i := 0; i < EFS; i++ { |
| VZ[2*EFS+1+i] = Z[i] |
| } |
| |
| K := ECDH_KDF2(sha, VZ[:], P1, 2*AESKEY) |
| |
| for i := 0; i < AESKEY; i++ { |
| K1[i] = K[i] |
| K2[i] = K[AESKEY+i] |
| } |
| |
| M := AES_CBC_IV0_DECRYPT(K1[:], C) |
| |
| if M == nil { |
| return nil |
| } |
| |
| L2 := inttoBytes(len(P2), 8) |
| |
| var AC []byte |
| |
| for i := 0; i < len(C); i++ { |
| AC = append(AC, C[i]) |
| } |
| for i := 0; i < len(P2); i++ { |
| AC = append(AC, P2[i]) |
| } |
| for i := 0; i < 8; i++ { |
| AC = append(AC, L2[i]) |
| } |
| |
| HMAC(sha, AC, K2[:], TAG) |
| |
| if !ncomp(T, TAG, len(T)) { |
| return nil |
| } |
| |
| return M |
| } |